diff --git a/core/common/base/src/main/java/com/buzbuz/smartautoclicker/core/base/extensions/Random.kt b/core/common/base/src/main/java/com/buzbuz/smartautoclicker/core/base/extensions/Random.kt index 15a1529f0..93ddb1376 100644 --- a/core/common/base/src/main/java/com/buzbuz/smartautoclicker/core/base/extensions/Random.kt +++ b/core/common/base/src/main/java/com/buzbuz/smartautoclicker/core/base/extensions/Random.kt @@ -22,7 +22,7 @@ import android.graphics.RectF import kotlin.random.Random fun Random.nextFloat(from: Float, until: Float): Float = - (until - from) * nextFloat() + (until - from) * nextFloat() + from fun Random.nextPositionIn(area: RectF): PointF = PointF(nextFloat(area.left, area.right), nextFloat(area.top, area.bottom)) diff --git a/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/domain/model/data/subject/quickclickgame/QuickClickGameTargetType.kt b/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/domain/model/data/subject/quickclickgame/QuickClickGameTargetType.kt index c37c02c11..fed91cd58 100644 --- a/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/domain/model/data/subject/quickclickgame/QuickClickGameTargetType.kt +++ b/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/domain/model/data/subject/quickclickgame/QuickClickGameTargetType.kt @@ -25,6 +25,8 @@ package com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subje enum class QuickClickGameTargetType { IMAGE_BLUE, IMAGE_RED, + IMAGE_GREEN, + IMAGE_YELLOW, NUMBER, TEXT_DAY, TEXT_GOODBYE, diff --git a/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/domain/model/monitoring/MonitoredViewType.kt b/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/domain/model/monitoring/MonitoredViewType.kt index f88824607..d2621b678 100644 --- a/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/domain/model/monitoring/MonitoredViewType.kt +++ b/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/domain/model/monitoring/MonitoredViewType.kt @@ -18,6 +18,8 @@ package com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring enum class MonitoredViewType { ACTION_TYPE_DIALOG_CLICK_ACTION, + ACTION_TYPE_DIALOG_COUNTER_ACTION, + ACTION_TYPE_DIALOG_TOGGLE_EVENT_ACTION, ACTIONS_BRIEF_FIRST_ITEM, ACTIONS_BRIEF_MENU_BUTTON_CREATE_ACTION, ACTIONS_BRIEF_MENU_BUTTON_SAVE, @@ -29,15 +31,25 @@ enum class MonitoredViewType { CONDITIONS_BRIEF_FIRST_ITEM, CONDITIONS_BRIEF_MENU_BUTTON_CREATE, CONDITIONS_BRIEF_MENU_BUTTON_SAVE, + COUNTER_ACTION_DIALOG_BUTTON_SAVE, + COUNTER_ACTION_DIALOG_FIELD_SELECT_COUNTER, + COUNTER_REACHED_DIALOG_BUTTON_SAVE, + COUNTER_REACHED_DIALOG_FIELD_COUNTER_SELECTION, + COUNTER_SELECTION_DIALOG_BUTTON_CREATE, EVENT_DIALOG_BUTTON_SAVE, EVENT_DIALOG_FIELD_ACTIONS, EVENT_DIALOG_FIELD_CONDITIONS, + EVENT_DIALOG_FIELD_INITIAL_STATE, EVENT_DIALOG_FIELD_OPERATOR_ITEM_AND, + EVENT_DIALOG_FIELD_OPERATOR_ITEM_OR, MAIN_MENU_BUTTON_CONFIG, MAIN_MENU_BUTTON_PLAY, SCENARIO_DIALOG_BUTTON_CREATE_EVENT, SCENARIO_DIALOG_BUTTON_SAVE, SCENARIO_DIALOG_ITEM_FIRST_EVENT, + SCENARIO_DIALOG_ITEM_SECOND_EVENT, + SCENARIO_DIALOG_ITEM_THIRD_EVENT, + SCENARIO_DIALOG_ITEM_FOURTH_EVENT, SCENARIO_DIALOG_TRIGGER_EVENT_TAB, SCREEN_CONDITION_CAPTURE_MENU_BUTTON_CAPTURE, @@ -56,6 +68,7 @@ enum class MonitoredViewType { TEXT_CONDITION_DIALOG_FIELD_TEXT_TO_DETECT, TIMER_REACHED_CONDITION_BUTTON_SAVE, + TOGGLE_EVENT_DIALOG_SELECT_TOGGLES, TIMER_REACHED_CONDITION_FIELD_AFTER, TIMER_REACHED_CONDITION_FIELD_RESTART, diff --git a/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/step/TutorialStepStartConditionMonitor.kt b/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/step/TutorialStepStartConditionMonitor.kt index a9e72a166..61742c536 100644 --- a/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/step/TutorialStepStartConditionMonitor.kt +++ b/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/step/TutorialStepStartConditionMonitor.kt @@ -44,7 +44,7 @@ internal class TutorialStepStartConditionMonitor @Inject constructor( fun monitorCondition( condition: TutorialStepStartCondition, subjectController: TutorialSubjectController, - onConditionReached: () -> Unit + onConditionReached: () -> Unit, ) = when (condition) { is TutorialStepStartCondition.MonitoredViewClicked -> { @@ -56,7 +56,15 @@ internal class TutorialStepStartConditionMonitor @Inject constructor( is TutorialStepStartCondition.MonitoredOverlayDisplayed -> { stepConditionMonitoringJob = coroutineScopeIo.launch { + // If we already are on the overlay wanted, we want to user to go away and then go back + val currentTop = overlayManager.getBackStackTop() + var awaitingCurrentLeave = currentTop?.tutorialMonitoringTag() == condition.type.name + overlayManager.backStackTopFlow.collect { newTop -> + if (awaitingCurrentLeave && condition.type.name == newTop?.tutorialMonitoringTag()) + return@collect + + awaitingCurrentLeave = false if (condition.type.name != newTop?.tutorialMonitoringTag()) return@collect onConditionReached() @@ -74,23 +82,25 @@ internal class TutorialStepStartConditionMonitor @Inject constructor( TutorialStepStartCondition.GameLost -> (subjectController as? QuickClickGameEngine)?.monitorNextCompletion { isWon -> - if (isWon) return@monitorNextCompletion + if (isWon) return@monitorNextCompletion false onConditionReached() + true } TutorialStepStartCondition.GameWon -> (subjectController as? QuickClickGameEngine)?.monitorNextCompletion { isWon -> - if (!isWon) return@monitorNextCompletion + if (!isWon) return@monitorNextCompletion false onConditionReached() + true } TutorialStepStartCondition.Immediate -> onConditionReached() - is TutorialStepStartCondition.MonitoredNumberInput -> - monitoredViewsManager.monitorNumber(condition.type, condition.expectedNumber) { - onConditionReached() - } + is TutorialStepStartCondition.MonitoredNumberInput -> + monitoredViewsManager.monitorNumber(condition.type, condition.expectedNumber) { + onConditionReached() + } } fun stopMonitoring(condition: TutorialStepStartCondition, subjectController: TutorialSubjectController) { diff --git a/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/subject/QuickClickGameEngine.kt b/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/subject/QuickClickGameEngine.kt index 3baea40b4..7be912382 100644 --- a/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/subject/QuickClickGameEngine.kt +++ b/core/common/tutorial/src/main/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/subject/QuickClickGameEngine.kt @@ -45,7 +45,7 @@ internal class QuickClickGameEngine ( private val coroutineScopeIo: CoroutineScope = CoroutineScope(SupervisorJob() + ioDispatcher) private var gameJob: Job? = null - private var onGameCompleted: ((isWon: Boolean) -> Unit)? = null + private var onGameCompleted: ((isWon: Boolean) -> Boolean)? = null private val _state: MutableStateFlow = MutableStateFlow(defaultState()) @@ -94,8 +94,9 @@ internal class QuickClickGameEngine ( targets = emptyMap() ) } - onGameCompleted?.invoke(isWon) - onGameCompleted = null + + val consumed = onGameCompleted?.invoke(isWon) ?: true + if (consumed) onGameCompleted = null gameJob = null } } @@ -103,6 +104,7 @@ internal class QuickClickGameEngine ( override fun stop() { Log.d(TAG, "Stop game") + onGameCompleted = null gameJob?.cancel() gameJob = null @@ -119,7 +121,7 @@ internal class QuickClickGameEngine ( } } - fun monitorNextCompletion(listener: ((isWon: Boolean) -> Unit)?) { + fun monitorNextCompletion(listener: ((isWon: Boolean) -> Boolean)?) { onGameCompleted = listener } diff --git a/core/common/tutorial/src/test/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/step/TutorialStepStartConditionMonitorTest.kt b/core/common/tutorial/src/test/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/step/TutorialStepStartConditionMonitorTest.kt new file mode 100644 index 000000000..159b37020 --- /dev/null +++ b/core/common/tutorial/src/test/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/step/TutorialStepStartConditionMonitorTest.kt @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.core.common.tutorial.impl.engine.step + +import android.os.Build + +import com.buzbuz.smartautoclicker.core.common.overlays.base.Overlay +import com.buzbuz.smartautoclicker.core.common.overlays.manager.OverlayManager +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.TutorialSubjectController +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepStartCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredOverlayType +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType +import com.buzbuz.smartautoclicker.core.common.tutorial.impl.engine.subject.QuickClickGameEngine +import com.buzbuz.smartautoclicker.core.common.tutorial.impl.monitoring.MonitoredViewsManagerImpl + +import io.mockk.every +import io.mockk.mockk +import io.mockk.slot +import io.mockk.verify + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.UnconfinedTestDispatcher + +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.eq +import org.mockito.kotlin.verify as mockitoVerify +import org.mockito.kotlin.whenever +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@ExperimentalCoroutinesApi +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [Build.VERSION_CODES.Q]) +class TutorialStepStartConditionMonitorTest { + + @Mock private lateinit var mockOverlayManager: OverlayManager + @Mock private lateinit var mockMonitoredViewsManager: MonitoredViewsManagerImpl + @Mock private lateinit var mockOverlay: Overlay + + /** Used for conditions that don't need a game engine. */ + private val mockSubjectController: TutorialSubjectController = mockk(relaxed = true) + + /** Concrete game engine mock — must be used when the condition casts to QuickClickGameEngine. */ + private val mockGameEngine: QuickClickGameEngine = mockk(relaxed = true) + + private val backStackTopFlow = MutableStateFlow(null) + + private lateinit var monitor: TutorialStepStartConditionMonitor + private lateinit var mockCloseable: AutoCloseable + + @Before + fun setUp() { + mockCloseable = MockitoAnnotations.openMocks(this) + whenever(mockOverlayManager.backStackTopFlow).thenReturn(backStackTopFlow) + whenever(mockOverlayManager.getBackStackTop()).thenReturn(null) + + monitor = TutorialStepStartConditionMonitor( + ioDispatcher = UnconfinedTestDispatcher(), + monitoredViewsManager = mockMonitoredViewsManager, + overlayManager = mockOverlayManager, + ) + } + + @After + fun tearDown() { + mockCloseable.close() + } + + // --- Immediate --- + + @Test + fun `monitorCondition Immediate calls onConditionReached immediately`() { + var reached = false + monitor.monitorCondition(TutorialStepStartCondition.Immediate, mockSubjectController) { reached = true } + assertEquals(true, reached) + } + + @Test + fun `stopMonitoring Immediate does nothing`() { + monitor.stopMonitoring(TutorialStepStartCondition.Immediate, mockSubjectController) + // no crash expected + } + + // --- MonitoredViewClicked --- + + @Test + fun `monitorCondition MonitoredViewClicked registers click listener`() { + val condition = TutorialStepStartCondition.MonitoredViewClicked(MonitoredViewType.MAIN_MENU_BUTTON_PLAY) + val listenerCaptor = argumentCaptor<() -> Unit>() + + monitor.monitorCondition(condition, mockSubjectController) {} + + mockitoVerify(mockMonitoredViewsManager).monitorNextClick(eq(MonitoredViewType.MAIN_MENU_BUTTON_PLAY), listenerCaptor.capture()) + } + + @Test + fun `monitorCondition MonitoredViewClicked listener triggers onConditionReached`() { + val condition = TutorialStepStartCondition.MonitoredViewClicked(MonitoredViewType.MAIN_MENU_BUTTON_PLAY) + val listenerCaptor = argumentCaptor<() -> Unit>() + var reached = false + + monitor.monitorCondition(condition, mockSubjectController) { reached = true } + mockitoVerify(mockMonitoredViewsManager).monitorNextClick(eq(MonitoredViewType.MAIN_MENU_BUTTON_PLAY), listenerCaptor.capture()) + listenerCaptor.firstValue.invoke() + + assertEquals(true, reached) + } + + @Test + fun `stopMonitoring MonitoredViewClicked stops click monitoring`() { + val condition = TutorialStepStartCondition.MonitoredViewClicked(MonitoredViewType.MAIN_MENU_BUTTON_PLAY) + monitor.stopMonitoring(condition, mockSubjectController) + mockitoVerify(mockMonitoredViewsManager).stopNextClickMonitoring(MonitoredViewType.MAIN_MENU_BUTTON_PLAY) + } + + // --- MonitoredTextInput --- + + @Test + fun `monitorCondition MonitoredTextInput registers text listener`() { + val condition = TutorialStepStartCondition.MonitoredTextInput( + type = MonitoredViewType.TEXT_CONDITION_DIALOG_FIELD_TEXT_TO_DETECT, + expectedText = "hello", + ) + val listenerCaptor = argumentCaptor<() -> Unit>() + + monitor.monitorCondition(condition, mockSubjectController) {} + + mockitoVerify(mockMonitoredViewsManager).monitorText( + eq(MonitoredViewType.TEXT_CONDITION_DIALOG_FIELD_TEXT_TO_DETECT), + eq("hello"), + listenerCaptor.capture(), + ) + } + + @Test + fun `monitorCondition MonitoredTextInput listener triggers onConditionReached`() { + val condition = TutorialStepStartCondition.MonitoredTextInput( + type = MonitoredViewType.TEXT_CONDITION_DIALOG_FIELD_TEXT_TO_DETECT, + expectedText = "hello", + ) + val listenerCaptor = argumentCaptor<() -> Unit>() + var reached = false + + monitor.monitorCondition(condition, mockSubjectController) { reached = true } + mockitoVerify(mockMonitoredViewsManager).monitorText(any(), any(), listenerCaptor.capture()) + listenerCaptor.firstValue.invoke() + + assertEquals(true, reached) + } + + @Test + fun `stopMonitoring MonitoredTextInput stops monitoring`() { + val condition = TutorialStepStartCondition.MonitoredTextInput( + type = MonitoredViewType.TEXT_CONDITION_DIALOG_FIELD_TEXT_TO_DETECT, + expectedText = "hello", + ) + monitor.stopMonitoring(condition, mockSubjectController) + mockitoVerify(mockMonitoredViewsManager).stopMonitoring(MonitoredViewType.TEXT_CONDITION_DIALOG_FIELD_TEXT_TO_DETECT) + } + + // --- MonitoredNumberInput --- + + @Test + fun `monitorCondition MonitoredNumberInput registers number listener`() { + val condition = TutorialStepStartCondition.MonitoredNumberInput( + type = MonitoredViewType.NUMBER_CONDITION_DIALOG_FIELD_VALUE_TO_DETECT, + expectedNumber = 42.0, + ) + val listenerCaptor = argumentCaptor<() -> Unit>() + + monitor.monitorCondition(condition, mockSubjectController) {} + + mockitoVerify(mockMonitoredViewsManager).monitorNumber( + eq(MonitoredViewType.NUMBER_CONDITION_DIALOG_FIELD_VALUE_TO_DETECT), + eq(42.0), + listenerCaptor.capture(), + ) + } + + @Test + fun `monitorCondition MonitoredNumberInput listener triggers onConditionReached`() { + val condition = TutorialStepStartCondition.MonitoredNumberInput( + type = MonitoredViewType.NUMBER_CONDITION_DIALOG_FIELD_VALUE_TO_DETECT, + expectedNumber = 42.0, + ) + val listenerCaptor = argumentCaptor<() -> Unit>() + var reached = false + + monitor.monitorCondition(condition, mockSubjectController) { reached = true } + mockitoVerify(mockMonitoredViewsManager).monitorNumber(any(), any(), listenerCaptor.capture()) + listenerCaptor.firstValue.invoke() + + assertEquals(true, reached) + } + + @Test + fun `stopMonitoring MonitoredNumberInput stops monitoring`() { + val condition = TutorialStepStartCondition.MonitoredNumberInput( + type = MonitoredViewType.NUMBER_CONDITION_DIALOG_FIELD_VALUE_TO_DETECT, + expectedNumber = 42.0, + ) + monitor.stopMonitoring(condition, mockSubjectController) + mockitoVerify(mockMonitoredViewsManager).stopMonitoring(MonitoredViewType.NUMBER_CONDITION_DIALOG_FIELD_VALUE_TO_DETECT) + } + + // --- GameWon --- + + @Test + fun `monitorCondition GameWon calls onConditionReached when game is won`() { + val listenerSlot = slot<((Boolean) -> Boolean)?>() + every { mockGameEngine.monitorNextCompletion(captureNullable(listenerSlot)) } returns Unit + var reached = false + + monitor.monitorCondition(TutorialStepStartCondition.GameWon, mockGameEngine) { reached = true } + listenerSlot.captured?.invoke(true) + + assertEquals(true, reached) + } + + @Test + fun `monitorCondition GameWon returns true when consumed`() { + val listenerSlot = slot<((Boolean) -> Boolean)?>() + every { mockGameEngine.monitorNextCompletion(captureNullable(listenerSlot)) } returns Unit + + monitor.monitorCondition(TutorialStepStartCondition.GameWon, mockGameEngine) {} + val consumed = listenerSlot.captured?.invoke(true) + + assertEquals(true, consumed) + } + + @Test + fun `monitorCondition GameWon does not call onConditionReached when game is lost`() { + val listenerSlot = slot<((Boolean) -> Boolean)?>() + every { mockGameEngine.monitorNextCompletion(captureNullable(listenerSlot)) } returns Unit + var reached = false + + monitor.monitorCondition(TutorialStepStartCondition.GameWon, mockGameEngine) { reached = true } + listenerSlot.captured?.invoke(false) + + assertEquals(false, reached) + } + + @Test + fun `monitorCondition GameWon returns false when not consumed`() { + val listenerSlot = slot<((Boolean) -> Boolean)?>() + every { mockGameEngine.monitorNextCompletion(captureNullable(listenerSlot)) } returns Unit + + monitor.monitorCondition(TutorialStepStartCondition.GameWon, mockGameEngine) {} + val consumed = listenerSlot.captured?.invoke(false) + + assertEquals(false, consumed) + } + + @Test + fun `stopMonitoring GameWon clears game completion listener`() { + monitor.stopMonitoring(TutorialStepStartCondition.GameWon, mockGameEngine) + verify { mockGameEngine.monitorNextCompletion(null) } + } + + // --- GameLost --- + + @Test + fun `monitorCondition GameLost calls onConditionReached when game is lost`() { + val listenerSlot = slot<((Boolean) -> Boolean)?>() + every { mockGameEngine.monitorNextCompletion(captureNullable(listenerSlot)) } returns Unit + var reached = false + + monitor.monitorCondition(TutorialStepStartCondition.GameLost, mockGameEngine) { reached = true } + listenerSlot.captured?.invoke(false) + + assertEquals(true, reached) + } + + @Test + fun `monitorCondition GameLost returns true when consumed`() { + val listenerSlot = slot<((Boolean) -> Boolean)?>() + every { mockGameEngine.monitorNextCompletion(captureNullable(listenerSlot)) } returns Unit + + monitor.monitorCondition(TutorialStepStartCondition.GameLost, mockGameEngine) {} + val consumed = listenerSlot.captured?.invoke(false) + + assertEquals(true, consumed) + } + + @Test + fun `monitorCondition GameLost does not call onConditionReached when game is won`() { + val listenerSlot = slot<((Boolean) -> Boolean)?>() + every { mockGameEngine.monitorNextCompletion(captureNullable(listenerSlot)) } returns Unit + var reached = false + + monitor.monitorCondition(TutorialStepStartCondition.GameLost, mockGameEngine) { reached = true } + listenerSlot.captured?.invoke(true) + + assertEquals(false, reached) + } + + @Test + fun `monitorCondition GameLost returns false when not consumed`() { + val listenerSlot = slot<((Boolean) -> Boolean)?>() + every { mockGameEngine.monitorNextCompletion(captureNullable(listenerSlot)) } returns Unit + + monitor.monitorCondition(TutorialStepStartCondition.GameLost, mockGameEngine) {} + val consumed = listenerSlot.captured?.invoke(true) + + assertEquals(false, consumed) + } + + @Test + fun `stopMonitoring GameLost clears game completion listener`() { + monitor.stopMonitoring(TutorialStepStartCondition.GameLost, mockGameEngine) + verify { mockGameEngine.monitorNextCompletion(null) } + } + + // --- MonitoredOverlayDisplayed: normal case (not already on overlay) --- + + @Test + fun `monitorCondition MonitoredOverlayDisplayed triggers when expected overlay appears`() { + val overlayType = MonitoredOverlayType.SCENARIO + whenever(mockOverlayManager.getBackStackTop()).thenReturn(null) + whenever(mockOverlay.tutorialMonitoringTag()).thenReturn(overlayType.name) + + var reached = false + monitor.monitorCondition( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) { reached = true } + + backStackTopFlow.value = mockOverlay + + assertEquals(true, reached) + } + + @Test + fun `monitorCondition MonitoredOverlayDisplayed does not trigger for unrelated overlay`() { + val overlayType = MonitoredOverlayType.SCENARIO + val otherOverlay = org.mockito.Mockito.mock(Overlay::class.java) + whenever(mockOverlayManager.getBackStackTop()).thenReturn(null) + whenever(otherOverlay.tutorialMonitoringTag()).thenReturn(MonitoredOverlayType.EVENT.name) + + var reached = false + monitor.monitorCondition( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) { reached = true } + + backStackTopFlow.value = otherOverlay + + assertEquals(false, reached) + } + + // --- MonitoredOverlayDisplayed: already on the expected overlay (new use case) --- + + @Test + fun `monitorCondition MonitoredOverlayDisplayed does not trigger immediately when already on expected overlay`() { + val overlayType = MonitoredOverlayType.SCENARIO + whenever(mockOverlayManager.getBackStackTop()).thenReturn(mockOverlay) + whenever(mockOverlay.tutorialMonitoringTag()).thenReturn(overlayType.name) + backStackTopFlow.value = mockOverlay + + var reached = false + monitor.monitorCondition( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) { reached = true } + + assertEquals(false, reached) + } + + @Test + fun `monitorCondition MonitoredOverlayDisplayed does not trigger when user stays on expected overlay`() { + val overlayType = MonitoredOverlayType.SCENARIO + whenever(mockOverlayManager.getBackStackTop()).thenReturn(mockOverlay) + whenever(mockOverlay.tutorialMonitoringTag()).thenReturn(overlayType.name) + backStackTopFlow.value = mockOverlay + + var reached = false + monitor.monitorCondition( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) { reached = true } + + // Emit the same overlay again — user hasn't left + backStackTopFlow.value = mockOverlay + + assertEquals(false, reached) + } + + @Test + fun `monitorCondition MonitoredOverlayDisplayed triggers after user leaves then returns to expected overlay`() { + val overlayType = MonitoredOverlayType.SCENARIO + val otherOverlay = org.mockito.Mockito.mock(Overlay::class.java) + whenever(mockOverlayManager.getBackStackTop()).thenReturn(mockOverlay) + whenever(mockOverlay.tutorialMonitoringTag()).thenReturn(overlayType.name) + whenever(otherOverlay.tutorialMonitoringTag()).thenReturn(MonitoredOverlayType.EVENT.name) + backStackTopFlow.value = mockOverlay + + var reached = false + monitor.monitorCondition( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) { reached = true } + + // User navigates away + backStackTopFlow.value = otherOverlay + assertEquals(false, reached) + + // User comes back to the expected overlay + backStackTopFlow.value = mockOverlay + assertEquals(true, reached) + } + + @Test + fun `monitorCondition MonitoredOverlayDisplayed does not trigger again after condition reached`() { + val overlayType = MonitoredOverlayType.SCENARIO + val otherOverlay = org.mockito.Mockito.mock(Overlay::class.java) + whenever(mockOverlayManager.getBackStackTop()).thenReturn(null) + whenever(mockOverlay.tutorialMonitoringTag()).thenReturn(overlayType.name) + whenever(otherOverlay.tutorialMonitoringTag()).thenReturn(MonitoredOverlayType.EVENT.name) + + var reachedCount = 0 + monitor.monitorCondition( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) { reachedCount++ } + + backStackTopFlow.value = mockOverlay + assertEquals(1, reachedCount) + + // Navigate away and back — job should be cancelled, no second callback + backStackTopFlow.value = otherOverlay + backStackTopFlow.value = mockOverlay + assertEquals(1, reachedCount) + } + + @Test + fun `stopMonitoring MonitoredOverlayDisplayed cancels the monitoring job`() { + val overlayType = MonitoredOverlayType.SCENARIO + whenever(mockOverlayManager.getBackStackTop()).thenReturn(null) + whenever(mockOverlay.tutorialMonitoringTag()).thenReturn(overlayType.name) + + var reached = false + monitor.monitorCondition( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) { reached = true } + + monitor.stopMonitoring( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) + + backStackTopFlow.value = mockOverlay + assertEquals(false, reached) + } + + @Test + fun `clearMonitoring cancels overlay monitoring job`() { + val overlayType = MonitoredOverlayType.SCENARIO + whenever(mockOverlayManager.getBackStackTop()).thenReturn(null) + whenever(mockOverlay.tutorialMonitoringTag()).thenReturn(overlayType.name) + + var reached = false + monitor.monitorCondition( + TutorialStepStartCondition.MonitoredOverlayDisplayed(overlayType), + mockSubjectController, + ) { reached = true } + + monitor.clearMonitoring() + + backStackTopFlow.value = mockOverlay + assertEquals(false, reached) + } +} diff --git a/core/common/tutorial/src/test/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/subject/QuickClickGameEngineTest.kt b/core/common/tutorial/src/test/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/subject/QuickClickGameEngineTest.kt index 348b53286..4f365e80f 100644 --- a/core/common/tutorial/src/test/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/subject/QuickClickGameEngineTest.kt +++ b/core/common/tutorial/src/test/java/com/buzbuz/smartautoclicker/core/common/tutorial/impl/engine/subject/QuickClickGameEngineTest.kt @@ -338,7 +338,7 @@ class QuickClickGameEngineTest { engine = createEngine(dispatcher) var callbackResult: Boolean? = null - engine.monitorNextCompletion { isWon -> callbackResult = isWon } + engine.monitorNextCompletion { isWon -> callbackResult = isWon; true } engine.start() advanceTimeBy(TEST_DURATION_SECONDS * 1_000 + 500) @@ -354,7 +354,7 @@ class QuickClickGameEngineTest { engine = createEngine(dispatcher) var callbackResult: Boolean? = null - engine.monitorNextCompletion { isWon -> callbackResult = isWon } + engine.monitorNextCompletion { isWon -> callbackResult = isWon; true } engine.start() advanceTimeBy(TEST_DURATION_SECONDS * 1_000 + 500) @@ -368,7 +368,7 @@ class QuickClickGameEngineTest { engine = createEngine(dispatcher) var callbackInvoked = false - engine.monitorNextCompletion { callbackInvoked = true } + engine.monitorNextCompletion { callbackInvoked = true; true } engine.monitorNextCompletion(null) engine.start() @@ -378,20 +378,63 @@ class QuickClickGameEngineTest { } @Test - fun `monitorNextCompletion callback is cleared after invocation`() = runTest { + fun `monitorNextCompletion callback is cleared after invocation when consumed`() = runTest { val dispatcher = StandardTestDispatcher(testScheduler) engine = createEngine(dispatcher) var invokeCount = 0 - engine.monitorNextCompletion { invokeCount++ } + engine.monitorNextCompletion { invokeCount++; true } engine.start() advanceTimeBy(TEST_DURATION_SECONDS * 1_000 + 500) - // Start a second game — callback must not fire again + // Start a second game — callback was consumed so must not fire again engine.start() advanceTimeBy(TEST_DURATION_SECONDS * 1_000 + 500) assertEquals(1, invokeCount) } + + @Test + fun `monitorNextCompletion callback is kept after invocation when not consumed`() = runTest { + whenever(mockRules.getScore()).thenReturn(TEST_SCORE_TO_REACH + 1) + + val dispatcher = StandardTestDispatcher(testScheduler) + engine = createEngine(dispatcher) + + var invokeCount = 0 + // Return false (not consumed) when game is lost, true (consumed) when won + engine.monitorNextCompletion { isWon -> invokeCount++; isWon } + + // First game: won — callback fires and is consumed + engine.start() + advanceTimeBy(TEST_DURATION_SECONDS * 1_000 + 500) + assertEquals(1, invokeCount) + + // Second game: callback was consumed, must not fire again + engine.start() + advanceTimeBy(TEST_DURATION_SECONDS * 1_000 + 500) + assertEquals(1, invokeCount) + } + + @Test + fun `monitorNextCompletion callback stays registered when returning false`() = runTest { + whenever(mockRules.getScore()).thenReturn(TEST_SCORE_TO_REACH - 1) + + val dispatcher = StandardTestDispatcher(testScheduler) + engine = createEngine(dispatcher) + + var invokeCount = 0 + // Always return false — never consumed + engine.monitorNextCompletion { invokeCount++; false } + + engine.start() + advanceTimeBy(TEST_DURATION_SECONDS * 1_000 + 500) + assertEquals(1, invokeCount) + + // Callback was not consumed, fires again on second game + engine.start() + advanceTimeBy(TEST_DURATION_SECONDS * 1_000 + 500) + assertEquals(2, invokeCount) + } } diff --git a/core/common/ui/src/main/res/drawable/ic_action_system.xml b/core/common/ui/src/main/res/drawable/ic_action_system.xml index b7256702e..0f195f4fd 100644 --- a/core/common/ui/src/main/res/drawable/ic_action_system.xml +++ b/core/common/ui/src/main/res/drawable/ic_action_system.xml @@ -13,7 +13,7 @@ android:scaleY="0.4"> diff --git a/feature/smart-config/src/main/res/drawable/ic_numbers.xml b/core/common/ui/src/main/res/drawable/ic_numbers.xml similarity index 100% rename from feature/smart-config/src/main/res/drawable/ic_numbers.xml rename to core/common/ui/src/main/res/drawable/ic_numbers.xml diff --git a/core/common/ui/src/main/res/drawable/ic_priority.xml b/core/common/ui/src/main/res/drawable/ic_priority.xml new file mode 100644 index 000000000..77130092c --- /dev/null +++ b/core/common/ui/src/main/res/drawable/ic_priority.xml @@ -0,0 +1,10 @@ + + + diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/changecounter/ChangeCounterDialog.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/changecounter/ChangeCounterDialog.kt index ce181e21d..334af8bdc 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/changecounter/ChangeCounterDialog.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/changecounter/ChangeCounterDialog.kt @@ -133,6 +133,17 @@ class ChangeCounterDialog( } } + override fun onStart() { + super.onStart() + viewModel.monitorSelectCounterView(viewBinding.counterToChange.root) + viewModel.monitorSaveButtonView(viewBinding.layoutTopBar.buttonSave) + } + + override fun onStop() { + viewModel.detachMonitoredViews() + super.onStop() + } + override fun back() { if (viewModel.hasUnsavedModifications()) { context.showCloseWithoutSavingDialog { diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/changecounter/ChangeCounterViewModel.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/changecounter/ChangeCounterViewModel.kt index db5017f5d..b6c1e8708 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/changecounter/ChangeCounterViewModel.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/changecounter/ChangeCounterViewModel.kt @@ -17,8 +17,11 @@ package com.buzbuz.smartautoclicker.feature.smart.config.ui.action.changecounter import android.content.Context +import android.view.View import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.MonitoredViewsManager +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType import com.buzbuz.smartautoclicker.core.domain.model.counter.CounterOperationValue import com.buzbuz.smartautoclicker.core.domain.model.action.ChangeCounter @@ -51,6 +54,7 @@ import kotlinx.coroutines.flow.combine class ChangeCounterViewModel @Inject constructor( @ApplicationContext context: Context, private val editionRepository: EditionRepository, + private val monitoredViewsManager: MonitoredViewsManager, ) : ViewModel() { /** The action being configured by the user. */ @@ -106,6 +110,19 @@ class ChangeCounterViewModel @Inject constructor( } } + fun monitorSelectCounterView(view: View) { + monitoredViewsManager.attach(MonitoredViewType.COUNTER_ACTION_DIALOG_FIELD_SELECT_COUNTER, view) + } + + fun monitorSaveButtonView(view: View) { + monitoredViewsManager.attach(MonitoredViewType.COUNTER_ACTION_DIALOG_BUTTON_SAVE, view) + } + + fun detachMonitoredViews() { + monitoredViewsManager.detach(MonitoredViewType.COUNTER_ACTION_DIALOG_FIELD_SELECT_COUNTER) + monitoredViewsManager.detach(MonitoredViewType.COUNTER_ACTION_DIALOG_BUTTON_SAVE) + } + private fun updateEditedChangeCounter(closure: (old: ChangeCounter) -> ChangeCounter) { editionRepository.editionState.getEditedAction()?.let { old -> editionRepository.updateEditedAction(closure(old)) diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/click/ClickDialog.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/click/ClickDialog.kt index ecf3e1eda..2393832a4 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/click/ClickDialog.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/click/ClickDialog.kt @@ -27,6 +27,7 @@ import android.view.ViewGroup import androidx.core.graphics.toPoint import androidx.core.graphics.toPointF +import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle @@ -222,7 +223,8 @@ class ClickDialog( setChecked(checkIndex) setDescription(checkIndex) - root.visibility = if (state.isTypeFieldVisible) View.VISIBLE else View.GONE + root.isVisible = state.isTypeFieldVisible + viewBinding.dividerClickTypeBottom.isVisible = state.isTypeFieldVisible } viewBinding.fieldClickSelection.apply { @@ -248,7 +250,9 @@ class ClickDialog( viewBinding.fieldClickOffset.apply { setEnabled(state.isClickOffsetEnabled) setDescription(state.clickOffsetDescription) - root.visibility = if (state.isClickOffsetVisible) View.VISIBLE else View.GONE + + root.isVisible = state.isClickOffsetVisible + viewBinding.dividerClickOffset.isVisible = state.isClickOffsetVisible } } diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/selection/ActionTypeSelectionDialog.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/selection/ActionTypeSelectionDialog.kt index a02e44b57..053e41da2 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/selection/ActionTypeSelectionDialog.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/selection/ActionTypeSelectionDialog.kt @@ -46,13 +46,35 @@ class ActionTypeSelectionDialog( override fun onStop() { super.onStop() - viewModel.stopViewMonitoring() + viewModel.stopViewCreateClickMonitoring() + viewModel.stopViewToggleEventMonitoring() + viewModel.stopViewCounterMonitoring() } override fun onChoiceViewBound(choice: ActionTypeChoice, view: View?) { + when (choice) { + ActionTypeChoice.Click -> + if (view != null) viewModel.monitorCreateClickView(view) + else viewModel.stopViewCreateClickMonitoring() + + ActionTypeChoice.ToggleEvent -> + if (view != null) viewModel.monitorCreateToggleEventView(view) + else viewModel.stopViewToggleEventMonitoring() + + ActionTypeChoice.ChangeCounter -> + if (view != null) viewModel.monitorCreateCounterView(view) + else viewModel.stopViewCounterMonitoring() + + ActionTypeChoice.Copy, + ActionTypeChoice.Intent, + ActionTypeChoice.Notification, + ActionTypeChoice.Pause, + ActionTypeChoice.SetText, + ActionTypeChoice.Swipe, + ActionTypeChoice.System -> Unit + } if (choice !is ActionTypeChoice.Click) return - if (view != null) viewModel.monitorCreateClickView(view) - else viewModel.stopViewMonitoring() + } } diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/selection/ActionTypeSelectionViewModel.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/selection/ActionTypeSelectionViewModel.kt index 7c0c9d514..5a168e746 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/selection/ActionTypeSelectionViewModel.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/selection/ActionTypeSelectionViewModel.kt @@ -32,7 +32,24 @@ class ActionTypeSelectionViewModel @Inject constructor( monitoredViewsManager.attach(MonitoredViewType.ACTION_TYPE_DIALOG_CLICK_ACTION, view) } - fun stopViewMonitoring() { + fun monitorCreateToggleEventView(view: View) { + monitoredViewsManager.attach(MonitoredViewType.ACTION_TYPE_DIALOG_TOGGLE_EVENT_ACTION, view) + } + + fun monitorCreateCounterView(view: View) { + monitoredViewsManager.attach(MonitoredViewType.ACTION_TYPE_DIALOG_COUNTER_ACTION, view) + } + + + fun stopViewCreateClickMonitoring() { monitoredViewsManager.detach(MonitoredViewType.ACTION_TYPE_DIALOG_CLICK_ACTION) } + + fun stopViewToggleEventMonitoring() { + monitoredViewsManager.detach(MonitoredViewType.ACTION_TYPE_DIALOG_TOGGLE_EVENT_ACTION) + } + + fun stopViewCounterMonitoring() { + monitoredViewsManager.detach(MonitoredViewType.ACTION_TYPE_DIALOG_COUNTER_ACTION) + } } diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/toggleevent/ToggleEventDialog.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/toggleevent/ToggleEventDialog.kt index f0229b25a..c553155ae 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/toggleevent/ToggleEventDialog.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/toggleevent/ToggleEventDialog.kt @@ -142,6 +142,16 @@ class ToggleEventDialog( } } + override fun onStart() { + super.onStart() + viewModel.monitorSelectTogglesView(viewBinding.fieldSelectionToggles.root) + } + + override fun onStop() { + super.onStop() + viewModel.stopViewMonitoring() + } + override fun back() { if (viewModel.hasUnsavedModifications()) { context.showCloseWithoutSavingDialog { diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/toggleevent/ToggleEventViewModel.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/toggleevent/ToggleEventViewModel.kt index 0e7c011b6..3709af796 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/toggleevent/ToggleEventViewModel.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/action/toggleevent/ToggleEventViewModel.kt @@ -17,11 +17,14 @@ package com.buzbuz.smartautoclicker.feature.smart.config.ui.action.toggleevent import android.content.Context +import android.view.View import androidx.annotation.StringRes import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.MonitoredViewsManager +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType import com.buzbuz.smartautoclicker.core.domain.model.action.ToggleEvent import com.buzbuz.smartautoclicker.core.domain.model.action.toggleevent.EventToggle import com.buzbuz.smartautoclicker.core.domain.model.event.Event @@ -47,6 +50,7 @@ import javax.inject.Inject class ToggleEventViewModel @Inject constructor( @ApplicationContext context: Context, private val editionRepository: EditionRepository, + private val monitoredViewsManager: MonitoredViewsManager, ) : ViewModel() { /** The action being configured by the user. */ @@ -155,6 +159,14 @@ class ToggleEventViewModel @Inject constructor( } } + fun monitorSelectTogglesView(view: View) { + monitoredViewsManager.attach(MonitoredViewType.TOGGLE_EVENT_DIALOG_SELECT_TOGGLES, view) + } + + fun stopViewMonitoring() { + monitoredViewsManager.detach(MonitoredViewType.TOGGLE_EVENT_DIALOG_SELECT_TOGGLES) + } + fun setNewEventToggles(toggles: List) { editionRepository.editionState.getEditedAction()?.let { toggleEvent -> editionRepository.updateEditedAction( diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/common/formatters/OperationsFormatter.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/common/formatters/OperationsFormatter.kt index d1b1c3e87..56e6b3aa6 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/common/formatters/OperationsFormatter.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/common/formatters/OperationsFormatter.kt @@ -54,7 +54,7 @@ internal fun ChangeCounter.OperationType.toNameRes(): Int = fun ComparisonOperation.toEffectDescription(context: Context, counterName: String? = null, operand: String) = context.getString( R.string.field_change_counter_check_effect_desc, - counterName ?: "", + if (counterName.isNullOrEmpty()) "?" else counterName, context.getString(toNameRes()), operand, ) diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/condition/trigger/counter/CounterReachedConditionDialog.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/condition/trigger/counter/CounterReachedConditionDialog.kt index ae0134da7..3627f2369 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/condition/trigger/counter/CounterReachedConditionDialog.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/condition/trigger/counter/CounterReachedConditionDialog.kt @@ -133,6 +133,17 @@ class CounterReachedConditionDialog( } } + override fun onStart() { + super.onStart() + viewModel.monitorSelectCounterView(viewBinding.counterToCheck.root) + viewModel.monitorSaveButtonView(viewBinding.layoutTopBar.buttonSave) + } + + override fun onStop() { + viewModel.detachMonitoredViews() + super.onStop() + } + override fun back() { if (viewModel.hasUnsavedModifications()) { context.showCloseWithoutSavingDialog { diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/condition/trigger/counter/CounterReachedConditionViewModel.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/condition/trigger/counter/CounterReachedConditionViewModel.kt index 5ac45ac77..6dc9232b6 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/condition/trigger/counter/CounterReachedConditionViewModel.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/condition/trigger/counter/CounterReachedConditionViewModel.kt @@ -17,8 +17,11 @@ package com.buzbuz.smartautoclicker.feature.smart.config.ui.condition.trigger.counter import android.content.Context +import android.view.View import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.MonitoredViewsManager +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType import com.buzbuz.smartautoclicker.core.domain.model.condition.TriggerCondition import com.buzbuz.smartautoclicker.core.domain.model.counter.CounterOperationValue @@ -51,6 +54,7 @@ import javax.inject.Inject class CounterReachedConditionViewModel @Inject constructor( @ApplicationContext context: Context, private val editionRepository: EditionRepository, + private val monitoredViewsManager: MonitoredViewsManager, ) : ViewModel() { /** The condition being configured by the user. */ @@ -107,6 +111,19 @@ class CounterReachedConditionViewModel @Inject constructor( } } + fun monitorSelectCounterView(view: View) { + monitoredViewsManager.attach(MonitoredViewType.COUNTER_REACHED_DIALOG_FIELD_COUNTER_SELECTION, view) + } + + fun monitorSaveButtonView(view: View) { + monitoredViewsManager.attach(MonitoredViewType.COUNTER_REACHED_DIALOG_BUTTON_SAVE, view) + } + + fun detachMonitoredViews() { + monitoredViewsManager.detach(MonitoredViewType.COUNTER_REACHED_DIALOG_FIELD_COUNTER_SELECTION) + monitoredViewsManager.detach(MonitoredViewType.COUNTER_REACHED_DIALOG_BUTTON_SAVE) + } + private fun updateEditedCondition( closure: (oldValue: TriggerCondition.OnCounterCountReached) -> TriggerCondition.OnCounterCountReached?, ) { diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/config/CountersConfigViewModel.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/config/CountersConfigViewModel.kt index e9f87f769..8dd39f66f 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/config/CountersConfigViewModel.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/config/CountersConfigViewModel.kt @@ -162,7 +162,7 @@ private fun Counter.toUiItem( readByButtonText = context.getReadByButtonText(readCount), readByButtonIsEmpty = readCount == 0, deleteButtonText = context.getDeleteButtonText(totalReferences), - deleteButtonEnabled = counterCount > 1, + deleteButtonEnabled = (writeCount == 0 && readCount == 0) || counterCount > 1, selectedForReplacement = forReplacement ) } diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/selection/CounterSelectionDialog.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/selection/CounterSelectionDialog.kt index b141e5974..fd4f3247e 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/selection/CounterSelectionDialog.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/selection/CounterSelectionDialog.kt @@ -91,7 +91,15 @@ class CounterSelectionDialog( } } + override fun onStart() { + super.onStart() + viewModel.monitorCreateCounterView(viewBinding.buttonNew) + } + override fun onStop() { + super.onStop() + viewModel.stopViewMonitoring() + } private fun updateCounterNames(counterNames: List) { viewBinding.layoutLoadableList.updateState(counterNames) counterNameAdapter.submitList(counterNames) diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/selection/CounterSelectionViewModel.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/selection/CounterSelectionViewModel.kt index d573b12a4..91cb70184 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/selection/CounterSelectionViewModel.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/counter/selection/CounterSelectionViewModel.kt @@ -17,7 +17,10 @@ package com.buzbuz.smartautoclicker.feature.smart.config.ui.counter.selection import android.content.Context +import android.view.View import androidx.lifecycle.ViewModel +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.MonitoredViewsManager +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType import com.buzbuz.smartautoclicker.feature.smart.config.R import com.buzbuz.smartautoclicker.feature.smart.config.domain.EditionRepository @@ -31,6 +34,7 @@ import javax.inject.Inject class CounterSelectionViewModel @Inject constructor( @ApplicationContext context: Context, editionRepository: EditionRepository, + private val monitoredViewsManager: MonitoredViewsManager, ) : ViewModel() { val counterNames: Flow> = editionRepository.editionState.allEditedCountersFlow @@ -45,4 +49,12 @@ class CounterSelectionViewModel @Inject constructor( ) }.sortedBy { counter -> counter.counterName } } + + fun monitorCreateCounterView(view: View) { + monitoredViewsManager.attach(MonitoredViewType.COUNTER_SELECTION_DIALOG_BUTTON_CREATE, view) + } + + fun stopViewMonitoring() { + monitoredViewsManager.detach(MonitoredViewType.COUNTER_SELECTION_DIALOG_BUTTON_CREATE) + } } diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/event/EventDialog.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/event/EventDialog.kt index 43fb6ee20..a515220c0 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/event/EventDialog.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/event/EventDialog.kt @@ -272,7 +272,9 @@ class EventDialog( viewModel.monitorViews( conditionsField = viewBinding.layoutConditionSelector, conditionOperatorAndView = viewBinding.fieldConditionsOperator.dualStateButton.buttonLeft, + conditionOperatorOrView = viewBinding.fieldConditionsOperator.dualStateButton.buttonRight, actionsField = viewBinding.layoutActionsSelector, + initialStateField = viewBinding.fieldIsEnabled.root, saveButton = viewBinding.layoutTopBar.buttonSave, ) } diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/event/EventDialogViewModel.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/event/EventDialogViewModel.kt index 7d19a3874..095ead9d1 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/event/EventDialogViewModel.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/event/EventDialogViewModel.kt @@ -172,11 +172,13 @@ class EventDialogViewModel @Inject constructor( } } - fun monitorViews(conditionsField: View, conditionOperatorAndView: View, actionsField: View, saveButton: View) { + fun monitorViews(conditionsField: View, conditionOperatorAndView: View, conditionOperatorOrView: View, actionsField: View, initialStateField: View, saveButton: View) { monitoredViewsManager.apply { attach(MonitoredViewType.EVENT_DIALOG_FIELD_CONDITIONS, conditionsField) attach(MonitoredViewType.EVENT_DIALOG_FIELD_OPERATOR_ITEM_AND, conditionOperatorAndView) + attach(MonitoredViewType.EVENT_DIALOG_FIELD_OPERATOR_ITEM_OR, conditionOperatorOrView) attach(MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, actionsField) + attach(MonitoredViewType.EVENT_DIALOG_FIELD_INITIAL_STATE, initialStateField) attach(MonitoredViewType.EVENT_DIALOG_BUTTON_SAVE, saveButton) } } @@ -184,6 +186,8 @@ class EventDialogViewModel @Inject constructor( fun stopViewMonitoring() { monitoredViewsManager.apply { detach(MonitoredViewType.EVENT_DIALOG_BUTTON_SAVE) + detach(MonitoredViewType.EVENT_DIALOG_FIELD_INITIAL_STATE) + detach(MonitoredViewType.EVENT_DIALOG_FIELD_OPERATOR_ITEM_OR) detach(MonitoredViewType.EVENT_DIALOG_FIELD_OPERATOR_ITEM_AND) detach(MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS) detach(MonitoredViewType.EVENT_DIALOG_FIELD_CONDITIONS) diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/scenario/imageevents/ImageEventListContent.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/scenario/imageevents/ImageEventListContent.kt index 100f9f15e..3a8598bc0 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/scenario/imageevents/ImageEventListContent.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/scenario/imageevents/ImageEventListContent.kt @@ -114,10 +114,10 @@ class ImageEventListContent(appContext: Context) : NavBarDialogContent(appContex } private fun onEventItemBound(index: Int, eventItemView: View?) { - if (index != 0) return + if (index > 3) return - if (eventItemView != null) viewModel.monitorFirstEventView(eventItemView) - else viewModel.stopViewMonitoring() + if (eventItemView != null) viewModel.monitorEventView(index, eventItemView) + else viewModel.stopEventViewMonitoring(index) } private fun updateEventList(newItems: List?) { diff --git a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/scenario/imageevents/ImageEventListViewModel.kt b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/scenario/imageevents/ImageEventListViewModel.kt index 33aac4a26..ed81743df 100644 --- a/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/scenario/imageevents/ImageEventListViewModel.kt +++ b/feature/smart-config/src/main/java/com/buzbuz/smartautoclicker/feature/smart/config/ui/scenario/imageevents/ImageEventListViewModel.kt @@ -76,11 +76,32 @@ class ImageEventListViewModel @Inject constructor( uiEvents.map { it.event } ) - fun monitorFirstEventView(view: View) { - monitoredViewsManager.attach(MonitoredViewType.SCENARIO_DIALOG_ITEM_FIRST_EVENT, view) + fun monitorEventView(index: Int, view: View) { + val type = when (index) { + 0 -> MonitoredViewType.SCENARIO_DIALOG_ITEM_FIRST_EVENT + 1 -> MonitoredViewType.SCENARIO_DIALOG_ITEM_SECOND_EVENT + 2 -> MonitoredViewType.SCENARIO_DIALOG_ITEM_THIRD_EVENT + 3 -> MonitoredViewType.SCENARIO_DIALOG_ITEM_FOURTH_EVENT + else -> return + } + monitoredViewsManager.attach(type, view) + } + + fun stopEventViewMonitoring(index: Int) { + val type = when (index) { + 0 -> MonitoredViewType.SCENARIO_DIALOG_ITEM_FIRST_EVENT + 1 -> MonitoredViewType.SCENARIO_DIALOG_ITEM_SECOND_EVENT + 2 -> MonitoredViewType.SCENARIO_DIALOG_ITEM_THIRD_EVENT + 3 -> MonitoredViewType.SCENARIO_DIALOG_ITEM_FOURTH_EVENT + else -> return + } + monitoredViewsManager.detach(type) } fun stopViewMonitoring() { monitoredViewsManager.detach(MonitoredViewType.SCENARIO_DIALOG_ITEM_FIRST_EVENT) + monitoredViewsManager.detach(MonitoredViewType.SCENARIO_DIALOG_ITEM_SECOND_EVENT) + monitoredViewsManager.detach(MonitoredViewType.SCENARIO_DIALOG_ITEM_THIRD_EVENT) + monitoredViewsManager.detach(MonitoredViewType.SCENARIO_DIALOG_ITEM_FOURTH_EVENT) } } diff --git a/feature/smart-config/src/main/res/layout/dialog_config_action_click.xml b/feature/smart-config/src/main/res/layout/dialog_config_action_click.xml index 3226e01a5..569d3fd7b 100644 --- a/feature/smart-config/src/main/res/layout/dialog_config_action_click.xml +++ b/feature/smart-config/src/main/res/layout/dialog_config_action_click.xml @@ -72,6 +72,7 @@ android:layout_marginBottom="@dimen/margin_vertical_small"/> diff --git a/feature/smart-config/src/main/res/layout/dialog_config_condition_counter.xml b/feature/smart-config/src/main/res/layout/dialog_config_condition_counter.xml index 6ac35c824..5aa1fc183 100644 --- a/feature/smart-config/src/main/res/layout/dialog_config_condition_counter.xml +++ b/feature/smart-config/src/main/res/layout/dialog_config_condition_counter.xml @@ -95,7 +95,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/margin_vertical_small" - android:text="@string/field_change_counter_effect_title"/> + android:text="@string/field_change_counter_check_effect_title"/> - قيمة العداد + قيمة العداد وصلت اسم العداد @@ -240,7 +240,7 @@ لم يتم تحديد أي شرط انقر على أول حالة تم اكتشافها - تم ضبط الحدث على "شرط واحد"، ولا يمكنك تحديد شرط محدد + تم ضبط عامل الشرط للحدث على \"OR\"، سيحدث النقر على أول شرط يتم اكتشافه انقر على %1$d، %2$d diff --git a/feature/smart-config/src/main/res/values-es/strings.xml b/feature/smart-config/src/main/res/values-es/strings.xml index d6f0ba513..c04a1e33c 100644 --- a/feature/smart-config/src/main/res/values-es/strings.xml +++ b/feature/smart-config/src/main/res/values-es/strings.xml @@ -202,7 +202,7 @@ - Valor del contador + Valor del contador alcanzado Nombre del contador @@ -240,7 +240,7 @@ Ninguna condición seleccionada Haga clic en la primera condición detectada - El evento está configurado en "Una condición", no puedes seleccionar una específica + El operador de condición del evento está configurado en \"OR\", el clic ocurrirá en la primera condición detectada Haga clic en %1$d, %2$d diff --git a/feature/smart-config/src/main/res/values-fr/strings.xml b/feature/smart-config/src/main/res/values-fr/strings.xml index 819ca379e..c38e6948b 100644 --- a/feature/smart-config/src/main/res/values-fr/strings.xml +++ b/feature/smart-config/src/main/res/values-fr/strings.xml @@ -37,7 +37,7 @@ Type de déclencheur Timer atteint Broadcast reçu - Valeur du compteur + Valeur du compteur atteinte Évènement d\'écran Déclencheur @@ -64,7 +64,7 @@ Pendant %1$s sur %2$s %1$s Pas de condition sélectionnée - L\'évènement est défini sur "Une condition", vous ne pouvez pas en spécifier une + L\'opérateur de condition de l\'évènement est défini sur \"OR\", le clic se produira sur la première condition détectée Clic simple sur %1$d, %2$d Dans [%1$d, %2$d] [%3$d, %4$d] Intéragir avec une autre application diff --git a/feature/smart-config/src/main/res/values-it/strings.xml b/feature/smart-config/src/main/res/values-it/strings.xml index 46f0ecb4d..cfdc3e54e 100644 --- a/feature/smart-config/src/main/res/values-it/strings.xml +++ b/feature/smart-config/src/main/res/values-it/strings.xml @@ -37,7 +37,7 @@ Tipo di innesco Timer raggiunto Broadcast ricevuto - Valore del contatore + Valore del contatore raggiunto Evento schermo Innesco @@ -64,7 +64,7 @@ Durante %1$s su %2$s %1$s Nessuna condizione selezionata - L\'evento è impostato su Una condizione, non è possibile selezionarne uno specifico + L\'operatore di condizione dell\'evento è impostato su \"OR\", il clic avverrà sulla prima condizione rilevata Clicca %1$d, %2$d Tra [%1$d, %2$d] [%3$d, %4$d] Interagisci con un\'altra applicazione diff --git a/feature/smart-config/src/main/res/values-ja/strings.xml b/feature/smart-config/src/main/res/values-ja/strings.xml index b13a6eeb5..1d5c39d5b 100644 --- a/feature/smart-config/src/main/res/values-ja/strings.xml +++ b/feature/smart-config/src/main/res/values-ja/strings.xml @@ -122,7 +122,7 @@ 検知エリア [%1$d、%2$d、%3$d、%4$d] で 許容する差異 - カウンターの値 + カウンターの値に到達 カウンター名 演算子 @@ -141,7 +141,7 @@ %1$s 条件が選択されていません 最初に検出された条件をクリックします - イベントは「1 つの条件」に設定されており、特定の条件を選択することはできません + イベントの条件演算子が \"OR\" に設定されており、最初に検出された条件でクリックが発生します %1$d、%2$d をクリックします クリックオフセット なし diff --git a/feature/smart-config/src/main/res/values-pt-rBR/strings.xml b/feature/smart-config/src/main/res/values-pt-rBR/strings.xml index a0a48aff1..9d4b65e75 100644 --- a/feature/smart-config/src/main/res/values-pt-rBR/strings.xml +++ b/feature/smart-config/src/main/res/values-pt-rBR/strings.xml @@ -200,7 +200,7 @@ - Valor do contador + Valor do contador alcançado Nome do contador @@ -239,7 +239,7 @@ Nenhuma condição selecionada Clique na primeira condição detectada - Evento está definido como "Uma Condição", você não pode selecionar uma específica + O operador de condição do evento está definido como \"OR\", o clique ocorrerá na primeira condição detectada Clique em %1$d, %2$d diff --git a/feature/smart-config/src/main/res/values-ru/strings.xml b/feature/smart-config/src/main/res/values-ru/strings.xml index 41c7a37e9..9f78e2cb7 100644 --- a/feature/smart-config/src/main/res/values-ru/strings.xml +++ b/feature/smart-config/src/main/res/values-ru/strings.xml @@ -202,7 +202,7 @@ - Значение счётчика + Значение счётчика достигнуто Название счётчика @@ -240,7 +240,7 @@ Условие не выбрано Нажать на первое обнаруженное условие - Событие настроено на «Одно условие», нельзя выбрать конкретное + Оператор условия события установлен на \"OR\", клик произойдёт по первому обнаруженному условию Нажать на %1$d, %2$d diff --git a/feature/smart-config/src/main/res/values-uk/strings.xml b/feature/smart-config/src/main/res/values-uk/strings.xml index c8fc9eb1b..392c8d759 100644 --- a/feature/smart-config/src/main/res/values-uk/strings.xml +++ b/feature/smart-config/src/main/res/values-uk/strings.xml @@ -203,7 +203,7 @@ - Значення лічильника + Значення лічильника досягнуто Назва лічильника @@ -242,7 +242,7 @@ Жодної умови не обрано Клікнути на першій виявленій умові - Подія встановлена на "Одна умова", ви не можете обрати конкретну + Оператор умови події встановлено на \"OR\", клік відбудеться на першій виявленій умові Клікнути на %1$d, %2$d diff --git a/feature/smart-config/src/main/res/values-zh-rCN/strings.xml b/feature/smart-config/src/main/res/values-zh-rCN/strings.xml index b8424e18f..782a7aeca 100644 --- a/feature/smart-config/src/main/res/values-zh-rCN/strings.xml +++ b/feature/smart-config/src/main/res/values-zh-rCN/strings.xml @@ -37,7 +37,7 @@ 触发器类型 计时器达到 收到广播 - 计数器数值 + 计数器数值达到 屏幕事件 触发器 @@ -64,7 +64,7 @@ 于 %2$s 持续 %1$s %1$s 未选择条件 - 事件设置为“一个条件”,您无法选择特定条件 + 事件的条件运算符设置为 “OR”,点击将发生在第一个检测到的条件上 点击 (%1$d, %2$d) 在[%1$d,%2$d] [%3$d,%4$d]中 调用其他的应用程序 diff --git a/feature/smart-config/src/main/res/values-zh-rTW/strings.xml b/feature/smart-config/src/main/res/values-zh-rTW/strings.xml index ba6623ed2..2dee005d9 100644 --- a/feature/smart-config/src/main/res/values-zh-rTW/strings.xml +++ b/feature/smart-config/src/main/res/values-zh-rTW/strings.xml @@ -37,7 +37,7 @@ 觸發器類型 計時器達到 收到廣播 - 計數器數值 + 計數器數值達到 螢幕事件 觸發器 @@ -64,7 +64,7 @@ 於 %2$s 持續 %1$s %1$s 未選擇條件 - 事件設置為「一個條件」,您無法選擇特定條件 + 事件的條件運算子設定為 \"OR\",點擊將發生在第一個偵測到的條件上 點擊 (%1$d, %2$d) 在[%1$d,%2$d] [%3$d,%4$d]中 調用其他的應用程式 diff --git a/feature/smart-config/src/main/res/values/strings.xml b/feature/smart-config/src/main/res/values/strings.xml index ee8bdbcfd..07e7d27af 100644 --- a/feature/smart-config/src/main/res/values/strings.xml +++ b/feature/smart-config/src/main/res/values/strings.xml @@ -304,7 +304,7 @@ - Counter value + Counter value reached Counter name Value @@ -343,7 +343,7 @@ No condition selected Click on the first detected condition - Event is set to "One Condition", you can\'t select a specific one + Event\'s condition operator is set to \"OR\", click will happen on the first detected condition Click on %1$d, %2$d diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/RootCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/RootCategory.kt index 196ee0850..e2b3635c8 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/RootCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/RootCategory.kt @@ -28,9 +28,10 @@ internal fun getRootCategory() = longDescriptionRes = R.string.tutorial_category_root_desc_long, iconRes = R.drawable.ic_tutorials, content = listOf( + TutorialCategory.Content.Divider, TutorialCategory.Content.Category(TutorialCategory.Type.BASICS), TutorialCategory.Content.Category(TutorialCategory.Type.COMBINE_CONDITIONS), - TutorialCategory.Content.Category(TutorialCategory.Type.EVENT_STATE), + TutorialCategory.Content.Category(TutorialCategory.Type.COMBINE_EVENTS), TutorialCategory.Content.Category(TutorialCategory.Type.COUNTERS), ), ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/BasicsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/BasicsCategory.kt index 8b9481881..8ddfa508a 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/BasicsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/BasicsCategory.kt @@ -28,6 +28,7 @@ internal fun getBasicsCategory() = longDescriptionRes = R.string.tutorial_category_basics_desc_long, iconRes = R.drawable.ic_category_basics, content = listOf( + TutorialCategory.Content.Divider, TutorialCategory.Content.Category(TutorialCategory.Type.SCREEN_CONDITIONS), TutorialCategory.Content.Category(TutorialCategory.Type.TRIGGER_CONDITIONS), TutorialCategory.Content.Category(TutorialCategory.Type.ACTIONS), diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/ActionsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/ActionsCategory.kt index 5cf4ec81e..29d0c968e 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/ActionsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/ActionsCategory.kt @@ -18,6 +18,7 @@ package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.acti import com.buzbuz.smartautoclicker.feature.tutorial.R import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow internal fun getActionsCategory() = TutorialCategory( @@ -26,5 +27,18 @@ internal fun getActionsCategory() = shortDescriptionRes = R.string.tutorial_category_action_desc_short, longDescriptionRes = R.string.tutorial_category_action_desc_long, iconRes = R.drawable.ic_click, - content = listOf(), + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.ACTIONS_LIST), + TutorialCategory.Content.Divider, + TutorialCategory.Content.Category(TutorialCategory.Type.CLICK_ACTION), + TutorialCategory.Content.Category(TutorialCategory.Type.SWIPE_ACTION), + TutorialCategory.Content.Category(TutorialCategory.Type.PAUSE_ACTION), + TutorialCategory.Content.Category(TutorialCategory.Type.WRITE_TEXT_ACTION), + TutorialCategory.Content.Category(TutorialCategory.Type.SYSTEM_ACTION), + TutorialCategory.Content.Category(TutorialCategory.Type.CHANGE_COUNTER_ACTION), + TutorialCategory.Content.Category(TutorialCategory.Type.TOGGLE_EVENT_ACTION), + TutorialCategory.Content.Category(TutorialCategory.Type.NOTIFICATION_ACTION), + TutorialCategory.Content.Category(TutorialCategory.Type.INTENT_ACTION), + ), ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/ActionsListSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/ActionsListSlideshow.kt new file mode 100644 index 000000000..32e626b62 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/ActionsListSlideshow.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getActionsListSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.ACTIONS_LIST, + nameRes = R.string.tutorial_slideshow_actions_list_title, + shortDescriptionRes = R.string.tutorial_slideshow_actions_list_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_actions_list_step_1_text, + tutorialImage = R.drawable.tutorial_instructions_action_order, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changecounter/ChangeCounterActionCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changecounter/ChangeCounterActionCategory.kt new file mode 100644 index 000000000..d7f8a1fb9 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changecounter/ChangeCounterActionCategory.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.changecounter + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getChangeCounterActionCategory() = + TutorialCategory( + type = TutorialCategory.Type.CHANGE_COUNTER_ACTION, + nameRes = R.string.tutorial_category_change_counter_action_name, + shortDescriptionRes = R.string.tutorial_category_change_counter_action_desc_short, + longDescriptionRes = R.string.tutorial_category_change_counter_action_desc_long, + iconRes = R.drawable.ic_change_counter, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.CHANGE_COUNTER_ACTION), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changecounter/ChangeCounterActionSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changecounter/ChangeCounterActionSlideshow.kt new file mode 100644 index 000000000..f279f94f5 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changecounter/ChangeCounterActionSlideshow.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.changecounter + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getChangeCounterActionSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.CHANGE_COUNTER_ACTION, + nameRes = R.string.tutorial_slideshow_change_counter_action_title, + shortDescriptionRes = R.string.tutorial_slideshow_change_counter_action_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_change_counter_action_step_1_text, + tutorialImage = R.drawable.ic_numbers, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_change_counter_action_step_2_text, + tutorialImage = R.drawable.ic_change_counter, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changeeventstate/ChangeEventStateActionCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changeeventstate/ChangeEventStateActionCategory.kt new file mode 100644 index 000000000..b9b5180c2 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changeeventstate/ChangeEventStateActionCategory.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.changeeventstate + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getChangeEventStateActionCategory() = + TutorialCategory( + type = TutorialCategory.Type.TOGGLE_EVENT_ACTION, + nameRes = R.string.tutorial_category_change_event_state_action_name, + shortDescriptionRes = R.string.tutorial_category_change_event_state_action_desc_short, + longDescriptionRes = R.string.tutorial_category_change_event_state_action_desc_long, + iconRes = R.drawable.ic_toggle_event, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.TOGGLE_EVENT_ACTION), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changeeventstate/ChangeEventStateActionSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changeeventstate/ChangeEventStateActionSlideshow.kt new file mode 100644 index 000000000..a3efb35c8 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/changeeventstate/ChangeEventStateActionSlideshow.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.changeeventstate + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getChangeEventStateActionSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.TOGGLE_EVENT_ACTION, + nameRes = R.string.tutorial_slideshow_toggle_event_action_title, + shortDescriptionRes = R.string.tutorial_slideshow_toggle_event_action_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_toggle_event_action_step_1_text, + tutorialImage = R.drawable.ic_toggle_event, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_toggle_event_action_step_2_text, + tutorialImage = R.drawable.tutorial_instructions_toggle_event, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_toggle_event_action_step_3_text, + tutorialImage = R.drawable.ic_cancel, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionCategory.kt new file mode 100644 index 000000000..e34a6e9b2 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionCategory.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.click + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getClickActionCategory() = + TutorialCategory( + type = TutorialCategory.Type.CLICK_ACTION, + nameRes = R.string.tutorial_category_click_action_name, + shortDescriptionRes = R.string.tutorial_category_click_action_desc_short, + longDescriptionRes = R.string.tutorial_category_click_action_desc_long, + iconRes = R.drawable.ic_click, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.CLICK_ACTION_TARGET), + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.CLICK_ACTION_OFFSET), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionOffsetSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionOffsetSlideshow.kt new file mode 100644 index 000000000..d9995e2eb --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionOffsetSlideshow.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.click + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getClickActionOffsetSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.CLICK_ACTION_OFFSET, + nameRes = R.string.tutorial_slideshow_click_action_offset_title, + shortDescriptionRes = R.string.tutorial_slideshow_click_action_offset_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_click_action_offset_step_1_text, + tutorialImage = R.drawable.tutorial_instructions_click_offset, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_PORTRAIT, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionTargetSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionTargetSlideshow.kt new file mode 100644 index 000000000..c7a037b36 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/click/ClickActionTargetSlideshow.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.click + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getClickActionTargetSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.CLICK_ACTION_TARGET, + nameRes = R.string.tutorial_slideshow_click_action_target_title, + shortDescriptionRes = R.string.tutorial_slideshow_click_action_target_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_click_action_target_step_1_text, + tutorialImage = R.drawable.tutorial_instructions_click_target_type, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_SQUARE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_click_action_target_step_2_text, + tutorialImage = R.drawable.tutorial_instructions_click_target_static, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_SQUARE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_click_action_target_step_3_text, + tutorialImage = R.drawable.tutorial_instructions_click_target_condition_and, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_click_action_target_step_4_text, + tutorialImage = R.drawable.tutorial_instructions_click_target_condition_or, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_SQUARE, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/intent/IntentActionCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/intent/IntentActionCategory.kt new file mode 100644 index 000000000..10581cf5f --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/intent/IntentActionCategory.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.intent + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getIntentActionCategory() = + TutorialCategory( + type = TutorialCategory.Type.INTENT_ACTION, + nameRes = R.string.tutorial_category_intent_action_name, + shortDescriptionRes = R.string.tutorial_category_intent_action_desc_short, + longDescriptionRes = R.string.tutorial_category_intent_action_desc_long, + iconRes = R.drawable.ic_intent, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.INTENT_ACTION), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/intent/IntentActionSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/intent/IntentActionSlideshow.kt new file mode 100644 index 000000000..b2dfb5663 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/intent/IntentActionSlideshow.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.intent + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getIntentActionSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.INTENT_ACTION, + nameRes = R.string.tutorial_slideshow_intent_action_title, + shortDescriptionRes = R.string.tutorial_slideshow_intent_action_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_intent_action_step_1_text, + tutorialImage = R.drawable.ic_intent, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_intent_action_step_2_text, + tutorialImage = R.drawable.ic_warning, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/notification/NotificationActionCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/notification/NotificationActionCategory.kt new file mode 100644 index 000000000..582aa6a6f --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/notification/NotificationActionCategory.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.notification + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getNotificationActionCategory() = + TutorialCategory( + type = TutorialCategory.Type.NOTIFICATION_ACTION, + nameRes = R.string.tutorial_category_notification_action_name, + shortDescriptionRes = R.string.tutorial_category_notification_action_desc_short, + longDescriptionRes = R.string.tutorial_category_notification_action_desc_long, + iconRes = R.drawable.ic_action_notification, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.NOTIFICATION_ACTION), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/notification/NotificationActionSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/notification/NotificationActionSlideshow.kt new file mode 100644 index 000000000..6ba14a473 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/notification/NotificationActionSlideshow.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.notification + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getNotificationActionSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.NOTIFICATION_ACTION, + nameRes = R.string.tutorial_slideshow_notification_action_title, + shortDescriptionRes = R.string.tutorial_slideshow_notification_action_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_notification_action_step_1_text, + tutorialImage = R.drawable.ic_action_notification, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_notification_action_step_2_text, + tutorialImage = R.drawable.ic_action_notification, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/eventstate/EventStateCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/pause/PauseActionCategory.kt similarity index 61% rename from feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/eventstate/EventStateCategory.kt rename to feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/pause/PauseActionCategory.kt index 447b46cad..0680b1ded 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/eventstate/EventStateCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/pause/PauseActionCategory.kt @@ -14,20 +14,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.eventstate +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.pause import com.buzbuz.smartautoclicker.feature.tutorial.R import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow - -internal fun getEventStateCategory() = +internal fun getPauseActionCategory() = TutorialCategory( - type = TutorialCategory.Type.EVENT_STATE, - nameRes = R.string.tutorial_category_event_state_name, - shortDescriptionRes = R.string.tutorial_category_event_state_desc_short, - longDescriptionRes = R.string.tutorial_category_event_state_desc_long, - iconRes = R.drawable.ic_toggle_event, + type = TutorialCategory.Type.PAUSE_ACTION, + nameRes = R.string.tutorial_category_pause_action_name, + shortDescriptionRes = R.string.tutorial_category_pause_action_desc_short, + longDescriptionRes = R.string.tutorial_category_pause_action_desc_long, + iconRes = R.drawable.ic_pause, content = listOf( - + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.PAUSE_ACTION), ), - ) \ No newline at end of file + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/pause/PauseActionSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/pause/PauseActionSlideshow.kt new file mode 100644 index 000000000..274b1638f --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/pause/PauseActionSlideshow.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.pause + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getPauseActionSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.PAUSE_ACTION, + nameRes = R.string.tutorial_slideshow_pause_action_title, + shortDescriptionRes = R.string.tutorial_slideshow_pause_action_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_pause_action_step_1_text, + tutorialImage = R.drawable.ic_wait, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/swipe/SwipeActionCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/swipe/SwipeActionCategory.kt new file mode 100644 index 000000000..89d24bef1 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/swipe/SwipeActionCategory.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.swipe + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getSwipeActionCategory() = + TutorialCategory( + type = TutorialCategory.Type.SWIPE_ACTION, + nameRes = R.string.tutorial_category_swipe_action_name, + shortDescriptionRes = R.string.tutorial_category_swipe_action_desc_short, + longDescriptionRes = R.string.tutorial_category_swipe_action_desc_long, + iconRes = R.drawable.ic_swipe, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.SWIPE_ACTION), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/swipe/SwipeActionSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/swipe/SwipeActionSlideshow.kt new file mode 100644 index 000000000..ad95fbeeb --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/swipe/SwipeActionSlideshow.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.swipe + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getSwipeActionSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.SWIPE_ACTION, + nameRes = R.string.tutorial_slideshow_swipe_action_title, + shortDescriptionRes = R.string.tutorial_slideshow_swipe_action_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_swipe_action_step_1_text, + tutorialImage = R.drawable.tutorial_instructions_swipe, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/system/SystemActionCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/system/SystemActionCategory.kt new file mode 100644 index 000000000..a7eb11146 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/system/SystemActionCategory.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.system + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getSystemActionCategory() = + TutorialCategory( + type = TutorialCategory.Type.SYSTEM_ACTION, + nameRes = R.string.tutorial_category_system_action_name, + shortDescriptionRes = R.string.tutorial_category_system_action_desc_short, + longDescriptionRes = R.string.tutorial_category_system_action_desc_long, + iconRes = R.drawable.ic_action_system, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.SYSTEM_ACTION), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/system/SystemActionSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/system/SystemActionSlideshow.kt new file mode 100644 index 000000000..afe774af4 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/system/SystemActionSlideshow.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.system + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getSystemActionSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.SYSTEM_ACTION, + nameRes = R.string.tutorial_slideshow_system_action_title, + shortDescriptionRes = R.string.tutorial_slideshow_system_action_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_system_action_step_1_text, + tutorialImage = R.drawable.ic_action_system, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/writetext/WriteTextActionCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/writetext/WriteTextActionCategory.kt new file mode 100644 index 000000000..1cf655f89 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/writetext/WriteTextActionCategory.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.writetext + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getWriteTextActionCategory() = + TutorialCategory( + type = TutorialCategory.Type.WRITE_TEXT_ACTION, + nameRes = R.string.tutorial_category_write_text_action_name, + shortDescriptionRes = R.string.tutorial_category_write_text_action_desc_short, + longDescriptionRes = R.string.tutorial_category_write_text_action_desc_long, + iconRes = R.drawable.ic_action_set_text, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.WRITE_TEXT_ACTION), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/writetext/WriteTextActionSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/writetext/WriteTextActionSlideshow.kt new file mode 100644 index 000000000..6abe108a5 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/actions/writetext/WriteTextActionSlideshow.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.writetext + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getWriteTextActionSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.WRITE_TEXT_ACTION, + nameRes = R.string.tutorial_slideshow_write_text_action_title, + shortDescriptionRes = R.string.tutorial_slideshow_write_text_action_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_write_text_action_step_1_text, + tutorialImage = R.drawable.tutorial_instructions_set_text_focus, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_write_text_action_step_2_text, + tutorialImage = R.drawable.ic_append_counter, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/ScreenConditionsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/ScreenConditionsCategory.kt index 950175c5e..243d9b7e9 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/ScreenConditionsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/ScreenConditionsCategory.kt @@ -28,10 +28,12 @@ internal fun getScreenConditionsCategory() = longDescriptionRes = R.string.tutorial_category_screen_condition_desc_long, iconRes = R.drawable.ic_screen_event, content = listOf( + TutorialCategory.Content.Divider, TutorialCategory.Content.Category(TutorialCategory.Type.IMAGE_CONDITION), TutorialCategory.Content.Category(TutorialCategory.Type.COLOR_CONDITION), TutorialCategory.Content.Category(TutorialCategory.Type.TEXT_CONDITION), TutorialCategory.Content.Category(TutorialCategory.Type.NUMBER_CONDITION), + TutorialCategory.Content.Divider, TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.SCREEN_CONDITIONS_TYPE), TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.SCREEN_CONDITIONS_DETECTION_THRESHOLD), ), diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/color/ColorConditionsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/color/ColorConditionsCategory.kt index 638004813..29d99d4ce 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/color/ColorConditionsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/color/ColorConditionsCategory.kt @@ -28,6 +28,7 @@ internal fun getColorConditionsCategory() = longDescriptionRes = R.string.tutorial_category_color_condition_desc_long, iconRes = R.drawable.ic_color_condition, content = listOf( + TutorialCategory.Content.Divider, TutorialCategory.Content.Tutorial(TutorialItem.Type.COLOR_CONDITION), ), ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/image/ImageConditionsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/image/ImageConditionsCategory.kt index 74b3d1067..be5fee7e1 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/image/ImageConditionsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/image/ImageConditionsCategory.kt @@ -29,8 +29,10 @@ internal fun getImageConditionsCategory() = longDescriptionRes = R.string.tutorial_category_image_condition_desc_long, iconRes = R.drawable.ic_condition, content = listOf( + TutorialCategory.Content.Divider, TutorialCategory.Content.Tutorial(TutorialItem.Type.IMAGE_DETECTION_STILL_TARGET), TutorialCategory.Content.Tutorial(TutorialItem.Type.IMAGE_DETECTION_MOVING_TARGET), + TutorialCategory.Content.Divider, TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.IMAGE_CONDITION_CAPTURE), TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.IMAGE_CONDITION_DETECTION_AREA), ), diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/number/NumberConditionsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/number/NumberConditionsCategory.kt index 4a7c7ca4e..ca721fe26 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/number/NumberConditionsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/number/NumberConditionsCategory.kt @@ -29,7 +29,9 @@ internal fun getNumberConditionsCategory() = longDescriptionRes = R.string.tutorial_category_number_condition_desc_long, iconRes = R.drawable.ic_number_condition, content = listOf( + TutorialCategory.Content.Divider, TutorialCategory.Content.Tutorial(TutorialItem.Type.NUMBER_CONDITION_STATIC_VALUE), + TutorialCategory.Content.Divider, TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.NUMBER_CONDITION_DETECTION_AREA), ), ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/text/TextConditionsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/text/TextConditionsCategory.kt index 77bd3be2c..4cecbe394 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/text/TextConditionsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/screenconditions/text/TextConditionsCategory.kt @@ -29,8 +29,10 @@ internal fun getTextConditionsCategory() = longDescriptionRes = R.string.tutorial_category_text_condition_desc_long, iconRes = R.drawable.ic_text_condition, content = listOf( + TutorialCategory.Content.Divider, TutorialCategory.Content.Tutorial(TutorialItem.Type.TEXT_CONDITION_STILL_TEXT), TutorialCategory.Content.Tutorial(TutorialItem.Type.TEXT_CONDITION_MOVING_TEXT), + TutorialCategory.Content.Divider, TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.TEXT_CONDITION_DETECTION_AREA), ), ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/triggerconditions/TriggerConditionsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/triggerconditions/TriggerConditionsCategory.kt index c40f96c7b..3ad6dbff4 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/triggerconditions/TriggerConditionsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/basics/triggerconditions/TriggerConditionsCategory.kt @@ -29,7 +29,9 @@ internal fun getTriggerConditionsCategory() = longDescriptionRes = R.string.tutorial_category_trigger_condition_desc_long, iconRes = R.drawable.ic_trigger_event, content = listOf( + TutorialCategory.Content.Divider, TutorialCategory.Content.Tutorial(TutorialItem.Type.TIMER_REACHED_CONDITION), + TutorialCategory.Content.Divider, TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.COUNTER_REACHED_CONDITION), TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.BROADCAST_RECEIVED_CONDITION), ), diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsCategory.kt index 2782ea4f6..4bd18c3eb 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsCategory.kt @@ -19,6 +19,7 @@ package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combinecond import com.buzbuz.smartautoclicker.feature.tutorial.R import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow internal fun getCombineConditionsCategory() = @@ -27,8 +28,13 @@ internal fun getCombineConditionsCategory() = nameRes = R.string.tutorial_category_combine_conditions_name, shortDescriptionRes = R.string.tutorial_category_combine_conditions_desc_short, longDescriptionRes = R.string.tutorial_category_combine_conditions_desc_long, - iconRes = R.drawable.ic_screen_event, + iconRes = R.drawable.ic_condition, content = listOf( - //TutorialCategory.Content.Tutorial(TutorialItem.Type.COMBINE_CONDITIONS_NOT_VISIBLE), + TutorialCategory.Content.Divider, + TutorialCategory.Content.Tutorial(TutorialItem.Type.COMBINE_CONDITIONS_OPERATOR_AND), + TutorialCategory.Content.Tutorial(TutorialItem.Type.COMBINE_CONDITIONS_OPERATOR_OR), + TutorialCategory.Content.Tutorial(TutorialItem.Type.COMBINE_CONDITIONS_NOT_VISIBLE), + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.COMBINE_CONDITIONS_ORDERING), ), ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsNotVisibleTargetTutorial.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsNotVisibleTargetTutorial.kt index 2718d5933..ba95e11a7 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsNotVisibleTargetTutorial.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsNotVisibleTargetTutorial.kt @@ -1,8 +1,29 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.Tutorial import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.TutorialInfo +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStep +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepEndCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepStartCondition import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.TutorialSubject +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredOverlayType +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType import com.buzbuz.smartautoclicker.feature.tutorial.R import com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image.TwoStillTargetsPressWhenOneVisibleRules import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem @@ -28,15 +49,13 @@ object CombineConditionsNotVisibleTargetTutorial : TutorialItem { durationSeconds = 10, rules = TwoStillTargetsPressWhenOneVisibleRules(), ), - // TODO: we need to guard the not visible with another visible condition, or a click spam will block the tutorial steps = listOf( - /* // Beginning, hide the overlay for now TutorialStep.ChangeFloatingUiVisibility( stepStartCondition = TutorialStepStartCondition.Immediate, newVisibility = false, ), - // Start screen, before first play + // Start screen, before first play. TutorialStep.TutorialOverlay( contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_1, stepStartCondition = TutorialStepStartCondition.Immediate, @@ -47,187 +66,96 @@ object CombineConditionsNotVisibleTargetTutorial : TutorialItem { stepStartCondition = TutorialStepStartCondition.GameLost, newVisibility = true, ), - // First play lost, open edit scenario + // First play lost, open edit scenario and go to screen condition list TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_3, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_2, stepStartCondition = TutorialStepStartCondition.Immediate, stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( MonitoredViewType.MAIN_MENU_BUTTON_CONFIG, ), ), - // Create Event + // Screen condition list: create first image condition and capture red target TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_4, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_3, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCREEN_CONDITIONS_BRIEF_MENU ), - ), - // Select condition field - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_5, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.EVENT_DIALOG_FIELD_CONDITIONS, - ), - ), - // Create a new condition - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_6, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( MonitoredViewType.CONDITIONS_BRIEF_MENU_BUTTON_CREATE, ), ), - // Create a new condition - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_7, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.SCREEN_CONDITION_TYPE_SELECTION_IMAGE, - ), - ), - // Take a screenshot + // Image condition dialog: toggle "is visible" to no TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_8, - image = TutorialStepImage( - imageResId = R.drawable.ic_capture, - imageDescResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_secondary_8, - ), - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.NextButton, - ), - // Ensure target is captured or retry - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_9, - image = TutorialStepImage( - imageResId = R.drawable.ic_cancel, - imageDescResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_secondary_9, - ), - stepStartCondition = TutorialStepStartCondition.MonitoredViewClicked( - MonitoredViewType.SCREEN_CONDITION_CAPTURE_MENU_BUTTON_CAPTURE, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_4, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.IMAGE_CONDITION, ), - stepEndCondition = TutorialStepEndCondition.NextButton, - ), - // Talk about area - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_10, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.NextButton, - ), - // Change visibility - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_11, - stepStartCondition = TutorialStepStartCondition.Immediate, stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( MonitoredViewType.SCREEN_CONDITION_DIALOG_FIELD_VISIBILITY, ), ), - // Save condition + // Screen condition dialog: save condition TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_12, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_5, stepStartCondition = TutorialStepStartCondition.Immediate, stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( MonitoredViewType.SCREEN_CONDITION_DIALOG_BUTTON_SAVE, ), ), - // Close condition list + // Screen condition list: create second image condition adn capture blue target TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_13, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.CONDITIONS_BRIEF_MENU_BUTTON_SAVE, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_6, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCREEN_CONDITIONS_BRIEF_MENU ), - ), - // Select action field - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_14, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, - ), - ), - // Create a new action - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_15, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.ACTIONS_BRIEF_MENU_BUTTON_CREATE_ACTION, + MonitoredViewType.CONDITIONS_BRIEF_MENU_BUTTON_CREATE, ), ), - // Create a new click + // Image condition dialog: Save condition and go back to event dialog TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_16, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.ACTION_TYPE_DIALOG_CLICK_ACTION, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_7, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.IMAGE_CONDITION, ), - ), - // Select click location - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_17, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.CLICK_DIALOG_FIELD_SELECT_POSITION_OR_CONDITION, - ), - ), - // Pick location - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_18, - image = TutorialStepImage( - imageResId = R.drawable.ic_visible_on, - imageDescResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_secondary_18, + MonitoredViewType.SCREEN_CONDITION_DIALOG_BUTTON_SAVE, ), - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.NextButton, ), - // Save click + // Event dialog: open actions list and create new click TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_19, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.CLICK_DIALOG_BUTTON_SAVE, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_8, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, ), - ), - // Close action list - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_20, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.ACTIONS_BRIEF_MENU_BUTTON_SAVE, + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, ), ), - // Save Event + // Click Dialog: Select "click on condition" TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_21, - stepStartCondition = TutorialStepStartCondition.Immediate, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.EVENT_DIALOG_BUTTON_SAVE, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_9, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CLICK, ), - ), - // Save scenario - TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_22, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.SCENARIO_DIALOG_BUTTON_SAVE, + MonitoredViewType.CLICK_DIALOG_FIELD_POSITION_TYPE_ITEM_ON_CONDITION, ), ), - // Play scenario + // Scenario saved, start it and start the game TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_23, - stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed, - stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( - MonitoredViewType.MAIN_MENU_BUTTON_PLAY, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_10, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, ), + stepEndCondition = TutorialStepEndCondition.NextButton, ), // Game won TutorialStep.TutorialOverlay( - contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_24, + contentTextResId = R.string.message_tutorial_combine_conditions_not_visible_target_step_11, stepStartCondition = TutorialStepStartCondition.GameWon, stepEndCondition = TutorialStepEndCondition.NextButton, ), - */ ) ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOperatorAndTutorial.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOperatorAndTutorial.kt new file mode 100644 index 000000000..8ca78ee16 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOperatorAndTutorial.kt @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions + +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.Tutorial +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.TutorialInfo +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStep +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepEndCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepImage +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepStartCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.TutorialSubject +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredOverlayType +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image.TwoStillTargetsPressWhenBothVisibleRules +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem + +object CombineConditionsOperatorAndTutorial : TutorialItem { + + override fun getType(): TutorialItem.Type = + TutorialItem.Type.COMBINE_CONDITIONS_OPERATOR_AND + + override fun getTutorialInfo(): TutorialInfo = + TutorialInfo( + id = getType().toTutorialId(), + nameResId = R.string.item_title_tutorial_combine_conditions_operator_and, + descResId = R.string.item_desc_tutorial_combine_conditions_operator_and, + ) + + override fun getTutorial(): Tutorial = + Tutorial( + info = getTutorialInfo(), + subject = TutorialSubject.QuickClickGame( + instructionsResId = R.string.message_game_tutorial_combine_conditions_operator_and, + scoreToReach = 30, + durationSeconds = 10, + rules = TwoStillTargetsPressWhenBothVisibleRules(), + ), + steps = listOf( + // Beginning, hide the overlay for now + TutorialStep.ChangeFloatingUiVisibility( + stepStartCondition = TutorialStepStartCondition.Immediate, + newVisibility = false, + ), + // Start screen, before first play. + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_1, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // First play lost, make floating menu visible + TutorialStep.ChangeFloatingUiVisibility( + stepStartCondition = TutorialStepStartCondition.GameLost, + newVisibility = true, + ), + // First play lost, open edit scenario and go to screen condition list + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_2, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.MAIN_MENU_BUTTON_CONFIG, + ), + ), + // Screen condition list: create first image condition and capture blue target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_3, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCREEN_CONDITIONS_BRIEF_MENU, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.CONDITIONS_BRIEF_MENU_BUTTON_CREATE, + ), + ), + // Screen condition dialog: save blue target condition + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_4, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.IMAGE_CONDITION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCREEN_CONDITION_DIALOG_BUTTON_SAVE, + ), + ), + // Screen condition list: create second image condition and capture red target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_5, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCREEN_CONDITIONS_BRIEF_MENU + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.CONDITIONS_BRIEF_MENU_BUTTON_CREATE, + ), + ), + // Image condition dialog: Save red target condition and go back to event dialog + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_6, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.IMAGE_CONDITION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCREEN_CONDITION_DIALOG_BUTTON_SAVE, + ), + ), + // Event dialog: Note about AND or OR + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_7, + image = TutorialStepImage( + imageResId = R.drawable.tutorial_instructions_condition_operator_and, + imageDescResId = R.string.message_tutorial_combine_conditions_operator_and_step_secondary_7, + ), + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Event dialog: open actions list and create new click + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_8, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Click Dialog: Select "click on condition" + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_9, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CLICK, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.CLICK_DIALOG_FIELD_POSITION_TYPE_ITEM_ON_CONDITION, + ), + ), + // Scenario saved, start it and start the game + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_10, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Game won + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_and_step_11, + stepStartCondition = TutorialStepStartCondition.GameWon, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + ) + ) + +} \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOperatorOrTutorial.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOperatorOrTutorial.kt new file mode 100644 index 000000000..c98ac9372 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOperatorOrTutorial.kt @@ -0,0 +1,174 @@ +/* +* Copyright (C) 2026 Kevin Buzeau +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions + +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.Tutorial +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.TutorialInfo +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStep +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepEndCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepStartCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.TutorialSubject +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredOverlayType +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image.TwoStillTargetsPressAnyRules +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem + +object CombineConditionsOperatorOrTutorial : TutorialItem { + + override fun getType(): TutorialItem.Type = + TutorialItem.Type.COMBINE_CONDITIONS_OPERATOR_OR + + override fun getTutorialInfo(): TutorialInfo = + TutorialInfo( + id = getType().toTutorialId(), + nameResId = R.string.item_title_tutorial_combine_conditions_operator_or, + descResId = R.string.item_desc_tutorial_combine_conditions_operator_or, + ) + + override fun getTutorial(): Tutorial = + Tutorial( + info = getTutorialInfo(), + subject = TutorialSubject.QuickClickGame( + instructionsResId = R.string.message_game_tutorial_combine_conditions_operator_or, + scoreToReach = 150, + durationSeconds = 10, + rules = TwoStillTargetsPressAnyRules( + blueScoreIncrement = 1, + redScoreIncrement = 2, + targetsBehaviour = TwoStillTargetsPressAnyRules.TargetsBehaviour.BLUE_BLINK_RED_BLINK, + ), + ), + steps = listOf( + // Beginning, hide the overlay for now + TutorialStep.ChangeFloatingUiVisibility( + stepStartCondition = TutorialStepStartCondition.Immediate, + newVisibility = false, + ), + // Start screen, before first play. + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_1, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // First play lost, make floating menu visible + TutorialStep.ChangeFloatingUiVisibility( + stepStartCondition = TutorialStepStartCondition.GameLost, + newVisibility = true, + ), + // First play lost, open edit scenario and go to screen condition list + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_2, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.MAIN_MENU_BUTTON_CONFIG, + ), + ), + // Screen condition list: create first image condition and capture blue target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_3, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCREEN_CONDITIONS_BRIEF_MENU + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.CONDITIONS_BRIEF_MENU_BUTTON_CREATE, + ), + ), + // Screen condition dialog: save blue target condition + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_4, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.IMAGE_CONDITION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCREEN_CONDITION_DIALOG_BUTTON_SAVE, + ), + ), + // Screen condition list: create second image condition and capture red target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_5, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCREEN_CONDITIONS_BRIEF_MENU + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.CONDITIONS_BRIEF_MENU_BUTTON_CREATE, + ), + ), + // Image condition dialog: Save red target condition and go back to condition list + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_6, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.IMAGE_CONDITION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCREEN_CONDITION_DIALOG_BUTTON_SAVE, + ), + ), + // ScreenCondition List: Note about OR and Condition priority. Ask for reorder red before blue + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_7, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCREEN_CONDITIONS_BRIEF_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Event dialog: Note about AND or OR + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_8, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_OPERATOR_ITEM_OR + ), + ), + // Event dialog: open actions list and create new click + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_9, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Click Dialog: Select "click on condition". As the condition is OR, click on detected nothing to select + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_10, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CLICK, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.CLICK_DIALOG_FIELD_POSITION_TYPE_ITEM_ON_CONDITION, + ), + ), + // Scenario saved, start it and start the game + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_11, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Game won + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_combine_conditions_operator_or_step_12, + stepStartCondition = TutorialStepStartCondition.GameWon, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + ) + ) + +} \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOrderingSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOrderingSlideshow.kt new file mode 100644 index 000000000..f6117bde1 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineconditions/CombineConditionsOrderingSlideshow.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getCombineConditionsOrderingSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.COMBINE_CONDITIONS_ORDERING, + nameRes = R.string.tutorial_slideshow_combine_conditions_ordering_title, + shortDescriptionRes = R.string.tutorial_slideshow_combine_conditions_ordering_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_combine_conditions_ordering_step_1_text, + tutorialImage = R.drawable.tutorial_instructions_condition_operator_and, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_SQUARE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_combine_conditions_ordering_step_2_text, + tutorialImage = R.drawable.tutorial_instructions_condition_operator_or, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_SQUARE, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/EventStateCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/EventStateCategory.kt new file mode 100644 index 000000000..2b641d4c4 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/EventStateCategory.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + + +internal fun getCombineEventsCategory() = + TutorialCategory( + type = TutorialCategory.Type.COMBINE_EVENTS, + nameRes = R.string.tutorial_category_combine_event_name, + shortDescriptionRes = R.string.tutorial_category_combine_event_desc_short, + longDescriptionRes = R.string.tutorial_category_combine_event_desc_long, + iconRes = R.drawable.ic_screen_event, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Category(TutorialCategory.Type.EVENTS_PRIORITY), + TutorialCategory.Content.Category(TutorialCategory.Type.EVENTS_STATE), + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.EVENTS_RELOADING), + ), + ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/EventsReloadingSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/EventsReloadingSlideshow.kt new file mode 100644 index 000000000..da9f76bd4 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/EventsReloadingSlideshow.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getEventsReloadingSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.EVENTS_RELOADING, + nameRes = R.string.tutorial_slideshow_events_reloading_title, + shortDescriptionRes = R.string.tutorial_slideshow_events_reloading_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_events_reloading_step_1_text, + tutorialImage = R.drawable.tutorial_instructions_event_reloading, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityBasicsSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityBasicsSlideshow.kt new file mode 100644 index 000000000..ebff93a7c --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityBasicsSlideshow.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.priority + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getEventsPrioritySlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.EVENTS_PRIORITY_BASICS, + nameRes = R.string.tutorial_slideshow_events_priority_title, + shortDescriptionRes = R.string.tutorial_slideshow_events_priority_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_events_priority_step_1_text, + tutorialImage = R.drawable.tutorial_instructions_event_priority, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_events_priority_step_2_text, + tutorialImage = R.drawable.tutorial_instructions_keep_executing, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityCategory.kt new file mode 100644 index 000000000..d520cbfad --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityCategory.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.priority + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + + +internal fun getEventsPriorityCategory() = + TutorialCategory( + type = TutorialCategory.Type.EVENTS_PRIORITY, + nameRes = R.string.tutorial_category_events_priority_name, + shortDescriptionRes = R.string.tutorial_category_events_priority_desc_short, + longDescriptionRes = R.string.tutorial_category_events_priority_desc_long, + iconRes = R.drawable.ic_priority, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.EVENTS_PRIORITY_BASICS), + TutorialCategory.Content.Tutorial(TutorialItem.Type.EVENTS_PRIORITY), + ), + ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityTutorial.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityTutorial.kt new file mode 100644 index 000000000..86a8c93e6 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/priority/EventsPriorityTutorial.kt @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.priority + +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.Tutorial +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.TutorialInfo +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStep +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepEndCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepImage +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepStartCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.TutorialSubject +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredOverlayType +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image.TwoStillTargetsPressAnyRules +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem + +object EventsPriorityTutorial : TutorialItem { + + override fun getType(): TutorialItem.Type = + TutorialItem.Type.EVENTS_PRIORITY + + override fun getTutorialInfo(): TutorialInfo = + TutorialInfo( + id = getType().toTutorialId(), + nameResId = R.string.item_title_tutorial_events_priority, + descResId = R.string.item_desc_tutorial_events_priority, + ) + + override fun getTutorial(): Tutorial = + Tutorial( + info = getTutorialInfo(), + subject = TutorialSubject.QuickClickGame( + instructionsResId = R.string.message_game_tutorial_events_priority, + scoreToReach = 200, + durationSeconds = 10, + rules = TwoStillTargetsPressAnyRules( + blueScoreIncrement = 1, + redScoreIncrement = 10, + targetsBehaviour = TwoStillTargetsPressAnyRules.TargetsBehaviour.BLUE_STILL_RED_BLINK, + ), + ), + steps = listOf( + // Beginning, hide the overlay for now + TutorialStep.ChangeFloatingUiVisibility( + stepStartCondition = TutorialStepStartCondition.Immediate, + newVisibility = true, + ), + // Play the game or open edit scenario + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_1, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Create Event for the blue target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_2, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + ), + ), + // Create Event for the red target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_3, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + ), + ), + // Save scenario + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_4, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_SAVE, + ), + ), + // Play and lose, explain why (order make blue click always clicked, red is never executed) + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_5, + stepStartCondition = TutorialStepStartCondition.GameLost, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Explain order and drag and drop to reorder. Reorder red before blue and save scenario + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_6, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Explain order and drag and drop to reorder. Reorder red before blue and save scenario + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_7, + image = TutorialStepImage( + imageResId = R.drawable.ic_reorder, + imageDescResId = R.string.message_tutorial_events_priority_step_7_secondary, + ), + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Priority is now ok, start scenario than start the game + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_8, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Game won + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_priority_step_9, + stepStartCondition = TutorialStepStartCondition.GameWon, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + ) + ) + +} \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateBasicsSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateBasicsSlideshow.kt new file mode 100644 index 000000000..08c6a73a8 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateBasicsSlideshow.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.state + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getEventsStateBasicsSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.EVENTS_STATE_BASICS, + nameRes = R.string.tutorial_slideshow_events_state_basics_title, + shortDescriptionRes = R.string.tutorial_slideshow_events_state_basics_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_events_state_basics_step_1_text, + tutorialImage = R.drawable.ic_toggle_event, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_events_state_basics_step_2_text, + tutorialImage = R.drawable.tutorial_instructions_toggle_event, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_LARGE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_events_state_basics_step_3_text, + tutorialImage = R.drawable.ic_cancel, + tutorialImageFormat = TutorialSlideshow.ImageFormat.ICON, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateCategory.kt new file mode 100644 index 000000000..135d83e67 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateCategory.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.state + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + + +internal fun getEventsStateCategory() = + TutorialCategory( + type = TutorialCategory.Type.EVENTS_STATE, + nameRes = R.string.tutorial_category_events_state_name, + shortDescriptionRes = R.string.tutorial_category_events_state_desc_short, + longDescriptionRes = R.string.tutorial_category_events_state_desc_long, + iconRes = R.drawable.ic_toggle_event, + content = listOf( + TutorialCategory.Content.Divider, + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.EVENTS_STATE_BASICS), + TutorialCategory.Content.Tutorial(TutorialItem.Type.EVENTS_STATE), + ), + ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateTutorial.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateTutorial.kt new file mode 100644 index 000000000..65eb8d308 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/combineevents/state/EventsStateTutorial.kt @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.state + +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.Tutorial +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.TutorialInfo +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStep +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepEndCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepImage +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepStartCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.TutorialSubject +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredOverlayType +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image.FourMovingTargetsInOrderTargetRules +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem + +object EventsStateTutorial : TutorialItem { + + override fun getType(): TutorialItem.Type = + TutorialItem.Type.EVENTS_STATE + + override fun getTutorialInfo(): TutorialInfo = + TutorialInfo( + id = getType().toTutorialId(), + nameResId = R.string.item_title_tutorial_events_state, + descResId = R.string.item_desc_tutorial_events_state, + ) + + override fun getTutorial(): Tutorial = + Tutorial( + info = getTutorialInfo(), + subject = TutorialSubject.QuickClickGame( + instructionsResId = R.string.message_game_tutorial_events_state, + scoreToReach = 200, + durationSeconds = 10, + rules = FourMovingTargetsInOrderTargetRules(), + ), + steps = listOf( + // Beginning, hide the overlay for now + TutorialStep.ChangeFloatingUiVisibility( + stepStartCondition = TutorialStepStartCondition.Immediate, + newVisibility = true, + ), + // Play the game or open edit scenario + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_1, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Scenario dialog: Create Event for the blue target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_2, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + ), + ), + // Event dialog: define a name + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_3, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Image Condition dialog: select game area + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_4, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.IMAGE_CONDITION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCREEN_CONDITION_DIALOG_FIELD_TYPE_ITEM_IN_AREA, + ), + ), + // Event dialog: create action + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_5, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Click action dialog: click on condition type + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_6, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CLICK, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.CLICK_DIALOG_FIELD_POSITION_TYPE_ITEM_ON_CONDITION, + ), + ), + // Scenario dialog: create red + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_7, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + ), + ), + // Scenario dialog: create green + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_8, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + ), + ), + // Scenario dialog: create yellow + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_9, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + ), + ), + // Scenario dialog: save and test + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_10, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_SAVE, + ), + ), + // Game: play and lose, it is too slow + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_11, + stepStartCondition = TutorialStepStartCondition.GameLost, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Scenario dialog: explain state and all enabled + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_12, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_ITEM_FIRST_EVENT, + ), + ), + // Event dialog: blue is the first target, so we want it enabled by default, open actions + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_13, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Action type selection: blue target: pick Change event state + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_14, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.ACTION_TYPE_SELECTION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.ACTION_TYPE_DIALOG_TOGGLE_EVENT_ACTION, + ), + ), + // Toggle Event dialog: blue target: explain toggle dialog, select changes + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_15, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.TOGGLE_EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.TOGGLE_EVENT_DIALOG_SELECT_TOGGLES, + ), + ), + // Toggle selection: blue target: enable red, disable others. Secondary show toggle ui and explain the + // 3 values + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_16, + image = TutorialStepImage( + imageResId = R.drawable.tutorial_instructions_toggle_event, + imageDescResId = R.string.message_tutorial_events_state_step_16_secondary, + ), + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT_TOGGLES, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Event dialog: blue target save + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_17, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_BUTTON_SAVE, + ), + ), + // Scenario dialog: Now modify red + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_18, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_ITEM_SECOND_EVENT, + ), + ), + // Event dialog: red needs to be disabled at start, so change the initial state + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_19, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_INITIAL_STATE, + ), + ), + // Event dialog: red target: add new Change Event State action + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_20, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Toggle selection: red target: enable green, disable others + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_21, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT_TOGGLES, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Scenario dialog: Now modify green + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_22, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_ITEM_THIRD_EVENT, + ), + ), + // Event dialog: green needs to be disabled at start, so change the initial state + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_23, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_INITIAL_STATE, + ), + ), + // Event dialog: green target: add new Change Event State action + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_24, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Toggle selection: green target: enable yellow, disable others + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_25, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT_TOGGLES, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Scenario dialog: Now modify yellow + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_26, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_ITEM_FOURTH_EVENT, + ), + ), + // Event dialog: yellow needs to be disabled at start, so change the initial state + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_27, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_INITIAL_STATE, + ), + ), + // Event dialog: yellow target: add new Change Event State action + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_28, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Toggle selection: yellow target: enable blue (as we want to loop) and disable others + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_29, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT_TOGGLES, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Scenario dialog: everything is ok save your scenario + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_30, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_SAVE, + ), + ), + // Game: start game (note about state reset, restart the scenario everytime we need to restart the game) + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_31, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Game won, resume what we learned + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_events_state_step_32, + stepStartCondition = TutorialStepStartCondition.GameWon, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + ) + ) + +} \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersBasicsTutorial.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersBasicsTutorial.kt new file mode 100644 index 000000000..b2eab5f42 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersBasicsTutorial.kt @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.counters + +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.Tutorial +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.TutorialInfo +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStep +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepEndCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepImage +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.step.TutorialStepStartCondition +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.TutorialSubject +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredOverlayType +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.monitoring.MonitoredViewType +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image.CountBlueValidateRedRules +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem + +object CountersBasicsTutorial : TutorialItem { + + override fun getType(): TutorialItem.Type = + TutorialItem.Type.COUNTERS_BASICS + + override fun getTutorialInfo(): TutorialInfo = + TutorialInfo( + id = getType().toTutorialId(), + nameResId = R.string.item_title_tutorial_counters_basics, + descResId = R.string.item_desc_tutorial_counters_basics, + ) + + override fun getTutorial(): Tutorial = + Tutorial( + info = getTutorialInfo(), + subject = TutorialSubject.QuickClickGame( + instructionsResId = R.string.message_game_tutorial_counters_basics, + scoreToReach = 70, + durationSeconds = 10, + rules = CountBlueValidateRedRules(), + ), + steps = listOf( + // Beginning, hide the overlay for now + TutorialStep.ChangeFloatingUiVisibility( + stepStartCondition = TutorialStepStartCondition.Immediate, + newVisibility = true, + ), + // Play the game or open edit scenario + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_1, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Scenario dialog: Create Event for the blue target that clicks on it + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_2, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + ), + ), + // Event dialog: Add a condition for the blue target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_3, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_CONDITIONS, + ), + ), + // Event dialog: Add actions for the blue target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_4, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Action list: create click on blue target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_5, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SMART_ACTIONS_BRIEF_MENU, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.ACTIONS_BRIEF_MENU_BUTTON_CREATE_ACTION, + ), + ), + // Click dialog: configure to click on the blue target and save + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_6, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CLICK, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Action list: create set counter action + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_7, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SMART_ACTIONS_BRIEF_MENU, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.ACTIONS_BRIEF_MENU_BUTTON_CREATE_ACTION, + ), + ), + // Action list: pick change counter action + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_8, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.ACTION_TYPE_SELECTION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.ACTION_TYPE_DIALOG_COUNTER_ACTION, + ), + ), + // Change Counter dialog: Click on select a counter + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_9, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CHANGE_COUNTER, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.COUNTER_ACTION_DIALOG_FIELD_SELECT_COUNTER, + ), + ), + // Counter Selection dialog: Create a counter, give it a name, keep starting at 0 and save. Select it + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_10, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.COUNTER_SELECTION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.COUNTER_SELECTION_DIALOG_BUTTON_CREATE, + ), + ), + // Change Counter dialog: Explain set operator on counter (=, +, -). Ask to do +1 + // Image shows selection between static & other counter operand. + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_11, + image = TutorialStepImage( + imageResId = R.drawable.tutorial_instructions_change_counter_value_type, + imageDescResId = R.string.message_tutorial_counters_basics_step_11_secondary, + ), + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CHANGE_COUNTER, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Event dialog: Event is ok, we click and count the number of clicks + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_12, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_BUTTON_SAVE, + ), + ), + // Scenario dialog: Need to act when counter = 10, click on trigger event tab + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_13, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_TRIGGER_EVENT_TAB, + ), + ), + // Scenario dialog: Create a new TriggerEvent + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_14, + stepStartCondition = TutorialStepStartCondition.Immediate, + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_CREATE_EVENT, + ), + ), + // Event dialog: First, create a new Counter Reached condition + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_15, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_CONDITIONS, + ), + ), + // Condition type dialog: Pick counter reached + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_16, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.TRIGGER_CONDITION_TYPE_SELECTION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.TRIGGER_CONDITION_TYPE_ON_COUNTER_REACHED, + ), + ), + // Counter reached dialog: Select the blue target counter created before + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_17, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.COUNTER_REACHED_CONDITION, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.COUNTER_REACHED_DIALOG_FIELD_COUNTER_SELECTION, + ), + ), + // Counter reached dialog: explain comparison operation. Ask to verify = 10 + // Image shows selection between static & other counter value. + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_18, + image = TutorialStepImage( + imageResId = R.drawable.tutorial_instructions_change_counter_value_type, + imageDescResId = R.string.message_tutorial_counters_basics_step_18_secondary, + ), + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.COUNTER_REACHED_CONDITION, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Event dialog: Add actions for the red target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_19, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_FIELD_ACTIONS, + ), + ), + // Action list: create click on red target + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_20, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SMART_ACTIONS_BRIEF_MENU, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.ACTIONS_BRIEF_MENU_BUTTON_CREATE_ACTION, + ), + ), + // Click dialog: configure to click on the red target and save. As this is trigger event, can't + // click on condition + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_21, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CLICK, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Action list: create set counter action + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_22, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SMART_ACTIONS_BRIEF_MENU, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.ACTIONS_BRIEF_MENU_BUTTON_CREATE_ACTION, + ), + ), + // Change Counter dialog: Click on select a counter and pick the blue target counter + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_23, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CHANGE_COUNTER, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.COUNTER_ACTION_DIALOG_FIELD_SELECT_COUNTER, + ), + ), + // Change Counter dialog: Ask to do "= 0" to reset the counter and save + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_24, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.CHANGE_COUNTER, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Event dialog: Trigger event is ok, triggers when 10, clicks on red and reset + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_25, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.EVENT, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.EVENT_DIALOG_BUTTON_SAVE, + ), + ), + // Scenario dialog: scenario is complete, when click & count, then reset; save it. + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_26, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.SCENARIO, + ), + stepEndCondition = TutorialStepEndCondition.MonitoredViewClicked( + MonitoredViewType.SCENARIO_DIALOG_BUTTON_SAVE, + ), + ), + // Game: Start the scenario and start the game + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_27, + stepStartCondition = TutorialStepStartCondition.MonitoredOverlayDisplayed( + MonitoredOverlayType.MAIN_MENU, + ), + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + // Game won: resume what we learned + TutorialStep.TutorialOverlay( + contentTextResId = R.string.message_tutorial_counters_basics_step_28, + stepStartCondition = TutorialStepStartCondition.GameWon, + stepEndCondition = TutorialStepEndCondition.NextButton, + ), + ) + ) + +} \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersCategory.kt index 3437a64b6..24fcb44ab 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersCategory.kt @@ -18,6 +18,8 @@ package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.counters import com.buzbuz.smartautoclicker.feature.tutorial.R import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow internal fun getCountersCategory() = @@ -28,6 +30,8 @@ internal fun getCountersCategory() = longDescriptionRes = R.string.tutorial_category_counters_desc_long, iconRes = R.drawable.ic_counter_reached, content = listOf( - + TutorialCategory.Content.Divider, + TutorialCategory.Content.Tutorial(TutorialItem.Type.COUNTERS_BASICS), + TutorialCategory.Content.Slideshow(TutorialSlideshow.Type.COUNTERS_VALUE_USAGES), ), ) \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersValueUsagesSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersValueUsagesSlideshow.kt new file mode 100644 index 000000000..19b1afd38 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/items/root/counters/CountersValueUsagesSlideshow.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.counters + +import com.buzbuz.smartautoclicker.feature.tutorial.R +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow + +internal fun getCountersValueUsagesSlideshow() = + TutorialSlideshow( + type = TutorialSlideshow.Type.COUNTERS_VALUE_USAGES, + nameRes = R.string.tutorial_slideshow_counters_value_usages_title, + shortDescriptionRes = R.string.tutorial_slideshow_counters_value_usages_desc, + slideshowItems = listOf( + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_counters_value_usages_step_1_text, + tutorialImage = R.drawable.ic_action_notification, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_SQUARE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_counters_value_usages_step_2_text, + tutorialImage = R.drawable.ic_action_set_text, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_SQUARE, + ), + TutorialSlideshow.SlideshowItem( + tutorialTextRes = R.string.tutorial_slideshow_counters_value_usages_step_3_text, + tutorialImage = R.drawable.tutorial_instructions_debug_report_counters, + tutorialImageFormat = TutorialSlideshow.ImageFormat.IMAGE_SQUARE, + ), + ), + ) diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialCategoryMapping.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialCategoryMapping.kt index 4725d020e..6e2df2e67 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialCategoryMapping.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialCategoryMapping.kt @@ -19,6 +19,15 @@ package com.buzbuz.smartautoclicker.feature.tutorial.data.mapping import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialCategory.Type.* import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.getActionsCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.changecounter.getChangeCounterActionCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.changeeventstate.getChangeEventStateActionCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.click.getClickActionCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.intent.getIntentActionCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.notification.getNotificationActionCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.pause.getPauseActionCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.swipe.getSwipeActionCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.system.getSystemActionCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.writetext.getWriteTextActionCategory import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.getBasicsCategory import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.screenconditions.color.getColorConditionsCategory import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.screenconditions.getScreenConditionsCategory @@ -28,7 +37,9 @@ import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.scree import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.triggerconditions.getTriggerConditionsCategory import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions.getCombineConditionsCategory import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.counters.getCountersCategory -import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.eventstate.getEventStateCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.getCombineEventsCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.priority.getEventsPriorityCategory +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.state.getEventsStateCategory import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.getRootCategory @@ -36,14 +47,25 @@ internal fun TutorialCategory.Type.toTutorialCategory(): TutorialCategory = when (this) { ACTIONS -> getActionsCategory() BASICS -> getBasicsCategory() + CHANGE_COUNTER_ACTION -> getChangeCounterActionCategory() + TOGGLE_EVENT_ACTION -> getChangeEventStateActionCategory() + CLICK_ACTION -> getClickActionCategory() COLOR_CONDITION -> getColorConditionsCategory() COMBINE_CONDITIONS -> getCombineConditionsCategory() COUNTERS -> getCountersCategory() - EVENT_STATE -> getEventStateCategory() + COMBINE_EVENTS -> getCombineEventsCategory() + EVENTS_PRIORITY -> getEventsPriorityCategory() + EVENTS_STATE -> getEventsStateCategory() IMAGE_CONDITION -> getImageConditionsCategory() + INTENT_ACTION -> getIntentActionCategory() + NOTIFICATION_ACTION -> getNotificationActionCategory() NUMBER_CONDITION -> getNumberConditionsCategory() + PAUSE_ACTION -> getPauseActionCategory() ROOT -> getRootCategory() SCREEN_CONDITIONS -> getScreenConditionsCategory() + SWIPE_ACTION -> getSwipeActionCategory() + SYSTEM_ACTION -> getSystemActionCategory() TEXT_CONDITION -> getTextConditionsCategory() TRIGGER_CONDITIONS -> getTriggerConditionsCategory() + WRITE_TEXT_ACTION -> getWriteTextActionCategory() } diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialItemMapping.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialItemMapping.kt index 68b510f13..a66f1390e 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialItemMapping.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialItemMapping.kt @@ -24,6 +24,11 @@ import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.scree import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.screenconditions.text.TextConditionsStillTextTutorial import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.triggerconditions.TimerReachedConditionTutorial import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions.CombineConditionsNotVisibleTargetTutorial +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions.CombineConditionsOperatorAndTutorial +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions.CombineConditionsOperatorOrTutorial +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.priority.EventsPriorityTutorial +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.state.EventsStateTutorial +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.counters.CountersBasicsTutorial import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialItem.Type.* @@ -33,6 +38,13 @@ internal fun TutorialItem.Type.toTutorialItem(): TutorialItem = COLOR_CONDITION -> ColorConditionsTutorial COMBINE_CONDITIONS_NOT_VISIBLE -> CombineConditionsNotVisibleTargetTutorial + COMBINE_CONDITIONS_OPERATOR_AND -> CombineConditionsOperatorAndTutorial + COMBINE_CONDITIONS_OPERATOR_OR -> CombineConditionsOperatorOrTutorial + + COUNTERS_BASICS -> CountersBasicsTutorial + + EVENTS_PRIORITY -> EventsPriorityTutorial + EVENTS_STATE -> EventsStateTutorial IMAGE_DETECTION_MOVING_TARGET -> ImageConditionsMovingTargetTutorial IMAGE_DETECTION_STILL_TARGET -> ImageConditionsStillTargetTutorial diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialSlideshowMapping.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialSlideshowMapping.kt index d452c0a4d..00994b3dd 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialSlideshowMapping.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/mapping/TutorialSlideshowMapping.kt @@ -16,6 +16,17 @@ */ package com.buzbuz.smartautoclicker.feature.tutorial.data.mapping +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.getActionsListSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.changecounter.getChangeCounterActionSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.click.getClickActionOffsetSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.click.getClickActionTargetSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.pause.getPauseActionSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.swipe.getSwipeActionSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.intent.getIntentActionSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.notification.getNotificationActionSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.changeeventstate.getChangeEventStateActionSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.system.getSystemActionSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.actions.writetext.getWriteTextActionSlideshow import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.screenconditions.getScreenConditionsThresholdSlideshow import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.screenconditions.getScreenConditionsTypeSlideshow import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.screenconditions.image.getImageConditionsCaptureSlideshow @@ -24,17 +35,39 @@ import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.scree import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.screenconditions.text.getTextConditionsDetectionAreaSlideshow import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.triggerconditions.getBroadcastReceivedSlideshow import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.basics.triggerconditions.getCounterReachedSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineconditions.getCombineConditionsOrderingSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.getEventsReloadingSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.state.getEventsStateBasicsSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.combineevents.priority.getEventsPrioritySlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.data.items.root.counters.getCountersValueUsagesSlideshow import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow +import com.buzbuz.smartautoclicker.feature.tutorial.domain.model.TutorialSlideshow.Type.* internal fun TutorialSlideshow.Type.toTutorialSlideshow(): TutorialSlideshow = when (this) { - TutorialSlideshow.Type.BROADCAST_RECEIVED_CONDITION -> getBroadcastReceivedSlideshow() - TutorialSlideshow.Type.COUNTER_REACHED_CONDITION -> getCounterReachedSlideshow() - TutorialSlideshow.Type.IMAGE_CONDITION_CAPTURE -> getImageConditionsCaptureSlideshow() - TutorialSlideshow.Type.IMAGE_CONDITION_DETECTION_AREA -> getImageConditionsDetectionAreaSlideshow() - TutorialSlideshow.Type.NUMBER_CONDITION_DETECTION_AREA -> getNumberConditionsDetectionAreaSlideshow() - TutorialSlideshow.Type.SCREEN_CONDITIONS_DETECTION_THRESHOLD -> getScreenConditionsThresholdSlideshow() - TutorialSlideshow.Type.SCREEN_CONDITIONS_TYPE -> getScreenConditionsTypeSlideshow() - TutorialSlideshow.Type.TEXT_CONDITION_DETECTION_AREA -> getTextConditionsDetectionAreaSlideshow() + ACTIONS_LIST -> getActionsListSlideshow() + BROADCAST_RECEIVED_CONDITION -> getBroadcastReceivedSlideshow() + CHANGE_COUNTER_ACTION -> getChangeCounterActionSlideshow() + CLICK_ACTION_OFFSET -> getClickActionOffsetSlideshow() + CLICK_ACTION_TARGET -> getClickActionTargetSlideshow() + COMBINE_CONDITIONS_ORDERING -> getCombineConditionsOrderingSlideshow() + COUNTER_REACHED_CONDITION -> getCounterReachedSlideshow() + COUNTERS_VALUE_USAGES -> getCountersValueUsagesSlideshow() + EVENTS_RELOADING -> getEventsReloadingSlideshow() + EVENTS_STATE_BASICS -> getEventsStateBasicsSlideshow() + EVENTS_PRIORITY_BASICS -> getEventsPrioritySlideshow() + IMAGE_CONDITION_CAPTURE -> getImageConditionsCaptureSlideshow() + IMAGE_CONDITION_DETECTION_AREA -> getImageConditionsDetectionAreaSlideshow() + INTENT_ACTION -> getIntentActionSlideshow() + NOTIFICATION_ACTION -> getNotificationActionSlideshow() + NUMBER_CONDITION_DETECTION_AREA -> getNumberConditionsDetectionAreaSlideshow() + PAUSE_ACTION -> getPauseActionSlideshow() + SCREEN_CONDITIONS_DETECTION_THRESHOLD -> getScreenConditionsThresholdSlideshow() + SCREEN_CONDITIONS_TYPE -> getScreenConditionsTypeSlideshow() + SWIPE_ACTION -> getSwipeActionSlideshow() + SYSTEM_ACTION -> getSystemActionSlideshow() + TOGGLE_EVENT_ACTION -> getChangeEventStateActionSlideshow() + TEXT_CONDITION_DETECTION_AREA -> getTextConditionsDetectionAreaSlideshow() + WRITE_TEXT_ACTION -> getWriteTextActionSlideshow() } diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/CountBlueValidateRedRules.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/CountBlueValidateRedRules.kt new file mode 100644 index 000000000..a176ae98c --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/CountBlueValidateRedRules.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image + +import android.graphics.PointF +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameRules +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameTargetState +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameTargetType + + +internal class CountBlueValidateRedRules : QuickClickGameRules { + + private val bluePosition = PointF(0.25f, 0.5f) + private val redPosition = PointF(0.75f, 0.5f) + + private var bluePressCount: Int = 0 + private var score: Int = 0 + + override fun getScore(): Int = score + + override fun onStart(): Map { + bluePressCount = 0 + score = 0 + return staticTargets() + } + + override fun onTargetHit( + current: Map, + type: QuickClickGameTargetType + ): Map { + when (type) { + QuickClickGameTargetType.IMAGE_BLUE -> + bluePressCount++ + + QuickClickGameTargetType.IMAGE_RED -> { + score += (REQUIRED_BLUE_PRESSES - (REQUIRED_BLUE_PRESSES - bluePressCount)) + .coerceAtLeast(-REQUIRED_BLUE_PRESSES) + bluePressCount = 0 + } + + else -> Unit + } + + return current + } + + override fun onTimerTick( + current: Map, + timeLeft: Long + ): Map = current + + private fun staticTargets(): Map = mapOf( + QuickClickGameTargetType.IMAGE_BLUE to QuickClickGameTargetState.StaticContent(bluePosition), + QuickClickGameTargetType.IMAGE_RED to QuickClickGameTargetState.StaticContent(redPosition), + ) +} + +private const val REQUIRED_BLUE_PRESSES = 10 \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/FourMovingTargetsInOrderTargetRules.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/FourMovingTargetsInOrderTargetRules.kt new file mode 100644 index 000000000..c561da40a --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/FourMovingTargetsInOrderTargetRules.kt @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image + +import android.graphics.RectF + +import com.buzbuz.smartautoclicker.core.base.extensions.nextPositionIn +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameRules +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameTargetState +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameTargetType + +import kotlin.random.Random + + + +internal class FourMovingTargetsInOrderTargetRules : QuickClickGameRules { + + private val random: Random = Random(System.currentTimeMillis()) + + private var score: Int = 0 + /** Index into [CLICK_ORDER] of the next target the user must click. */ + private var nextExpectedIndex: Int = 0 + + override fun getScore(): Int = score + + override fun onStart(): Map { + score = 0 + nextExpectedIndex = 0 + return getNewTargets() + } + + override fun onTargetHit( + current: Map, + type: QuickClickGameTargetType, + ): Map { + val expected = CLICK_ORDER[nextExpectedIndex] + + if (type != expected) { + // Wrong target — shuffle everything back + nextExpectedIndex = 0 + return getNewTargets() + } + + val isLastInSequence = nextExpectedIndex == CLICK_ORDER.lastIndex + + return if (isLastInSequence) { + // Yellow clicked correctly — bonus points, restart sequence + score += YELLOW_BONUS_SCORE + nextExpectedIndex = 0 + getNewTargets() + } else { + // Correct non-final target — award 1 pt and remove it + score += 1 + nextExpectedIndex++ + current.toMutableMap().apply { remove(type) } + } + } + + override fun onTimerTick( + current: Map, + timeLeft: Long, + ): Map = current + + private fun getNewTargets(): Map { + val left = TARGET_MARGIN + val right = 1f - TARGET_MARGIN + val midX = (left + right) / 2f + val midY = (left + right) / 2f + + // One target per quadrant — guarantees full-area coverage with no overlap + val quadrants = listOf( + RectF(left, left, midX - QUADRANT_GAP, midY - QUADRANT_GAP), + RectF(midX + QUADRANT_GAP, left, right, midY - QUADRANT_GAP), + RectF(left, midY + QUADRANT_GAP, midX - QUADRANT_GAP, right), + RectF(midX + QUADRANT_GAP, midY + QUADRANT_GAP, right, right), + ).shuffled(random) + + return CLICK_ORDER.zip(quadrants).associate { (type, quadrant) -> + type to QuickClickGameTargetState.StaticContent(random.nextPositionIn(quadrant)) + } + } +} + +/** Expected click order: blue → red → green → yellow */ +private val CLICK_ORDER = listOf( + QuickClickGameTargetType.IMAGE_BLUE, + QuickClickGameTargetType.IMAGE_RED, + QuickClickGameTargetType.IMAGE_GREEN, + QuickClickGameTargetType.IMAGE_YELLOW, +) + +private const val TARGET_MARGIN = 0.12f +private const val QUADRANT_GAP = 0.12f +private const val YELLOW_BONUS_SCORE = 10 diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/TwoStillTargetsPressAnyRules.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/TwoStillTargetsPressAnyRules.kt new file mode 100644 index 000000000..d225e63e3 --- /dev/null +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/data/subjects/quickcountgame/image/TwoStillTargetsPressAnyRules.kt @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2026 Kevin Buzeau + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.buzbuz.smartautoclicker.feature.tutorial.data.subjects.quickcountgame.image + +import android.graphics.PointF +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameRules +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameTargetState +import com.buzbuz.smartautoclicker.core.common.tutorial.domain.model.data.subject.quickclickgame.QuickClickGameTargetType + +internal class TwoStillTargetsPressAnyRules( + private val blueScoreIncrement: Int, + private val redScoreIncrement: Int, + private val targetsBehaviour: TargetsBehaviour, +) : QuickClickGameRules { + + private val bluePosition = PointF(0.25f, 0.5f) + private val redPosition = PointF(0.75f, 0.5f) + private var score: Int = 0 + + override fun getScore(): Int = score + + override fun onStart(): Map { + score = 0 + return buildTargetsForTimeLeft(0) + } + + override fun onTargetHit( + current: Map, + type: QuickClickGameTargetType + ): Map { + when (type) { + QuickClickGameTargetType.IMAGE_RED -> score += redScoreIncrement + QuickClickGameTargetType.IMAGE_BLUE -> score += blueScoreIncrement + else -> Unit + } + return current + } + + override fun onTimerTick( + current: Map, + timeLeft: Long + ): Map = + buildTargetsForTimeLeft(timeLeft) + + private fun buildTargetsForTimeLeft(timeLeft: Long): Map = + when (targetsBehaviour) { + TargetsBehaviour.BLUE_BLINK_RED_BLINK -> + when (timeLeft % 3) { + 0L -> mapOf( + QuickClickGameTargetType.IMAGE_BLUE to QuickClickGameTargetState.StaticContent(bluePosition), + QuickClickGameTargetType.IMAGE_RED to QuickClickGameTargetState.StaticContent(redPosition), + ) + 1L -> mapOf( + QuickClickGameTargetType.IMAGE_BLUE to QuickClickGameTargetState.StaticContent(bluePosition), + ) + else -> mapOf( + QuickClickGameTargetType.IMAGE_RED to QuickClickGameTargetState.StaticContent(redPosition), + ) + } + + TargetsBehaviour.BLUE_STILL_RED_BLINK -> + when (timeLeft % 2) { + 0L -> mapOf( + QuickClickGameTargetType.IMAGE_BLUE to QuickClickGameTargetState.StaticContent(bluePosition), + QuickClickGameTargetType.IMAGE_RED to QuickClickGameTargetState.StaticContent(redPosition), + ) + else -> mapOf( + QuickClickGameTargetType.IMAGE_BLUE to QuickClickGameTargetState.StaticContent(bluePosition), + ) + } + } + + enum class TargetsBehaviour { + BLUE_BLINK_RED_BLINK, + BLUE_STILL_RED_BLINK, + } +} \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/GetTutorialCategoryUseCase.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/GetTutorialCategoryUseCase.kt index 76922e99d..5235a22d0 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/GetTutorialCategoryUseCase.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/GetTutorialCategoryUseCase.kt @@ -44,18 +44,7 @@ class GetTutorialCategoryUseCase @Inject constructor( categoryNameRes = nameRes, items = buildList { add(this@toUiState.toHeaderUiItem()) - - val items = content.filter { item -> item !is TutorialCategory.Content.Slideshow } - if (items.isNotEmpty()) { - add(TutorialCategoryUiItems.SectionDivider) - addAll(items.map { categoryContent -> categoryContent.toUiItem(completionState)}) - } - - val slideshows = content.filterIsInstance() - if (slideshows.isNotEmpty()) { - add(TutorialCategoryUiItems.SectionDivider) - addAll(slideshows.map { slideshow -> slideshow.toSlideshowUiItem() }) - } + addAll(content.map { it.toUiItem(completionState) }) } ) @@ -66,8 +55,9 @@ class GetTutorialCategoryUseCase @Inject constructor( iconRes = iconRes, ) - private fun TutorialCategory.Content.toUiItem(completionState: Map): TutorialCategoryUiItems.Item = + private fun TutorialCategory.Content.toUiItem(completionState: Map): TutorialCategoryUiItems = when (this) { + is TutorialCategory.Content.Divider -> TutorialCategoryUiItems.SectionDivider is TutorialCategory.Content.Category -> toCategoryUiItem() is TutorialCategory.Content.Tutorial -> toTutorialUiItem(completionState) is TutorialCategory.Content.Slideshow -> toSlideshowUiItem() diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialCategory.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialCategory.kt index ecb39c255..26bf71aeb 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialCategory.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialCategory.kt @@ -29,6 +29,7 @@ data class TutorialCategory( ) { sealed interface Content { + data object Divider : Content data class Category(val type: Type) : Content data class Tutorial(val type: TutorialItem.Type) : Content data class Slideshow(val type: TutorialSlideshow.Type) : Content @@ -37,15 +38,26 @@ data class TutorialCategory( enum class Type { ACTIONS, BASICS, + CHANGE_COUNTER_ACTION, + CLICK_ACTION, COLOR_CONDITION, COMBINE_CONDITIONS, COUNTERS, - EVENT_STATE, + COMBINE_EVENTS, + EVENTS_PRIORITY, + EVENTS_STATE, IMAGE_CONDITION, + INTENT_ACTION, + NOTIFICATION_ACTION, NUMBER_CONDITION, + PAUSE_ACTION, ROOT, SCREEN_CONDITIONS, + SWIPE_ACTION, + SYSTEM_ACTION, TEXT_CONDITION, + TOGGLE_EVENT_ACTION, TRIGGER_CONDITIONS, + WRITE_TEXT_ACTION, } } diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialItem.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialItem.kt index ad428fe13..3836c413a 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialItem.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialItem.kt @@ -27,7 +27,12 @@ interface TutorialItem { enum class Type { COMBINE_CONDITIONS_NOT_VISIBLE, + COMBINE_CONDITIONS_OPERATOR_AND, + COMBINE_CONDITIONS_OPERATOR_OR, COLOR_CONDITION, + COUNTERS_BASICS, + EVENTS_PRIORITY, + EVENTS_STATE, IMAGE_DETECTION_MOVING_TARGET, IMAGE_DETECTION_STILL_TARGET, NUMBER_CONDITION_STATIC_VALUE, diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialSlideshow.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialSlideshow.kt index bec4961e1..6ad98decf 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialSlideshow.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/model/TutorialSlideshow.kt @@ -37,16 +37,33 @@ data class TutorialSlideshow( ICON(48, 48, 16), IMAGE_SQUARE(128, 128), IMAGE_LARGE(256, 128), + IMAGE_PORTRAIT(128, 256), } enum class Type { + ACTIONS_LIST, BROADCAST_RECEIVED_CONDITION, + CHANGE_COUNTER_ACTION, + CLICK_ACTION_OFFSET, + CLICK_ACTION_TARGET, + COMBINE_CONDITIONS_ORDERING, COUNTER_REACHED_CONDITION, + COUNTERS_VALUE_USAGES, + EVENTS_STATE_BASICS, + EVENTS_PRIORITY_BASICS, + EVENTS_RELOADING, IMAGE_CONDITION_CAPTURE, IMAGE_CONDITION_DETECTION_AREA, + INTENT_ACTION, + NOTIFICATION_ACTION, NUMBER_CONDITION_DETECTION_AREA, + PAUSE_ACTION, SCREEN_CONDITIONS_TYPE, SCREEN_CONDITIONS_DETECTION_THRESHOLD, - TEXT_CONDITION_DETECTION_AREA + SWIPE_ACTION, + SYSTEM_ACTION, + TOGGLE_EVENT_ACTION, + TEXT_CONDITION_DETECTION_AREA, + WRITE_TEXT_ACTION, } } \ No newline at end of file diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/ui/game/clickcount/ClickCountGameFragment.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/ui/game/clickcount/ClickCountGameFragment.kt index 6702eb441..8dff76125 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/ui/game/clickcount/ClickCountGameFragment.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/ui/game/clickcount/ClickCountGameFragment.kt @@ -78,7 +78,6 @@ class ClickCountGameFragment : Fragment() { super.onViewCreated(view, savedInstanceState) viewBinding.gameArea.forceLayout() - lockMenuPosition() lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { @@ -98,6 +97,7 @@ class ClickCountGameFragment : Fragment() { override fun onStart() { super.onStart() + lockMenuPosition() if (viewModel.shouldDisplayFloatingUi.value && overlayManager.isOverlayStackHidden()) { overlayManager.restoreVisibility() } @@ -111,6 +111,7 @@ class ClickCountGameFragment : Fragment() { overlayManager.hideAll() } overlayManager.removeTopOverlay() + overlayManager.unlockMenuPosition() } override fun onDestroy() { @@ -232,6 +233,8 @@ class ClickCountGameFragment : Fragment() { when (type) { QuickClickGameTargetType.IMAGE_BLUE -> blueTarget QuickClickGameTargetType.IMAGE_RED -> redTarget + QuickClickGameTargetType.IMAGE_GREEN -> greenTarget + QuickClickGameTargetType.IMAGE_YELLOW -> yellowTarget QuickClickGameTargetType.TEXT_DAY -> dayTarget QuickClickGameTargetType.TEXT_GOODBYE -> goodbyeTarget QuickClickGameTargetType.TEXT_HELLO -> helloTarget diff --git a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/ui/game/timing/TimingGameFragment.kt b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/ui/game/timing/TimingGameFragment.kt index db91b4cd2..5686efe78 100644 --- a/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/ui/game/timing/TimingGameFragment.kt +++ b/feature/tutorial/src/main/java/com/buzbuz/smartautoclicker/feature/tutorial/ui/game/timing/TimingGameFragment.kt @@ -64,8 +64,6 @@ class TimingGameFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - lockMenuPosition() - lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { launch { viewModel.uiState.collect(::updateUi) } @@ -84,6 +82,7 @@ class TimingGameFragment : Fragment() { override fun onStart() { super.onStart() + lockMenuPosition() if (viewModel.shouldDisplayFloatingUi.value && overlayManager.isOverlayStackHidden()) { overlayManager.restoreVisibility() } @@ -97,6 +96,7 @@ class TimingGameFragment : Fragment() { overlayManager.hideAll() } overlayManager.removeTopOverlay() + overlayManager.unlockMenuPosition() } override fun onDestroy() { diff --git a/feature/tutorial/src/main/res/drawable/ic_game_target_green.xml b/feature/tutorial/src/main/res/drawable/ic_game_target_green.xml new file mode 100644 index 000000000..91f4be86e --- /dev/null +++ b/feature/tutorial/src/main/res/drawable/ic_game_target_green.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/feature/tutorial/src/main/res/drawable/ic_game_target_yellow.xml b/feature/tutorial/src/main/res/drawable/ic_game_target_yellow.xml new file mode 100644 index 000000000..3ffe7a1bb --- /dev/null +++ b/feature/tutorial/src/main/res/drawable/ic_game_target_yellow.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/feature/tutorial/src/main/res/drawable/ic_target_green.xml b/feature/tutorial/src/main/res/drawable/ic_target_green.xml new file mode 100644 index 000000000..f0b408d0d --- /dev/null +++ b/feature/tutorial/src/main/res/drawable/ic_target_green.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/feature/tutorial/src/main/res/drawable/ic_target_yellow.xml b/feature/tutorial/src/main/res/drawable/ic_target_yellow.xml new file mode 100644 index 000000000..f4eb1612c --- /dev/null +++ b/feature/tutorial/src/main/res/drawable/ic_target_yellow.xml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_action_order.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_action_order.webp new file mode 100644 index 000000000..35890e74f Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_action_order.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_capture_transparent_bg.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_capture_transparent_bg.webp deleted file mode 100644 index 3204d7ec5..000000000 Binary files a/feature/tutorial/src/main/res/drawable/tutorial_instructions_capture_transparent_bg.webp and /dev/null differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_capture_transparent_bg_fallback.png b/feature/tutorial/src/main/res/drawable/tutorial_instructions_capture_transparent_bg_fallback.png deleted file mode 100644 index b092b095a..000000000 Binary files a/feature/tutorial/src/main/res/drawable/tutorial_instructions_capture_transparent_bg_fallback.png and /dev/null differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_change_counter_value_type.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_change_counter_value_type.webp new file mode 100644 index 000000000..927124d8a Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_change_counter_value_type.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_offset.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_offset.webp new file mode 100644 index 000000000..daffb519c Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_offset.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_condition_and.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_condition_and.webp new file mode 100644 index 000000000..362e2b192 Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_condition_and.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_condition_or.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_condition_or.webp new file mode 100644 index 000000000..4acdad64a Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_condition_or.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_static.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_static.webp new file mode 100644 index 000000000..df43476bf Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_static.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_type.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_type.webp new file mode 100644 index 000000000..2594da34a Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_click_target_type.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_condition_operator_and.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_condition_operator_and.webp new file mode 100644 index 000000000..49731e5c7 Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_condition_operator_and.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_condition_operator_or.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_condition_operator_or.webp new file mode 100644 index 000000000..d302b0cac Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_condition_operator_or.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_debug_report_counters.png b/feature/tutorial/src/main/res/drawable/tutorial_instructions_debug_report_counters.png new file mode 100644 index 000000000..763fa17b6 Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_debug_report_counters.png differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_event_priority.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_event_priority.webp new file mode 100644 index 000000000..97b8d8698 Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_event_priority.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_event_reloading.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_event_reloading.webp new file mode 100644 index 000000000..fdc846798 Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_event_reloading.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_keep_executing.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_keep_executing.webp new file mode 100644 index 000000000..686412a27 Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_keep_executing.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_set_text_focus.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_set_text_focus.webp new file mode 100644 index 000000000..82f7e72a5 Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_set_text_focus.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_swipe.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_swipe.webp new file mode 100644 index 000000000..1a2f7fdaf Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_swipe.webp differ diff --git a/feature/tutorial/src/main/res/drawable/tutorial_instructions_toggle_event.webp b/feature/tutorial/src/main/res/drawable/tutorial_instructions_toggle_event.webp new file mode 100644 index 000000000..482c4d54e Binary files /dev/null and b/feature/tutorial/src/main/res/drawable/tutorial_instructions_toggle_event.webp differ diff --git a/feature/tutorial/src/main/res/layout-land/fragment_click_count_game.xml b/feature/tutorial/src/main/res/layout-land/fragment_click_count_game.xml index e328579eb..0b8c1f85e 100644 --- a/feature/tutorial/src/main/res/layout-land/fragment_click_count_game.xml +++ b/feature/tutorial/src/main/res/layout-land/fragment_click_count_game.xml @@ -140,6 +140,20 @@ app:srcCompat="@drawable/ic_game_target_secondary" android:visibility="invisible" /> + + + + + + + + + + إجراء الإيقاف المؤقت + تعلّم كيف يؤثر الإيقاف المؤقت على تنفيذ الإجراءات والاكتشاف + يوقف إجراء الإيقاف المؤقت السيناريو بأكمله للمدة + المحددة: خلال هذا الوقت، لا يُنفَّذ أي إجراء ولا يحدث أي اكتشاف للشاشة.\n\nمن أكثر حالات الاستخدام + شيوعًا إضافة إيقاف مؤقت في نهاية قائمة الإجراءات. عندما تنقر على مكان ما، يحتاج التطبيق إلى وقت + لمعالجة النقرة وعرض النتيجة — وعادةً ما تريد الانتظار حتى هذه اللحظة قبل أن يعود Klick\'r + لتحليل الشاشة.\n\nالإيقاف المؤقت بين إجراءين أيضًا صالح، لكن الإضافة في نهاية القائمة غالبًا ما + تكون الأهم. + + + إجراء السحب + تعلّم كيف يُنفَّذ إيماءة السحب + يُنفِّذ إجراء السحب إيماءة سحب في خط مستقيم + من موضع البداية إلى موضع النهاية. كلتا الإحداثيتين ثابتتان ومحددتان في إعداد الإجراء.\n\nتتحكم + المدة في الوقت الذي يستغرقه الإيماءة من البداية إلى النهاية: مدة أقصر تُنتج سحبًا أسرع، بينما + مدة أطول تُنتج سحبًا أبطأ وأكثر تحكمًا. + + + إزاحة النقر + تعلّم كيف تضبط موضع النقر على شرط مكتشف + عند النقر على شرط مكتشف، يُطبَّق النقر + افتراضيًا على مركز المنطقة المكتشفة.\n\nتتيح لك إزاحة النقر تحريك هذا الموضع بعدد ثابت من البكسلات + على المحورين X وY بالنسبة لمركز الشرط. هذا مفيد عندما يكون العنصر الذي تريد لمسه قريبًا من — + لكن ليس بالضبط في — مركز المنطقة المكتشفة. + + + هدف النقر + تعلّم كيف تُعدّ مكان تطبيق النقر + يمكن لإجراء النقر أن يستهدف نوعين من + المواضع: موضع ثابت دائمًا متطابق، أو موضع شرط مكتشف.\n\nاختر طريقة التوجيه من منتقي الهدف في + مربع حوار إعداد الإجراء. + مع الموضع الثابت، يحدث النقر دائمًا + عند نفس الإحداثيات الدقيقة بغض النظر عما يُعرض على الشاشة.\n\nتذكّر أن هذه الإحداثيات حساسة + للدوران: إذا دار الجهاز، قد ينتهي النقر في موضع غير متوقع أو حتى خارج حدود الشاشة. + مع موضع الشرط، يُطبَّق النقر على مركز + شرط الصورة المكتشف، تتبعًا للهدف أينما ظهر على الشاشة.\n\nمع عامل التشغيل AND، يجب استيفاء جميع + الشروط، لذا فإن كل شرط صورة له موضع متاح. يمكنك اختيار أي منها بحرية وتحسينه بإزاحة. + مع عامل التشغيل OR، يُقيَّم فقط الشرط + الأول المستوفى ويُتجاهل الباقي. لذلك لا يمكن لـ Klick\'r معرفة أي شرط سيُكتشف مسبقًا.\n\nبناءً + على ذلك، مع عامل التشغيل OR لا يمكنك اختيار شرط محدد كهدف: سيُطبَّق النقر دائمًا على أول شرط + مكتشف في وقت التشغيل، أيًّا كان. + + + ترتيب الشروط والسرعة + كيف يؤثر ترتيب شروطك على سرعة فحص الحدث + + يؤثر ترتيب الشروط في القائمة على سرعة فحص + الحدث.\n\nمع عامل التشغيل AND، يتوقف الفحص بمجرد العثور على أول شرط غير مستوفٍ. وضع الشروط الأقل احتمالاً أولاً + يتيح للتطبيق تخطي الباقي في وقت أبكر، مما يجعل حدثك أسرع. + + مع عامل التشغيل OR، يتوقف الفحص بمجرد + العثور على أول شرط مستوفٍ. وضع الشروط الأكثر احتمالاً أولاً يتيح للتطبيق الانتهاء في وقت أبكر دون فحص + الباقي.\n\nفي كلتا الحالتين، وضع أهم شرط في أعلى القائمة طريقة بسيطة للحفاظ على سرعة السيناريو. + + + + حالة الأحداث + تعلّم كيفية تفعيل الأحداث وتعطيلها + أثناء تشغيل السيناريو + + كل حدث في السيناريو (أحداث الشاشة وأحداث + المُشغِّل) له حالة: إما مُفعَّل أو مُعطَّل.\n\nعند التفعيل، يعمل الحدث بشكل طبيعي ويفحص شروطه + كالمعتاد. عند التعطيل، يُتخطَّى كليًا كأنه غير موجود.\n\nبشكل افتراضي، يبدأ كل حدث مُفعَّلًا. يمكنك تغيير ذلك + من خلال حقل الحالة الابتدائية في إعدادات الحدث. + + أثناء تشغيل السيناريو، يمكنك تغيير حالة أي حدث + باستخدام إجراء تغيير حالة الحدث. يتيح هذا الإجراء تفعيل أو تعطيل أو تبديل حالة حدث واحد أو أكثر.\n\nهذا + يفتح إمكانيات كثيرة: أحداث تُشغِّل بعضها البعض واحداً تلو الآخر، أحداث تُعطِّل نفسها بعد تشغيلها مرة واحدة، أو + مجموعات أحداث لا يكون فيها إلا حدث واحد نشطاً في الوقت نفسه. + + عندما تكون جميع الأحداث في السيناريو + مُعطَّلة، يتوقف السيناريو من تلقاء نفسه. لا يوجد ما يجب فعله، فيتوقف Klick\'r تلقائيًا.\n\nهذه طريقة بسيطة + لإنهاء سيناريو: اجعل آخر حدث يُعطِّل جميع الأحداث الأخرى بعد إنجاز مهمته، وكل شيء سيتوقف تلقائيًا. + + + + قائمة الإجراءات + تعلّم كيف يتم تنفيذ قائمة الإجراءات + تُنفَّذ الإجراءات بالترتيب، واحدًا تلو الآخر. يمكنك + تغيير ترتيب إجراء باستخدام زرَّي << و >>، أو بالنقر مباشرة على رقم فهرسه.\n\nحاوِل أن تبقي + قوائم الإجراءات قصيرة. يُنفِّذ المُنقِّر التلقائي العادي إجراءً واحدًا لكل حدث — هذا هو النموذج الذي ينبغي + اتباعه. إذا وجدت نفسك تُضيف إجراءات كثيرة إلى حدث واحد، فهذا عادةً مؤشر على أن العمل ينبغي توزيعه على + أحداث متعددة، يستجيب كل منها لما يُعرض فعلاً على الشاشة. هذه هي فلسفة الرؤية والتصرف في Klick\'r: اكتشف + أولاً، ثم تصرف. + + + إجراء كتابة النص + تعلّم كيفية إدخال نص في حقل إدخال نشط + قبل تشغيل إجراء كتابة النص، يجب أن يكون حقل + الإدخال الهدف في حالة تركيز بالفعل، تمامًا كما لو نقرت عليه لإظهار لوحة المفاتيح.\n\nلتحقيق ذلك، أضف إجراء + نقر على ذلك الحقل قبل إجراء كتابة النص. إذا ظهر تأثير انتقالي بعد النقر، فإن إجراء انتظار بينهما يمكن أن + يساعد في التأكد من جاهزية الحقل.\n\nيحتوي الإجراء أيضًا على خيار التحقق: عند تفعيله، سيضغط تلقائيًا على + Enter بعد تعيين النص، مما يؤكد أو يُرسل القيمة المُدخَلة. + يمكنك إدراج قيمة عداد في النص المراد كتابته. + اضغط على زر إضافة عداد في تكوين الإجراء لاختيار عداد: سيُدرج العنصر النائب {اسمالعداد} في موضع + المؤشر الحالي في حقل النص.\n\nعند التشغيل، يُستبدل كل عنصر نائب {اسمالعداد} بالقيمة الحالية للعداد + قبل لصق النص في الحقل. على سبيل المثال، إذا كان عداد اسمه تفاح يساوي 18، فإن النص + \"عندي {تفاح} تفاحات\" سيصبح \"عندي 18 تفاحة\". + + + إجراء النظام + تعلّم كيفية تشغيل إجراءات تنقل Android + يُنفِّذ إجراء النظام أحد إجراءات التنقل المدمجة في + Android: رجوع أو الرئيسية أو التطبيقات الأخيرة.\n\nهذه هي نفس إجراءات أزرار التنقل في أسفل شاشتك. لا تتطلب + إحداثيات وتعمل على مستوى النظام، بغض النظر عن التطبيق المفتوح حاليًا. + + + إجراء تعديل العداد + تعلّم كيفية تعديل قيمة عداد + يُطبِّق إجراء تعديل العداد عملية على عداد + باستخدام قيمة ثابتة محددة مسبقًا. ثلاث عمليات متاحة: جمع القيمة على العداد (+)، أو طرحها منه (−)، أو ضبط + العداد على تلك القيمة بالضبط (=).\n\nهذه هي الطريقة الأكثر شيوعًا لتحديث العداد — على سبيل المثال، إضافة 1 + في كل مرة يُكتشف فيها شرط، أو إعادة ضبطه إلى 0 عند الوصول إلى هدف. + بدلاً من قيمة ثابتة، يمكنك استخدام القيمة + الحالية لعداد آخر كمعامل. تنطبق العمليات الثلاث ذاتها (+، −، =)، لكن المقدار يُقرأ من العداد المحدد في وقت + التشغيل بدلاً من تثبيته أثناء التكوين.\n\nيتيح لك هذا بناء سيناريوهات ديناميكية تتفاعل فيها العدادات مع + بعضها. + + + إجراء الإشعار + تعلّم كيفية عرض إشعار أثناء تشغيل السيناريو + يعرض إجراء الإشعار إشعار Android بعنوان + ورسالة من اختيارك.\n\nيمكنك إدراج القيمة الحالية لعداد في نص الإشعار باستخدام زر إضافة عداد، أو بكتابة + العنصر النائب {اسمالعداد} مباشرةً. عند التشغيل يُستبدل بقيمة العداد — على سبيل المثال، + \"عندي {تفاح} تفاحات\" تصبح \"عندي 18 تفاحة\". + يتحكم مستوى أهمية الإشعار في مدى بروز + الإشعار عند عرضه. قد تُظهر المستويات الأعلى لافتة منبثقة وتُصدر صوتًا، بينما تصل المستويات الأدنى بصمت إلى + درج الإشعارات.\n\nيعتمد السلوك الدقيق على الجهاز ويمكن تخصيصه في إعدادات إشعارات Android الخاصة + بـ Klick\'r. + + + إجراء تغيير حالة الحدث + تعلّم كيفية تفعيل الأحداث وتعطيلها في وقت التشغيل + يُتخطَّى الحدث المُعطَّل كليًّا أثناء دورة + السيناريو — لا تُفحص شروطه قط ولا تُنفَّذ إجراءاته. هذا يعني أنه لا يستهلك أي وقت معالجة.\n\nتعطيل الأحداث + التي لا تستخدمها حاليًا طريقة رائعة لتحسين الأداء. على سبيل المثال، في سيناريو يتناوب بين مرحلة قائمة ومرحلة + لعبة، يُبقي تعطيل جميع أحداث القائمة أثناء مرحلة اللعبة (والعكس) الأحداث ذات الصلة فقط نشطةً في أي وقت. + عند تكوين الإجراء، يمكنك اختيار تغيير حالة جميع + أحداث السيناريو دفعةً واحدة، أو تحديد حالة جديدة لكل حدث على حدة.\n\nثلاثة تغييرات للحالة متاحة لكل حدث: + تفعيله أو تعطيله أو تبديله من قيمته الحالية — يصبح الحدث المُفعَّل مُعطَّلاً والمُعطَّل مُفعَّلاً. + إذا انتهى الأمر بتعطيل جميع أحداث السيناريو + في الوقت ذاته، يتوقف السيناريو تلقائيًا إذ لم يعد هناك ما يُنفَّذ.\n\nيمكن استخدام هذا عمدًا كطريقة نظيفة + لإنهاء السيناريو عند الوصول إلى الهدف: إجراء تغيير حالة الحدث الأخير الذي يُعطِّل جميع الأحداث سيوقف + السيناريو. + + + إجراء Intent + تعلّم كيفية التواصل مع التطبيقات الأخرى + Intent هو الطريقة التي تتواصل بها التطبيقات مع بعضها + على Android. يتيح لك إجراء Intent توظيف هذا النظام مباشرةً من سيناريوك.\n\nتتوفر مجموعة من القوالب المُعرَّفة + مسبقًا لتسهيل ذلك. الأكثر شيوعًا هو تشغيل تطبيق، الذي يُشغِّل تطبيقًا آخر على جهازك تمامًا كما لو نقرت + على أيقونته من مُشغِّل التطبيقات. + تتيح لك علامة التبويب المتقدمة تحديد Intent خام + يدويًا، مما يمنحك تحكمًا كاملاً في الإجراء والفئة والبيانات والإضافات. لا يُنصح بهذا للمستخدمين العاديين — + بل هو موجَّه لمطوري Android الذين يعرفون كيف تعمل Intents.\n\nستُضاف المزيد من القوالب الجاهزة في تحديثات + مستقبلية لتسهيل حالات الاستخدام الشائعة دون الحاجة إلى الخيارات المتقدمة. + + + + أولوية الأحداث + تعرّف على كيفية تأثير ترتيب الأحداث في قائمتك على الأحداث التي يتم تنفيذها + تتم معالجة كل إطار من الشاشة بفحص أحداثك واحداً تلو الآخر، من الأعلى إلى الأسفل.\n\nيحدد موضع الحدث في قائمتك متى تتاح له فرصة التنفيذ. بشكل افتراضي، بمجرد استيفاء شروط الحدث وتنفيذ إجراءاته، يُعتبر الإطار مكتملاً. تتوقف المعالجة لذلك الإطار ويبدأ التالي من الحدث الأول في القائمة.\n\nهذا يعني أنه بشكل افتراضي لا يمكن تنفيذ سوى حدث واحد لكل إطار. + يمكنك تغيير هذا السلوك باستخدام حقل استمر في التنفيذ في إعدادات الحدث. عند تفعيله، بعد تنفيذ هذا الحدث، تستمر المعالجة إلى الحدث التالي في القائمة بدلاً من التوقف.\n\nهذا يتيح تنفيذ أحداث متعددة في نفس الإطار.\n\nمثال: تحتوي قائمتك على الحدث أ متبوعاً بالحدث ب. إذا استمر الكشف عن الحدث أ ولم يكن لديه استمر في التنفيذ مفعّلاً، فسيتم تنفيذه في كل إطار ولن يحظى الحدث ب بأي فرصة للتنفيذ.\n\nفعّل استمر في التنفيذ للحدث أ وسيتم فحص كلا الحدثين في كل إطار.\n\nيتوفر أيضاً درس تعليمي تفاعلي لممارسة هذا المفهوم. + + + + إعادة تحميل الحدث + تعرّف على كيفية تصرّف إعادة تحميل الحدث في سيناريوك + يتيح لك معامل إعادة تحميل الحدث تخطّي حدث لفترة + زمنية محددة بمجرد تحقّقه. \n\nالحدث في حالة إعادة التحميل لا يزال يُعتبر مُفعَّلاً: إعادة التحميل وحالة + الحدث مستقلّتان. \n\nإذا تم تعطيل الحدث أثناء إعادة التحميل، سيتم مسح مؤقت إعادة التحميل، بحيث لا يُطبَّق + وقت الانتظار عند إعادة تفعيل الحدث. + + + + استخدام قيم العدّاد + تعرّف على الطرق المختلفة لعرض واستخدام قيم العدّاد في السيناريو الخاص بك + + يمكنك عرض القيمة الحالية للعدّاد داخل إجراء + الإشعار. يُفيد ذلك في متابعة التقدم أثناء تشغيل السيناريو، أو لعرض ملخص في النهاية.\n\nلإدراج عدّاد، + اضغط على زر «إضافة عدّاد» في إعدادات الإجراء. سيُضاف عنصر نائب مثل {counterName} إلى نصك. + أثناء التشغيل، يُستبدَل العنصر النائب بالقيمة الفعلية للعدّاد. مثلاً، إذا كان عدّاد باسم score + يساوي 42، فإن النص «النتيجة الحالية: {score}» يصبح «النتيجة الحالية: 42». + + يمكنك أيضاً إدراج قيمة عدّاد في إجراء كتابة + النص، بحيث يتضمّن النص المكتوب القيمة الحالية لحظة تنفيذ الإجراء.\n\nيعمل العنصر النائب بنفس الطريقة + كما في إجراء الإشعار: اضغط على زر «إضافة عدّاد» أو اكتب {counterName} مباشرةً. مثلاً، إذا كان + عدّاد باسم score يساوي 42، فإن النص «نتيجتي هي {score}» يصبح «نتيجتي هي 42». + + تُسجَّل قيم العدّادات في تقرير التصحيح. + إذا لم يعمل شيء في السيناريو كما هو متوقع، فإن التقاط تقرير التصحيح سيُظهر لك بالضبط كيف تغيّرت + عداداتك عبر الزمن، مما يُسهّل العثور على المشكلة. + diff --git a/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_not_visible.xml index 9eae0df3f..7142fbf3e 100644 --- a/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - الجمع بين شروط متعددة - قم بإنشاء ودمج شروط متعددة لحدثك - انقر على الزر الأزرق فقط عندما يكون الزر الأحمر مرئيًا + رؤية الشروط + استخدم خيار الرؤية لتشغيل نقرة عندما لا + يكون الهدف ظاهرًا على الشاشة + انقر على الزر الأزرق فقط عندما لا يكون + الزر الأحمر مرئيًا - دعونا نغير قواعد اللعبة مرة أخرى. توقف الهدف الأزرق عن الحركة، - ولكن الآن يجب النقر عليه فقط عندما يكون الهدف الأحمر مرئيًا.\n\nأولاً، ابدأ اللعبة وتحقق مما إذا كان بإمكانك الفوز - بنفسك. + قواعد جديدة! توقّف الهدف الأزرق عن + الحركة، لكن يجب النقر عليه فقط عندما يكون الهدف الأحمر غير مرئي. + \n\nابدأ اللعبة وانظر إن كنت تستطيع الفوز بمفردك. - مرة أخرى، يبدو من المستحيل الفوز يدويًا، لذلك دعونا نستخدم Smart - AutoClicker.\n\nتم الاحتفاظ بالسيناريو الخاص بالبرنامج التعليمي السابق وتحميله لهذا البرنامج التعليمي، ولكننا سنفعل ذلك - بحاجة إلى تغيير بعض المعلمات للفوز بهذه اللعبة الجديدة.\n\nانقر فوق رمز تكوين السيناريو - ابدأ في تحديث السيناريو الجديد الخاص بك. + مرة أخرى، يبدو من المستحيل الفوز + يدويًا، لذا لنستخدم Klick\'r. \n\nافتح قائمة إعداد السيناريو، وأنشئ حدث شاشة جديد، وابدأ في إضافة شروط + لأهداف اللعبة. - ما زلنا نريد النقر على الهدف الأزرق، ولكن فقط عندما يكون اللون الأحمر مرئيًا.\n - لذا نحتاج إلى إضافة شرط لهذا الهدف الأحمر في حدثنا.\n\nانقر على الحدث الذي أنشأته مسبقًا لتعديله. + أولاً، نحتاج إلى شرط يتحقق من أن + الهدف الأحمر غير مرئي على الشاشة. \n\nأنشئ شرط صورة جديدًا والتقط الهدف الأحمر. - سنقوم بدمج عدة شروط، لذلك نحن بحاجة إلى التحقق من عامل الشرط - لهذا الحدث.\n\nيشير عامل الشرط إلى كيفية تفسير الشروط المتعددة معًا.\n - \'واحد\' يعني أنه يجب استيفاء شرط واحد فقط من شروط هذا الحدث بالترتيب - لتنفيذ الإجراءات.\n\n\'الكل\' يعني أنه يجب استيفاء جميع شروط هذا الحدث من أجل تنفيذ الإجراءات. - \n\nبما أننا نريد اكتشاف ما إذا كان هناك شيئين معروضين معًا، فسنستخدم \'الكل\' + نريد النقر فقط عندما يكون الهدف + الأحمر غير مرئي، لذا اضبط خيار «مرئي» على لا. بهذه الطريقة لن يتحقق الشرط إلا عندما يكون الهدف الأحمر + غائبًا عن الشاشة. - نحن الآن بحاجة إلى تحديث شروطنا.\n\nانقر فوق حقل الشروط لعرضه - قائمة الشروط. + الإعدادات الأخرى مناسبة لحالتنا — + تابع واحفظ هذا الشرط. - الشرط السابق لكشف الهدف الأزرق لا يزال صحيحا، ولكننا بحاجة - جديد للهدف الأحمر.\n\nانقر فوق الزر "إنشاء شرط" لإنشاء شرط جديد له. + هذا الشرط وحده كافٍ للفوز باللعبة، + لكنه سينشّط أيضًا عندما لا تكون اللعبة قيد التشغيل، وهذا غير مثالي. + \n\nلتجنب ذلك، سنقرنه بشرط ثانٍ يتحقق مما إذا كان الهدف الأزرق مرئيًا. + أنشئ شرط صورة جديدًا والتقط الهدف الأزرق. - تمامًا كما هو الحال مع الهدف الأزرق، ابدأ اللعبة لإظهار الهدف الأحمر. - بمجرد ظهوره، التقط لقطة شاشة له! - استخدم زر الالتقاط في القائمة العائمة لالتقاط لقطة الشاشة. + لهذا الشرط، نريد التحقق من أن الهدف + الأزرق مرئي، لذا الإعدادات الافتراضية كلها صحيحة. احفظ الشرط وارجع إلى الحدث للمتابعة. - هل تحتوي لقطة الشاشة على الهدف الأحمر؟ يمكنك قصه من أجل فقط - احصل على الجزء المثير للاهتمام للكشف، وهو الهدف الأحمر. - إذا كانت لقطة الشاشة الخاصة بك لا تحتوي على الهدف الأحمر، فيمكنك ذلك - اضغط على هذا الزر لاتخاذ واحدة جديدة. + مع وجود شروط متعددة، يصبح مشغّل + الشروط مهمًا. نريد أن ينشّط الحدث عندما يكون الهدف الأزرق مرئيًا والهدف الأحمر غير مرئي، لذا نحتاج إلى + المشغّل و؛ وهو القيمة الافتراضية فعلاً، إذن كل شيء على ما يرام. + \n\nأنشئ الآن إجراء نقر جديدًا للمتابعة. - تم الآن تسجيل صورة الحالة الخاصة بك!\n\nبما أن الهدف الأحمر لا يتحرك، فإننا - يمكنه الاحتفاظ بالتكوين الافتراضي.\nانقر فوق زر الحفظ لتسجيله والعودة إلى قائمة الشروط. + نريد النقر على الهدف الأزرق، لذا + اختر نوع الموضع «على الشرط» وحدد شرط الصورة الخاص بالهدف الأزرق. + \n\nعند الانتهاء، احفظ النقر، ثم الحدث والسيناريو، وارجع إلى اللعبة. - قم بإغلاق قائمة الشروط للعودة إلى تكوين الحدث. + شغّل السيناريو وابدأ اللعبة + للفوز! \n\nإن لم ينجح ذلك، تحقق من أن شروطك تم التقاطها بشكل صحيح وأن مدة النقر مضبوطة على 1 مللي + ثانية. - لدينا الآن شرطان، واحد لكل هدف، وسيتم تنفيذ الإجراءات - فقط في حالة اكتشاف كليهما.\n\nانقر فوق حقل "الإجراءات" لعرض قائمة الإجراءات الخاصة بالحدث الخاص بنا. + تهانينا! لقد تعلّمت استخدام شرط + «غير مرئي». احرص دائمًا على دمجه مع شرط آخر على الأقل لتجنب تشغيل الإجراءات عن غير قصد طوال مدة + سيناريوك. - تم بالفعل ضبط الإجراء للنقر على الحرف الأزرق، وسيكون كذلك - يتم تنفيذه عندما تكون الأحرف الزرقاء والحمراء مرئية معًا.\n\nهذا هو بالضبط السلوك الذي نحتاجه للتغلب على - اللعبة، لذا لا داعي لتعديل النقر على الإجراء.\n\nأغلق قائمة الإجراءات للعودة إلى تكوين الحدث. - - انقر على زر حفظ لحفظ الحدث الخاص بك. - - يجب حفظ كافة التغييرات في السيناريو الخاص بك حتى يتم تسجيلها.\n\nانقر فوق - زر الحفظ لحفظ التغييرات. - - نحن مستعدون للفوز بهذه اللعبة!\n\nانقر على زر البدء لبدء اللعبة - الكشف ثم ابدأ اللعبة. - - تهانينا!\n\nأنت تعرف الآن كيفية الجمع بين شروط متعددة لحدث ما، - ولكن هناك الكثير لنتعلمه! diff --git a/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..da0a95d21 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,67 @@ + + + + + + مشغّل الشروط و + استخدم المشغّل و للنقر فقط عندما تكون عدة + أهداف مرئية في الوقت ذاته + انقر على الزر الأزرق فقط عندما يكون كل من + الهدف الأزرق والهدف الأحمر مرئيين + + قواعد جديدة! يعرض اللعبة الآن هدفين. + انقر على الأزرق، لكن فقط عندما يكون الهدفان الأزرق والأحمر على الشاشة في الوقت ذاته. + \n\nابدأ اللعبة وانظر إن كنت تستطيع مواكبة الوتيرة بمفردك. + + التوقيت ضيق جدًا للتعامل معه يدويًا، + لذا لنستخدم Klick\'r. \n\nافتح قائمة إعداد السيناريو، وأنشئ حدث شاشة جديدًا، وابدأ في إضافة شروط + لأهداف اللعبة. + + نحتاج إلى شرط واحد لكل هدف. لنبدأ + بالهدف الأزرق. \n\nأنشئ شرط صورة جديدًا والتقط الهدف الأزرق. + + نريد أن يتحقق هذا الشرط عندما يكون + الهدف الأزرق مرئيًا، لذا الإعدادات الافتراضية كلها صحيحة. احفظ هذا الشرط. + + الآن لنضف الشرط الثاني للهدف الأحمر. + \n\nأنشئ شرط صورة آخر والتقط الهدف الأحمر. + + الأمر نفسه هنا — يجب أن يكون الهدف + الأحمر مرئيًا، لذا الإعدادات الافتراضية صحيحة. احفظ هذا الشرط وارجع إلى الحدث. + + مع تحديد شرطين، يحدد مشغّل الشروط كيفية + دمجهما. اختر المشغّل باستخدام المحدد الموضح أعلاه. + \n\n• و: يُنشَّط الحدث فقط عندما تتحقق جميع الشروط.\n• أو: يُنشَّط الحدث بمجرد تحقق شرط واحد. + \n\nللعبتنا نحتاج إلى كلا الهدفين على الشاشة في الوقت ذاته، لذا اختر و. + محدد مشغّل الشروط + + و هو المشغّل الافتراضي بالفعل، لذا نحن + جاهزون. \n\nافتح الآن قسم الإجراءات وأنشئ إجراء نقر جديدًا. + + نريد النقر على الهدف الأزرق، لذا اختر + نوع الموضع «على الشرط» وحدد شرط الصورة الخاص بالهدف الأزرق. + \n\nعند الانتهاء، احفظ النقر، ثم الحدث والسيناريو، وارجع إلى اللعبة. + + شغّل السيناريو وابدأ اللعبة للفوز! + \n\nإن لم ينجح ذلك، تحقق من أن كلا الشرطين تم التقاطهما بشكل صحيح وأن مدة النقر مضبوطة على 1 مللي + ثانية. + + تهانينا! لقد تعلّمت استخدام المشغّل و. + يُنشَّط الحدث الآن فقط عندما تتحقق جميع شروطه في الوقت ذاته. + + diff --git a/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..9fc6e0d59 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ar/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,68 @@ + + + + + + مشغّل الشروط أو + استخدم المشغّل أو للنقر على أول هدف يظهر على + الشاشة + انقر على أي هدف بمجرد ظهوره على الشاشة + + تحدٍّ جديد! قد يظهر هدفان على الشاشة. + الهدف الأحمر يساوي نقطتين والهدف الأزرق يساوي نقطة واحدة، لذا انقر على أيهما يظهر في أسرع وقت ممكن. + \n\nابدأ اللعبة وانظر كيف ستؤدي. + + سريع جدًا للتعامل معه يدويًا، لذا لنستخدم + Klick\'r. \n\nافتح قائمة إعداد السيناريو، وأنشئ حدث شاشة جديدًا، وابدأ في إضافة شروط لأهداف اللعبة. + + نحتاج إلى شرط واحد لكل هدف. لنبدأ + بالهدف الأزرق. \n\nأنشئ شرط صورة جديدًا والتقط الهدف الأزرق. + + يجب أن يتحقق هذا الشرط عندما يكون الهدف + الأزرق مرئيًا، لذا الإعدادات الافتراضية كلها صحيحة. احفظ هذا الشرط. + + الآن لنضف الشرط الثاني للهدف الأحمر. + \n\nأنشئ شرط صورة آخر والتقط الهدف الأحمر. + + الأمر نفسه هنا، يجب أن يكون الهدف الأحمر + مرئيًا، لذا الإعدادات الافتراضية صحيحة. احفظ هذا الشرط. + + مع أو، تُفحص الشروط بالترتيب وينشّط الحدث + بمجرد تحقق أولها، لذا يهم ترتيب شروطك. \n\nالهدف الأحمر يمنح نقاطًا أكثر، لذا نريده أن يُفحص أولاً. + استخدم الزر « لتحريكه قبل الهدف الأزرق، ثم ارجع إلى مربع حوار الحدث. + + الآن اضبط مشغّل الشروط على أو. سيُنشَّط + الحدث بمجرد ظهور أي من الهدفين. إذا كان كلاهما مرئيًا في الوقت ذاته، سيُكتشف الشرط الأحمر أولاً لأنه + ذو أولوية أعلى. \n\nاختر أو. + + تم تعيين المشغّل أو الآن. افتح قسم + الإجراءات وأنشئ إجراء نقر جديدًا. + + نريد النقر على الهدف الذي نشّط الحدث. + اختر نوع الموضع «على الشرط». مع أو، يمكن اكتشاف شرط واحد فقط بشكل إيجابي في كل مرة، لذا لا داعي لاختيار + شرط محدد. سينقر Klick\'r تلقائيًا على موقع الشرط الذي تحقق. \n\nعند الانتهاء، احفظ النقر، ثم الحدث + والسيناريو، وارجع إلى اللعبة. + + شغّل السيناريو وابدأ اللعبة للفوز! + \n\nإن لم ينجح ذلك، تحقق من أن شروطك تم التقاطها بشكل صحيح وأن مدة النقر مضبوطة على 1 مللي ثانية. + + تهانينا! لقد تعلّمت استخدام المشغّل أو + وفهمت لماذا تهم أولوية الشروط. بوضع الشرط الأحمر أولاً، يعطي Klick\'r الأولوية دائمًا للهدف ذي القيمة + الأعلى عندما يكون كلاهما مرئيًا في الوقت ذاته. + + diff --git a/feature/tutorial/src/main/res/values-ar/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-ar/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..2925192e7 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ar/strings_tutorial_counters_basics.xml @@ -0,0 +1,94 @@ + + + + أساسيات العدادات + تعلم كيفية استخدام إجراء «تغيير العداد» وشرط «على العداد وصلت». + انقر 10 مرات على الهدف الأزرق، ثم انقر مرة واحدة على الهدف الأحمر + + مرحباً بك في درس العدادات! + \n\nهنا، ستقوم بأتمتة لعبة تنقر فيها على الهدف الأزرق 10 مرات، ثم تنقر على الهدف الأحمر مرة واحدة للتحقق من العدد وكسب 10 نقاط. يمكنك تجربة اللعبة أولاً، أو الانتقال مباشرة إلى تكوين السيناريو. + + أولاً، نحتاج إلى إنشاء حدث شاشة يكتشف الهدف الأزرق وينقر عليه. + \n\nانقر على «إنشاء حدث» للبدء. + + لنبدأ بإضافة شرط للكشف عن الهدف الأزرق. انقر على حقل الشروط لفتح قائمة الشروط وإنشاء هذا الشرط. + \n\nسيستمر الدرس بمجرد إنشاء شرطك. + + ممتاز! الآن انقر على حقل الإجراءات لإضافة الإجراءات التي ستُنفَّذ عند اكتشاف الهدف الأزرق. + + نحتاج أولاً إلى إجراء نقر للضغط على الهدف الأزرق. انقر على زر الإنشاء لإضافة إجراء جديد. + + قم بتكوين النقر على الهدف الأزرق، ثم احفظ الإجراء. + \n\nسيستمر الدرس بمجرد حفظ النقر. + + نحتاج أيضاً إلى حساب عدد مرات النقر على الهدف الأزرق. يمكن تحقيق ذلك باستخدام إجراء «تغيير العداد»، بإضافة واحد في كل مرة ننقر. + \n\nانقر على زر الإنشاء مجدداً لإضافة إجراء ثانٍ. + + اختر إجراء «تغيير العداد» لزيادة عداد في كل مرة يُنقر فيها على الهدف الأزرق. + + أولاً، نحتاج إلى اختيار العداد الذي سيتم تحديثه. انقر على «اختر عداداً» لفتح قائمة العدادات. + + القائمة فارغة حالياً. انقر على زر الإنشاء لإنشاء عداد جديد. أعطه اسماً (مثل «نقرات زرقاء»)، اترك القيمة الابتدائية عند 0، ثم احفظه واخترنه. + + الآن قم بتكوين طريقة تغيير العداد في كل مرة يُنقر فيها على الهدف الأزرق. + \n\nاضبط العملية على + والقيمة على 1، لكي يزداد العداد بمقدار 1 في كل نقرة. + \n\nثم احفظ الإجراء وعد إلى مربع حوار الحدث. + يمكن أن تكون القيمة رقماً ثابتاً أو القيمة الحالية لعداد آخر. + + رائع! سيقوم حدث الشاشة هذا بالنقر على الهدف الأزرق وزيادة العداد في كل اكتشاف. + \n\nاحفظ الحدث للعودة إلى السيناريو. + + الآن نحتاج إلى حدث يتفاعل عندما يصل العداد إلى 10. هذا النوع من الأحداث لا يُشغَّل بواسطة الشاشة، بل هو حدث زناد (مشغل). + \n\nانقر على تبويب «أحداث الزناد» لفتح قائمة أحداث الزناد. + + انقر على زر الإنشاء لإضافة حدث زناد جديد. + + تماماً كحدث الشاشة، يحتاج حدث الزناد إلى شروط. انقر على حقل الشروط لفتح قائمة الشروط وإنشاء شرط زناد جديد. + + اختر نوع شرط «على العداد وصلت» لتشغيل هذا الحدث عندما يبلغ العداد قيمة محددة. + + اختر العداد الذي أنشأته سابقاً (الذي يحسب النقرات الزرقاء) لاستخدامه كمشغل. + + الآن اضبط المقارنة بحيث يتحقق الشرط عندما يساوي العداد 10. توجد عدة عوامل مقارنة، لكننا هنا نحتاج إلى التحقق من المساواة، لذا اختر «=\". ثم أدخل 10 كقيمة، واحفظ الشرط وعد إلى مربع حوار الحدث. + يمكن أن تكون القيمة المراد المقارنة بها رقماً ثابتاً أو القيمة الحالية لعداد آخر. + + تم ضبط الشرط! الآن نحتاج إلى تحديد ما يحدث عندما يصل العداد إلى 10. انقر على حقل الإجراءات لفتح قائمة الإجراءات. + + أولاً، أنشئ إجراء نقر وضعه يدوياً على الهدف الأحمر للتحقق من العدد. + + قم بتكوين النقر على الهدف الأحمر، ثم احفظ الإجراء. لاحظ أنه في حدث الزناد، يجب دائماً تحديد موضع النقر يدوياً. + \n\nسيستمر الدرس بمجرد حفظ النقر. + + الآن أنشئ إجراءً ثانياً لإعادة ضبط العداد. انقر على زر الإنشاء مجدداً واختر إجراء «تغيير العداد». + + نريد ضبط عداد النقرات الزرقاء على 0، لذا اختر أولاً عداد النقرات الزرقاء. + + اضبط العملية على = والقيمة على 0 لإعادة ضبط العداد بعد كل تحقق. ثم احفظ الإجراء وعد إلى مربع حوار الحدث للمتابعة. + + سيقوم حدث الزناد هذا بالنقر على الهدف الأحمر وإعادة ضبط العداد في كل مرة يُحسب فيها 10 نقرات زرقاء. تُنفَّذ قائمة أحداث الزناد بين كل إطار شاشة، قبل قائمة أحداث الشاشة، لذا بمجرد أن يصل العداد إلى 10، يُشغَّل هذا الحدث فوراً: يُنقر على الهدف الأحمر ويُعاد ضبط العداد، ليبدأ من جديد. + \n\nاحفظ الحدث للعودة إلى السيناريو. + + اكتمل السيناريو! سينقر على الهدف الأزرق، ويحسب كل نقرة، ثم يتحقق بالهدف الأحمر كل 10 نقرات ويبدأ من جديد. + \n\nاحفظ السيناريو لتطبيق تكوينك. + + كل شيء جاهز! ابدأ السيناريو، ثم شغّل اللعبة وشاهد Klick\'r يتولى العد بدلاً عنك. + + أحسنت! لقد تعلمت كيفية استخدام العدادات لتتبع القيم عبر أحداث متعددة. + \n\nبدمج إجراء «تغيير العداد» وشرط «على العداد وصلت»، يمكنك الآن بناء أتمتة تتفاعل مع الأنماط المتكررة. + + diff --git a/feature/tutorial/src/main/res/values-ar/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-ar/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..50e4415e7 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ar/strings_tutorial_events_priority.xml @@ -0,0 +1,65 @@ + + + + + تحديد أولوية حدث + إعطاء الأولوية لحدث على حدث آخر + انقر على الأهداف بأسرع ما يمكن. أزرق = نقطة واحدة؛ + أحمر = 10 نقاط + + لعبة جديدة! نحتاج إلى النقر على الأهداف بأسرع ما يمكن، + لكن الهدف الأحمر يمنح نقاطاً أكثر. يمكنك تجربة اللعبة أولاً أو فتح قائمة إعداد السيناريو لبدء + الأتمتة. + + نريد اكتشاف هدفين مختلفين، الأزرق والأحمر. في هذا + الدرس، سننشئ حدثين منفصلين: أحدهما للهدف الأزرق والآخر للهدف الأحمر. \n\nأولاً، أنشئ الحدث للهدف + الأزرق؛ يجب أن ينقر عليه عند اكتشافه. لا تنسَ استخدام ميزات الاختبار للتأكد من اكتشاف الشرط بشكل + صحيح. \n\nسيتقدم الدرس بعد حفظ حدث الهدف الأزرق. + + رائع! الآن نحتاج إلى نفس الشيء، لكن للهدف الأحمر. + انقر على زر إنشاء حدث وأنشئ حدثاً للهدف الأحمر؛ يجب أن ينقر عليه عند اكتشافه. \n\nسيتقدم الدرس بعد + حفظ حدث الهدف الأحمر. + + تحتوي قائمتنا الآن على حدثين، أحدهما لكل هدف. احفظ + السيناريو واختبره مع اللعبة. + + يبدو أن هناك خطأ ما. السيناريو ينقر فقط على الهدف + الأزرق، متجاهلاً الأحمر تماماً، مما يمنعنا من الفوز. \n\nلماذا يحدث هذا؟ لأن الحدث الأزرق يسبق + الأحمر، وبما أنه يُفعَّل دائماً، لا يتم تقييم الإطار الحالي أكثر من ذلك ويبدأ الإطار التالي من أول + قائمة الأحداث. \n\nهناك عدة طرق لإصلاح ذلك. افتح مربع حوار إعداد السيناريو لمعرفة كيفية ذلك. + + يمكننا إصلاح المشكلة بطريقتين: \n\nيمكننا تغيير خيار + \"مواصلة التنفيذ\" لحدث الهدف الأزرق لمواصلة معالجة نفس الإطار وتنفيذ الحدث الأحمر أيضاً. سيؤدي ذلك + إلى تشغيل كلا النقرتين عندما يكون كلا الهدفين مرئيين في نفس الوقت. \n\nأو يمكننا نقل حدث الهدف الأحمر + إلى أعلى القائمة، بحيث يُفحص أولاً وينقر عليه دائماً عند ظهوره، لكن الهدف الأزرق لن يُنقر عليه بعد + الآن عند ظهور الأحمر أيضاً. \n\nالفرق الرئيسي بين الحلين هو السرعة: وضع الحدث الأحمر أولاً يعني + التفاعل بأسرع ما يمكن عند ظهوره، مع كوننا أبطأ قليلاً عندما يكون الهدف الأزرق فقط مرئياً. + + بما أن اللعبة تمنح 10 نقاط للهدف الأحمر، نريد التفاعل + معه بأسرع ما يمكن عند ظهوره عن طريق نقل حدثه إلى أعلى القائمة. \n\nانقل الحدث الأحمر إلى المرتبة + الأولى واحفظ السيناريو. يجب أن تتمكن من الفوز الآن. + يمكنك إعادة ترتيب الأحداث بالضغط المطول على + هذه الأيقونة وسحب الحدث إلى المكان الصحيح. + + كالمعتاد، ابدأ السيناريو أولاً ثم ابدأ اللعبة. \n\nإذا + لم تتمكن من الفوز بعد، تأكد من أن كل حدث يعمل بشكل منفرد باستخدام ميزات الاختبار. + + رائع! أنت الآن تفهم كيف تعمل أولوية الأحداث وكيف تتصرف + حلقة أحداث الشاشة. هذا هو المفتاح لبناء وإدارة السيناريوهات المعقدة. + + diff --git a/feature/tutorial/src/main/res/values-ar/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-ar/strings_tutorial_events_state.xml new file mode 100644 index 000000000..b6925a888 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ar/strings_tutorial_events_state.xml @@ -0,0 +1,134 @@ + + + + + تعطيل الأحداث غير المستخدمة + غيّر حالة أحداث متعددة لتحسين أداء سيناريو معقد. + انقر على الأهداف بالترتيب: أزرق، أحمر، أخضر ثم أصفر. + + لعبة جديدة! هذه المرة عليك النقر على أربعة أهداف ملونة + بالترتيب: الأزرق أولاً، ثم الأحمر، ثم الأخضر، وأخيراً الأصفر. \n\nيمكنك تجربة اللعبة أولاً لترى كيف + تعمل، أو فتح إعدادات السيناريو مباشرةً لبدء الأتمتة. + + نحتاج إلى اكتشاف أربعة أهداف مختلفة، واحد لكل لون. سننشئ + حدثاً واحداً لكل هدف. \n\nابدأ بالهدف الأزرق: أنشئ حدثاً جديداً يكتشفه داخل منطقة اللعبة وينقر عليه. + + عند استخدام أحداث متعددة، من المهم تخصيص أسمائها لتسهيل + التمييز بينها. أعطِ هذا الحدث اسماً واضحاً مثل \"الهدف الأزرق\" حتى تتعرف عليه بسهولة في سيناريوك. + \n\nبعد الانتهاء، أنشئ شرط صورة جديداً والتقط الهدف الأزرق. + + بما أن الهدف يتحرك، يجب ضبط نوع الاكتشاف على \"منطقة الكشف\" + ثم تحديد منطقة اللعبة. \n\nبعد ضبط المنطقة بشكل صحيح، احفظها وعُد إلى مربع حوار الحدث. + + تم ضبط شرطك. نحتاج الآن إلى إجراء نقر حتى ينقر الحدث على + الهدف المكتشف. \n\nأنشئ إجراء نقر جديداً للمتابعة. + + الهدف يتحرك، لذا لا يمكننا تحديد موضع ثابت. غيّر نوع النقر + في حقل \"انقر فوق\" إلى \"انقر على الحالة المكتشفة\" وحدد شرط الهدف الأزرق. بهذه الطريقة سيقع النقر دائماً في المكان الذي وُجد فيه الهدف + بالضبط.\n\nبعد تحديد الشرط، احفظ النقر وعُد إلى مربع حوار الحدث. + + حدث الهدف الأزرق جاهز! أنشئ الآن حدثاً للهدف الأحمر بنفس + الطريقة: اكتشفه في منطقة اللعبة وانقر عليه. سيتقدم البرنامج التعليمي بمجرد حفظ حدث الهدف الأحمر. + + رائع! أنشئ الآن نفس الحدث للهدف الأخضر. سيتقدم البرنامج + التعليمي بمجرد حفظ حدث الهدف الأخضر. + + لقد اقتربت من الانتهاء! أنشئ حدثاً أخيراً للهدف الأصفر. + سيتقدم البرنامج التعليمي بمجرد حفظ حدث الهدف الأصفر. + + الأحداث الأربعة جاهزة. بما أننا حددناها بترتيب تسلسل اللعبة، + فأولويتها صحيحة. \n\nاحفظ السيناريو واختبره في اللعبة لترى أداءه. + + السيناريو يكتشف الأهداف وينقر عليها، لكنه على الأرجح بطيء + جداً للفوز. \n\nحالياً، الأحداث الأربعة نشطة في آنٍ واحد، لذا في كل إطار يتحقق السيناريو من الأزرق، ثم + الأحمر، ثم الأخضر، ثم الأصفر؛ بغض النظر عن الهدف الذي تم النقر عليه للتو. هذا يُضيّع وقتاً ثميناً! + \n\nافتح إعدادات السيناريو لتتعلم كيفية تحسين ذلك. + + كل حدث له حالة أولية: يمكن أن يبدأ ممكّناً أو معطلاً. الآن + الأحداث الأربعة ممكّنة، لذا يتم التحقق من جميعها في كل إطار. \n\nالحل هو إبقاء حدث الهدف الحالي فقط نشطاً + وتعطيل البقية. عند النقر على هدف، سيمكّن حدثه الهدف التالي ويعطّل الآخرين. \n\nلنبدأ بتعديل حدث الهدف + الأزرق. + + الهدف الأزرق هو الأول للنقر عليه، لذا يجب أن يبدأ حدثه + ممكّناً؛ لا داعي لتغيير أي شيء هنا. \n\nنحتاج فقط إلى إضافة إجراء \"تغيير حالة الحدث\" حتى يتم تمكين حدث الهدف + الأحمر وتعطيل الآخرين عند النقر على الهدف الأزرق. انقر على منطقة الإجراءات لإضافة هذا الإجراء. + + حدد نوع الإجراء \"تغيير حالة الحدث\". + + يتيح لك هذا الإجراء تغيير حالة أي حدث في سيناريوك عند + تشغيل هذا الحدث. انقر على حقل \"لا تغييرات\" لاختيار الأحداث التي تريد تغيير حالتها. + + لكل حدث في القائمة، يمكنك تعيين إحدى الحالات الثلاث: + \n• تمكين: يصبح الحدث نشطاً ويتم التحقق منه في كل إطار \n• تعطيل: يصبح الحدث غير نشط ويُتخطى كلياً + \n• عكس: ينتقل بين النشط وغير النشط في كل مرة \n\nبما أنه تم النقر على الأزرق للتو، مكّن حدث الهدف + الأحمر وعطّل جميع الآخرين. انقر على التالي عند الانتهاء. + يعرض كل صف من صفوف الحدث ثلاثة خيارات: تمكين، + تعطيل، وتبديل. انقر على الخيار الذي تريد تطبيقه عند تنفيذ هذا الإجراء. + + ممتاز! احفظ حدث الهدف الأزرق. + + افتح الآن حدث الهدف الأحمر في القائمة لتهيئته بنفس + الطريقة. + + بخلاف حدث الهدف الأزرق، يجب ألا يكون هذا الحدث نشطاً في + بداية السيناريو، لأن هدفه ليس الأول. غيّر حالته الأولية إلى معطّل. + + أضف الآن إجراء \"تغيير حالة الحدث\" حتى يتم تمكين حدث الهدف + التالي وتعطيل الآخرين عند النقر على هذا الهدف. انقر على منطقة الإجراءات. + + اضبط التبديلات: مكّن الهدف الأخضر وعطّل جميع الآخرين. + انقر على التالي عند الانتهاء. + + عمل رائع! افتح الآن حدث الهدف الأخضر لتهيئته بنفس + الطريقة. + + يجب ألا يكون الهدف الأخضر نشطاً في البداية أيضاً. غيّر + حالته الأولية إلى معطّل. + + أضف الآن إجراء \"تغيير حالة الحدث\" حتى يتم تمكين حدث الهدف + الأصفر وتعطيل الآخرين عند النقر على الهدف الأخضر. انقر على منطقة الإجراءات. + + اضبط التبديلات: مكّن الهدف الأصفر وعطّل جميع الآخرين. + انقر على التالي عند الانتهاء. + + لقد اقتربت من الانتهاء! افتح حدث الهدف الأصفر لإنهاء + الإعداد. + + الهدف الأصفر هو الأخير في التسلسل، لذا يجب أن يبدأ معطلاً + أيضاً. غيّر حالته الأولية إلى معطّل. + + أضف إجراء \"تغيير حالة الحدث\" إلى حدث الهدف الأصفر كذلك. عند + النقر على الأصفر، نريد العودة إلى البداية: مكّن الهدف الأزرق وعطّل جميع الآخرين. انقر على منطقة + الإجراءات. + + اضبط التبديلات: مكّن الهدف الأزرق وعطّل جميع الآخرين. + بهذه الطريقة سيتكرر التسلسل إلى ما لا نهاية. انقر على التالي عند الانتهاء. + + جميع الأحداث مهيأة بالكامل الآن. احفظ السيناريو لتطبيق + التغييرات. + + جميع الأحداث مهيأة! احفظ السيناريو ثم ابدأ اللعبة. تذكر + تشغيل السيناريو قبل بدء اللعبة. \n\nبما أن سيناريونا يحتوي على حالة داخلية، يجب إعادة تشغيله في كل مرة + تُعيد فيها بدء اللعبة لضمان عدم انتظاره للهدف الأخير من الجلسة السابقة. يمكن أتمتة ذلك بسهولة عن طريق + اكتشاف ما إذا كان زر البدء مرئياً لإعادة ضبط حالات الأحداث. + + لقد فزت! \n\nبالتحكم في الأحداث النشطة في كل لحظة، يعرف + السيناريو دائماً بالضبط أي هدف يبحث عنه التالي — دون إهدار إطارات في فحص أهداف خارج التسلسل. \n\nهكذا + يتيح لك إجراء تبديل الحدث إنشاء أتمتة تسلسلية مُوجَّهة بالحالة. + + diff --git a/feature/tutorial/src/main/res/values-es/strings_categories.xml b/feature/tutorial/src/main/res/values-es/strings_categories.xml index f9a70efcd..114ca8f64 100644 --- a/feature/tutorial/src/main/res/values-es/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-es/strings_categories.xml @@ -1,4 +1,4 @@ - + + Acción Pausa + Aprende cómo la pausa afecta la ejecución de acciones y la detección + Una Acción Pausa suspende el escenario completo durante + una duración configurada: durante ese tiempo, no se ejecuta ninguna acción y no se realiza ninguna detección + de pantalla.\n\nUn caso de uso muy habitual es añadir una Pausa al final de tu lista de acciones. Cuando + pulsas en algún lugar, la aplicación necesita tiempo para procesar el clic y mostrar el resultado — y + normalmente querrás esperar ese momento antes de que Klick\'r vuelva a analizar la pantalla.\n\nUna pausa + entre dos acciones también es válida, pero añadir una al final de la lista suele ser la necesidad más + importante. + + + Acción Deslizamiento + Aprende cómo se realiza el gesto de deslizamiento + Una Acción Deslizamiento realiza un gesto de arrastrar + en línea recta desde una posición de inicio hasta una posición de fin. Ambas coordenadas son fijas y se + establecen al configurar la acción.\n\nLa duración controla cuánto tiempo tarda el gesto: una duración más + corta produce un deslizamiento más rápido, mientras que una más larga produce uno más lento y controlado. + + + Desplazamiento del clic + Aprende a ajustar la posición del clic en una condición detectada + Al hacer clic en una condición detectada, el + clic se aplica por defecto en el centro del área detectada.\n\nEl desplazamiento del clic te permite mover + esa posición un número fijo de píxeles a lo largo de los ejes X e Y, relativo al centro de la condición. + Esto es útil cuando el elemento que quieres pulsar está cerca — pero no exactamente — del centro del área + detectada. + + + Objetivo del clic + Aprende a configurar dónde se aplicará el clic + Una Acción Clic puede apuntar a dos tipos de + posiciones: una posición estática siempre idéntica, o la posición de una condición detectada.\n\nElige tu + método en el selector de objetivo del diálogo de configuración de la acción. + Con una posición estática, el clic siempre + ocurre en las mismas coordenadas, independientemente de lo que esté en pantalla.\n\nTen en cuenta que esas + coordenadas son sensibles a la rotación: si el dispositivo rota, el clic puede acabar en una posición + inesperada o fuera de los límites de la pantalla. + Con una posición de condición, el clic se aplica + en el centro de una Condición de imagen detectada, siguiendo al objetivo donde quiera que aparezca.\n\nCon + el operador AND, todas las condiciones deben cumplirse, por lo que cada Condición de imagen tiene una + posición disponible. Puedes elegir libremente cualquiera y refinarla con un desplazamiento. + Con el operador OR, solo se evalúa la primera + condición cumplida y las demás se omiten. Por ello, Klick\'r no puede saber de antemano cuál se detectará. + \n\nEn consecuencia, con el operador OR no puedes elegir una condición específica como objetivo: el clic + siempre se aplicará en la primera detectada, sea cual sea en tiempo de ejecución. + + + Orden de condiciones y velocidad + Cómo el orden de tus condiciones afecta la + velocidad de comprobación del evento + + El orden de las condiciones en la lista + afecta la velocidad de comprobación del evento.\n\nCon el operador Y, la comprobación se detiene en cuanto se + encuentra la primera condición NO cumplida. Colocar primero las condiciones menos probables permite a la app + saltarse el resto antes, haciendo tu evento más rápido. + + Con el operador O, la comprobación se + detiene en cuanto se encuentra la primera condición cumplida. Colocar primero las condiciones más probables + permite a la app terminar antes, sin comprobar el resto.\n\nEn ambos casos, poner la condición más importante + al principio de la lista es una forma sencilla de mantener tu escenario rápido. + + + + Estado de los eventos + Aprende a activar y desactivar eventos mientras un + escenario está en marcha + + Cada evento de tu escenario (Eventos de Pantalla + y Eventos Disparador) tiene un estado: está activado o desactivado.\n\nCuando está activado, el + evento se ejecuta con normalidad y verifica sus condiciones como de costumbre. Cuando está desactivado, se + omite por completo, como si no existiera.\n\nPor defecto, todos los eventos comienzan activados. Puedes cambiar + esto con el campo Estado inicial en los ajustes del evento. + + Mientras un escenario está en marcha, puedes + cambiar el estado de cualquier evento usando la acción Cambiar estado del evento. Esta acción permite + activar, desactivar o alternar el estado de uno o más eventos.\n\nEsto abre muchas posibilidades: eventos que + se activan uno tras otro, eventos que se desactivan solos después de ejecutarse una vez, o grupos de eventos + donde solo uno está activo a la vez. + + Cuando todos los eventos del escenario están + desactivados, el escenario se para solo. No hay nada más que hacer, así que Klick\'r se detiene + automáticamente.\n\nEsta es una forma sencilla de terminar un escenario: haz que tu último evento desactive a + todos los demás una vez cumplido su objetivo, y todo se para por sí solo. + + + + Lista de acciones + Aprende cómo se ejecuta la lista de acciones + Las acciones se ejecutan en orden, una tras otra. + Puedes cambiar el orden de una acción usando los botones << y >>, o pulsando directamente en su + número de índice.\n\nIntenta mantener tus listas de acciones cortas. Un autoclicker normal realiza una acción + por evento — ese es el modelo a seguir. Si te encuentras añadiendo muchas acciones a un solo evento, normalmente + es señal de que el trabajo debería dividirse en varios eventos, cada uno reaccionando a lo que realmente se + muestra en pantalla. Esta es la filosofía ver-y-actuar de Klick\'r: detectar primero, luego actuar. + + + Acción Escribir texto + Aprende a introducir texto en un campo de entrada activo + Antes de que se ejecute la acción Escribir texto, + el campo de entrada objetivo ya debe estar enfocado, igual que si lo pulsaras para mostrar el teclado.\n\nPara + lograrlo, añade una acción Clic en ese campo antes de la acción Escribir texto. Si hay una animación de + transición tras el clic, una acción Esperar entre ambas puede ayudar a asegurarse de que el campo esté listo. + \n\nLa acción también tiene una opción Validar: cuando está activada, pulsa automáticamente Intro tras establecer + el texto, confirmando o enviando el valor. + Puedes insertar el valor de un contador en el texto + a escribir. Pulsa el botón Añadir contador en la configuración de la acción para seleccionar un contador: insertará + el marcador {nombreContador} en la posición actual del cursor.\n\nEn tiempo de ejecución, cada marcador + {nombreContador} se reemplaza por el valor actual del contador antes de pegar el texto en el campo. Por + ejemplo, si un contador llamado manzanas tiene el valor 18, el texto \"Tengo {manzanas} manzanas\" se + convierte en \"Tengo 18 manzanas\". + + + Acción del sistema + Aprende a activar acciones de navegación de Android + Una Acción del sistema ejecuta una de las acciones de + navegación integradas de Android: Atrás, Inicio o Recientes.\n\nSon las mismas acciones que los botones de + navegación en la parte inferior de tu pantalla. No requieren coordenadas y funcionan a nivel del sistema, + independientemente de qué aplicación esté abierta. + + + Acción Cambiar contador + Aprende a modificar el valor de un contador + Una acción Cambiar contador aplica una operación + a un contador usando un valor estático predefinido. Hay tres operaciones disponibles: añadir el valor al contador + (+), restarlo del contador (−) o establecer el contador a ese valor exacto (=).\n\nEsta es la forma más común de + actualizar un contador — por ejemplo, añadir 1 cada vez que se detecta una condición, o restablecerlo a 0 cuando + se alcanza un objetivo. + En lugar de un valor estático, puedes usar el + valor actual de otro contador como operando. Las mismas tres operaciones (+, −, =) se aplican, pero la cantidad + se lee del contador seleccionado en tiempo de ejecución en lugar de estar fijada en la configuración.\n\nEsto te + permite construir escenarios dinámicos donde los contadores interactúan entre sí. + + + Acción Notificación + Aprende a mostrar una notificación durante tu escenario + Una acción Notificación muestra una notificación + de Android con un título y un mensaje de tu elección.\n\nPuedes insertar el valor actual de un contador en el + texto de la notificación usando el botón Añadir contador, o escribiendo directamente el marcador + {nombreContador}. En tiempo de ejecución se reemplaza por el valor del contador — por ejemplo, + \"Tengo {manzanas} manzanas\" se convierte en \"Tengo 18 manzanas\". + El nivel de importancia de la notificación + controla la intrusividad con la que se presenta. Los niveles más altos pueden mostrar un banner emergente y + reproducir un sonido, mientras que los más bajos se entregan silenciosamente en el cajón de notificaciones. + \n\nEl comportamiento exacto depende del dispositivo y puede personalizarse en la configuración de + notificaciones de Android para Klick\'r. + + + Acción Cambiar estado del evento + Aprende a activar y desactivar eventos en tiempo de ejecución + Un evento desactivado se omite completamente + durante el bucle del escenario — sus condiciones nunca se comprueban y sus acciones nunca se ejecutan. Esto + significa que no consume ningún tiempo de procesamiento.\n\nDesactivar eventos que no estás usando es una + excelente forma de mejorar el rendimiento. Por ejemplo, en un escenario que alterna entre una fase de menú y + una fase de juego, desactivar todos los eventos del menú mientras estás en la fase de juego (y viceversa) + mantiene activos solo los eventos relevantes en cada momento. + Al configurar la acción, puedes elegir cambiar + el estado de todos los eventos del escenario a la vez, o definir un nuevo estado para cada evento + individualmente.\n\nHay tres cambios de estado disponibles para cada evento: activarlo, desactivarlo, o + alternarlo desde su valor actual — un evento activado se desactiva y uno desactivado se activa. + Si todos los eventos del escenario acaban + desactivados al mismo tiempo, el escenario se detiene automáticamente, ya que no queda nada por ejecutar. + \n\nEsto puede usarse intencionalmente como una forma limpia de terminar un escenario una vez alcanzado un + objetivo: una última acción Cambiar estado del evento que desactive todos los eventos detendrá el escenario. + + + Acción Intent + Aprende a comunicarte con otras aplicaciones + Los Intents son la forma en que las aplicaciones se + comunican entre sí en Android. La acción Intent te permite aprovechar este sistema directamente desde tu + escenario.\n\nHay un conjunto de plantillas predefinidas disponibles para facilitar esto. La más común es + Iniciar aplicación, que lanza otra app en tu dispositivo exactamente como si hubieras pulsado su icono desde + el lanzador. + La pestaña Avanzado te permite definir un Intent + sin procesar manualmente, dándote control total sobre la acción, categoría, datos y extras. Esto no es + recomendado para usuarios habituales — está orientado a desarrolladores Android que ya saben cómo funcionan + los Intents.\n\nMás plantillas listas para usar se añadirán en futuras actualizaciones para facilitar los + casos de uso comunes sin necesidad de recurrir a las opciones avanzadas. + + + + Prioridad de eventos + Aprende cómo el orden de los eventos en tu lista afecta cuáles se ejecutan + Cada fotograma capturado desde tu pantalla se procesa verificando tus eventos uno a uno, de arriba a abajo.\n\nLa posición de un evento en tu lista determina cuándo tiene la oportunidad de ejecutarse. Por defecto, en cuanto se cumplen las condiciones de un evento y se ejecutan sus acciones, el fotograma se considera procesado. El procesamiento se detiene para ese fotograma y el siguiente comienza desde el primer evento de la lista.\n\nEsto significa que por defecto solo un evento puede ejecutarse por fotograma. + Puedes cambiar este comportamiento usando el campo seguir ejecutando en la configuración del evento. Cuando está activado, después de que ese evento se ejecuta, el procesamiento continúa con el siguiente evento en lugar de detenerse.\n\nEsto permite que varios eventos se ejecuten en el mismo fotograma.\n\nEjemplo: tu lista contiene el Evento A seguido del Evento B. Si el Evento A sigue siendo detectado y no tiene seguir ejecutando activado, se ejecutará en cada fotograma y el Evento B nunca tendrá la oportunidad de ejecutarse.\n\nActiva seguir ejecutando en el Evento A y ambos eventos serán verificados en cada fotograma.\n\nTambién hay un tutorial interactivo disponible para practicar este concepto. + + + + Recarga de eventos + Aprende cómo la recarga de un evento se comporta en tu escenario + El parámetro de recarga de eventos te permite omitir + un evento durante un tiempo determinado una vez que se cumple. \n\nUn evento en estado de recarga sigue + considerándose activado: la recarga y el estado del evento son independientes. \n\nSi el evento se desactiva + mientras está en recarga, el temporizador de recarga se borrará, por lo que el tiempo de espera ya no se aplica + cuando el evento se vuelve a activar. + + + + Usar valores de contador + Aprende las diferentes formas de mostrar y usar los valores de contador en tu escenario + + Puedes mostrar el valor actual de un contador + dentro de una acción Notificación. Esto es útil para seguir el progreso mientras tu escenario se ejecuta, + o para mostrar un resumen al final.\n\nPara insertar un contador, pulsa el botón Agregar contador en la + configuración de la acción. Esto añade un marcador como {counterName} en tu texto. En tiempo de + ejecución, el marcador es reemplazado por el valor actual del contador. Por ejemplo, si un contador llamado + score tiene el valor 42, el texto \"Puntuación actual: {score}\" se convierte en + \"Puntuación actual: 42\". + + También puedes insertar el valor de un + contador en una acción Escribir texto, para que el texto escrito incluya el valor actual en el momento en + que se ejecuta la acción.\n\nEl marcador funciona igual que en la acción Notificación: pulsa el botón + Agregar contador o escribe {counterName} directamente. Por ejemplo, si un contador llamado + score tiene el valor 42, el texto \"Mi puntuación es {score}\" se convierte en + \"Mi puntuación es 42\". + + Los valores de los contadores se registran + en el informe de depuración. Si algo no funciona como se espera en tu escenario, capturar un informe de + depuración te mostrará exactamente cómo cambiaron tus contadores con el tiempo, lo que facilitará encontrar + el problema. + diff --git a/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_not_visible.xml index c4144b9f5..d39bd2c93 100644 --- a/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - Combinar múltiples condiciones - Crea y combina múltiples condiciones para tu evento - Haz clic en el botón azul solo cuando el botón rojo sea visible + Visibilidad de condiciones + Usa la opción Visibilidad para activar un + clic cuando un objetivo no está en pantalla + Pulsa el botón azul solo cuando el botón + rojo no sea visible - Cambiemos las reglas del juego nuevamente. El objetivo azul ha dejado de moverse, - pero ahora solo debe hacer clic cuando el objetivo rojo sea visible.\n\nPrimero, inicia el juego y verifica si puedes ganar por ti mismo. + ¡Nuevas reglas! El objetivo azul ha + dejado de moverse, pero solo debe pulsarse cuando el objetivo rojo no sea visible. + \n\nInicia el juego y comprueba si puedes ganar por ti mismo. - Una vez más, parece imposible ganar manualmente, así que usemos Smart - AutoClicker.\n\nTu escenario del tutorial anterior se ha mantenido y se carga para este tutorial, pero necesitaremos cambiar - algunos parámetros para ganar este nuevo juego.\n\nHaz clic en el icono de configuración del escenario para comenzar a actualizar - tu nuevo escenario. + Una vez más, parece imposible ganar + manualmente, así que usemos Klick\'r. \n\nAbre el menú de configuración del escenario, crea un nuevo Evento de + Pantalla y empieza a añadir condiciones para los objetivos del juego. - Todavía queremos hacer clic en el objetivo azul, pero solo cuando el rojo esté - visible.\nAsí que necesitamos agregar una condición para este objetivo rojo en nuestro evento.\n\nHaz clic en el evento que creaste - previamente para editarlo. + Primero necesitamos una condición que + compruebe cuándo el objetivo rojo NO está visible en pantalla. \n\nCrea una nueva condición de imagen y captura + el objetivo rojo. - Combinaremos varias condiciones, así que necesitamos verificar el operador de condición - para este evento.\n\nEl operador de condición indica cómo se interpretarán juntas varias condiciones.\n - \'Uno\' significa que solo una de las condiciones de este evento debe cumplirse para ejecutar las acciones.\n\n - \'Todos\' significa que todas las condiciones de este evento deben cumplirse para ejecutar las acciones.\n\n - Como queremos detectar si dos cosas se muestran juntas, usaremos \'Todos\'. + Queremos pulsar solo cuando el objetivo + rojo no sea visible, así que pon la opción «Es visible» en No. De este modo, la condición solo se cumplirá + cuando el objetivo rojo no aparezca en pantalla. - Ahora necesitamos actualizar nuestras condiciones.\n\nHaz clic en el campo \"Condiciones\" para mostrar - la lista de condiciones. + El resto de ajustes son correctos para + nuestro caso — adelante, guarda esta condición. - La condición anterior de detectar el objetivo azul sigue siendo correcta, pero necesitamos - una nueva para el objetivo rojo.\n\nHaz clic en el botón de crear condición para crear una nueva condición para él. + Esta condición por sí sola es suficiente + para ganar el juego, pero también se activaría cuando el juego no está en marcha, lo que no es ideal. + \n\nPara evitarlo, combinémosla con una segunda condición que compruebe si el objetivo azul es visible. + Crea una nueva Condición de Imagen y captura el objetivo azul. - Al igual que con el objetivo azul, inicia el juego para mostrar el objetivo rojo. - Una vez que sea visible, ¡toma una captura de pantalla! - Utiliza el botón de captura en el menú flotante para tomar la captura de pantalla. + Para esta condición queremos verificar + que el objetivo azul es visible, por lo que los valores predeterminados son todos correctos. Guarda la condición + y vuelve al Evento para continuar. - ¿Tu captura de pantalla contiene el objetivo rojo? Puedes recortarla para obtener solo la - parte interesante para la detección, el objetivo rojo. - Si tu captura de pantalla no contiene el objetivo rojo, puedes - pulsar este botón para tomar una nueva. + Con varias condiciones, el operador de + condición importa. Queremos que el evento se active cuando el objetivo azul sea visible Y el rojo no lo sea, + así que necesitamos el operador Y; y ya es el valor predeterminado, así que todo está bien. + \n\nAhora crea una nueva acción de clic para continuar. - ¡Tu imagen de condición ya está registrada!\n\nComo el objetivo rojo no se mueve, podemos - mantener la configuración predeterminada.\nHaz clic en el botón de guardar para registrarla y volver a la lista de condiciones. + Queremos pulsar sobre el objetivo azul, + así que selecciona el tipo de posición «En condición» y elige la Condición de Imagen del objetivo azul. + \n\nCuando hayas terminado, guarda el clic, luego tu evento y escenario, y vuelve al juego. - Cierra la lista de condiciones para volver a la configuración del evento. + ¡Inicia tu escenario y lanza el juego + para ganar! \n\nSi no funciona, comprueba que tus condiciones están capturadas correctamente y que la duración + del clic está ajustada a 1 ms. - Ahora tenemos dos condiciones, una para cada objetivo, y las acciones se ejecutarán - solo si ambas se detectan.\n\nHaz clic en el campo \"Acciones\" para mostrar la lista de acciones de nuestro evento. + ¡Enhorabuena! Has aprendido a usar + una condición «No visible». Combínala siempre con al menos otra condición para evitar activar acciones de forma + involuntaria durante todo tu escenario. - La acción ya está configurada para hacer clic en el personaje azul, y solo se ejecutará - cuando los personajes azul y rojo sean visibles juntos.\n\nEste es exactamente el comportamiento que necesitamos para ganar el - juego, así que no hace falta editar nuestra acción de clic.\n\nCierra la lista de acciones para volver a la configuración del evento. - - Haz clic en el botón de guardar para guardar tu evento. - - Todos los cambios deben guardarse en tu escenario para registrarse.\n\nHaz clic - en el botón de guardar para guardar tus cambios. - - ¡Estamos listos para ganar este juego!\n\nHaz clic en el botón de inicio para iniciar la - detección y luego inicia el juego. - - ¡Felicitaciones!\n\nAhora sabes cómo combinar varias condiciones para un evento. - ¡pero hay mucho más que aprender! diff --git a/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..d84b1f9a3 --- /dev/null +++ b/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,70 @@ + + + + + + Operador de condición Y + Usa el operador Y para hacer clic solo cuando + varios objetivos son visibles al mismo tiempo + Pulsa el botón azul solo cuando tanto el + objetivo azul como el rojo estén visibles + + ¡Nuevas reglas! El juego ahora muestra dos + objetivos. Debes pulsar el azul, pero solo cuando ambos objetivos, el azul y el rojo, estén en pantalla al + mismo tiempo. \n\nInicia el juego y comprueba si puedes seguir el ritmo por tu cuenta. + + El tiempo es demasiado ajustado para + manejarlo manualmente, así que usemos Klick\'r. \n\nAbre el menú de configuración del escenario, crea un + nuevo Evento de Pantalla y empieza a añadir condiciones para los objetivos del juego. + + Necesitamos una condición por objetivo. + Empecemos con el azul. \n\nCrea una nueva condición de imagen y captura el objetivo azul. + + Queremos que esta condición se cumpla + cuando el objetivo azul sea visible, así que la configuración predeterminada es correcta. Guarda esta + condición. + + Ahora añadamos la segunda condición para + el objetivo rojo. \n\nCrea otra condición de imagen y captura el objetivo rojo. + + Lo mismo aquí — el objetivo rojo debe ser + visible, así que la configuración predeterminada es correcta. Guarda esta condición y vuelve al Evento. + + Con dos condiciones definidas, el operador + de condición determina cómo se combinan. Selecciona el operador usando el selector de arriba. + \n\n• Y: el evento se activa solo cuando TODAS las condiciones se cumplen.\n• O: el evento se activa en + cuanto UNA condición se cumple.\n\nPara nuestro juego necesitamos los dos objetivos en pantalla al mismo + tiempo, así que selecciona Y. + El selector del operador de + condición + + Y ya es el operador predeterminado, así + que estamos listos. \n\nAhora abre la sección Acciones y crea una nueva acción de clic. + + Queremos pulsar sobre el objetivo azul, + así que selecciona el tipo de posición «En condición» y elige la condición de imagen del objetivo azul. + \n\nCuando hayas terminado, guarda el clic, luego tu evento y escenario, y vuelve al juego. + + ¡Inicia tu escenario y lanza el juego + para ganar! \n\nSi no funciona, comprueba que ambas condiciones estén capturadas correctamente y que la + duración del clic esté ajustada a 1 ms. + + ¡Enhorabuena! Has aprendido a usar el + operador Y. El evento ahora se activa solo cuando todas sus condiciones se cumplen al mismo tiempo. + + diff --git a/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..9dfdcb39b --- /dev/null +++ b/feature/tutorial/src/main/res/values-es/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,73 @@ + + + + + + Operador de condición O + Usa el operador O para hacer clic en el primer + objetivo que aparezca en pantalla + Haz clic en cualquier objetivo en cuanto + aparezca en pantalla + + ¡Nuevo reto! Dos objetivos pueden aparecer + en pantalla. El rojo vale 2 puntos y el azul vale 1 punto, así que haz clic en el que aparezca lo antes + posible. \n\nInicia el juego y comprueba cómo te va. + + Demasiado rápido para manejarlo manualmente, + así que usemos Klick\'r. \n\nAbre el menú de configuración del escenario, crea un nuevo Evento de Pantalla y + empieza a añadir condiciones para los objetivos del juego. + + Necesitamos una condición por objetivo. + Empecemos con el azul. \n\nCrea una nueva condición de imagen y captura el objetivo azul. + + Esta condición debe activarse cuando el + objetivo azul sea visible, así que la configuración predeterminada es correcta. Guarda esta condición. + + Ahora añadamos la segunda condición para el + objetivo rojo. \n\nCrea otra condición de imagen y captura el objetivo rojo. + + Lo mismo aquí, el objetivo rojo debe ser + visible, así que la configuración predeterminada es correcta. Guarda esta condición. + + Con O, las condiciones se comprueban en + orden y el evento se activa en cuanto la primera coincide, así que el orden de tus condiciones importa. + \n\nEl objetivo rojo otorga más puntos, así que queremos que se compruebe primero. Usa el botón « para + moverlo antes del azul, luego vuelve al diálogo Evento. + + Ahora establece el operador de condición en + O. El evento se activará en cuanto aparezca cualquiera de los objetivos. Si ambos son visibles al mismo + tiempo, la condición roja se detectará primero ya que tiene mayor prioridad. \n\nSelecciona O. + + El operador O ya está configurado. Abre la + sección Acciones y crea una nueva acción de clic. + + Queremos hacer clic en el objetivo que + activó el evento. Selecciona el tipo de posición «En condición». Con O, solo una condición puede detectarse + positivamente a la vez, así que no hace falta seleccionar ninguna condición específica. Klick\'r hará clic + automáticamente en la ubicación de la condición que coincidió. \n\nCuando hayas terminado, guarda el clic, + luego tu evento y escenario, y vuelve al juego. + + ¡Inicia tu escenario y lanza el juego para + ganar! \n\nSi no funciona, comprueba que tus condiciones estén capturadas correctamente y que la duración del + clic esté ajustada a 1 ms. + + ¡Enhorabuena! Has aprendido a usar el + operador O y por qué importa la prioridad de las condiciones. Al colocar la condición roja primero, Klick\'r + siempre prioriza el objetivo de mayor valor cuando ambos son visibles al mismo tiempo. + + diff --git a/feature/tutorial/src/main/res/values-es/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-es/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..08fcedf7c --- /dev/null +++ b/feature/tutorial/src/main/res/values-es/strings_tutorial_counters_basics.xml @@ -0,0 +1,129 @@ + + + + Conceptos básicos de contadores + Aprende a usar la acción Contador de cambios y la condición + Contador alcanzado. + Haz clic 10 veces en el objetivo azul, luego haz clic una vez + en el objetivo rojo + + ¡Bienvenido al tutorial de Contadores! + \n\nAquí, automatizarás un juego en el que haces clic en el objetivo azul 10 veces y luego haces clic en el + objetivo rojo una vez para validar tu cuenta y ganar 10 puntos. Puedes probar el juego primero o ir directamente + a la configuración del escenario. + + Primero, necesitamos crear un Evento de pantalla que detecte + el objetivo azul y haga clic en él. \n\nHaz clic en Crear evento para empezar. + + Empecemos añadiendo una condición para detectar el objetivo + azul. Haz clic en el campo Condiciones para abrir la lista de condiciones y crear esta condición. + \n\nEl tutorial continuará una vez que tu condición esté creada. + + ¡Bien! Ahora haz clic en el campo Acciones para añadir las + acciones que se ejecutarán cuando se detecte el objetivo azul. + + Primero necesitamos una acción Hacer clic para tocar el + objetivo azul. Haz clic en el botón de crear para añadir una nueva acción. + + Configura el clic para tocar el objetivo azul y luego guarda + la acción. \n\nEl tutorial continuará una vez que el clic esté guardado. + + También necesitamos contar cuántas veces hemos hecho clic en + el objetivo azul. Esto se puede lograr con una acción Contador de cambios, añadiendo uno cada vez que hacemos + clic. \n\nHaz clic de nuevo en el botón de crear para añadir una segunda acción. + + Selecciona la acción Contador de cambios para incrementar un + contador cada vez que se haga clic en el objetivo azul. + + Primero, necesitamos elegir qué contador actualizar. Haz clic + en Seleccionar un contador para abrir la lista de contadores. + + La lista está vacía por ahora. Haz clic en el botón de crear + para crear un nuevo contador. Dale un nombre (p. ej., «Clics azules»), deja el valor inicial en 0, luego + guárdalo y selecciónalo. + + Ahora configura cómo cambia el contador cada vez que se hace + clic en el objetivo azul. \n\nEstablece el operador en + y el valor en 1, para que el contador aumente en 1 con + cada clic. \n\nLuego guarda la acción y vuelve al diálogo del evento. + El valor puede ser un número fijo o el valor + actual de otro contador. + + ¡Genial! Este Evento de pantalla ahora hará clic en el + objetivo azul e incrementará tu contador en cada detección. \n\nGuarda el evento para volver al escenario. + + Ahora necesitamos un evento que reaccione cuando el contador + llegue a 10. Este tipo de evento no se activa por la pantalla, por lo que es un Evento de disparo. + \n\nHaz clic en la pestaña Eventos de disparo para abrir la lista de Eventos de disparo. + + Haz clic en el botón de crear para añadir un nuevo Evento + de disparo. + + Al igual que un Evento de pantalla, un Evento de disparo + necesita condiciones. Haz clic en el campo Condiciones para abrir la lista de condiciones y crear una nueva + condición de disparo. + + Selecciona el tipo de condición Contador alcanzado para + activar este evento cuando un contador alcance un valor específico. + + Selecciona el contador que creaste antes (el que cuenta los + clics azules) para usarlo como disparador. + + Ahora establece la comparación para que la condición se + cumpla cuando el contador sea igual a 10. Hay varios operadores de comparación, pero aquí necesitamos comprobar + cuándo es igual, así que selecciona «=». Luego introduce 10 como valor, guarda la condición y vuelve al diálogo + del evento. + El valor con el que comparar puede ser un número + fijo o el valor actual de otro contador. + + ¡Condición establecida! Ahora necesitamos definir qué ocurre + cuando el contador llega a 10. Haz clic en el campo Acciones para abrir la lista de acciones. + + Primero, crea una acción Hacer clic y colócala manualmente + en el objetivo rojo para validar la cuenta. + + Configura el clic para tocar el objetivo rojo y luego guarda + la acción. Ten en cuenta que en un Evento de disparo, la posición del clic debe establecerse siempre manualmente. + \n\nEl tutorial continuará una vez que el clic esté guardado. + + Ahora crea una segunda acción para reiniciar el contador. + Haz clic de nuevo en el botón de crear y selecciona la acción Contador de cambios. + + Queremos establecer el contador de clics azules en 0, así + que primero, selecciona el contador de clics azules. + + Establece el operador en = y el valor en 0 para reiniciar + el contador tras cada validación. Luego guarda la acción y vuelve al diálogo del evento para continuar. + + Este Evento de disparo hará clic en el objetivo rojo y + reiniciará el contador cada vez que se cuenten 10 clics azules. La lista de Eventos de disparo se ejecuta entre + cada fotograma de pantalla, antes que la lista de Eventos de pantalla, por lo que cuando el contador llega a 10, + este evento se ejecuta de inmediato: se hace clic en el objetivo rojo y el contador se reinicia, listo para + empezar de nuevo. \n\nGuarda el evento para volver al escenario. + + ¡El escenario está completo! Hará clic en el objetivo azul, + contará cada clic y luego validará con el objetivo rojo cada 10 clics y empezará de nuevo. \n\nGuarda el + escenario para aplicar tu configuración. + + ¡Todo está listo! Inicia el escenario, luego lanza el juego + y observa cómo Klick\'r gestiona el conteo por ti. + + ¡Bien hecho! Has aprendido a usar Contadores para registrar + valores a lo largo de múltiples eventos. \n\nCombinado con la acción Contador de cambios y la condición + Contador alcanzado, ahora puedes crear automatizaciones que reaccionen a patrones repetidos. + + diff --git a/feature/tutorial/src/main/res/values-es/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-es/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..a2284cc07 --- /dev/null +++ b/feature/tutorial/src/main/res/values-es/strings_tutorial_events_priority.xml @@ -0,0 +1,71 @@ + + + + + Priorizar un evento + Priorizar un Evento sobre otro Evento + Haz clic lo más rápido posible en los objetivos. Azul = 1 punto; + Rojo = 10 puntos + + ¡Nuevo juego! Tenemos que hacer clic en los objetivos lo más + rápido posible, pero el rojo vale más puntos. Puedes probar el juego primero o abrir el menú de configuración + del escenario para empezar a automatizarlo. + + Queremos detectar dos objetivos diferentes, el azul y el + rojo. Para este tutorial, crearemos dos eventos distintos: uno para el objetivo azul y otro para el objetivo + rojo. \n\nPrimero, crea el Evento para el objetivo azul; debe hacer clic en él cuando se detecte. No olvides + usar las funciones de prueba para asegurarte de que tu condición se detecta correctamente. \n\nEl tutorial + avanzará una vez que guardes el Evento del objetivo azul. + + ¡Genial! Ahora necesitamos lo mismo, pero para el objetivo + rojo. Haz clic en el botón Crear evento y crea uno para el objetivo rojo; debe hacer clic en él cuando se + detecte. \n\nEl tutorial avanzará una vez que guardes el Evento del objetivo rojo. + + Nuestra lista ahora tiene dos eventos, uno para cada + objetivo. Guarda tu Escenario y pruébalo con el juego. + + Algo parece estar mal. El escenario solo hace clic en el + objetivo azul, ignorando completamente el rojo, lo que nos impide ganar el juego. \n\n¿Por qué ocurre esto? + Porque el evento azul está antes que el rojo, y como siempre se activa, el fotograma actual no se evalúa más + y el siguiente comienza desde el principio de la lista de Eventos. \n\nHay varias formas de solucionar esto. + Abre el diálogo de configuración del escenario para aprender cómo. + + Podemos solucionar el problema de dos formas: \n\nPodemos + cambiar la opción \"Seguir ejecutando\" del evento del objetivo azul para continuar procesando el mismo + fotograma y también ejecutar el evento rojo. Esto activará ambos clics cuando ambos objetivos sean visibles al + mismo tiempo. \n\nO podemos mover el evento del objetivo rojo al principio de la lista, para que se compruebe + primero y siempre se haga clic en él cuando sea visible, pero el objetivo azul ya no se hará clic cuando el + rojo también esté visible. \n\nLa diferencia clave entre ambas soluciones es la velocidad: colocar el evento + rojo primero significa que reaccionamos lo más rápido posible cuando aparece, siendo algo más lentos cuando + solo el objetivo azul es visible. + + Como el juego da 10 puntos por el objetivo rojo, queremos + reaccionar lo más rápido posible cuando aparece moviendo el evento rojo al principio de la lista. \n\nMueve el + evento rojo al primer lugar y guarda el escenario. Ahora deberías poder ganar el juego. + Puedes reordenar los Eventos manteniendo pulsada + esta icono y arrastrando el evento al lugar correcto. + + Como de costumbre, inicia primero tu escenario y luego el + juego. \n\nSi aún no puedes ganar, asegúrate de que cada evento funciona por sí solo usando las funciones de + prueba. + + ¡Genial! Ahora entiendes cómo funciona la prioridad de + eventos y cómo se comporta el bucle de Eventos de Pantalla. Esto es clave para crear y gestionar escenarios + complejos. + + diff --git a/feature/tutorial/src/main/res/values-es/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-es/strings_tutorial_events_state.xml new file mode 100644 index 000000000..99cdd182e --- /dev/null +++ b/feature/tutorial/src/main/res/values-es/strings_tutorial_events_state.xml @@ -0,0 +1,150 @@ + + + + + Desactivar eventos no utilizados + Cambia el estado de múltiples eventos para optimizar un escenario complejo. + Haz clic en los objetivos en orden: azul, rojo, verde y luego amarillo. + + ¡Nuevo juego! Esta vez debes hacer clic en cuatro objetivos de + colores en orden: primero azul, luego rojo, luego verde y finalmente amarillo. \n\nPuedes probar el juego + primero para ver cómo funciona, o abrir directamente la configuración del escenario para empezar a + automatizarlo. + + Necesitamos detectar cuatro objetivos distintos, uno por color. + Crearemos un Evento por objetivo. \n\nEmpieza con el objetivo azul: crea un nuevo Evento que lo detecte dentro + del área de juego y haga clic en él. + + Cuando usas varios eventos, es importante personalizar su nombre + para no perderse. Dale a este Evento un nombre claro, como \"Objetivo azul\", para identificarlo fácilmente en + tu escenario. \n\nCuando termines, crea una nueva condición de Imagen y captura el objetivo azul. + + Como el objetivo se mueve, debemos establecer el tipo de + detección en \"Área de detección\" y seleccionar el área de juego. \n\nUna vez que el área esté correctamente + configurada, guárdala y vuelve al diálogo Evento. + + Tu condición está lista. Ahora necesitamos una acción Clic para + que el Evento haga clic en el objetivo detectado. \n\nCrea una nueva acción Clic para continuar. + + El objetivo se mueve, así que no podemos definir una posición + fija. Establece el campo \"Hacer clic en\" en \"Haga clic en la condición detectada\" y selecciona tu condición de objetivo azul. Así, el clic siempre + caerá exactamente donde se encontró el objetivo.\n\nUna vez seleccionada la condición, guarda el clic y vuelve + al diálogo Evento. + + ¡El Evento del objetivo azul está listo! Ahora crea un Evento + para el objetivo rojo de la misma forma: detéctalo en el área de juego y haz clic en él. El tutorial avanzará + cuando tu Evento del objetivo rojo esté guardado. + + ¡Genial! Ahora crea el mismo Evento para el objetivo verde. El + tutorial avanzará cuando tu Evento del objetivo verde esté guardado. + + ¡Casi terminado! Crea un último Evento para el objetivo + amarillo. El tutorial avanzará cuando tu Evento del objetivo amarillo esté guardado. + + Los cuatro Eventos están listos. Como los definimos en el orden + de la secuencia del juego, su prioridad es correcta. \n\nGuarda tu Escenario y pruébalo en el juego para ver su + rendimiento. + + El escenario detecta y hace clic en los objetivos, pero + probablemente es demasiado lento para ganar. \n\nActualmente, los cuatro Eventos están activos al mismo tiempo, + así que en cada fotograma el escenario comprueba azul, luego rojo, luego verde, luego amarillo; sin importar en + qué objetivo se acaba de hacer clic. ¡Esto desperdicia tiempo valioso! \n\nAbre la configuración del escenario + para aprender cómo mejorar esto. + + Cada Evento tiene un estado inicial: puede empezar activado o + desactivado. Ahora mismo los cuatro Eventos están activados, por lo que todos se comprueban en cada fotograma. + \n\nLa solución es mantener activo solo el Evento del objetivo actual y desactivar el resto. Cuando se hace clic + en un objetivo, su Evento activará el siguiente y desactivará los demás. \n\nEmpecemos editando el Evento del + objetivo azul. + + El objetivo azul es el primero en hacer clic, así que su + Evento debe empezar activado; no hay nada que cambiar aquí. \n\nSolo necesitamos añadir una acción \"Alternar + evento\" para que cuando se haga clic en el objetivo azul, el Evento del objetivo rojo se active y los demás se + desactiven. Pulsa en el área Acciones para añadir esta acción. + + Selecciona el tipo de acción \"Cambiar el estado del evento\". + + Esta acción te permite cambiar el estado de cualquier Evento de + tu escenario cuando este Evento se activa. Pulsa el campo \"Sin cambios\" para seleccionar qué Eventos cambiar. + + Para cada Evento de la lista, puedes establecer uno de tres + estados: \n• Activar: el Evento se vuelve activo y se comprobará en cada fotograma \n• Desactivar: el Evento se + vuelve inactivo y se omite por completo \n• Invertir: cambia entre activo e inactivo cada vez \n\nComo acaba de + hacerse clic en azul, activa el Evento del objetivo rojo y desactiva todos los demás. Pulsa Siguiente cuando + hayas terminado. + Cada fila de Evento muestra tres opciones: Activar, + Desactivar y Alternar. Pulsa la que quieras aplicar cuando se ejecute esta acción. + + ¡Perfecto! Guarda el Evento del objetivo azul. + + Ahora abre el Evento del objetivo rojo en la lista para + configurarlo de la misma forma. + + A diferencia del Evento del objetivo azul, este Evento no debe + estar activo al inicio del escenario, ya que su objetivo no es el primero. Cambia su estado inicial a + Desactivado. + + Ahora añade una acción \"Cambiar el estado del evento\" para que cuando se + haga clic en este objetivo, el Evento del siguiente objetivo se active y los demás se desactiven. Pulsa el área + Acciones. + + Establece los conmutadores: activa el objetivo verde y + desactiva todos los demás. Pulsa Siguiente cuando hayas terminado. + + ¡Buen trabajo! Ahora abre el Evento del objetivo verde para + configurarlo de la misma forma. + + El objetivo verde tampoco debe estar activo al inicio. Cambia + su estado inicial a Desactivado. + + Ahora añade una acción \"Cambiar el estado del evento\" para que cuando se + haga clic en el objetivo verde, el Evento del objetivo amarillo se active y los demás se desactiven. Pulsa el + área Acciones. + + Establece los conmutadores: activa el objetivo amarillo y + desactiva todos los demás. Pulsa Siguiente cuando hayas terminado. + + ¡Casi listo! Abre el Evento del objetivo amarillo para + terminar la configuración. + + El objetivo amarillo es el último de la secuencia, así que + también debe empezar desactivado. Cambia su estado inicial a Desactivado. + + Añade también una acción \"Cambiar el estado del evento\" al Evento del + objetivo amarillo. Cuando se haga clic en amarillo, queremos volver al principio: activa el objetivo azul y + desactiva todos los demás. Pulsa el área Acciones. + + Establece los conmutadores: activa el objetivo azul y desactiva + todos los demás. De esta forma, la secuencia se repetirá indefinidamente. Pulsa Siguiente cuando hayas + terminado. + + Todos los Eventos están ahora completamente configurados. + Guarda tu Escenario para aplicar los cambios. + + ¡Todos los Eventos están configurados! Guarda tu Escenario y + luego inicia el juego. Recuerda iniciar tu Escenario antes de lanzar el juego. \n\nComo nuestro escenario tiene + un estado interno, debes reiniciarlo cada vez que reinicies el juego para asegurarte de que no esté esperando el + último objetivo de la sesión anterior. Esto puede automatizarse fácilmente detectando si el botón de inicio es + visible para restablecer los estados de los eventos. + + ¡Ganaste! \n\nAl controlar qué Eventos están activos en cada + momento, el escenario siempre sabe exactamente qué objetivo buscar a continuación, sin fotogramas desperdiciados + comprobando objetivos fuera de secuencia. \n\nAsí es como la acción Alternar evento te permite crear + automatizaciones secuenciales y basadas en estado. + + diff --git a/feature/tutorial/src/main/res/values-fr/strings_categories.xml b/feature/tutorial/src/main/res/values-fr/strings_categories.xml index 53277f03b..c586fcbe5 100644 --- a/feature/tutorial/src/main/res/values-fr/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-fr/strings_categories.xml @@ -1,4 +1,4 @@ - + + Action Pause + Apprenez comment la pause affecte l\'exécution des actions et la détection + Une Action Pause suspend l\'intégralité du scénario + pendant une durée configurée : pendant ce temps, aucune action ne s\'exécute et aucune détection d\'écran + n\'a lieu.\n\nUn cas d\'usage très courant est d\'ajouter une Pause à la fin de votre liste d\'actions. + Lorsque vous cliquez quelque part, l\'application cliquée a besoin de temps pour traiter le clic et afficher + le résultat — et vous souhaitez généralement attendre ce moment avant que Klick\'r ne recommence à analyser + l\'écran.\n\nUne pause entre deux actions est également valide, mais en ajouter une à la fin de la liste est + souvent le besoin le plus important. + + + Action Glissement + Apprenez comment le geste de glissement est effectué + Une Action Glissement effectue un geste de glisser en + ligne droite d\'une position de départ à une position d\'arrivée. Les deux coordonnées sont fixes et définies + lors de la configuration de l\'action.\n\nLa durée du glissement contrôle le temps que met le geste pour + parcourir le trajet : une durée plus courte produit un glissement plus rapide, tandis qu\'une durée plus + longue produit un glissement plus lent et plus contrôlé. + + + Décalage du clic + Apprenez à affiner la position du clic sur une condition détectée + Lorsque vous cliquez sur une condition + détectée, le clic est par défaut appliqué au centre de la zone détectée.\n\nLe décalage du clic vous permet + de déplacer cette position d\'un nombre fixe de pixels le long des axes X et Y, par rapport au centre de la + condition. Cela est utile lorsque l\'élément sur lequel vous souhaitez appuyer est proche — mais pas + exactement — du centre de la zone détectée. + + + Cible du clic + Apprenez à configurer où le clic sera appliqué + Une Action Clic peut cibler deux types de + positions : une position statique toujours identique, ou la position d\'une condition détectée.\n\nChoisissez + votre méthode de ciblage dans le sélecteur de cible du dialogue de configuration de l\'action. + Avec une position statique, le clic se produit + toujours aux mêmes coordonnées exactes, quelle que soit la situation à l\'écran.\n\nGardez à l\'esprit que + ces coordonnées sont sensibles à la rotation de l\'écran : si l\'appareil pivote, le clic peut se retrouver + à une position inattendue ou même en dehors des limites de l\'écran. + Avec une position de condition, le clic est + appliqué au centre d\'une Condition d\'image détectée. Cela permet au clic de suivre la cible où qu\'elle + apparaisse à l\'écran.\n\nLorsque l\'opérateur de l\'événement est ET, toutes les conditions doivent être + remplies, donc chaque Condition d\'image possède une position disponible. Vous pouvez choisir librement + l\'une d\'elles comme cible, et affiner éventuellement avec un décalage. + Lorsque l\'opérateur de l\'événement est OU, + seule la première condition remplie est évaluée, les autres étant ignorées. De ce fait, Klick\'r ne peut pas + savoir à l\'avance quelle condition sera détectée.\n\nEn conséquence, avec l\'opérateur OU, vous ne pouvez + pas choisir une condition spécifique comme cible du clic : le clic sera toujours appliqué sur la première + condition détectée, quelle qu\'elle soit lors de l\'exécution. + + + Ordre des conditions et vitesse + Comment l\'ordre de vos conditions influence la + vitesse de vérification de l\'événement + + L\'ordre des conditions dans la liste a + un impact sur la vitesse de vérification de l\'événement.\n\nAvec l\'opérateur ET, la vérification s\'arrête + dès que la première condition non remplie est trouvée. Mettre en premier les conditions les moins probables + permet à l\'application de sauter les suivantes plus tôt, rendant votre événement plus rapide. + + Avec l\'opérateur OU, la vérification + s\'arrête dès que la première condition remplie est trouvée. Mettre en premier les conditions les plus + probables permet à l\'application de terminer plus tôt, sans vérifier le reste.\n\nDans les deux cas, mettre la + condition la plus importante en haut de la liste est un moyen simple de garder votre scénario rapide. + + + + État des événements + Apprenez à activer et désactiver des événements pendant + l\'exécution d\'un scénario + + Chaque événement de votre scénario (Événements + Écran et Événements Déclencheur) possède un état : il est soit activé, soit + désactivé.\n\nLorsqu\'il est activé, l\'événement s\'exécute normalement et vérifie ses conditions comme + d\'habitude. Lorsqu\'il est désactivé, il est entièrement ignoré, comme s\'il n\'existait pas.\n\nPar défaut, + chaque événement démarre activé. Vous pouvez modifier cela avec le champ État initial dans les + paramètres de l\'événement. + + Pendant l\'exécution d\'un scénario, vous pouvez + modifier l\'état de n\'importe quel événement avec l\'action Changer l\'état d\'un événement. Cette + action permet d\'activer, de désactiver ou de basculer l\'état d\'un ou plusieurs événements.\n\nCela ouvre de + nombreuses possibilités : des événements qui s\'activent les uns après les autres, des événements qui se + désactivent après s\'être déclenchés une fois, ou des groupes d\'événements dont un seul est + actif à la fois. + + Lorsque tous les événements du scénario sont + désactivés, le scénario s\'arrête tout seul. Il n\'y a plus rien à faire, donc Klick\'r s\'arrête + automatiquement.\n\nC\'est une façon simple de terminer un scénario : il suffit que le dernier événement + désactive tous les autres une fois son rôle accompli, et tout s\'arrête par lui-même. + + + + Liste d\'actions + Apprenez comment la liste d\'actions est exécutée + Les actions sont exécutées dans l\'ordre, l\'une après + l\'autre. Vous pouvez modifier l\'ordre d\'une action à l\'aide des boutons << et >>, ou en appuyant + directement sur son numéro d\'index.\n\nEssayez de garder vos listes d\'actions courtes. Un autoclicker classique + n\'effectue qu\'une action par événement — c\'est le modèle à suivre. Si vous vous retrouvez à ajouter beaucoup + d\'actions à un seul événement, c\'est généralement le signe que le travail devrait être réparti sur plusieurs + événements, chacun réagissant à ce qui est réellement affiché à l\'écran. C\'est la philosophie voir-et-agir + de Klick\'r : détecter d\'abord, puis agir. + + + Action Écrire du texte + Apprenez à saisir du texte dans un champ de saisie actif + Avant que l\'action Écrire du texte s\'exécute, le + champ de saisie cible doit déjà être focalisé, comme si vous l\'aviez appuyé pour faire apparaître le clavier. + \n\nPour y parvenir, ajoutez une action Clic sur ce champ avant l\'action Écrire du texte. Si une animation de + transition se produit après le clic, une action Attente entre les deux peut aider à s\'assurer que le champ est + prêt.\n\nL\'action dispose également d\'une option Valider : lorsqu\'elle est activée, elle appuie automatiquement + sur Entrée après la saisie du texte, confirmant ou soumettant la valeur. + Vous pouvez insérer la valeur d\'un compteur dans + le texte à écrire. Appuyez sur le bouton Ajouter un compteur dans la configuration de l\'action pour choisir un + compteur : il insérera le marqueur {nomDuCompteur} à la position actuelle du curseur.\n\nÀ l\'exécution, + chaque marqueur {nomDuCompteur} est remplacé par la valeur actuelle du compteur avant que le texte ne soit + collé dans le champ. Par exemple, si un compteur nommé pommes a la valeur 18, le texte + \"J\'ai {pommes} pommes\" devient \"J\'ai 18 pommes\". + + + Action Système + Apprenez à déclencher des actions de navigation Android + Une Action Système exécute l\'une des actions de + navigation intégrées d\'Android : Retour, Accueil ou Applications récentes.\n\nCe sont les mêmes actions que + les boutons de navigation en bas de votre écran. Elles ne nécessitent aucune coordonnée et fonctionnent au + niveau du système, quelle que soit l\'application actuellement ouverte. + + + Action Modifier le compteur + Apprenez à modifier la valeur d\'un compteur + Une action Modifier le compteur applique une + opération à un compteur à l\'aide d\'une valeur statique prédéfinie. Trois opérations sont disponibles : ajouter + la valeur au compteur (+), la soustraire du compteur (−) ou définir le compteur à cette valeur exacte (=).\n\nC\'est + la façon la plus courante de mettre à jour un compteur — par exemple, ajouter 1 chaque fois qu\'une condition est + détectée, ou le réinitialiser à 0 lorsqu\'un objectif est atteint. + Au lieu d\'une valeur statique, vous pouvez + utiliser la valeur actuelle d\'un autre compteur comme opérande. Les mêmes trois opérations (+, −, =) s\'appliquent, + mais le montant est lu depuis le compteur sélectionné à l\'exécution plutôt qu\'étant fixé lors de la configuration. + \n\nCela vous permet de construire des scénarios dynamiques où les compteurs interagissent entre eux. + + + Action Notification + Apprenez à afficher une notification pendant votre scénario + Une action Notification affiche une notification + Android avec un titre et un message de votre choix.\n\nVous pouvez insérer la valeur actuelle d\'un compteur dans + le texte de la notification à l\'aide du bouton Ajouter un compteur, ou en tapant directement le marqueur + {nomDuCompteur}. À l\'exécution, il est remplacé par la valeur du compteur — par exemple, + \"J\'ai {pommes} pommes\" devient \"J\'ai 18 pommes\". + Le niveau d\'importance de la notification + contrôle le degré d\'intrusion avec lequel elle est présentée. Les niveaux élevés peuvent afficher une bannière + et jouer un son, tandis que les niveaux faibles sont livrés silencieusement dans le tiroir des notifications. + \n\nLe comportement exact dépend de l\'appareil et peut être personnalisé dans les paramètres de notifications + Android de Klick\'r. + + + Action Changer l\'état d\'un événement + Apprenez à activer et désactiver des événements à l\'exécution + Un événement désactivé est complètement ignoré + pendant la boucle du scénario — ses conditions ne sont jamais vérifiées et ses actions ne s\'exécutent jamais. + Il ne consomme donc aucun temps de traitement.\n\nDésactiver les événements que vous n\'utilisez pas est un + excellent moyen d\'améliorer les performances. Par exemple, dans un scénario qui alterne entre une phase menu et + une phase jeu, désactiver tous les événements liés au menu pendant la phase jeu (et vice versa) permet de ne + garder actifs que les événements pertinents à chaque instant. + Lors de la configuration de l\'action, vous + pouvez choisir de modifier l\'état de tous les événements du scénario en une seule fois, ou définir un nouvel + état pour chaque événement individuellement.\n\nTrois changements d\'état sont disponibles pour chaque événement : + l\'activer, le désactiver, ou basculer depuis sa valeur actuelle — un événement activé devient désactivé et un + événement désactivé devient activé. + Si tous les événements du scénario se retrouvent + désactivés en même temps, le scénario s\'arrête automatiquement, car il ne reste rien à exécuter.\n\nCela peut + être utilisé intentionnellement comme moyen propre de terminer un scénario une fois un objectif atteint : une + dernière action Changer l\'état d\'un événement qui désactive tous les événements mettra fin au scénario. + + + Action Intent + Apprenez à communiquer avec d\'autres applications + Les Intents sont la façon dont les applications + communiquent entre elles sur Android. L\'action Intent vous permet d\'utiliser ce système directement depuis + votre scénario.\n\nUn ensemble de modèles prédéfinis est disponible pour faciliter cela. Le plus courant est + Démarrer une application, qui lance une autre application sur votre appareil exactement comme si vous aviez + appuyé sur son icône depuis le lanceur. + L\'onglet Avancé vous permet de définir un Intent brut + manuellement, vous donnant un contrôle total sur l\'action, la catégorie, les données et les extras. Cela n\'est + pas recommandé pour les utilisateurs réguliers — c\'est destiné aux développeurs Android qui savent déjà comment + fonctionnent les Intents.\n\nDavantage de modèles prêts à l\'emploi seront ajoutés dans les futures mises à jour + pour faciliter les cas d\'utilisation courants sans recourir aux options avancées. + + + + Priorité des événements + Apprenez comment l\'ordre des événements dans votre liste influence leur exécution + Chaque image capturée depuis votre écran est traitée en vérifiant vos événements un par un, de haut en bas.\n\nLa position d\'un événement dans votre liste détermine à quel moment il a la chance de s\'exécuter. Par défaut, dès qu\'un événement voit ses conditions remplies et ses actions exécutées, l\'image est considérée comme traitée. Le traitement s\'arrête pour cette image et la suivante repart depuis le premier événement de la liste.\n\nCela signifie qu\'un seul événement peut s\'exécuter par image par défaut. + Vous pouvez modifier ce comportement via le champ Continuer l\'éxécution dans les paramètres de l\'événement. Lorsqu\'il est activé, après l\'exécution de cet événement, le traitement passe à l\'événement suivant dans la liste au lieu de s\'arrêter.\n\nCela permet à plusieurs événements de s\'exécuter sur la même image.\n\nExemple : votre liste contient l\'Événement A suivi de l\'Événement B. Si l\'Événement A est toujours détecté et que Continuer l\'éxécution n\'est pas activé, il s\'exécutera à chaque image et l\'Événement B n\'aura jamais la chance de s\'exécuter.\n\nActivez Continuer l\'éxécution sur l\'Événement A et les deux événements seront vérifiés à chaque image.\n\nUn tutoriel interactif est également disponible pour pratiquer ce concept. + + + + Rechargement d\'un événement + Apprenez comment le rechargement d\'un événement se comporte dans votre scénario + Le paramètre de rechargement d\'événement vous permet + d\'ignorer un événement pendant une durée donnée une fois qu\'il est déclenché. \n\nUn événement en état de + rechargement est toujours considéré comme activé : le rechargement et l\'état de l\'événement sont indépendants. + \n\nSi l\'événement est désactivé pendant son rechargement, le minuteur de rechargement sera effacé, ce qui + signifie que le délai ne s\'applique plus lorsque l\'événement est réactivé. + + + + Utiliser les valeurs de compteur + Découvrez les différentes façons d\'afficher et d\'utiliser les valeurs de compteur dans votre scénario + + Vous pouvez afficher la valeur actuelle d\'un + compteur dans une action Notification. C\'est utile pour surveiller la progression pendant l\'exécution de + votre scénario, ou pour afficher un résumé à la fin.\n\nPour insérer un compteur, appuyez sur le bouton + Ajouter un compteur dans la configuration de l\'action. Cela ajoute un espace réservé comme + {counterName} dans votre texte. À l\'exécution, cet espace réservé est remplacé par la valeur + actuelle du compteur. Par exemple, si un compteur nommé score a la valeur 42, le texte + \"Score actuel : {score}\" devient \"Score actuel : 42\". + + Vous pouvez également insérer la valeur d\'un + compteur dans une action Écrire du texte, afin que le texte saisi inclue la valeur actuelle au moment où + l\'action s\'exécute.\n\nL\'espace réservé fonctionne de la même façon que dans l\'action Notification : + appuyez sur le bouton Ajouter un compteur ou tapez directement {counterName}. Par exemple, si un + compteur nommé score a la valeur 42, le texte \"Mon score est {score}\" devient + \"Mon score est 42\". + + Les valeurs des compteurs sont enregistrées + dans le rapport de débogage. Si quelque chose ne fonctionne pas comme prévu dans votre scénario, capturer + un rapport de débogage vous montrera exactement comment vos compteurs ont évolué, ce qui facilitera la + recherche du problème. + diff --git a/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_not_visible.xml index c6f45020a..64e13b732 100644 --- a/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - Combinez plusieurs conditions - Créez et combinez plusieurs conditions pour votre événement - Cliquez sur le bouton bleu uniquement lorsque le bouton rouge est visible + Visibilité des conditions + Utilisez l\'option Visibilité pour déclencher + un clic quand une cible n\'est pas à l\'écran + Cliquez sur le bouton bleu uniquement + quand le bouton rouge n\'est pas visible + + Nouvelles règles ! La cible bleue ne + bouge plus, mais elle ne doit être cliquée que lorsque la cible rouge n\'est pas visible. + \n\nLancez le jeu et voyez si vous pouvez gagner par vous-même. + + Encore une fois, il semble impossible + de gagner manuellement, alors utilisons Klick\'r. \n\nOuvrez le menu de configuration du scénario, créez un + nouvel Événement Écran et commencez à ajouter des conditions pour les cibles du jeu. + + D\'abord, nous avons besoin d\'une + condition qui vérifie que la cible rouge N\'EST PAS visible à l\'écran. \n\nCréez une nouvelle condition image + et capturez la cible rouge. + + Nous voulons cliquer uniquement quand + la cible rouge n\'est pas visible, donc réglez l\'option « Est visible » sur Non. Ainsi, la condition ne sera + remplie que lorsque la cible rouge est absente de l\'écran. + + Les autres paramètres conviennent à + notre cas — allez-y et enregistrez cette condition. + + Cette condition seule suffit à gagner + le jeu, mais elle se déclencherait aussi quand le jeu n\'est pas en cours, ce qui n\'est pas idéal. + \n\nPour éviter cela, associons-la à une deuxième condition qui vérifie que la cible bleue est visible. + Créez une nouvelle Condition Image et capturez la cible bleue. + + Pour cette condition, nous voulons + vérifier que la cible bleue est visible, donc les paramètres par défaut sont tous corrects. Enregistrez la + condition et revenez à l\'Événement pour continuer. + + Avec plusieurs conditions, l\'opérateur + de condition est important. Nous voulons que l\'événement se déclenche quand la cible bleue est visible ET que + la cible rouge ne l\'est pas, donc l\'opérateur ET est nécessaire ; et c\'est déjà la valeur par défaut, donc + tout va bien. \n\nCréez maintenant une nouvelle action de clic pour continuer. + + Nous voulons cliquer sur la cible + bleue, donc sélectionnez le type de position « Sur condition » et choisissez la condition Image de la cible + bleue. \n\nUne fois terminé, enregistrez le clic, puis votre événement et votre scénario, et revenez au + jeu. + + Démarrez votre scénario et lancez le + jeu pour gagner ! \n\nSi ça ne fonctionne pas, vérifiez que vos conditions sont bien capturées et que la durée + du clic est réglée sur 1 ms. + + Félicitations ! Vous avez appris à + utiliser une condition « Non visible ». Associez-la toujours à au moins une autre condition pour éviter de + déclencher des actions involontairement tout au long de votre scénario. - Changeons à nouveau les règles du jeu. La cible bleue a cessé de bouger, mais elle ne doit être cliquée - que lorsque la cible rouge est visible.\n\nTout d\'abord, lancez le jeu et vérifiez si vous pouvez gagner par vous-même. - - Encore une fois, il semble impossible de gagner manuellement, alors utilisons Smart - AutoClicker.\n\nVotre scénario du tutoriel précédent a été conservé et chargé pour ce tutoriel, mais nous devrons - changer quelques paramètres pour gagner ce nouveau jeu.\n\nCliquez sur l\'icône de configuration du scénario pour - commencer à mettre à jour votre nouveau scénario. - - Nous voulons toujours cliquer sur la cible bleue, mais seulement lorsque la cible rouge est visible.\n - Nous devons donc ajouter une condition pour cette cible rouge dans notre Événement.\n\nCliquez sur l\'Événement que vous avez - précédemment créé pour le modifier. - - Nous allons combiner plusieurs conditions, nous devons donc vérifier l\'opérateur de Condition - pour cet événement.\n\nL\'opérateur de Condition indique comment plusieurs conditions seront interprétées ensemble.\n - \'Un\' signifie qu\'une seule des conditions de cet Événement doit être remplie pour exécuter les actions.\n\n - \'Toutes\' signifie que toutes les conditions de cet Événement doivent être remplies pour exécuter les actions.\n\n - Comme nous voulons détecter si deux choses sont affichées ensemble, nous utiliserons \'Toutes\'. - - Maintenant, nous devons mettre à jour nos Conditions.\n\nCliquez sur le champ "Conditions" pour afficher - la liste des Conditions. - - La Condition précédente de détection de la cible bleue est toujours correcte, mais nous avons besoin - d\'une nouvelle pour la cible rouge.\n\nCliquez sur le bouton de création de Condition pour créer une nouvelle Condition pour celle-ci. - - Tout comme pour la cible bleue, commencez le jeu afin de montrer la cible rouge. Une fois qu\'elle est visible, - prenez une capture d\'écran ! - Utilisez le bouton de capture dans le menu flottant pour prendre la capture d\'écran. - - Votre capture d\'écran contient-elle la cible rouge ? Vous pouvez la recadrer pour obtenir uniquement la - partie intéressante pour la détection, la cible rouge. - Si votre capture d\'écran ne contient pas la cible rouge, vous pouvez appuyer sur ce bouton pour en prendre une nouvelle. - - Votre image de Condition est maintenant enregistrée ! Comme la cible rouge ne bouge pas, nous pouvons - conserver la configuration par défaut.\nCliquez sur le bouton "Enregistrer" pour l\'enregistrer et revenir à la liste des Conditions. - - Fermez la liste des Conditions pour revenir à la configuration de l\'Événement - - Nous avons maintenant deux Conditions, une pour chaque cible, et les Actions ne seront exécutées que si les - deux sont détectées.\n\nCliquez sur le champ "Actions" pour afficher la liste des Actions pour notre Événement. - - L\'action est déjà configurée pour cliquer sur le personnage bleu, et elle ne sera exécutée que lorsque les personnages bleu et rouge sont visibles ensemble.\n\nC\'est exactement le comportement dont nous avons besoin pour battre le - jeu, donc pas besoin de modifier notre Action de clic.\n\nFermez la liste des Actions pour revenir à la configuration de l\'Événement. - - Cliquez sur le bouton "Enregistrer" pour revenir à la configuration du Scénario. - - Toutes les modifications doivent être enregistrées dans votre scénario pour être enregistrées.\n\nCliquez - sur le bouton "Enregistrer" pour enregistrer vos modifications. - - Nous sommes prêts à gagner ce jeu !\n\nCliquez sur le bouton de démarrage pour lancer la - détection, puis démarrez le jeu. - - Félicitations !\n\nVous savez désormais comment combiner plusieurs conditions pour un Événement, mais il y a encore beaucoup à apprendre ! diff --git a/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..1867ada3d --- /dev/null +++ b/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,72 @@ + + + + + + Opérateur de condition ET + Utilisez l\'opérateur ET pour cliquer uniquement + quand plusieurs cibles sont visibles en même temps + Cliquez sur le bouton bleu uniquement quand + les cibles bleue et rouge sont toutes les deux visibles + + Nouvelles règles ! Le jeu affiche maintenant + deux cibles. Cliquez sur la bleue, mais seulement quand les deux cibles bleue et rouge sont à l\'écran en même + temps. \n\nLancez le jeu et voyez si vous arrivez à suivre le rythme par vous-même. + + Le timing est trop serré pour le gérer + manuellement, alors utilisons Klick\'r. \n\nOuvrez le menu de configuration du scénario, créez un nouvel + Événement Écran et commencez à ajouter des conditions pour les cibles du jeu. + + Nous avons besoin d\'une condition par + cible. Commençons par la bleue. \n\nCréez une nouvelle condition image et capturez la cible bleue. + + Nous voulons que cette condition soit + remplie quand la cible bleue est visible, donc les paramètres par défaut sont tous corrects. Enregistrez cette + condition. + + Ajoutons maintenant la deuxième condition + pour la cible rouge. \n\nCréez une autre condition image et capturez la cible rouge. + + Pareil ici — la cible rouge doit être + visible, donc les paramètres par défaut sont corrects. Enregistrez cette condition et revenez à + l\'Événement. + + Avec deux conditions définies, l\'opérateur + de condition détermine comment elles sont combinées. Sélectionnez l\'opérateur à l\'aide du sélecteur + ci-dessus. \n\n• ET : l\'événement se déclenche uniquement quand TOUTES les conditions sont remplies.\n• + OU : l\'événement se déclenche dès qu\'UNE condition est remplie.\n\nPour notre jeu, nous avons besoin des + deux cibles à l\'écran en même temps, donc sélectionnez ET. + Le sélecteur d\'opérateur de + condition + + ET est déjà l\'opérateur par défaut, donc + tout est bon. \n\nOuvrez maintenant la section Actions et créez une nouvelle action de clic. + + Nous voulons cliquer sur la cible bleue, + donc sélectionnez le type de position « Sur condition » et choisissez la condition image de la cible bleue. + \n\nUne fois terminé, enregistrez le clic, puis votre événement et votre scénario, et revenez au jeu. + + Démarrez votre scénario et lancez le jeu + pour gagner ! \n\nSi ça ne fonctionne pas, vérifiez que les deux conditions sont bien capturées et que la + durée du clic est réglée sur 1 ms. + + Félicitations ! Vous avez appris à + utiliser l\'opérateur ET. L\'événement se déclenche désormais uniquement quand toutes ses conditions sont + remplies en même temps. + + diff --git a/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..685e81a59 --- /dev/null +++ b/feature/tutorial/src/main/res/values-fr/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,74 @@ + + + + + + Opérateur de condition OU + Utilisez l\'opérateur OU pour cliquer sur la + première cible qui apparaît à l\'écran + Cliquez sur n\'importe quelle cible dès + qu\'elle apparaît à l\'écran + + Nouveau défi ! Deux cibles peuvent apparaître + à l\'écran. La rouge vaut 2 points et la bleue vaut 1 point, alors cliquez sur celle qui s\'affiche le plus + vite possible. \n\nLancez le jeu et voyez comment vous vous en sortez. + + Trop rapide à gérer manuellement, alors + utilisons Klick\'r. \n\nOuvrez le menu de configuration du scénario, créez un nouvel Événement Écran et + commencez à ajouter des conditions pour les cibles du jeu. + + Nous avons besoin d\'une condition par cible. + Commençons par la bleue. \n\nCréez une nouvelle condition image et capturez la cible bleue. + + Cette condition doit se déclencher quand la + cible bleue est visible, donc les paramètres par défaut sont tous corrects. Enregistrez cette condition. + + Ajoutons maintenant la deuxième condition + pour la cible rouge. \n\nCréez une autre condition image et capturez la cible rouge. + + Pareil ici, la cible rouge doit être visible, + donc les paramètres par défaut sont corrects. Enregistrez cette condition. + + Avec OU, les conditions sont vérifiées dans + l\'ordre et l\'événement se déclenche dès que la première correspond, donc l\'ordre de vos conditions est + important. \n\nLa cible rouge rapporte plus de points, donc nous voulons qu\'elle soit vérifiée en premier. + Utilisez le bouton « pour la déplacer avant la bleue, puis revenez à la boîte de dialogue Événement. + + Réglez maintenant l\'opérateur de condition + sur OU. L\'événement se déclenchera dès que l\'une ou l\'autre cible apparaît. Si les deux sont visibles en + même temps, la condition rouge sera détectée en premier car elle a la priorité la plus haute. + \n\nSélectionnez OU. + + L\'opérateur OU est maintenant défini. Ouvrez + la section Actions et créez une nouvelle action de clic. + + Nous voulons cliquer sur la cible qui a + déclenché l\'événement. Sélectionnez le type de position « Sur condition ». Avec OU, une seule condition peut + être détectée positivement à la fois, donc aucune condition spécifique n\'a besoin d\'être sélectionnée. + Klick\'r cliquera automatiquement à l\'emplacement de la condition qui a correspondu. \n\nUne fois terminé, + enregistrez le clic, puis votre événement et votre scénario, et revenez au jeu. + + Démarrez votre scénario et lancez le jeu + pour gagner ! \n\nSi ça ne fonctionne pas, vérifiez que vos conditions sont bien capturées et que la durée + du clic est réglée sur 1 ms. + + Félicitations ! Vous avez appris à utiliser + l\'opérateur OU et l\'importance de la priorité des conditions. En plaçant la condition rouge en premier, + Klick\'r favorise toujours la cible à plus haute valeur quand les deux sont visibles en même temps. + + diff --git a/feature/tutorial/src/main/res/values-fr/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-fr/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..3ccb946dd --- /dev/null +++ b/feature/tutorial/src/main/res/values-fr/strings_tutorial_counters_basics.xml @@ -0,0 +1,131 @@ + + + + Les bases des compteurs + Apprenez à utiliser l\'action Modifier compteur et la condition + Compteur atteint. + Cliquez 10 fois sur la cible bleue, puis une fois sur la cible + rouge + + Bienvenue dans le tutoriel sur les Compteurs ! + \n\nIci, vous allez automatiser un jeu où vous devez cliquer sur la cible bleue 10 fois, puis sur la cible rouge + une fois pour valider votre décompte et gagner 10 points. Vous pouvez d\'abord essayer le jeu, ou passer + directement à la configuration du scénario. + + Nous allons d\'abord créer un Événement d\'écran qui détecte la + cible bleue et clique dessus. \n\nCliquez sur Créer un événement pour commencer. + + Commençons par ajouter une condition pour détecter la cible + bleue. Cliquez sur le champ Conditions pour ouvrir la liste des conditions et créer cette condition. + \n\nLe tutoriel avancera une fois votre condition créée. + + Bien ! Cliquez maintenant sur le champ Actions pour ajouter + les actions qui s\'exécuteront lorsque la cible bleue est détectée. + + Nous avons d\'abord besoin d\'une action Clic pour appuyer sur + la cible bleue. Cliquez sur le bouton créer pour ajouter une nouvelle action. + + Configurez le clic pour appuyer sur la cible bleue, puis + enregistrez l\'action. \n\nLe tutoriel avancera une fois le clic enregistré. + + Nous devons aussi compter le nombre de fois où nous avons + cliqué sur la cible bleue. Pour cela, nous pouvons utiliser l\'action Modifier compteur, en ajoutant 1 à chaque + clic. \n\nCliquez à nouveau sur le bouton créer pour ajouter une deuxième action. + + Sélectionnez l\'action Modifier compteur pour incrémenter un + compteur à chaque clic sur la cible bleue. + + Nous devons d\'abord choisir quel compteur mettre à jour. + Cliquez sur Sélectionner un compteur pour ouvrir la liste des compteurs. + + La liste est vide pour l\'instant. Cliquez sur le bouton + créer pour créer un nouveau compteur. Donnez-lui un nom (ex. « Clics bleus »), laissez la valeur de départ à 0, + puis enregistrez-le et sélectionnez-le. + + Configurez maintenant comment le compteur évolue à chaque + clic sur la cible bleue. \n\nDéfinissez l\'opérateur sur + et la valeur sur 1, afin que le compteur augmente de + 1 à chaque clic. \n\nEnregistrez ensuite l\'action et revenez au dialogue Événement. + La valeur peut être un nombre fixe, ou la valeur + actuelle d\'un autre compteur. + + Parfait ! Cet Événement d\'écran va maintenant cliquer sur la + cible bleue et incrémenter votre compteur à chaque détection. \n\nEnregistrez l\'événement pour revenir au + scénario. + + Nous avons maintenant besoin d\'un événement qui réagit quand + le compteur atteint 10. Ce type d\'événement n\'est pas déclenché par l\'écran, c\'est donc un Événement de + déclenchement. \n\nCliquez sur l\'onglet Événements de déclenchement pour ouvrir la liste correspondante. + + Cliquez sur le bouton créer pour ajouter un nouvel Événement + de déclenchement. + + Tout comme un Événement d\'écran, un Événement de + déclenchement a besoin de conditions. Cliquez sur le champ Conditions pour ouvrir la liste des conditions et en + créer une nouvelle. + + Sélectionnez le type de condition Compteur atteint pour + déclencher cet événement lorsqu\'un compteur atteint une valeur précise. + + Sélectionnez le compteur que vous avez créé précédemment + (celui qui compte les clics bleus) pour l\'utiliser comme déclencheur. + + Définissez maintenant la comparaison pour que la condition + soit remplie lorsque le compteur est égal à 10. Il existe plusieurs opérateurs de comparaison, mais ici nous + devons vérifier l\'égalité, donc sélectionnez « = ». Entrez ensuite 10 comme valeur, enregistrez la condition + et revenez au dialogue Événement. + La valeur à comparer peut être un nombre fixe, ou + la valeur actuelle d\'un autre compteur. + + La condition est définie ! Nous devons maintenant préciser + ce qui se passe quand le compteur atteint 10. Cliquez sur le champ Actions pour ouvrir la liste des actions. + + Créez d\'abord une action Clic et placez-la manuellement sur + la cible rouge pour valider le décompte. + + Configurez le clic pour appuyer sur la cible rouge, puis + enregistrez l\'action. Notez que dans un Événement de déclenchement, la position du clic doit toujours être + définie manuellement. \n\nLe tutoriel avancera une fois le clic enregistré. + + Créez maintenant une deuxième action pour remettre le + compteur à zéro. Cliquez à nouveau sur le bouton créer et sélectionnez l\'action Modifier compteur. + + Nous voulons remettre le compteur de clics bleus à 0, donc + commencez par sélectionner ce compteur. + + Définissez l\'opérateur sur = et la valeur sur 0 pour + remettre le compteur à zéro après chaque validation. Enregistrez ensuite l\'action et revenez au dialogue + Événement pour continuer. + + Cet Événement de déclenchement va cliquer sur la cible rouge + et remettre le compteur à zéro chaque fois que 10 clics bleus sont comptés. La liste des Événements de + déclenchement est traitée entre chaque image d\'écran, avant la liste des Événements d\'écran ; ainsi, dès que + le compteur atteint 10, cet événement s\'exécute immédiatement : la cible rouge est cliquée et le compteur + remis à zéro, prêt à repartir. \n\nEnregistrez l\'événement pour revenir au scénario. + + Le scénario est complet ! Il va cliquer sur la cible bleue, + compter chaque clic, puis valider sur la cible rouge tous les 10 clics et recommencer. \n\nEnregistrez le + scénario pour appliquer votre configuration. + + Tout est prêt ! Démarrez le scénario, puis lancez le jeu et + regardez Klick\'r gérer le décompte à votre place. + + Bravo ! Vous avez appris à utiliser les Compteurs pour + suivre des valeurs à travers plusieurs événements. \n\nAssociés à l\'action Modifier compteur et à la condition + Compteur atteint, vous pouvez désormais créer des automatisations qui réagissent à des schémas répétitifs. + + diff --git a/feature/tutorial/src/main/res/values-fr/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-fr/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..7dd379733 --- /dev/null +++ b/feature/tutorial/src/main/res/values-fr/strings_tutorial_events_priority.xml @@ -0,0 +1,73 @@ + + + + + Prioriser un événement + Prioriser un Événement par rapport à un autre + Cliquez le plus vite possible sur les cibles. Bleu = 1 point ; + Rouge = 10 points + + Nouveau jeu ! Nous devons cliquer sur les cibles le plus vite + possible, mais la rouge rapporte plus de points. Vous pouvez tester le jeu d\'abord ou ouvrir le menu de + configuration du scénario pour commencer à automatiser ce jeu. + + Nous voulons détecter deux cibles différentes, la bleue et la + rouge. Pour ce tutoriel, nous allons créer deux événements distincts : un premier pour la cible bleue et un + second pour la cible rouge. \n\nCommencez par créer l\'Événement pour la cible bleue ; il doit cliquer dessus + quand elle est détectée. N\'oubliez pas d\'utiliser les fonctions de test pour vous assurer que votre condition + est bien détectée. \n\nLe tutoriel avancera une fois votre Événement de cible bleue enregistré. + + Super ! Maintenant, nous avons besoin de la même chose, mais + pour la cible rouge. Cliquez sur le bouton Créer un événement et créez-en un pour la cible rouge ; il doit + cliquer dessus quand elle est détectée. \n\nLe tutoriel avancera une fois votre Événement de cible rouge + enregistré. + + Notre liste contient maintenant deux événements, un pour + chaque cible. Enregistrez votre Scénario et testez-le sur le jeu. + + Quelque chose ne va pas. Le scénario ne clique que sur la + cible bleue, ignorant complètement la rouge, ce qui nous empêche de gagner. \n\nPourquoi ? Parce que + l\'événement bleu est avant le rouge, et comme il est toujours déclenché, l\'image courante n\'est pas évaluée + plus loin et la suivante repart depuis le début de la liste d\'Événements. \n\nIl existe plusieurs façons de + corriger cela. Ouvrez la boîte de dialogue de configuration du scénario pour apprendre comment. + + Nous pouvons résoudre le problème de deux façons : \n\nNous + pouvons modifier l\'option « Continuer l\'exécution » de l\'événement de la cible bleue pour continuer à + traiter la même image et exécuter également l\'événement rouge. Cela déclenchera les deux clics quand les deux + cibles sont visibles en même temps. \n\nOu nous pouvons déplacer l\'événement de la cible rouge en haut de la + liste, afin qu\'il soit vérifié en premier et toujours cliqué quand il est visible, mais la cible bleue ne sera + plus cliquée quand la rouge est aussi affichée. \n\nLa différence clé entre les deux solutions est la vitesse : + placer l\'événement rouge en premier signifie que nous réagissons le plus rapidement possible quand il apparaît, + tout en étant légèrement plus lent quand seule la cible bleue est visible. + + Comme le jeu donne 10 points pour la cible rouge, nous + voulons réagir le plus vite possible quand elle apparaît en déplaçant l\'événement rouge en haut de la liste. + \n\nDéplacez l\'événement rouge en premier et enregistrez le scénario. Vous devriez pouvoir gagner + maintenant. + Vous pouvez réorganiser les Événements en appuyant + longuement sur cette icône et en faisant glisser l\'événement à la bonne place. + + Comme d\'habitude, démarrez d\'abord votre scénario, puis + lancez le jeu. \n\nSi vous ne parvenez toujours pas à gagner, vérifiez que chaque événement fonctionne + individuellement à l\'aide des fonctions de test. + + Super ! Vous comprenez maintenant comment fonctionne la + priorité des événements et comment se comporte la boucle d\'Événements Écran. C\'est la clé pour créer et + gérer des scénarios complexes. + + diff --git a/feature/tutorial/src/main/res/values-fr/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-fr/strings_tutorial_events_state.xml new file mode 100644 index 000000000..61cc9fb13 --- /dev/null +++ b/feature/tutorial/src/main/res/values-fr/strings_tutorial_events_state.xml @@ -0,0 +1,153 @@ + + + + + Désactiver les événements inutilisés + Modifiez l\'état de plusieurs événements pour optimiser un scénario complexe. + Cliquez sur les cibles dans l\'ordre : bleu, rouge, vert puis jaune. + + Nouveau jeu ! Cette fois, vous devez cliquer sur quatre cibles + colorées dans l\'ordre : bleu en premier, puis rouge, puis vert, et enfin jaune. \n\nVous pouvez d\'abord tester + le jeu pour voir comment il fonctionne, ou ouvrir directement la configuration du scénario pour commencer à + l\'automatiser. + + Nous devons détecter quatre cibles différentes, une par couleur. + Nous allons créer un Événement par cible. \n\nCommencez par la cible bleue : créez un nouvel Événement qui la + détecte dans la zone de jeu et clique dessus. + + Lorsqu\'on utilise plusieurs événements, il est important de + personnaliser leur nom pour s\'y retrouver. Donnez à cet Événement un nom clair, comme « Cible bleue », pour + l\'identifier facilement dans votre scénario. \n\nUne fois terminé, créez une nouvelle condition Image et + capturez la cible bleue. + + La cible étant en mouvement, nous devons définir le type de + détection sur « Zone de détection » puis sélectionner la zone de jeu. \n\nUne fois la zone correctement configurée, + enregistrez-la et revenez au dialogue Événement. + + Votre condition est définie. Nous avons maintenant besoin d\'une + action Clic pour que l\'Événement clique sur la cible détectée. \n\nCréez une nouvelle action Clic pour + continuer. + + La cible est en mouvement, nous ne pouvons donc pas définir une + position fixe. Définissez le champ « Cliquer sur » sur « Cliquer sur la condition détectée » et sélectionnez votre condition de cible bleue. + Ainsi, le clic atterrira toujours exactement là où la cible a été trouvée.\n\nUne fois la condition + sélectionnée, enregistrez le clic et revenez au dialogue Événement. + + L\'Événement pour la cible bleue est prêt ! Créez maintenant un + Événement pour la cible rouge de la même façon : détectez-la dans la zone de jeu et cliquez dessus. Le tutoriel + avancera une fois votre Événement de cible rouge enregistré. + + Super ! Créez maintenant le même Événement pour la cible verte. + Le tutoriel avancera une fois votre Événement de cible verte enregistré. + + Presque fini ! Créez un dernier Événement pour la cible jaune. + Le tutoriel avancera une fois votre Événement de cible jaune enregistré. + + Les quatre Événements sont prêts. Comme nous les avons définis + dans l\'ordre de la séquence du jeu, leur priorité est correcte. \n\nEnregistrez votre Scénario et testez-le + sur le jeu pour voir ses performances. + + Le scénario détecte et clique sur les cibles, mais c\'est + probablement trop lent pour gagner. \n\nActuellement, les quatre Événements sont actifs en même temps, donc à + chaque image le scénario vérifie bleu, puis rouge, puis vert, puis jaune ; peu importe quelle cible vient d\'être + cliquée. Cela fait perdre un temps précieux ! \n\nOuvrez la configuration du scénario pour apprendre comment + améliorer cela. + + Chaque Événement a un état initial : il peut démarrer activé ou + désactivé. Actuellement, les quatre Événements sont activés, donc tous sont vérifiés à chaque image. \n\nLa + solution est de ne garder actif que l\'Événement de la cible actuelle et de désactiver les autres. Quand une + cible est cliquée, son Événement activera la suivante et désactivera les autres. \n\nCommençons par éditer + l\'Événement de la cible bleue. + + La cible bleue est la première à cliquer, donc son Événement + doit démarrer activé ; pas de changement ici. \n\nNous devons simplement ajouter une action « Etat + d\'événement » pour que, quand la cible bleue est cliquée, l\'Événement de la cible rouge soit activé et les + autres désactivés. Appuyez sur la zone Actions pour ajouter cette action. + + Sélectionnez le type d\'action « État d\'évènement ». + + Cette action vous permet de modifier l\'état de n\'importe quel + Événement de votre scénario lorsque cet Événement est déclenché. Appuyez sur le champ « Aucun changement » pour + choisir quels Événements modifier. + + Pour chaque Événement de la liste, vous pouvez définir l\'un + des trois états : \n• Activer : l\'Événement devient actif et sera vérifié à chaque image \n• Désactiver : + l\'Événement devient inactif et est entièrement ignoré \n• Inverser : alterne entre actif et inactif à chaque + fois \n\nPuisque bleu vient d\'être cliqué, activez l\'Événement de la cible rouge et désactivez tous les + autres. Appuyez sur Suivant quand vous avez terminé. + Chaque ligne d\'Événement affiche trois options : + Activer, Désactiver et Basculer. Appuyez sur celle que vous souhaitez appliquer lors de l\'exécution de cette + action. + + Parfait ! Enregistrez l\'Événement de la cible bleue. + + Ouvrez maintenant l\'Événement de la cible rouge dans la liste + pour le configurer de la même façon. + + Contrairement à l\'Événement de la cible bleue, cet Événement + ne doit pas être actif au démarrage du scénario, car sa cible n\'est pas la première. Changez son état initial + sur Désactivé. + + Ajoutez maintenant une action « État d\'évènement » pour + que, quand cette cible est cliquée, l\'Événement de la prochaine cible soit activé et les autres désactivés. + Appuyez sur la zone Actions. + + Définissez les changements : activez la cible verte et désactivez + toutes les autres. Appuyez sur Suivant quand vous avez terminé. + + Bien joué ! Ouvrez maintenant l\'Événement de la cible verte + pour le configurer de la même façon. + + La cible verte ne doit pas non plus être active au démarrage. + Changez son état initial sur Désactivé. + + Ajoutez maintenant une action « État d\'évènement » pour + que, quand la cible verte est cliquée, l\'Événement de la cible jaune soit activé et les autres désactivés. + Appuyez sur la zone Actions. + + Définissez les changements : activez la cible jaune et désactivez + toutes les autres. Appuyez sur Suivant quand vous avez terminé. + + Presque fini ! Ouvrez l\'Événement de la cible jaune pour + terminer la configuration. + + La cible jaune est la dernière de la séquence, donc elle doit + aussi démarrer désactivée. Changez son état initial sur Désactivé. + + Ajoutez également une action « État d\'évènement » à + l\'Événement de la cible jaune. Quand jaune est cliqué, nous voulons revenir au début : activez la cible bleue + et désactivez toutes les autres. Appuyez sur la zone Actions. + + Définissez les changements : activez la cible bleue et désactivez + toutes les autres. Ainsi, la séquence bouclera indéfiniment. Appuyez sur Suivant quand vous avez terminé. + + Tous les Événements sont maintenant entièrement configurés. + Enregistrez votre Scénario pour appliquer les modifications. + + Tous les Événements sont configurés ! Enregistrez votre + Scénario puis lancez le jeu. N\'oubliez pas de démarrer votre Scénario avant de lancer le jeu. \n\nComme notre + scénario a un état interne, vous devez le redémarrer à chaque fois que vous recommencez le jeu pour éviter + qu\'il attende la dernière cible de la session précédente. Cela peut facilement être automatisé en détectant si + le bouton de démarrage est visible pour réinitialiser les états des événements. + + Vous avez gagné ! \n\nEn contrôlant quels Événements sont + actifs à tout moment, le scénario sait toujours exactement quelle cible chercher ensuite — aucune image + gaspillée à vérifier des cibles hors séquence. \n\nC\'est ainsi que l\'action Etat d\'événement vous permet + de créer une automatisation séquentielle et pilotée par état. + + diff --git a/feature/tutorial/src/main/res/values-it/strings_categories.xml b/feature/tutorial/src/main/res/values-it/strings_categories.xml index 7b3008774..fa17eacf6 100644 --- a/feature/tutorial/src/main/res/values-it/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-it/strings_categories.xml @@ -1,4 +1,4 @@ - + + Azione Pausa + Scopri come la pausa influisce sull\'esecuzione delle azioni e sul rilevamento + Un\'Azione Pausa sospende l\'intero scenario per una + durata configurata: durante quel tempo non viene eseguita nessuna azione e non avviene nessun rilevamento + dello schermo.\n\nUn caso d\'uso molto comune è aggiungere una Pausa alla fine della lista delle azioni. + Quando si tocca qualcosa, l\'app toccata ha bisogno di tempo per elaborare il tocco e mostrare il risultato + — e di solito si vuole aspettare quel momento prima che Klick\'r riprenda ad analizzare lo schermo.\n\nUna + pausa tra due azioni è ugualmente valida, ma aggiungerne una alla fine della lista è spesso la necessità più + importante. + + + Azione Scorrimento + Scopri come viene eseguito il gesto di scorrimento + Un\'Azione Scorrimento esegue un gesto di trascinamento + in linea retta da una posizione iniziale a una finale. Entrambe le coordinate sono fisse e impostate nella + configurazione.\n\nLa durata controlla quanto tempo impiega il gesto dall\'inizio alla fine: una durata + minore produce uno scorrimento più rapido, mentre una maggiore produce uno scorrimento più lento e + controllato. + + + Offset del clic + Scopri come affinare la posizione del clic su una condizione rilevata + Quando si fa clic su una condizione rilevata, + il clic viene applicato per impostazione predefinita al centro dell\'area rilevata.\n\nL\'offset del clic + consente di spostare quella posizione di un numero fisso di pixel lungo gli assi X e Y, relativo al centro + della condizione. È utile quando l\'elemento da toccare è vicino — ma non esattamente — al centro dell\'area + rilevata. + + + Obiettivo del clic + Scopri come configurare dove verrà applicato il clic + Un\'Azione Clic può mirare a due tipi di + posizioni: una posizione statica sempre identica, o la posizione di una condizione rilevata.\n\nScegli il + metodo di mira nel selettore di obiettivo nel dialogo di configurazione dell\'azione. + Con una posizione statica, il clic avviene + sempre alle stesse coordinate esatte, indipendentemente da cosa c\'è sullo schermo.\n\nTieni presente che + quelle coordinate sono sensibili alla rotazione: se il dispositivo ruota, il clic potrebbe finire in una + posizione inaspettata o persino fuori dai bordi dello schermo. + Con una posizione di condizione, il clic viene + applicato al centro di una Condizione immagine rilevata, seguendo il bersaglio ovunque appaia sullo + schermo.\n\nCon l\'operatore AND, tutte le condizioni devono essere soddisfatte, quindi ogni Condizione + immagine ha una posizione disponibile. Puoi scegliere liberamente quale usare e affinarla con un offset. + Con l\'operatore OR, viene valutata solo la + prima condizione soddisfatta e le altre vengono ignorate. Pertanto Klick\'r non può sapere in anticipo quale + condizione sarà rilevata.\n\nDi conseguenza, con l\'operatore OR non puoi scegliere una condizione specifica + come obiettivo: il clic verrà sempre applicato sulla prima condizione rilevata, qualunque essa sia a runtime. + + + Ordine delle condizioni e velocità + Come l\'ordine delle condizioni influenza la + velocità di controllo dell\'evento + + L\'ordine delle condizioni nell\'elenco + influisce sulla velocità di controllo dell\'evento.\n\nCon l\'operatore E, il controllo si interrompe non + appena viene trovata la prima condizione NON soddisfatta. Mettere prima le condizioni meno probabili permette + all\'app di saltare le successive prima, rendendo il tuo evento più veloce. + + Con l\'operatore O, il controllo si + interrompe non appena viene trovata la prima condizione soddisfatta. Mettere prima le condizioni più probabili + permette all\'app di terminare prima, senza controllare il resto.\n\nIn entrambi i casi, mettere la condizione + più importante in cima alla lista è un modo semplice per mantenere veloce il tuo scenario. + + + + Stato degli eventi + Impara ad abilitare e disabilitare gli eventi mentre uno + scenario è in esecuzione + + Ogni evento del tuo scenario (Eventi Schermo ed + Eventi Trigger) ha uno stato: è abilitato o disabilitato.\n\nQuando è abilitato, l\'evento viene + eseguito normalmente e controlla le sue condizioni come al solito. Quando è disabilitato, viene completamente + ignorato, come se non esistesse.\n\nPer impostazione predefinita, ogni evento inizia abilitato. Puoi cambiarlo + tramite il campo Stato iniziale nelle impostazioni dell\'evento. + + Mentre uno scenario è in esecuzione, puoi + modificare lo stato di qualsiasi evento con l\'azione Cambia stato evento. Questa azione ti consente di + abilitare, disabilitare o alternare lo stato di uno o più eventi.\n\nQuesto apre molte possibilità: eventi che + si attivano uno dopo l\'altro, eventi che si disabilitano da soli dopo essere stati eseguiti una volta, o + gruppi di eventi in cui solo uno è attivo alla volta. + + Quando tutti gli eventi dello scenario sono + disabilitati, lo scenario si ferma da solo. Non c\'è più nulla da fare, quindi Klick\'r si ferma + automaticamente.\n\nÈ un modo semplice per terminare uno scenario: fai in modo che l\'ultimo evento disabiliti + tutti gli altri una volta completato il suo compito, e tutto si ferma da solo. + + + + Lista azioni + Scopri come viene eseguita la lista delle azioni + Le azioni vengono eseguite in ordine, una dopo l\'altra. + Puoi cambiare l\'ordine di un\'azione usando i pulsanti << e >>, o toccando direttamente il suo + numero di indice.\n\nCerca di mantenere le liste di azioni brevi. Un autoclicker normale esegue un\'azione per + evento — questo è il modello da seguire. Se ti trovi ad aggiungere molte azioni a un singolo evento, è + generalmente un segnale che il lavoro dovrebbe essere suddiviso in più eventi, ciascuno che reagisce a ciò che + è effettivamente sullo schermo. Questa è la filosofia vedi-e-agisci di Klick\'r: rileva prima, poi agisci. + + + Azione Scrivi testo + Scopri come inserire testo in un campo di input attivo + Prima che l\'azione Scrivi testo venga eseguita, + il campo di input target deve essere già focalizzato, proprio come lo toccheresti per far apparire la tastiera. + \n\nPer farlo, aggiungi un\'azione Clic su quel campo prima dell\'azione Scrivi testo. Se dopo il clic viene + riprodotta un\'animazione di transizione, un\'azione Attendi tra le due può aiutare a garantire che il campo + sia pronto.\n\nL\'azione dispone anche di un\'opzione Valida: quando abilitata, preme automaticamente Invio + dopo l\'impostazione del testo, confermando o inviando il valore. + Puoi inserire il valore di un contatore nel testo + da scrivere. Premi il pulsante Aggiungi contatore nella configurazione dell\'azione per selezionare un contatore: + inserirà il segnaposto {nomeContatore} nella posizione corrente del cursore.\n\nA runtime, ogni segnaposto + {nomeContatore} viene sostituito dal valore attuale del contatore prima che il testo venga incollato nel + campo. Ad esempio, se un contatore chiamato mele ha il valore 18, il testo \"Ho {mele} mele\" diventa + \"Ho 18 mele\". + + + Azione di sistema + Scopri come attivare le azioni di navigazione di Android + Un\'Azione di sistema esegue una delle azioni di + navigazione integrate di Android: Indietro, Home o App recenti.\n\nSono le stesse azioni dei pulsanti di + navigazione in fondo allo schermo. Non richiedono coordinate e funzionano a livello di sistema, indipendentemente + dall\'app attualmente aperta. + + + Azione Modifica contatore + Scopri come modificare il valore di un contatore + Un\'azione Modifica contatore applica + un\'operazione a un contatore usando un valore statico predefinito. Sono disponibili tre operazioni: aggiungere + il valore al contatore (+), sottrarlo dal contatore (−) o impostare il contatore a quel valore esatto (=). + \n\nQuesto è il modo più comune per aggiornare un contatore — ad esempio, aggiungere 1 ogni volta che una + condizione viene rilevata, o azzerarlo quando un obiettivo è raggiunto. + Invece di un valore statico, puoi usare il + valore attuale di un altro contatore come operando. Le stesse tre operazioni (+, −, =) si applicano, ma + l\'importo viene letto dal contatore selezionato a runtime anziché essere fisso alla configurazione.\n\nQuesto + ti permette di costruire scenari dinamici in cui i contatori interagiscono tra loro. + + + Azione Notifica + Scopri come visualizzare una notifica durante il tuo scenario + Un\'azione Notifica visualizza una notifica + Android con un titolo e un messaggio a tua scelta.\n\nPuoi inserire il valore attuale di un contatore nel testo + della notifica usando il pulsante Aggiungi contatore, o digitando direttamente il segnaposto + {nomeContatore}. A runtime viene sostituito dal valore del contatore — ad esempio, \"Ho {mele} mele\" + diventa \"Ho 18 mele\". + Il livello di importanza della notifica + controlla quanto intrusivamente viene presentata. I livelli più alti possono mostrare un banner e riprodurre + un suono, mentre quelli più bassi vengono consegnati silenziosamente nel cassetto delle notifiche.\n\nIl + comportamento esatto dipende dal dispositivo e può essere personalizzato nelle impostazioni di notifica Android + per Klick\'r. + + + Azione Cambia stato evento + Scopri come abilitare e disabilitare eventi a runtime + Un evento disabilitato viene completamente + saltato durante il ciclo dello scenario — le sue condizioni non vengono mai verificate e le sue azioni non + vengono mai eseguite. Ciò significa che non consuma alcun tempo di elaborazione.\n\nDisabilitare gli eventi che + non stai usando è un ottimo modo per migliorare le prestazioni. Ad esempio, in uno scenario che alterna tra una + fase menu e una fase gioco, disabilitare tutti gli eventi del menu durante la fase gioco (e viceversa) mantiene + attivi solo gli eventi rilevanti in un dato momento. + Durante la configurazione dell\'azione, puoi + scegliere di cambiare lo stato di tutti gli eventi dello scenario in una volta, o definire un nuovo stato per + ogni evento individualmente.\n\nSono disponibili tre cambiamenti di stato per ogni evento: abilitarlo, + disabilitarlo o alternarlo dal suo valore attuale — un evento abilitato diventa disabilitato e uno disabilitato + diventa abilitato. + Se tutti gli eventi dello scenario risultano + disabilitati contemporaneamente, lo scenario si interrompe automaticamente, poiché non c\'è più nulla da + eseguire.\n\nQuesto può essere usato intenzionalmente come modo pulito per terminare uno scenario una volta + raggiunto un obiettivo: un\'ultima azione Cambia stato evento che disabilita tutti gli eventi fermerà lo + scenario. + + + Azione Intent + Scopri come comunicare con altre applicazioni + Gli Intent sono il modo in cui le applicazioni + comunicano tra loro su Android. L\'azione Intent ti permette di sfruttare questo sistema direttamente dal + tuo scenario.\n\nÈ disponibile un set di modelli predefiniti per semplificare questa operazione. Il più comune + è Avvia applicazione, che lancia un\'altra app sul tuo dispositivo esattamente come se avessi toccato la sua + icona dal launcher. + La scheda Avanzate ti permette di definire manualmente + un Intent grezzo, dandoti pieno controllo sull\'azione, la categoria, i dati e gli extra. Non è consigliato + per gli utenti normali — è rivolto agli sviluppatori Android che sanno già come funzionano gli Intent.\n\nAltri + modelli pronti all\'uso saranno aggiunti nei futuri aggiornamenti per rendere più semplici i casi d\'uso comuni + senza dover ricorrere alle opzioni avanzate. + + + + Priorità degli eventi + Scopri come l\'ordine degli eventi nella tua lista influisce su quali vengono eseguiti + Ogni fotogramma catturato dal tuo schermo viene elaborato verificando gli eventi uno per uno, dall\'alto verso il basso.\n\nLa posizione di un evento nella lista determina quando ottiene la possibilità di essere eseguito. Per impostazione predefinita, non appena le condizioni di un evento sono soddisfatte e le sue azioni vengono eseguite, il fotogramma è considerato completo. L\'elaborazione si ferma per quel fotogramma e il successivo riparte dal primo evento della lista.\n\nQuesto significa che per impostazione predefinita un solo evento può essere eseguito per fotogramma. + Puoi modificare questo comportamento usando il campo Continuare a eseguire nelle impostazioni dell\'evento. Quando è abilitato, dopo l\'esecuzione di quell\'evento, l\'elaborazione continua con l\'evento successivo nella lista invece di fermarsi.\n\nQuesto permette a più eventi di essere eseguiti sullo stesso fotogramma.\n\nEsempio: la tua lista contiene l\'Evento A seguito dall\'Evento B. Se l\'Evento A continua ad essere rilevato e non ha Continuare a eseguire abilitato, verrà eseguito ogni fotogramma e l\'Evento B non avrà mai la possibilità di eseguirsi.\n\nAbilita Continuare a eseguire sull\'Evento A e entrambi gli eventi verranno controllati ogni fotogramma.\n\nÈ disponibile anche un tutorial interattivo per praticare questo concetto. + + + + Ricarica dell\'evento + Scopri come si comporta il ricaricamento di un evento nel tuo scenario + Il parametro di ricarica dell\'evento ti consente di + saltare un evento per un determinato periodo di tempo una volta che è soddisfatto. \n\nUn evento in stato di + ricarica è ancora considerato abilitato: il ricaricamento e lo stato dell\'evento sono indipendenti. \n\nSe + l\'evento viene disabilitato mentre è in fase di ricarica, il timer di ricarica verrà azzerato, quindi il tempo + di attesa non si applica più quando l\'evento viene riabilitato. + + + + Usare i valori dei contatori + Scopri i diversi modi per visualizzare e usare i valori dei contatori nel tuo scenario + + Puoi mostrare il valore attuale di un + contatore all\'interno di un\'azione Notifica. Questo è utile per monitorare i progressi mentre il tuo + scenario è in esecuzione, o per visualizzare un riepilogo alla fine.\n\nPer inserire un contatore, premi + il pulsante Aggiungi contatore nella configurazione dell\'azione. Questo aggiunge un segnaposto come + {counterName} nel tuo testo. In fase di esecuzione, il segnaposto viene sostituito con il valore + attuale del contatore. Ad esempio, se un contatore chiamato score ha il valore 42, il testo + \"Punteggio attuale: {score}\" diventa \"Punteggio attuale: 42\". + + Puoi anche inserire il valore di un contatore + in un\'azione Scrivi testo, in modo che il testo digitato includa il valore attuale nel momento in cui + l\'azione viene eseguita.\n\nIl segnaposto funziona allo stesso modo dell\'azione Notifica: premi il pulsante + Aggiungi contatore o digita {counterName} direttamente. Ad esempio, se un contatore chiamato + score ha il valore 42, il testo \"Il mio punteggio è {score}\" diventa + \"Il mio punteggio è 42\". + + I valori dei contatori vengono registrati nel + rapporto di debug. Se qualcosa non funziona come previsto nel tuo scenario, catturare un rapporto di debug + ti mostrerà esattamente come sono cambiati i tuoi contatori nel tempo, rendendo più facile trovare il + problema. + diff --git a/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_not_visible.xml index 4c568ce5b..cb8e6ef80 100644 --- a/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - Combina condizioni multiple - Crea e combina condizioni multiple per il tuo evento - Clicca sul pulsante blu solo quando il pulsante rosso è visibile + Visibilità delle condizioni + Usa l\'opzione Visibilità per attivare un + clic quando un obiettivo non è sullo schermo + Tocca il pulsante blu solo quando il + pulsante rosso non è visibile - Cambiamo di nuovo le regole del gioco. Il bersaglio blu ha smesso di muoversi, - ma ora dovrebbe essere cliccato solo quando il bersaglio rosso è visibile.\n\nInizia il gioco e verifica se puoi vincere - da solo. + Nuove regole! L\'obiettivo blu ha + smesso di muoversi, ma deve essere toccato solo quando l\'obiettivo rosso non è visibile. + \n\nAvvia il gioco e vedi se riesci a vincere da solo. - Ancora una volta, sembra impossibile vincere manualmente, quindi utilizziamo Smart - AutoClicker.\n\nIl tuo scenario per il tutorial precedente è stato conservato e caricato per questo tutorial, ma dovremo - apportare alcune modifiche per vincere questo nuovo gioco.\n\nFai clic sull\'icona di configurazione dello scenario per - iniziare a aggiornare il tuo nuovo scenario. + Ancora una volta, sembra impossibile + vincere manualmente, quindi usiamo Klick\'r. \n\nApri il menu di configurazione dello scenario, crea un nuovo + Evento Schermo e inizia ad aggiungere condizioni per gli obiettivi del gioco. - Vogliamo ancora cliccare sul bersaglio blu, ma solo quando è visibile il rosso.\n - Quindi dobbiamo aggiungere una condizione per questo bersaglio rosso nel nostro evento.\n\nFai clic sull\'evento creato - in precedenza per modificarlo. + Prima di tutto, abbiamo bisogno di una + condizione che verifichi quando l\'obiettivo rosso NON è visibile sullo schermo. \n\nCrea una nuova condizione + immagine e acquisisci l\'obiettivo rosso. - Combineremo diverse condizioni, quindi dobbiamo verificare l\'operatore di condizione - per questo evento.\n\nL\'operatore di condizione indica come verranno interpretate insieme più condizioni.\n - "Uno" significa che solo una delle condizioni per questo evento deve essere soddisfatta per - eseguire le azioni.\n\n"Tutte" significa che tutte le condizioni per questo evento devono essere soddisfatte per eseguire - le azioni. \n\nPoiché vogliamo rilevare se due cose sono visualizzate insieme, useremo "Tutte". + Vogliamo toccare solo quando l\'obiettivo + rosso non è visibile, quindi imposta l\'opzione «È visibile» su No. In questo modo la condizione sarà soddisfatta + solo quando l\'obiettivo rosso è assente dallo schermo. - Ora dobbiamo aggiornare le nostre condizioni.\n\nFai clic sulla campo Condizioni per - visualizzare l\'elenco delle condizioni. + Le altre impostazioni vanno bene per il + nostro caso — vai avanti e salva questa condizione. - La condizione precedente che rileva il bersaglio blu è ancora corretta, ma ne abbiamo bisogno - di una nuova per il bersaglio rosso.\n\nFai clic sul pulsante Crea condizione per creare una nuova condizione per esso. + Questa condizione da sola è sufficiente + per vincere il gioco, ma si attiverebbe anche quando il gioco non è in esecuzione, il che non è l\'ideale. + \n\nPer evitarlo, combiniamola con una seconda condizione che verifichi se l\'obiettivo blu è visibile. + Crea una nuova Condizione Immagine e acquisisci l\'obiettivo blu. - Come per il bersaglio blu, avvia il gioco per mostrare il bersaglio rosso. - Una volta che è visibile, scatta uno screenshot di esso! - Utilizza il pulsante di acquisizione nel menu a comparsa per scattare lo screenshot. + Per questa condizione vogliamo + verificare che l\'obiettivo blu sia visibile, quindi le impostazioni predefinite sono tutte corrette. Salva la + condizione e torna all\'Evento per continuare. - Il tuo screenshot contiene il bersaglio rosso? Puoi ritagliarlo in modo da ottenere solo - la parte interessante per il rilevamento, ovvero il bersaglio rosso. - Se il tuo screenshot non contiene il bersaglio rosso, puoi premere questo pulsante per scattarne uno nuovo. + Con più condizioni, l\'operatore di + condizione è importante. Vogliamo che l\'evento si attivi quando l\'obiettivo blu è visibile E quello rosso non + lo è, quindi abbiamo bisogno dell\'operatore E; ed è già il valore predefinito, quindi siamo a posto. + \n\nOra crea una nuova azione di clic per continuare. - La tua immagine di condizione è ora registrata!\n\nPoiché il bersaglio rosso non si sta muovendo, - possiamo mantenere la configurazione predefinita.\nFare clic sul pulsante Salva per registrarlo e tornare all\'elenco delle condizioni. + Vogliamo toccare l\'obiettivo blu, + quindi seleziona il tipo di posizione «Su condizione» e scegli la Condizione Immagine dell\'obiettivo blu. + \n\nQuando hai finito, salva il clic, poi il tuo evento e scenario, e torna al gioco. - Chiudere l\'elenco delle condizioni per tornare alla configurazione degli eventi. + Avvia il tuo scenario e lancia il + gioco per vincere! \n\nSe non funziona, verifica che le tue condizioni siano acquisite correttamente e che la + durata del clic sia impostata su 1 ms. - Ora abbiamo due condizioni, una per ciascun bersaglio, e le azioni verranno eseguite - solo se entrambe sono rilevate.\n\nFai clic sulla campo Azioni per visualizzare l\'elenco delle azioni per il nostro evento. + Congratulazioni! Hai imparato a usare + una condizione «Non visibile». Combinala sempre con almeno un\'altra condizione per evitare di attivare azioni + involontariamente per tutta la durata del tuo scenario. - L\'azione è già impostata per fare clic sul personaggio blu e verrà eseguita solo quando - i personaggi blu e rosso saranno visibili insieme.\n\nQuesto è esattamente il comportamento di cui abbiamo bisogno per vincere - il gioco, quindi non c\'è bisogno di modificare l\'azione di clic.\n\nChiudere l\'elenco Azioni per tornare alla configurazione degli eventi. - - Fare clic sul pulsante Salva per salvare l\'evento. - - Tutte le modifiche devono essere salvate nel tuo scenario per essere registrate.\n\nFai - clic sul pulsante Salva per salvare le tue modifiche. - - Siamo pronti per vincere questo gioco!\n\nFai clic sul pulsante Avvia per avviare la - rilevazione e quindi avvia il gioco. - - Congratulazioni!\n\nOra sai come combinare condizioni multiple per un evento, ma c\'è ancora molto da imparare! diff --git a/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..7c3b1954a --- /dev/null +++ b/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,73 @@ + + + + + + Operatore di condizione E + Usa l\'operatore E per fare clic solo quando + più obiettivi sono visibili contemporaneamente + Tocca il pulsante blu solo quando sia + l\'obiettivo blu che quello rosso sono visibili + + Nuove regole! Il gioco ora mostra due + obiettivi. Devi toccare quello blu, ma solo quando entrambi gli obiettivi, blu e rosso, sono sullo schermo + contemporaneamente. \n\nAvvia il gioco e vedi se riesci a stare al passo da solo. + + I tempi sono troppo stretti per gestirli + manualmente, quindi usiamo Klick\'r. \n\nApri il menu di configurazione dello scenario, crea un nuovo Evento + Schermo e inizia ad aggiungere condizioni per gli obiettivi del gioco. + + Abbiamo bisogno di una condizione per + ogni obiettivo. Iniziamo con quello blu. \n\nCrea una nuova condizione immagine e acquisisci l\'obiettivo + blu. + + Vogliamo che questa condizione sia + soddisfatta quando l\'obiettivo blu è visibile, quindi le impostazioni predefinite sono tutte corrette. + Salva questa condizione. + + Ora aggiungiamo la seconda condizione per + l\'obiettivo rosso. \n\nCrea un\'altra condizione immagine e acquisisci l\'obiettivo rosso. + + Stessa cosa qui — l\'obiettivo rosso deve + essere visibile, quindi le impostazioni predefinite sono corrette. Salva questa condizione e torna + all\'Evento. + + Con due condizioni definite, l\'operatore + di condizione determina come vengono combinate. Seleziona l\'operatore tramite il selettore mostrato sopra. + \n\n• E: l\'evento si attiva solo quando TUTTE le condizioni sono soddisfatte.\n• O: l\'evento si attiva + appena UNA condizione è soddisfatta.\n\nPer il nostro gioco abbiamo bisogno di entrambi gli obiettivi sullo + schermo contemporaneamente, quindi seleziona E. + Il selettore dell\'operatore di + condizione + + E è già l\'operatore predefinito, quindi + siamo a posto. \n\nOra apri la sezione Azioni e crea una nuova azione di tocco. + + Vogliamo toccare l\'obiettivo blu, quindi + seleziona il tipo di posizione «Su condizione» e scegli la condizione immagine dell\'obiettivo blu. + \n\nQuando hai finito, salva il tocco, poi il tuo evento e scenario, e torna al gioco. + + Avvia il tuo scenario e lancia il gioco + per vincere! \n\nSe non funziona, verifica che entrambe le condizioni siano acquisite correttamente e che la + durata del tocco sia impostata su 1 ms. + + Congratulazioni! Hai imparato a usare + l\'operatore E. L\'evento ora si attiva solo quando tutte le sue condizioni sono soddisfatte allo stesso + tempo. + + diff --git a/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..e1ff41ba7 --- /dev/null +++ b/feature/tutorial/src/main/res/values-it/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,75 @@ + + + + + + Operatore di condizione O + Usa l\'operatore O per toccare il primo obiettivo + che appare sullo schermo + Tocca qualsiasi obiettivo non appena appare + sullo schermo + + Nuova sfida! Due obiettivi possono apparire + sullo schermo. Quello rosso vale 2 punti e quello blu vale 1 punto, quindi tocca quello che compare il prima + possibile. \n\nAvvia il gioco e vedi come te la cavi. + + Troppo veloce da gestire manualmente, quindi + usiamo Klick\'r. \n\nApri il menu di configurazione dello scenario, crea un nuovo Evento Schermo e inizia ad + aggiungere condizioni per gli obiettivi del gioco. + + Abbiamo bisogno di una condizione per ogni + obiettivo. Iniziamo con quello blu. \n\nCrea una nuova condizione immagine e acquisisci l\'obiettivo blu. + + Questa condizione deve attivarsi quando + l\'obiettivo blu è visibile, quindi le impostazioni predefinite sono tutte corrette. Salva questa + condizione. + + Ora aggiungiamo la seconda condizione per + l\'obiettivo rosso. \n\nCrea un\'altra condizione immagine e acquisisci l\'obiettivo rosso. + + Stessa cosa qui, l\'obiettivo rosso deve + essere visibile, quindi le impostazioni predefinite sono corrette. Salva questa condizione. + + Con O, le condizioni vengono verificate in + ordine e l\'evento si attiva non appena la prima corrisponde, quindi l\'ordine delle condizioni è importante. + \n\nL\'obiettivo rosso assegna più punti, quindi vogliamo che venga verificato per primo. Usa il pulsante « + per spostarlo prima di quello blu, poi torna alla finestra Evento. + + Ora imposta l\'operatore di condizione su O. + L\'evento si attiverà non appena uno dei due obiettivi apparirà. Se entrambi sono visibili contemporaneamente, + la condizione rossa verrà rilevata per prima poiché ha la priorità più alta. \n\nSeleziona O. + + L\'operatore O è ora impostato. Apri la + sezione Azioni e crea una nuova azione di tocco. + + Vogliamo toccare l\'obiettivo che ha + attivato l\'evento. Seleziona il tipo di posizione «Su condizione». Con O, solo una condizione può essere + rilevata positivamente alla volta, quindi non è necessario selezionare una condizione specifica. Klick\'r + toccherà automaticamente la posizione della condizione che ha corrisposto. \n\nQuando hai finito, salva il + tocco, poi il tuo evento e scenario, e torna al gioco. + + Avvia il tuo scenario e lancia il gioco per + vincere! \n\nSe non funziona, verifica che le tue condizioni siano acquisite correttamente e che la durata del + tocco sia impostata su 1 ms. + + Congratulazioni! Hai imparato a usare + l\'operatore O e perché la priorità delle condizioni è importante. Mettendo la condizione rossa per prima, + Klick\'r favorisce sempre l\'obiettivo di valore più alto quando entrambi sono visibili allo stesso + tempo. + + diff --git a/feature/tutorial/src/main/res/values-it/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-it/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..a72a6d7c7 --- /dev/null +++ b/feature/tutorial/src/main/res/values-it/strings_tutorial_counters_basics.xml @@ -0,0 +1,130 @@ + + + + Basi dei contatori + Impara a usare l\'azione Modificare contatore e la condizione + Valore del contatore. + Clicca 10 volte sul bersaglio blu, poi clicca una volta sul + bersaglio rosso + + Benvenuto nel tutorial sui Contatori! + \n\nQui automatizzerai un gioco in cui clicchi sul bersaglio blu 10 volte, poi clicchi sul bersaglio rosso una + volta per convalidare il conteggio e guadagnare 10 punti. Puoi prima provare il gioco, oppure passare + direttamente alla configurazione dello scenario. + + Per prima cosa, dobbiamo creare un Evento schermo che rilevi + il bersaglio blu e ci clicchi sopra. \n\nFai clic su Crea evento per iniziare. + + Iniziamo aggiungendo una condizione per rilevare il bersaglio + blu. Fai clic sul campo Condizioni per aprire l\'elenco delle condizioni e crea questa condizione. + \n\nIl tutorial continuerà una volta creata la condizione. + + Bene! Ora fai clic sul campo Azioni per aggiungere le azioni + che verranno eseguite quando il bersaglio blu viene rilevato. + + Per prima cosa abbiamo bisogno di un\'azione Clic per toccare + il bersaglio blu. Fai clic sul pulsante crea per aggiungere una nuova azione. + + Configura il clic per toccare il bersaglio blu, poi salva + l\'azione. \n\nIl tutorial continuerà una volta salvato il clic. + + Dobbiamo anche contare quante volte abbiamo cliccato sul + bersaglio blu. Questo si può fare con un\'azione Modificare contatore, aggiungendo uno ogni volta che clicchiamo. + \n\nFai clic di nuovo sul pulsante crea per aggiungere una seconda azione. + + Seleziona l\'azione Modificare contatore per incrementare un + contatore ogni volta che il bersaglio blu viene cliccato. + + Per prima cosa dobbiamo scegliere quale contatore aggiornare. + Fai clic su Seleziona un contatore per aprire l\'elenco dei contatori. + + L\'elenco è vuoto per ora. Fai clic sul pulsante crea per + creare un nuovo contatore. Dagli un nome (es. "Clic blu"), mantieni il valore iniziale a 0, poi salvalo e + selezionalo. + + Ora configura come cambia il contatore ogni volta che il + bersaglio blu viene cliccato. \n\nImposta l\'operatore su + e il valore su 1, in modo che il contatore aumenti + di 1 ad ogni clic. \n\nPoi salva l\'azione e torna alla finestra di dialogo dell\'Evento. + Il valore può essere un numero fisso, o il valore + attuale di un altro contatore. + + Ottimo! Questo Evento schermo cliccherà ora il bersaglio blu + e incrementerà il contatore ad ogni rilevamento. \n\nSalva l\'evento per tornare allo scenario. + + Ora abbiamo bisogno di un evento che reagisca quando il + contatore raggiunge 10. Questo tipo di evento non è attivato dallo schermo, quindi è un Evento di attivazione. + \n\nFai clic sulla scheda Trigger per aprire l\'elenco degli Eventi di attivazione. + + Fai clic sul pulsante crea per aggiungere un nuovo Evento + di attivazione. + + Proprio come un Evento schermo, un Evento di attivazione + ha bisogno di condizioni. Fai clic sul campo Condizioni per aprire l\'elenco delle condizioni e crea una nuova + condizione di attivazione. + + Seleziona il tipo di condizione Valore del contatore per + attivare questo evento quando un contatore raggiunge un valore specifico. + + Seleziona il contatore che hai creato in precedenza (quello + che conta i clic blu) per usarlo come trigger. + + Ora imposta il confronto in modo che la condizione sia + soddisfatta quando il contatore è uguale a 10. Ci sono diversi operatori di confronto, ma qui dobbiamo + verificare quando è uguale, quindi seleziona \"=\". Poi inserisci 10 come valore, salva la condizione e torna + alla finestra di dialogo dell\'Evento. + Il valore da confrontare può essere un numero + fisso, o il valore attuale di un altro contatore. + + La condizione è impostata! Ora dobbiamo definire cosa + succede quando il contatore raggiunge 10. Fai clic sul campo Azioni per aprire l\'elenco delle azioni. + + Per prima cosa, crea un\'azione Clic e posizionala + manualmente sul bersaglio rosso per convalidare il conteggio. + + Configura il clic per toccare il bersaglio rosso, poi salva + l\'azione. Tieni presente che in un Evento di attivazione la posizione del clic deve essere sempre impostata + manualmente. \n\nIl tutorial continuerà una volta salvato il clic. + + Ora crea una seconda azione per azzerare il contatore. Fai + clic di nuovo sul pulsante crea e seleziona l\'azione Modificare contatore. + + Vogliamo impostare il contatore dei clic blu a 0, quindi + per prima cosa seleziona il contatore dei clic blu. + + Imposta l\'operatore su = e il valore su 0 per azzerare il + contatore dopo ogni convalida. Poi salva l\'azione e torna alla finestra di dialogo dell\'Evento per + procedere. + + Questo Evento di attivazione cliccherà il bersaglio rosso e + azzererà il contatore ogni volta che vengono contati 10 clic blu. L\'elenco degli Eventi di attivazione viene + eseguito tra un fotogramma e l\'altro, prima dell\'elenco degli Eventi schermo, quindi non appena il contatore + è uguale a 10, questo evento si esegue immediatamente: il bersaglio rosso viene cliccato e il contatore + azzerato, pronto a ricominciare. \n\nSalva l\'evento per tornare allo scenario. + + Lo scenario è completo! Cliccherà il bersaglio blu, conterà + ogni clic, poi convaliderà con il bersaglio rosso ogni 10 clic e ricomincia da capo. \n\nSalva lo scenario per + applicare la tua configurazione. + + Tutto è pronto! Avvia lo scenario, poi lancia il gioco e + guarda Klick\'r gestire il conteggio per te. + + Ben fatto! Hai imparato a usare i Contatori per tracciare + valori attraverso più eventi. \n\nCombinati con l\'azione Modificare contatore e la condizione Valore del + contatore, puoi ora costruire automazioni che reagiscono a schemi ripetuti. + + diff --git a/feature/tutorial/src/main/res/values-it/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-it/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..51ca323a2 --- /dev/null +++ b/feature/tutorial/src/main/res/values-it/strings_tutorial_events_priority.xml @@ -0,0 +1,73 @@ + + + + + Dare priorità a un evento + Dare priorità a un Evento rispetto a un altro + Fai clic il più velocemente possibile sui bersagli. + Blu = 1 punto; Rosso = 10 punti + + Nuovo gioco! Dobbiamo fare clic sui bersagli il più + velocemente possibile, ma quello rosso vale più punti. Puoi prima provare il gioco oppure aprire il menu di + configurazione dello scenario per iniziare ad automatizzarlo. + + Vogliamo rilevare due bersagli diversi, quello blu e quello + rosso. Per questo tutorial, creeremo due eventi distinti: uno per il bersaglio blu e uno per il bersaglio + rosso. \n\nInnanzitutto, crea l\'Evento per il bersaglio blu; deve fare clic su di esso quando viene + rilevato. Non dimenticare di usare le funzioni di test per assicurarti che la tua condizione venga rilevata + correttamente. \n\nIl tutorial procederà una volta salvato il tuo Evento per il bersaglio blu. + + Ottimo! Ora abbiamo bisogno della stessa cosa, ma per il + bersaglio rosso. Fai clic sul pulsante Crea evento e creane uno per il bersaglio rosso; deve fare clic su di + esso quando viene rilevato. \n\nIl tutorial procederà una volta salvato il tuo Evento per il bersaglio + rosso. + + La nostra lista ora ha due eventi, uno per ogni bersaglio. + Salva il tuo Scenario e testalo con il gioco. + + Qualcosa sembra sbagliato. Lo scenario fa clic solo sul + bersaglio blu, ignorando completamente quello rosso, il che ci impedisce di vincere. \n\nPerché succede questo? + Perché l\'evento blu viene prima di quello rosso, e poiché viene sempre attivato, il fotogramma corrente non + viene valutato oltre e il successivo riparte dall\'inizio dell\'elenco degli Eventi. \n\nCi sono diversi modi + per risolvere questo problema. Apri la finestra di configurazione dello scenario per scoprire come. + + Possiamo risolvere il problema in due modi: \n\nPossiamo + modificare l\'opzione \"Continua esecuzione\" dell\'evento del bersaglio blu per continuare a elaborare lo + stesso fotogramma ed eseguire anche l\'evento rosso. Questo attiverà entrambi i clic quando entrambi i + bersagli sono visibili contemporaneamente. \n\nOppure possiamo spostare l\'evento del bersaglio rosso in cima + all\'elenco, in modo che venga controllato per primo e sempre cliccato quando visibile, ma il bersaglio blu + non verrà più cliccato quando anche quello rosso è visibile. \n\nLa differenza chiave tra le due soluzioni è + la velocità: mettere l\'evento rosso per primo significa reagire il più velocemente possibile quando appare, + essendo leggermente più lenti quando è visibile solo il bersaglio blu. + + Poiché il gioco dà 10 punti per il bersaglio rosso, + vogliamo reagire il più velocemente possibile quando appare spostando l\'evento rosso in cima all\'elenco. + \n\nSposta l\'evento rosso al primo posto e salva lo scenario. Ora dovresti riuscire a vincere il + gioco. + Puoi riordinare gli Eventi tenendo premuta questa + icona e trascinando l\'evento nella posizione corretta. + + Come al solito, avvia prima il tuo scenario e poi il gioco. + \n\nSe non riesci ancora a vincere, assicurati che ogni evento funzioni individualmente usando le funzioni di + test. + + Ottimo! Ora capisci come funziona la priorità degli eventi + e come si comporta il ciclo degli Eventi Schermo. Questo è fondamentale per creare e gestire scenari + complessi. + + diff --git a/feature/tutorial/src/main/res/values-it/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-it/strings_tutorial_events_state.xml new file mode 100644 index 000000000..e61e6613a --- /dev/null +++ b/feature/tutorial/src/main/res/values-it/strings_tutorial_events_state.xml @@ -0,0 +1,151 @@ + + + + + Disabilitare gli eventi non utilizzati + Modifica lo stato di più eventi per ottimizzare uno scenario complesso. + Clicca sui bersagli nell\'ordine: blu, rosso, verde e poi giallo. + + Nuovo gioco! Questa volta devi cliccare su quattro bersagli + colorati nell\'ordine: prima blu, poi rosso, poi verde e infine giallo. \n\nPuoi provare il gioco prima per + vedere come funziona, oppure aprire direttamente la configurazione dello scenario per iniziare ad + automatizzarlo. + + Dobbiamo rilevare quattro bersagli diversi, uno per ogni + colore. Creeremo un Evento per bersaglio. \n\nInizia con il bersaglio blu: crea un nuovo Evento che lo rilevi + nell\'area di gioco e ci clicchi sopra. + + Quando si usano più eventi, è importante personalizzare il + loro nome per tenere traccia di ciò che si sta facendo. Dai a questo Evento un nome chiaro, come \"Bersaglio + blu\", per identificarlo facilmente nel tuo scenario. \n\nUna volta terminato, crea una nuova condizione + Immagine e acquisisci il bersaglio blu. + + Poiché il bersaglio si muove, dobbiamo impostare il tipo di + rilevamento su \"Area di rilevamento\" e selezionare l\'area di gioco. \n\nOnce l\'area è configurata correttamente, + salvala e torna alla finestra Evento. + + La tua condizione è impostata. Ora abbiamo bisogno di un\'azione + Clic affinché l\'Evento clicchi sul bersaglio rilevato. \n\nCrea una nuova azione Clic per continuare. + + Il bersaglio si muove, quindi non possiamo definire una + posizione fissa. Imposta il campo \"Clicca su\" su \"Clicca sulla condizione rilevata\" e seleziona la condizione del bersaglio blu. + In questo modo, il clic atterrerà sempre esattamente dove è stato trovato il bersaglio.\n\nOnce selezionata la + condizione, salva il clic e torna alla finestra Evento. + + L\'Evento per il bersaglio blu è pronto! Ora crea un Evento per + il bersaglio rosso nello stesso modo: rilevalo nell\'area di gioco e cliccaci sopra. Il tutorial procederà + una volta salvato il tuo Evento del bersaglio rosso. + + Ottimo! Ora crea lo stesso Evento per il bersaglio verde. Il + tutorial procederà una volta salvato il tuo Evento del bersaglio verde. + + Quasi finito! Crea un ultimo Evento per il bersaglio giallo. Il + tutorial procederà una volta salvato il tuo Evento del bersaglio giallo. + + I quattro Eventi sono pronti. Poiché li abbiamo definiti + nell\'ordine della sequenza di gioco, la loro priorità è corretta. \n\nSalva il tuo Scenario e testalo nel + gioco per vedere come si comporta. + + Lo scenario rileva e clicca sui bersagli, ma è probabilmente + troppo lento per vincere. \n\nAttualmente, tutti e quattro gli Eventi sono attivi contemporaneamente, quindi ad + ogni fotogramma lo scenario controlla blu, poi rosso, poi verde, poi giallo; indipendentemente da quale + bersaglio è stato appena cliccato. Questo spreca tempo prezioso! \n\nApri la configurazione dello scenario per + imparare come migliorare questo aspetto. + + Ogni Evento ha uno stato iniziale: può partire abilitato o + disabilitato. Al momento tutti e quattro gli Eventi sono abilitati, quindi vengono tutti controllati ad ogni + fotogramma. \n\nLa soluzione è mantenere attivo solo l\'Evento del bersaglio corrente e disabilitare gli altri. + Quando si clicca su un bersaglio, il suo Evento abiliterà il successivo e disabiliterà gli altri. \n\nIniziamo + modificando l\'Evento del bersaglio blu. + + Il bersaglio blu è il primo da cliccare, quindi il suo Evento + deve partire abilitato; nessuna modifica necessaria qui. \n\nDobbiamo solo aggiungere un\'azione \"Attiva/ + disattiva evento\" in modo che quando si clicca sul bersaglio blu, l\'Evento del bersaglio rosso venga abilitato + e gli altri disabilitati. Tocca l\'area Azioni per aggiungere questa azione. + + Seleziona il tipo di azione \"Cambia stato evento\". + + Questa azione ti permette di cambiare lo stato di qualsiasi + Evento nel tuo scenario quando questo Evento viene attivato. Tocca il campo \"Nessuna modifica\" per selezionare + quali Eventi modificare. + + Per ogni Evento nella lista, puoi impostare uno di tre stati: + \n• Abilita: l\'Evento diventa attivo e verrà controllato ad ogni fotogramma \n• Disabilita: l\'Evento diventa + inattivo e viene saltato completamente \n• Invertire: alterna tra attivo e inattivo ogni volta \n\nPoiché blu è + stato appena cliccato, abilita l\'Evento del bersaglio rosso e disabilita tutti gli altri. Tocca Avanti quando + hai finito. + Ogni riga Evento mostra tre opzioni: Abilita, + Disabilita e Commuta. Tocca quella che vuoi applicare quando questa azione viene eseguita. + + Perfetto! Salva l\'Evento del bersaglio blu. + + Ora apri l\'Evento del bersaglio rosso nella lista per + configurarlo nello stesso modo. + + A differenza dell\'Evento del bersaglio blu, questo Evento non + deve essere attivo all\'inizio dello scenario, poiché il suo bersaglio non è il primo. Cambia il suo stato + iniziale su Disabilitato. + + Ora aggiungi un\'azione \"Cambia stato evento\" in modo + che quando si clicca su questo bersaglio, l\'Evento del bersaglio successivo venga abilitato e gli altri + disabilitati. Tocca l\'area Azioni. + + Imposta le attivazioni: abilita il bersaglio verde e disabilita + tutti gli altri. Tocca Avanti quando hai finito. + + Ottimo lavoro! Ora apri l\'Evento del bersaglio verde per + configurarlo nello stesso modo. + + Anche il bersaglio verde non deve essere attivo all\'inizio. + Cambia il suo stato iniziale su Disabilitato. + + Ora aggiungi un\'azione \"Cambia stato evento\" in modo + che quando si clicca sul bersaglio verde, l\'Evento del bersaglio giallo venga abilitato e gli altri + disabilitati. Tocca l\'area Azioni. + + Imposta le attivazioni: abilita il bersaglio giallo e + disabilita tutti gli altri. Tocca Avanti quando hai finito. + + Quasi finito! Apri l\'Evento del bersaglio giallo per + completare la configurazione. + + Il bersaglio giallo è l\'ultimo della sequenza, quindi deve + anch\'esso partire disabilitato. Cambia il suo stato iniziale su Disabilitato. + + Aggiungi anche un\'azione \"Cambia stato evento\" + all\'Evento del bersaglio giallo. Quando si clicca su giallo, vogliamo tornare all\'inizio: abilita il bersaglio + blu e disabilita tutti gli altri. Tocca l\'area Azioni. + + Imposta le attivazioni: abilita il bersaglio blu e disabilita + tutti gli altri. In questo modo, la sequenza si ripeterà indefinitamente. Tocca Avanti quando hai finito. + + Tutti gli Eventi sono ora completamente configurati. Salva il + tuo Scenario per applicare le modifiche. + + Tutti gli Eventi sono configurati! Salva il tuo Scenario e poi + avvia il gioco. Ricorda di avviare il tuo Scenario prima di lanciare il gioco. \n\nPoiché il nostro scenario ha + uno stato interno, devi riavviarlo ogni volta che riavvii il gioco per assicurarti che non stia aspettando + l\'ultimo bersaglio della sessione precedente. Questo può essere facilmente automatizzato rilevando se il + pulsante di avvio è visibile per reimpostare gli stati degli eventi. + + Hai vinto! \n\nControllando quali Eventi sono attivi in ogni + momento, lo scenario sa sempre esattamente quale bersaglio cercare dopo — nessun fotogramma sprecato a + controllare bersagli fuori sequenza. \n\nÈ così che l\'azione Attiva/disattiva evento ti permette di creare + un\'automazione sequenziale e guidata dallo stato. + + diff --git a/feature/tutorial/src/main/res/values-ja/strings_categories.xml b/feature/tutorial/src/main/res/values-ja/strings_categories.xml index 610bdc951..83fa32805 100644 --- a/feature/tutorial/src/main/res/values-ja/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-ja/strings_categories.xml @@ -1,4 +1,4 @@ - + + ポーズアクション + ポーズがアクションの実行と検出に与える影響を学ぶ + ポーズアクションはシナリオ全体を設定した時間だけ + 一時停止します。その間、アクションは実行されず、画面の検出も行われません。\n\nよくある使い方は、アクション + リストの末尾にポーズを追加することです。どこかをタップすると、タップされたアプリがそれを処理して結果を表示 + するまでに時間がかかります。Klick\'r が再び画面を分析し始める前に、その瞬間を待ちたいことが多いでしょう。 + \n\n2つのアクションの間にポーズを入れることも有効ですが、リストの末尾に追加することの方が重要なケースが + 多いです。 + + + スワイプアクション + スワイプジェスチャーの実行方法を学ぶ + スワイプアクションは開始位置から終了位置まで直線的な + ドラッグジェスチャーを実行します。両方の座標は固定されており、アクションの設定で指定します。\n\nデュレーション + はジェスチャーが開始から終了まで要する時間を制御します。短いデュレーションはより速いスワイプを生み出し、長い + デュレーションはよりゆっくりと制御されたスワイプを生み出します。 + + + クリックオフセット + 検出された条件に対するクリック位置の調整方法を学ぶ + 検出された条件をクリックする場合、デフォルトでは + クリックは検出された領域の中心に適用されます。\n\nクリックオフセットを使うと、その位置を条件の中心を基準に + X軸とY軸方向にピクセル単位で移動できます。タップしたい要素が検出された領域の中心の近くにあるが、厳密に + 中心ではない場合に便利です。 + + + クリックターゲット + クリックが適用される場所の設定方法を学ぶ + クリックアクションは2種類の位置を対象にできます: + 常に同じ固定位置、または検出された条件の位置です。\n\nアクション設定ダイアログのターゲットセレクターで + ターゲット指定の方法を選択してください。 + 固定位置の場合、クリックは画面に何が表示されて + いるかに関係なく、常に同じ正確な座標で発生します。\n\nこれらの座標は回転に敏感であることに注意してください: + デバイスが回転すると、クリックが予期しない位置に当たったり、画面の端を超えてしまうことがあります。 + 条件の位置の場合、クリックは検出された画像条件の + 中心に適用され、画面上のどこに表示されてもターゲットを追跡します。\n\nANDオペレーターでは、すべての条件が + 満たされる必要があるため、各画像条件には利用可能な位置があります。自由にどれかを選んでオフセットで + 調整できます。 + ORオペレーターでは、最初に満たされた条件のみが + 評価され、残りは無視されます。そのため、Klick\'r はどの条件が検出されるかを事前に知ることができません。 + \n\n結果として、ORオペレーターでは特定の条件をターゲットとして選ぶことができません:クリックは常に実行時に + 最初に検出された条件に適用されます。 + + + 条件の順序と速度 + 条件の順序がイベントの確認速度に与える影響 + + リスト内の条件の順序はイベントの確認速度に影響します。\n\nAND + 演算子を使用する場合、最初に満たされない条件が見つかった時点で確認が停止します。最も満たされにくい条件を先頭に置くことで、アプリが残りの条件を早くスキップできるようになり、イベントが速くなります。 + + OR + 演算子を使用する場合、最初に満たされた条件が見つかった時点で確認が停止します。最も満たされやすい条件を先頭に置くことで、アプリが残りを確認せずに早く完了できます。\n\nどちらの場合も、最も重要な条件をリストの先頭に置くこ + とが、シナリオを速く保つシンプルな方法です。 + + + + イベントの状態 + シナリオの実行中にイベントを有効・無効にする方法を学ぶ + + シナリオ内のすべてのイベント(スクリーンイベントとトリガーイベント)には状態があります:有効 + または無効です。\n\n有効の場合、イベントは通常どおり実行され、条件を確認します。無効の場合、存在しないかのように完全にスキップされます。\n\nデフォルトでは、すべてのイベントは有効な状態で開始さ + れます。イベント設定の初期状態フィールドで変更できます。 + + シナリオの実行中は、イベント状態を変更アクションを使って任意のイベントの状態を変更で + きます。このアクションにより、1つ以上のイベントを有効化・無効化、または切り替えることができます。\n\nこれにより多くのことが可能になります:次々とお互いをオンにするイベント、一度実行されたら自分でオフになるイベント、ま + たは同時に1つだけがアクティブなイベントのグループ。 + + シナリオ内のすべてのイベントが無効になったとき、シナリオは自動的に停止します。やるこ + とが何もなくなるため、Klick\'rが自動的に停止します。\n\nこれはシナリオを終了するシンプルな方法です:最後のイベントが役割を果たした後に他のすべてを無効にすれば、すべてが自動的に停止します。 + + + + アクションリスト + アクションリストの実行方法を学ぶ + アクションは順番に、一つずつ実行されます。<< と + >> ボタンを使うか、インデックス番号を直接タップしてアクションの順序を変更できます。\n\nアクションリストは + 短く保つようにしましょう。通常のオートクリッカーはイベントごとに一か所をタップします——それが従うべきモデルです。一つの + イベントに多くのアクションを追加していると感じたら、それは作業を複数のイベントに分割すべきサインです。各イベントが + 実際に画面に表示されているものに反応するようにしましょう。これが Klick\'r の「見て動く」哲学です:まず検出、それから + アクション。 + + + テキスト入力アクション + フォーカスされた入力フィールドへのテキスト入力方法を学ぶ + テキスト入力アクションが実行される前に、対象の入力 + フィールドがすでにフォーカスされている必要があります——キーボードを表示するためにタップするのと同じです。\n\nこれを + 実現するには、テキスト入力アクションの前にそのフィールドへのクリックアクションを追加してください。クリック後に + トランジションアニメーションが再生される場合は、間に待機アクションを入れるとフィールドの準備が整うのを確認するのに + 役立ちます。\n\nアクションには「確定」オプションもあります:有効にすると、テキスト設定後に自動的に Enter が押され、 + 入力が確定または送信されます。 + 書き込むテキストにカウンターの値を挿入できます。 + アクション設定の「カウンターを追加」ボタンを押してカウンターを選択すると、テキストフィールドの現在のカーソル位置に + プレースホルダー {カウンター名} が挿入されます。\n\n実行時には、テキストがフィールドに貼り付けられる前に + すべての {カウンター名} プレースホルダーがカウンターの現在値に置き換えられます。例えば、りんご + という名前のカウンターの値が18の場合、「りんごが{りんご}個あります」は「りんごが18個あります」になります。 + + + システムアクション + Android のナビゲーションアクションを実行する方法を学ぶ + システムアクションは Android の組み込みナビゲーション + アクションの一つを実行します:戻る、ホーム、または最近使用したアプリ。\n\nこれらは画面下部のナビゲーションボタンと + 同じアクションです。座標は不要で、現在開いているアプリに関係なくシステムレベルで動作します。 + + + カウンター変更アクション + カウンターの値を変更する方法を学ぶ + カウンター変更アクションは、事前定義された静的な値 + を使ってカウンターに操作を適用します。利用可能な操作は3つ:カウンターに値を加算する(+)、カウンターから減算する + (−)、またはカウンターをその値に設定する(=)。\n\nこれはカウンターを更新する最も一般的な方法です——例えば、条件が + 検出されるたびに1を加えたり、目標達成時に0にリセットしたりします。 + 静的な値の代わりに、別のカウンターの現在値を + オペランドとして使用できます。同じ3つの操作(+、−、=)が適用されますが、量は設定時に固定されるのではなく、実行時に + 選択されたカウンターから読み取られます。\n\nこれにより、カウンター同士が相互作用する動的なシナリオを構築できます。 + + + 通知アクション + シナリオ中に通知を表示する方法を学ぶ + 通知アクションは、お好みのタイトルとメッセージで + Android 通知を表示します。\n\n「カウンターを追加」ボタンを使うか、プレースホルダー {カウンター名} を直接 + 入力することで、通知テキストにカウンターの現在値を挿入できます。実行時にはカウンターの値に置き換えられます——例えば、 + 「りんごが{りんご}個あります」は「りんごが18個あります」になります。 + 通知の重要度レベルは、通知がどれほど目立つ形で + 表示されるかを制御します。高い重要度レベルではヘッドアップバナーが表示されたり音が鳴ったりしますが、低いものは + 通知トレイに静かに届きます。\n\n正確な動作はデバイスによって異なり、Klick\'r の Android 通知設定でさらに + カスタマイズできます。 + + + イベント状態変更アクション + 実行時にイベントを有効・無効にする方法を学ぶ + 無効化されたイベントはシナリオループ中に完全に + スキップされます——その条件は一切チェックされず、アクションも実行されません。つまり、処理時間を全く消費しません。 + \n\n使用していないイベントを無効化することはパフォーマンス向上に非常に効果的です。例えば、メニューフェーズとゲーム + フェーズを交互に行うシナリオでは、ゲームフェーズ中にメニュー関連のイベントをすべて無効化する(逆も同様)ことで、 + 常に関連するイベントだけをアクティブに保てます。 + アクションを設定する際、シナリオ内のすべての + イベントの状態を一括変更するか、各イベントの新しい状態を個別に定義するかを選択できます。\n\n各イベントに対して + 3つの状態変更が利用可能です:有効にする、無効にする、または現在の値からトグルする——有効なイベントは無効になり、 + 無効なイベントは有効になります。 + シナリオ内のすべてのイベントが同時に無効になった + 場合、実行するものが何もなくなるため、シナリオは自動的に停止します。\n\nこれを意図的に利用することで、目標達成後に + シナリオをクリーンに終了させることができます:すべてのイベントを無効にする最後のイベント状態変更アクションがシナリオ + を停止させます。 + + + Intent アクション + 他のアプリケーションと通信する方法を学ぶ + Intent は Android でアプリが互いに通信する方法です。 + Intent アクションを使うと、シナリオから直接このシステムを活用できます。\n\n使いやすくするための定義済みテンプレートが + 用意されています。最も一般的なのは「アプリを起動」で、ランチャーからアイコンをタップしたときと全く同じように、デバイス + 上の別のアプリを起動します。 + 「詳細設定」タブでは、生の Intent を手動で定義し、 + アクション、カテゴリ、データ、extras を完全に制御できます。これは一般ユーザーには推奨されません——Intent の仕組みを + すでに知っている Android 開発者向けです。\n\n将来のアップデートでは、詳細設定に頼らずに一般的なユースケースを簡単に + 設定できるよう、すぐに使えるテンプレートが追加される予定です。 + + + + イベントの優先順位 + リスト内のイベントの順序が実行されるイベントに与える影響を学びます + 画面からキャプチャされた各フレームは、イベントを上から下に1つずつ確認することで処理されます。\n\nイベントリスト内のイベントの位置が、そのイベントが実行される機会を得るタイミングを決定します。デフォルトでは、イベントの条件が満たされてアクションが実行されると、そのフレームは処理済みとみなされます。そのフレームの処理は停止し、次のフレームはリストの最初のイベントから再開します。\n\nつまり、デフォルトでは1フレームにつき1つのイベントしか実行できません。 + この動作は、イベント設定の実行を続けるフィールドで変更できます。有効にすると、そのイベントが実行された後、処理が停止する代わりにリストの次のイベントへ続きます。\n\nこれにより、同じフレームで複数のイベントを実行できます。\n\n例:リストにイベントAの次にイベントBが含まれているとします。イベントAが継続して検出され、実行を続けるが有効でない場合、イベントAは毎フレーム実行され、イベントBは一度も実行される機会がありません。\n\nイベントAで実行を続けるを有効にすると、両方のイベントが毎フレーム確認されます。\n\nこの概念を練習するためのインタラクティブなチュートリアルも利用できます。 + + + + イベントのリロード + シナリオ内でのイベントのリロードの動作について学ぶ + イベントリロードパラメーターを使用すると、条件が + 満たされた後、一定時間イベントをスキップできます。 \n\nリロード状態のイベントはまだ有効と見なされます:リロードと + イベントの状態は独立しています。 \n\nリロード中にイベントが無効化された場合、リロードタイマーはクリアされるため、 + イベントが再度有効化されたときにクールダウンは適用されません。 + + + + カウンター値の使い方 + シナリオでカウンターの値を表示・使用するさまざまな方法を学びましょう + + 通知アクションの中に、カウンターの現在値を表示できます。これはシナリオの実行中に進行状況を確認したり、終了時にまとめを表示したりするのに便利です。\n\nカウンターを挿入するには、アクション設定の「カウンターを追加」ボタンを押してください。これにより、テキストに {counterName} のようなプレースホルダーが追加されます。実行時には、このプレースホルダーがカウンターの実際の値に置き換えられます。例えば、score という名前のカウンターの値が42の場合、「現在のスコア: {score}」は「現在のスコア: 42」になります。 + + テキスト書き込みアクションにもカウンターの値を挿入できます。これにより、アクションが実行された時点の現在値がテキストに含まれます。\n\nプレースホルダーの使い方は通知アクションと同じです。「カウンターを追加」ボタンを押すか、{counterName} を直接入力してください。例えば、score という名前のカウンターの値が42の場合、「私のスコアは {score} です」は「私のスコアは 42 です」になります。 + + カウンターの値はデバッグレポートに記録されます。シナリオで予期しない動作が発生した場合は、デバッグレポートを取得することで、カウンターがどのように変化したかを正確に確認でき、問題の原因を見つけやすくなります。 + diff --git a/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_not_visible.xml index 85b4e2041..9a6e587cf 100644 --- a/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - 複数の条件を組み合わせる - イベントの複数の条件を作成して組み合わせる - 赤いボタンが表示されている場合にのみ青いボタンをクリックしてください - もう一度ゲームのルールを変えてみましょう。青い標的は動きを止め、\n ただし、現在は赤いターゲットが表示されている場合にのみクリックする必要があります。\n\nまずはゲームを開始して勝てるか確認してください\n 自分で。 - やはり手動で勝つのは無理そうなのでスマートを使いましょう\n オートクリッカー。\n\n前のチュートリアルのシナリオは保持され、このチュートリアルでも読み込まれますが、\n この新しいゲームに勝つには、いくつかのパラメータを変更する必要があります。\n\nシナリオ設定アイコンをクリックして、\n 新しいシナリオの更新を開始します。 - 引き続き青いターゲットをクリックしますが、それは赤色のターゲットが表示されている場合のみです。\n\n したがって、この赤いターゲットの条件をイベントに追加する必要があります。\n\n以前に作成したイベントをクリックして編集します。 - いくつかの条件を組み合わせるので、Condition 演算子を確認する必要があります。\n このイベントのために。\n\nCondition 演算子は、複数の条件がどのようにまとめて解釈されるかを示します。\n\n 「1 つ」は、このイベントの条件を 1 つだけ満たす必要があることを意味します。\n アクションを実行します。\n\n「すべて」は、アクションを実行するには、このイベントのすべての条件が満たされる必要があることを意味します。\n \n\n2 つのものが一緒に表示されているかどうかを検出したいので、「すべて」を使用します。 - 次に、条件を更新する必要があります。\n\n「条件」フィールドをクリックして表示します。\n 条件リスト。 - 青いターゲットを検出する以前の条件は依然として正しいですが、次のことが必要です。\n 赤いターゲットの新しいもの。\n\n「条件の作成」ボタンをクリックして、新しい条件を作成します。 - 青いターゲットの場合と同様に、赤いターゲットを表示するためにゲームを開始します。\n 表示されたら、スクリーンショットを撮ってください。 - フローティング メニューのキャプチャ ボタンを使用してスクリーンショットを撮ります。 - スクリーンショットには赤いターゲットが含まれていますか?トリミングできるのは、次の目的だけです。\n 検出に興味深い部分、つまり赤いターゲットを取得します。 - スクリーンショットに赤いターゲットが含まれていない場合は、\n 新しいボタンを押すには、このボタンを押してください。 - あなたのコンディション画像が記録されました!\n\n赤いターゲットは動いていないので、\n デフォルト設定を維持できます。\n保存ボタンをクリックすると登録され、条件一覧に戻ります。 - 条件リストを閉じて、イベント設定に戻ります。 - これで、各ターゲットに 1 つずつ、合計 2 つの条件があり、アクションが実行されます。\n 両方が検出された場合のみ。\n\n「アクション」フィールドをクリックして、イベントのアクションリストを表示します。 - アクションは青い文字をクリックするようにすでに設定されており、\n 青文字と赤文字が同時に表示されている場合に実行されます。\n\nこれはまさに、\n ゲームなので、クリックアクションを編集する必要はありません。\n\n[アクション] リストを閉じて、イベント設定に戻ります。 - 保存ボタンをクリックしてイベントを保存します。 - 登録するには、すべての変更をシナリオに保存する必要があります。\n\n保存ボタンをクリックして変更を保存します。 - 私たちはこの試合に勝つ準備ができています!\n\n開始ボタンをクリックして開始します\n 検出してゲームを開始します。 - おめでとう!\n\nこれで、イベントの複数の条件を組み合わせる方法がわかりました。\n しかし、学ぶべきことはまだたくさんあります。 + + 条件の可視性 + 「表示」オプションを使って、ターゲットが画面に表示されていないときにタップを実行しましょう + 赤いボタンが見えないときだけ青いボタンをタップしてください + + 新しいルールです!青いターゲットは動かなくなりましたが、赤いターゲットが見えないときだけタップする必要があります。 + \n\nゲームを起動して、自分で勝てるか試してみましょう。 + + やはり手動では勝てそうにないので、Klick\'rを使いましょう。 + \n\nシナリオ設定メニューを開き、新しいスクリーンイベントを作成して、ゲームのターゲットに対する条件を追加していきます。 + + まず、赤いターゲットが画面に表示されていないことを確認する条件が必要です。 + \n\n新しい画像条件を作成し、赤いターゲットをキャプチャしてください。 + + 赤いターゲットが見えないときだけタップしたいので、「表示中」オプションを「いいえ」に設定してください。これにより、赤いターゲットが画面から消えたときだけ条件が満たされます。 + + その他の設定はこのケースに合っています — このまま条件を保存してください。 + + この条件だけでゲームに勝つことはできますが、ゲームが起動していないときも条件が満たされてしまい、好ましくありません。 + \n\nそれを防ぐため、青いターゲットが表示されているかどうかを確認する2つ目の条件と組み合わせましょう。 + 新しい画像条件を作成して、青いターゲットをキャプチャしてください。 + + この条件では青いターゲットが表示されているかを確認したいので、デフォルト設定のままで問題ありません。条件を保存してイベントに戻り、チュートリアルを続けましょう。 + + 複数の条件がある場合、条件演算子が重要になります。青いターゲットが表示されていて、かつ赤いターゲットが表示されていないときにイベントを発動させたいので、AND演算子が必要です。これはすでにデフォルト値なので問題ありません。 + \n\n続けて、新しいタップアクションを作成してください。 + + 青いターゲットをタップしたいので、位置タイプ「条件の上」を選択し、青いターゲットの画像条件を指定してください。 + \n\n完了したら、タップを保存し、イベントとシナリオも保存してゲームに戻りましょう。 + + シナリオを開始してゲームを起動し、勝利を目指しましょう! + \n\nうまくいかない場合は、条件が正しくキャプチャされているか、タップ時間が1msに設定されているかを確認してください。 + + おめでとうございます!「非表示」条件の使い方を習得しました。シナリオ全体で意図せずアクションが実行されないよう、必ず他の条件と組み合わせて使用してください。 + diff --git a/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..b9a145851 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,56 @@ + + + + + + 条件演算子 AND + AND演算子を使って、複数のターゲットが同時に表示されているときだけタップしましょう + 青と赤の両方のターゲットが見えているときだけ青いボタンをタップしてください + + 新しいルールです!ゲームに2つのターゲットが登場します。青いターゲットをタップしますが、青と赤の両方が同時に画面に表示されているときだけです。 + \n\nゲームを起動して、自分でついていけるか試してみましょう。 + + 手動で対応するには難しすぎるので、Klick\'rを使いましょう。 + \n\nシナリオ設定メニューを開き、新しいスクリーンイベントを作成して、ゲームのターゲットに対する条件を追加していきます。 + + ターゲットごとに1つの条件が必要です。まず青いターゲットから始めましょう。 + \n\n新しい画像条件を作成し、青いターゲットをキャプチャしてください。 + + この条件は青いターゲットが表示されているときに満たされるようにしたいので、デフォルト設定のままで問題ありません。この条件を保存してください。 + + 次に赤いターゲットの2つ目の条件を追加しましょう。 + \n\nもう1つ画像条件を作成し、赤いターゲットをキャプチャしてください。 + + こちらも同じです — 赤いターゲットが表示されている必要があるので、デフォルト設定のままで問題ありません。この条件を保存してイベントに戻りましょう。 + + 2つの条件が設定された状態で、条件演算子がそれらの組み合わせ方を決定します。上に表示されたセレクターで演算子を選択してください。 + \n\n• AND: すべての条件が満たされたときだけイベントが発動します。\n• OR: 1つの条件が満たされた時点でイベントが発動します。\n\nこのゲームでは両方のターゲットが同時に画面にある必要があるので、ANDを選択してください。 + 条件演算子セレクター + + ANDはすでにデフォルトの演算子なので準備完了です。 + \n\nアクションセクションを開き、新しいタップアクションを作成してください。 + + 青いターゲットをタップしたいので、位置タイプ「条件の上」を選択し、青いターゲットの画像条件を指定してください。 + \n\n完了したら、タップを保存し、イベントとシナリオも保存してゲームに戻りましょう。 + + シナリオを開始してゲームを起動し、勝利を目指しましょう! + \n\nうまくいかない場合は、両方の条件が正しくキャプチャされているか、タップ時間が1msに設定されているかを確認してください。 + + おめでとうございます!AND演算子の使い方を習得しました。これでイベントはすべての条件が同時に満たされたときだけ発動するようになります。 + + diff --git a/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..7bcc06bfa --- /dev/null +++ b/feature/tutorial/src/main/res/values-ja/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,57 @@ + + + + + + 条件演算子 OR + OR演算子を使って、最初に現れたターゲットをタップしましょう + 画面にターゲットが現れたらすぐにタップしてください + + 新しいチャレンジです!2つのターゲットが画面に現れることがあります。赤いターゲットは2ポイント、青いターゲットは1ポイントです。どちらが現れても、できるだけ素早くタップしましょう。 + \n\nゲームを起動して、自分でどこまでできるか試してみましょう。 + + 手動で対応するには速すぎるので、Klick\'rを使いましょう。 + \n\nシナリオ設定メニューを開き、新しいスクリーンイベントを作成して、ゲームのターゲットに対する条件を追加していきます。 + + ターゲットごとに1つの条件が必要です。まず青いターゲットから始めましょう。 + \n\n新しい画像条件を作成し、青いターゲットをキャプチャしてください。 + + この条件は青いターゲットが表示されているときに満たされるようにしたいので、デフォルト設定のままで問題ありません。この条件を保存してください。 + + 次に赤いターゲットの2つ目の条件を追加しましょう。 + \n\nもう1つ画像条件を作成し、赤いターゲットをキャプチャしてください。 + + こちらも同じです。赤いターゲットが表示されている必要があるので、デフォルト設定のままで問題ありません。この条件を保存してください。 + + ORでは条件が順番にチェックされ、最初に一致した条件でイベントが発動するため、条件の順序が重要です。 + \n\n赤いターゲットのほうがポイントが高いので、最初にチェックされるようにしたいです。«ボタンを使って赤い条件を青い条件の前に移動し、イベントダイアログに戻ってください。 + + 次に条件演算子をORに設定します。どちらかのターゲットが現れると即座にイベントが発動します。両方が同時に表示された場合は、優先度が高い赤い条件が先にマッチします。 + \n\nORを選択してください。 + + OR演算子が設定されました。アクションセクションを開き、新しいタップアクションを作成してください。 + + イベントを発動させたターゲットをタップしたいので、位置タイプ「条件の上」を選択してください。ORでは同時に正に検出できる条件は1つだけなので、特定の条件を選択する必要はありません。Klick\'rが一致した条件の場所に自動的にタップします。 + \n\n完了したら、タップを保存し、イベントとシナリオも保存してゲームに戻りましょう。 + + シナリオを開始してゲームを起動し、勝利を目指しましょう! + \n\nうまくいかない場合は、条件が正しくキャプチャされているか、タップ時間が1msに設定されているかを確認してください。 + + おめでとうございます!OR演算子の使い方と条件の優先度がなぜ重要かを学びました。赤い条件を最初に配置することで、両方が同時に表示された場合でも、Klick\'rは常に高ポイントのターゲットを優先します。 + + diff --git a/feature/tutorial/src/main/res/values-ja/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-ja/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..fcc8c5686 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ja/strings_tutorial_counters_basics.xml @@ -0,0 +1,82 @@ + + + + カウンターの基本 + 「カウンターを変更する」アクションと「カウンター到達時」条件の使い方を学びましょう。 + 青いターゲットを10回クリックし、その後赤いターゲットを1回クリックしてください + + カウンターのチュートリアルへようこそ! + \n\nここでは、青いターゲットを10回クリックし、その後赤いターゲットを1回クリックしてカウントを確認し10ポイントを獲得するゲームを自動化します。先にゲームを試してみるか、直接シナリオの設定に進むことができます。 + + まず、青いターゲットを検出してクリックする画面イベントを作成する必要があります。\n\n「イベントを作成」をタップして始めましょう。 + + まず、青いターゲットを検出する条件を追加しましょう。「条件」フィールドをタップして条件リストを開き、条件を作成してください。\n\n条件が作成されるとチュートリアルが続きます。 + + よくできました!次に「アクション」フィールドをタップして、青いターゲットが検出されたときに実行するアクションを追加してください。 + + まず、青いターゲットをタップするクリックアクションが必要です。「作成」ボタンをタップして新しいアクションを追加してください。 + + 青いターゲットをタップするようにクリックを設定し、アクションを保存してください。\n\nクリックが保存されるとチュートリアルが続きます。 + + また、青いターゲットを何回クリックしたかを数える必要があります。これは「カウンターを変更する」アクションを使い、クリックのたびに1ずつ加算することで実現できます。\n\n「作成」ボタンをもう一度タップして2つ目のアクションを追加してください。 + + 青いターゲットがクリックされるたびにカウンターを増やすため、「カウンターを変更する」アクションを選択してください。 + + まず、更新するカウンターを選択します。「カウンターを選択」をタップしてカウンターリストを開いてください。 + + リストは今空です。「作成」ボタンをタップして新しいカウンターを作成してください。名前を付け(例:「青のクリック数」)、開始値を0のままにして、保存して選択してください。 + + 次に、青いターゲットがクリックされるたびにカウンターがどのように変化するかを設定します。\n\n演算子を「+」に、値を「1」に設定して、クリックのたびにカウンターが1増えるようにしてください。\n\nその後、アクションを保存してイベントのダイアログに戻ってください。 + 値には固定の数値か、別のカウンターの現在の値を使用できます。 + + すばらしい!この画面イベントは、検出のたびに青いターゲットをクリックしてカウンターを増やします。\n\nイベントを保存してシナリオに戻ってください。 + + 次に、カウンターが10に達したときに反応するイベントが必要です。このようなイベントは画面によってトリガーされないため、トリガーイベントになります。\n\n「トリガー」タブをタップしてトリガーイベントのリストを開いてください。 + + 「作成」ボタンをタップして新しいトリガーイベントを追加してください。 + + 画面イベントと同様に、トリガーイベントにも条件が必要です。「条件」フィールドをタップして条件リストを開き、新しいトリガー条件を作成してください。 + + カウンターが特定の値に達したときにこのイベントをトリガーするため、「カウンター到達時」条件タイプを選択してください。 + + 先ほど作成したカウンター(青いクリック数を数えているもの)を選択してトリガーとして使用してください。 + + カウンターが10と等しいときに条件が満たされるように比較を設定してください。いくつかの比較演算子がありますが、ここでは等しいかどうかを確認するため「=」を選択してください。次に値として10を入力し、条件を保存してイベントのダイアログに戻ってください。 + 比較する値には固定の数値か、別のカウンターの現在の値を使用できます。 + + 条件が設定されました!次に、カウンターが10に達したときに何が起こるかを定義する必要があります。「アクション」フィールドをタップしてアクションリストを開いてください。 + + まず、クリックアクションを作成し、カウントを確認するために赤いターゲットの位置に手動で配置してください。 + + 赤いターゲットをタップするようにクリックを設定し、アクションを保存してください。トリガーイベントでは、クリック位置は常に手動で設定する必要があることに注意してください。\n\nクリックが保存されるとチュートリアルが続きます。 + + 次に、カウンターをリセットする2つ目のアクションを作成します。「作成」ボタンをもう一度タップして「カウンターを変更する」アクションを選択してください。 + + 青いクリック数のカウンターを0にリセットするため、まず青いクリック数のカウンターを選択してください。 + + 演算子を「=」に、値を「0」に設定して、確認のたびにカウンターをリセットしてください。その後、アクションを保存してイベントのダイアログに戻って続けてください。 + + このトリガーイベントは、青いクリックが10回カウントされるたびに赤いターゲットをクリックしてカウンターをリセットします。トリガーイベントリストは各画面フレームの間、画面イベントリストの前に実行されるため、カウンターが10になるとすぐにこのイベントが実行されます。赤いターゲットがクリックされてカウンターがリセットされ、また最初から始める準備が整います。\n\nイベントを保存してシナリオに戻ってください。 + + シナリオが完成しました!青いターゲットをクリックして各クリックをカウントし、10回クリックするごとに赤いターゲットで確認してまた最初から始めます。\n\nシナリオを保存して設定を適用してください。 + + 準備完了です!シナリオを開始し、ゲームを起動して、Klick\'rがカウントを代わりに処理するのを見てください。 + + よくできました!複数のイベントにまたがって値を追跡するためのカウンターの使い方を学びました。\n\n「カウンターを変更する」アクションと「カウンター到達時」条件を組み合わせることで、繰り返しのパターンに反応する自動化を構築できるようになりました。 + + diff --git a/feature/tutorial/src/main/res/values-ja/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-ja/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..86e180231 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ja/strings_tutorial_events_priority.xml @@ -0,0 +1,64 @@ + + + + + イベントの優先設定 + あるイベントを別のイベントより優先させる + できるだけ速くターゲットをタップしてください。青 = 1ポイント; + 赤 = 10ポイント + + 新しいゲームです!できるだけ速くターゲットをタップする必要がありますが、 + 赤いターゲットの方が高得点です。まずゲームを試したり、シナリオ設定メニューを開いて自動化を始めることができます。 + + 青と赤の2つの異なるターゲットを検出したいと思います。このチュートリアルでは、 + 青いターゲット用と赤いターゲット用の2つの別々のイベントを作成します。\n\nまず、青いターゲット用のイベントを作成してください。 + 検出されたときにタップするものです。テスト機能を使って条件が正しく検出されることを確認することを忘れずに。\n\n青いターゲットの + イベントを保存するとチュートリアルが進みます。 + + 素晴らしい!今度は同じことを赤いターゲット用に行います。 + イベント作成ボタンをタップして、赤いターゲット用のイベントを作成してください。検出されたときにタップするものです。 + \n\n赤いターゲットのイベントを保存するとチュートリアルが進みます。 + + リストにそれぞれのターゲット用の2つのイベントが追加されました。 + シナリオを保存してゲームでテストしてください。 + + 何かがおかしいようです。シナリオは青いターゲットだけをタップして、 + 赤いターゲットを完全に無視しており、ゲームに勝てません。\n\nなぜこうなるのでしょうか?青いイベントが赤いイベントより前にあり、 + 常にトリガーされるため、現在のフレームはそれ以上評価されず、次のフレームはイベントリストの先頭から始まるからです。\n\n + これを修正する方法はいくつかあります。シナリオ設定ダイアログを開いて方法を確認してください。 + + 問題を2つの方法で修正できます:\n\n青いターゲットのイベントの + 「実行を継続」オプションを変更して、同じフレームの処理を続けて赤いイベントも実行できるようにする方法があります。これにより、 + 両方のターゲットが同時に表示されているときに両方のタップが実行されます。\n\nまたは、赤いターゲットのイベントをリストの先頭に + 移動して、最初にチェックされ表示時に常にタップされるようにする方法があります。ただし、赤いターゲットも表示されているときは + 青いターゲットはタップされなくなります。\n\n2つの解決策の重要な違いは速度です。赤いイベントを最初に置くことで、表示されたとき + にできるだけ速く反応できますが、青いターゲットのみが表示されているときは少し遅くなります。 + + ゲームは赤いターゲットで10ポイントが得られるため、赤いイベントを + リストの先頭に移動して、表示されたときにできるだけ速く反応したいと思います。\n\n赤いイベントを一番上に移動してシナリオを + 保存してください。これでゲームに勝てるはずです。 + このアイコンを長押しして正しい位置にドラッグすることで + イベントを並べ替えることができます。 + + いつものように、まずシナリオを開始してからゲームを始めてください。 + \n\nまだ勝てない場合は、テスト機能を使って各イベントが単独で動作することを確認してください。 + + 素晴らしい!これでイベントの優先順位がどのように機能するか、 + また画面イベントループがどのように動作するかを理解できました。これは複雑なシナリオを構築・管理するための鍵です。 + + diff --git a/feature/tutorial/src/main/res/values-ja/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-ja/strings_tutorial_events_state.xml new file mode 100644 index 000000000..aeabc7604 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ja/strings_tutorial_events_state.xml @@ -0,0 +1,139 @@ + + + + + 未使用のイベントを無効化 + 複数のイベントの状態を変更して、複雑なシナリオを最適化します。 + ターゲットを順番にタップ:青、赤、緑、次に黄色。 + + 新しいゲームです!今回は4つの色付きターゲットを順番にクリックする + 必要があります:まず青、次に赤、次に緑、最後に黄色。\n\nゲームを先に試してみるか、シナリオの設定を開いてすぐに + 自動化を始めることができます。 + + 4つの異なるターゲットを検出する必要があります。各色に1つずつ + イベントを作成します。\n\nまず青いターゲットから始めましょう。ゲームエリア内で青いターゲットを検出してクリックする + 新しいイベントを作成してください。 + + 複数のイベントを使う場合、それぞれに分かりやすい名前を付けることが + 大切です。このイベントに「青いターゲット」などの明確な名前を付けて、シナリオ内で簡単に識別できるようにしましょう。 + \n\n完了したら、新しい画像条件を作成して青いターゲットをキャプチャしてください。 + + ターゲットが動いているため、検出タイプを「検知エリア」に設定して + ゲームエリアを選択する必要があります。\n\nエリアの設定が完了したら保存してイベントダイアログに戻ってください。 + + 条件の設定が完了しました。次に、検出したターゲットをクリックする + ためのクリックアクションが必要です。\n\n新しいクリックアクションを作成して続けてください。 + + ターゲットが動いているため、固定の位置を指定することができません。 + 「タップ位置」フィールドを「検出された条件をクリックします」に変更し、青いターゲットの条件を選択してください。こうすることで、ターゲットが + 見つかった場所に正確にクリックが届きます。\n\n条件を選択したらクリックを保存してイベントダイアログに戻って + ください。 + + 青いターゲットのイベントが完成しました!次は同じ方法で赤いターゲット + のイベントを作成してください:ゲームエリアで検出してクリックします。赤いターゲットのイベントが保存されるとチュートリアルが + 進みます。 + + よくできました!次は緑のターゲットに同じイベントを作成してください。 + 緑のターゲットのイベントが保存されるとチュートリアルが進みます。 + + もう少しです!黄色のターゲットに最後のイベントを作成してください。 + 黄色のターゲットのイベントが保存されるとチュートリアルが進みます。 + + 4つのイベントの準備ができました。ゲームの順序で定義したので + 優先度は正しく設定されています。\n\nシナリオを保存してゲームでテストしてみましょう。 + + シナリオはターゲットを検出してクリックしていますが、おそらく + 勝つには遅すぎます。\n\n現在4つのイベントが同時にアクティブなので、毎フレームで青、赤、緑、黄色の順に確認します。 + どのターゲットをクリックしたばかりでも関係ありません。これは貴重な時間を無駄にしています!\n\n改善方法を学ぶには + シナリオの設定を開いてください。 + + 各イベントには初期状態があります:有効または無効で開始できます。 + 現在4つのイベントはすべて有効なので、毎フレームすべてがチェックされます。\n\n解決策は現在のターゲットのイベントだけを + アクティブにして残りを無効にすることです。ターゲットがクリックされると、そのイベントが次のターゲットを有効にして他を + 無効にします。\n\nまず青いターゲットのイベントを編集しましょう。 + + 青いターゲットは最初にクリックするものなので、そのイベントは有効な + 状態で開始する必要があります。ここでは変更不要です。\n\n青いターゲットをクリックしたときに赤いターゲットのイベントを + 有効にして他を無効にする「イベントの状態を変更する」アクションを追加するだけです。このアクションを追加するにはアクションエリアを + タップしてください。 + + アクションタイプ「イベントの状態を変更する」を選択してください。 + + このアクションを使うと、このイベントが発動したときにシナリオ内の + 任意のイベントの状態を変更できます。「変更なし」フィールドをタップして変更するイベントを選びましょう。 + + リスト内の各イベントに3つの状態のいずれかを設定できます: + \n• 有効化:イベントがアクティブになり毎フレームチェックされます \n• 無効化:イベントが非アクティブになり完全に + スキップされます \n• 反転:毎回アクティブと非アクティブを切り替えます \n\n青がクリックされたので、赤いターゲットの + イベントを有効にして他をすべて無効にしてください。完了したら「次へ」をタップしてください。 + 各イベント行には「有効化」「無効化」「切替」の3つの + オプションが表示されます。このアクションが実行されたときに適用したいものをタップしてください。 + + 完璧です!青いターゲットのイベントを保存してください。 + + 次は一覧から赤いターゲットのイベントを開いて、同じように設定 + してください。 + + 青いターゲットのイベントとは異なり、このイベントはシナリオの + 開始時にアクティブであってはなりません。そのターゲットが最初ではないからです。初期状態を無効に変更してください。 + + このターゲットをクリックしたときに次のターゲットのイベントを有効に + して他を無効にする「イベントの状態を変更する」アクションを追加してください。アクションエリアをタップしてください。 + + 切替を設定してください:緑のターゲットを有効にして他をすべて + 無効にしてください。完了したら「次へ」をタップしてください。 + + よくできました!次は緑のターゲットのイベントを開いて同じように + 設定してください。 + + 緑のターゲットも開始時にアクティブであってはなりません。初期状態を + 無効に変更してください。 + + 緑のターゲットをクリックしたときに黄色のターゲットのイベントを + 有効にして他を無効にする「イベントの状態を変更する」アクションを追加してください。アクションエリアをタップしてください。 + + 切替を設定してください:黄色のターゲットを有効にして他をすべて + 無効にしてください。完了したら「次へ」をタップしてください。 + + もう少しです!設定を完了するために黄色のターゲットのイベントを + 開いてください。 + + 黄色のターゲットはシーケンスの最後なので、無効な状態で開始する + 必要があります。初期状態を無効に変更してください。 + + 黄色のターゲットのイベントにも「イベントの状態を変更する」アクションを追加 + してください。黄色をクリックしたら最初に戻りたいので:青いターゲットを有効にして他をすべて無効にしてください。 + アクションエリアをタップしてください。 + + 切替を設定してください:青いターゲットを有効にして他をすべて + 無効にしてください。これにより、シーケンスが無限に繰り返されます。完了したら「次へ」をタップしてください。 + + すべてのイベントの設定が完了しました。変更を適用するには + シナリオを保存してください。 + + すべてのイベントが設定されました!シナリオを保存してからゲームを + 開始してください。ゲームを起動する前にシナリオを開始することを忘れないでください。\n\nシナリオには内部状態があるため、 + ゲームを再起動するたびにシナリオも再起動する必要があります。これにより前のゲームセッションの最後のターゲットを + 待ち続けることがなくなります。スタートボタンが表示されているかどうかを検出してイベントの状態をリセットすることで + 簡単に自動化できます。 + + 勝利しました!\n\nどのイベントが常にアクティブかを制御することで、 + シナリオは次に探すべきターゲットを常に正確に把握できます。順序外のターゲットを確認するフレームを無駄にすることが + ありません。\n\nこれがイベント切替アクションを使って順序的で状態駆動の自動化を構築できる仕組みです。 + + diff --git a/feature/tutorial/src/main/res/values-pt-rBR/strings_categories.xml b/feature/tutorial/src/main/res/values-pt-rBR/strings_categories.xml index af228aad8..5a4e62193 100644 --- a/feature/tutorial/src/main/res/values-pt-rBR/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-pt-rBR/strings_categories.xml @@ -1,4 +1,4 @@ - + + Ação Pausa + Aprenda como a pausa afeta a execução de ações e a detecção + Uma Ação Pausa suspende o cenário inteiro por uma + duração configurada: durante esse tempo, nenhuma ação é executada e nenhuma detecção de tela ocorre.\n\nUm + caso de uso muito comum é adicionar uma Pausa no final da sua lista de ações. Quando você toca em algum + lugar, o aplicativo precisa de tempo para processar o toque e exibir o resultado — e você geralmente quer + aguardar esse momento antes que o Klick\'r volte a analisar a tela.\n\nUma pausa entre duas ações também é + válida, mas adicionar uma ao final da lista costuma ser a necessidade mais importante. + + + Ação Deslizar + Aprenda como o gesto de deslizamento é realizado + Uma Ação Deslizar realiza um gesto de arrastar em + linha reta de uma posição inicial até uma posição final. Ambas as coordenadas são fixas e definidas na + configuração da ação.\n\nA duração controla quanto tempo o gesto leva do início ao fim: uma duração menor + produz um deslizamento mais rápido, enquanto uma maior produz um mais lento e controlado. + + + Deslocamento do clique + Aprenda a ajustar a posição do clique em uma condição detectada + Ao clicar em uma condição detectada, o clique + é aplicado por padrão no centro da área detectada.\n\nO deslocamento do clique permite mover essa posição + um número fixo de pixels ao longo dos eixos X e Y, em relação ao centro da condição. Isso é útil quando o + elemento que você quer tocar está próximo — mas não exatamente — do centro da área detectada. + + + Alvo do clique + Aprenda a configurar onde o clique será aplicado + Uma Ação Clique pode mirar dois tipos de + posições: uma posição estática sempre igual, ou a posição de uma condição detectada.\n\nEscolha seu método + no seletor de alvo no diálogo de configuração da ação. + Com uma posição estática, o clique sempre + ocorre nas mesmas coordenadas exatas, independentemente do que está na tela.\n\nLembre-se que essas + coordenadas são sensíveis à rotação: se o dispositivo girar, o clique pode acabar em uma posição inesperada + ou fora dos limites da tela. + Com uma posição de condição, o clique é + aplicado no centro de uma Condição de imagem detectada, seguindo o alvo onde quer que apareça na tela. + \n\nCom o operador AND, todas as condições devem ser cumpridas, então cada Condição de imagem tem uma + posição disponível. Você pode escolher livremente qualquer uma e refiná-la com um deslocamento. + Com o operador OR, apenas a primeira condição + cumprida é avaliada e as demais são ignoradas. Por isso, o Klick\'r não pode saber antecipadamente qual + condição será detectada.\n\nEm consequência, com o operador OR você não pode escolher uma condição específica + como alvo: o clique sempre será aplicado na primeira condição detectada, seja ela qual for em tempo de + execução. + + + Ordem das condições e velocidade + Como a ordem das suas condições afeta a + velocidade de verificação do evento + + A ordem das condições na lista afeta a + velocidade de verificação do evento.\n\nCom o operador E, a verificação para assim que a primeira condição NÃO + cumprida é encontrada. Colocar primeiro as condições menos prováveis permite ao app pular as demais mais cedo, + tornando seu evento mais rápido. + + Com o operador OU, a verificação para + assim que a primeira condição cumprida é encontrada. Colocar primeiro as condições mais prováveis permite ao + app terminar mais cedo, sem verificar o restante.\n\nEm ambos os casos, colocar a condição mais importante no + topo da lista é uma forma simples de manter seu cenário rápido. + + + + Estado dos eventos + Aprenda a ativar e desativar eventos enquanto um cenário + está em execução + + Cada evento do seu cenário (Eventos de Tela e + Eventos Gatilho) tem um estado: está ativado ou desativado.\n\nQuando ativado, o evento executa + normalmente e verifica suas condições como de costume. Quando desativado, é completamente ignorado, como se não + existisse.\n\nPor padrão, todos os eventos começam ativados. Você pode mudar isso com o campo Estado + inicial nas configurações do evento. + + Enquanto um cenário está em execução, você pode + mudar o estado de qualquer evento usando a ação Alterar estado do evento. Esta ação permite ativar, + desativar ou alternar o estado de um ou mais eventos.\n\nIsso abre muitas possibilidades: eventos que se ativam + um após o outro, eventos que se desativam sozinhos após executar uma vez, ou grupos de eventos onde apenas um + está ativo por vez. + + Quando todos os eventos do cenário estão + desativados, o cenário para sozinho. Não há mais nada a fazer, então o Klick\'r para automaticamente.\n\nÉ + uma forma simples de encerrar um cenário: faça seu último evento desativar todos os outros ao concluir sua + tarefa, e tudo para por conta própria. + + + + Lista de ações + Aprenda como a lista de ações é executada + As ações são executadas em ordem, uma após a outra. + Você pode alterar a ordem de uma ação usando os botões << e >>, ou tocando diretamente no seu + número de índice.\n\nTente manter suas listas de ações curtas. Um autoclicker comum realiza uma ação por evento + — esse é o modelo a seguir. Se você se encontrar adicionando muitas ações a um único evento, geralmente é sinal + de que o trabalho deve ser dividido em vários eventos, cada um reagindo ao que está realmente na tela. Essa é a + filosofia ver-e-agir do Klick\'r: detectar primeiro, depois agir. + + + Ação Escrever texto + Aprenda a inserir texto em um campo de entrada ativo + Antes que a ação Escrever texto seja executada, o + campo de entrada alvo já deve estar com foco, assim como você o tocaria para exibir o teclado.\n\nPara isso, + adicione uma ação Clique nesse campo antes da ação Escrever texto. Se uma animação de transição ocorrer após o + clique, uma ação Aguardar entre as duas pode ajudar a garantir que o campo esteja pronto.\n\nA ação também possui + uma opção Validar: quando ativada, ela pressiona automaticamente Enter após definir o texto, confirmando ou + enviando o valor. + Você pode inserir o valor de um contador no texto + a escrever. Pressione o botão Adicionar contador na configuração da ação para selecionar um contador: ele + inserirá o marcador {nomeDoContador} na posição atual do cursor.\n\nEm tempo de execução, cada marcador + {nomeDoContador} é substituído pelo valor atual do contador antes de o texto ser colado no campo. Por + exemplo, se um contador chamado maçãs tem o valor 18, o texto \"Tenho {maçãs} maçãs\" se torna + \"Tenho 18 maçãs\". + + + Ação do sistema + Aprenda a acionar ações de navegação do Android + Uma Ação do sistema executa uma das ações de navegação + integradas do Android: Voltar, Início ou Recentes.\n\nSão as mesmas ações que os botões de navegação na parte + inferior da tela. Não requerem coordenadas e funcionam no nível do sistema, independentemente do aplicativo + aberto. + + + Ação Alterar contador + Aprenda a modificar o valor de um contador + Uma ação Alterar contador aplica uma operação + a um contador usando um valor estático predefinido. Três operações estão disponíveis: adicionar o valor ao + contador (+), subtrair do contador (−) ou definir o contador para esse valor exato (=).\n\nEsta é a forma mais + comum de atualizar um contador — por exemplo, adicionar 1 toda vez que uma condição é detectada, ou redefini-lo + para 0 quando um objetivo é atingido. + Em vez de um valor estático, você pode usar o + valor atual de outro contador como operando. As mesmas três operações (+, −, =) se aplicam, mas o valor é lido + do contador selecionado em tempo de execução, em vez de ser fixo na configuração.\n\nIsso permite construir + cenários dinâmicos onde os contadores interagem entre si. + + + Ação Notificação + Aprenda a exibir uma notificação durante seu cenário + Uma ação Notificação exibe uma notificação + Android com um título e uma mensagem de sua escolha.\n\nVocê pode inserir o valor atual de um contador no texto + da notificação usando o botão Adicionar contador, ou digitando diretamente o marcador {nomeDoContador}. + Em tempo de execução ele é substituído pelo valor do contador — por exemplo, \"Tenho {maçãs} maçãs\" se torna + \"Tenho 18 maçãs\". + O nível de importância da notificação controla + o grau de intrusividade com que ela é apresentada. Níveis mais altos podem mostrar um banner e reproduzir um + som, enquanto os mais baixos são entregues silenciosamente na gaveta de notificações.\n\nO comportamento exato + depende do dispositivo e pode ser personalizado nas configurações de notificação do Android para o Klick\'r. + + + Ação Alterar estado do evento + Aprenda a ativar e desativar eventos em tempo de execução + Um evento desativado é completamente ignorado + durante o loop do cenário — suas condições nunca são verificadas e suas ações nunca são executadas. Isso + significa que não consome nenhum tempo de processamento.\n\nDesativar eventos que você não está usando é uma + ótima maneira de melhorar o desempenho. Por exemplo, em um cenário que alterna entre uma fase de menu e uma + fase de jogo, desativar todos os eventos do menu durante a fase de jogo (e vice-versa) mantém apenas os eventos + relevantes ativos a cada momento. + Ao configurar a ação, você pode optar por + alterar o estado de todos os eventos do cenário de uma vez, ou definir um novo estado para cada evento + individualmente.\n\nTrês mudanças de estado estão disponíveis para cada evento: ativá-lo, desativá-lo ou + alterná-lo a partir de seu valor atual — um evento ativado se torna desativado e um desativado se torna ativado. + Se todos os eventos do cenário acabarem + desativados ao mesmo tempo, o cenário para automaticamente, pois não há mais nada a executar.\n\nIsso pode ser + usado intencionalmente como uma forma limpa de encerrar um cenário após atingir um objetivo: uma última ação + Alterar estado do evento que desativa todos os eventos encerrará o cenário. + + + Ação Intent + Aprenda a se comunicar com outros aplicativos + Intents são a forma como os aplicativos se comunicam + entre si no Android. A ação Intent permite que você use esse sistema diretamente no seu cenário.\n\nUm conjunto + de modelos predefinidos está disponível para facilitar isso. O mais comum é Iniciar aplicativo, que abre outro + app no seu dispositivo exatamente como se você tivesse tocado no seu ícone no lançador. + A guia Avançado permite definir um Intent bruto + manualmente, dando controle total sobre a ação, categoria, dados e extras. Isso não é recomendado para usuários + comuns — é voltado para desenvolvedores Android que já sabem como os Intents funcionam.\n\nMais modelos prontos + para usar serão adicionados em atualizações futuras para facilitar os casos de uso comuns sem precisar recorrer + às opções avançadas. + + + + Prioridade dos eventos + Aprenda como a ordem dos eventos na sua lista afeta quais eventos são executados + Cada quadro capturado da sua tela é processado verificando seus eventos um a um, de cima para baixo.\n\nA posição de um evento na sua lista determina quando ele tem a chance de ser executado. Por padrão, assim que as condições de um evento são atendidas e suas ações são executadas, o quadro é considerado concluído. O processamento para naquele quadro e o próximo recomeça a partir do primeiro evento da lista.\n\nIsso significa que por padrão apenas um evento pode ser executado por quadro. + Você pode alterar esse comportamento usando o campo Continue executando nas configurações do evento. Quando ativado, após esse evento ser executado, o processamento continua para o próximo evento na lista em vez de parar.\n\nIsso permite que vários eventos sejam executados no mesmo quadro.\n\nExemplo: sua lista contém o Evento A seguido do Evento B. Se o Evento A continua sendo detectado e não tem Continue executando ativado, ele será executado em cada quadro e o Evento B nunca terá chance de executar.\n\nAtive Continue executando no Evento A e ambos os eventos serão verificados em cada quadro.\n\nUm tutorial interativo também está disponível para praticar esse conceito. + + + + Recarga de eventos + Aprenda como a recarga de um evento se comporta no seu cenário + O parâmetro de recarga de eventos permite que você + ignore um evento por um período de tempo determinado após ser cumprido. \n\nUm evento em estado de recarga ainda + é considerado ativado: a recarga e o estado do evento são independentes. \n\nSe o evento for desativado enquanto + estiver em recarga, o temporizador de recarga será limpo, de modo que o tempo de espera não se aplica mais + quando o evento é reativado. + + + + Usar valores de contador + Aprenda as diferentes formas de exibir e usar os valores de contador no seu cenário + + Você pode mostrar o valor atual de um contador + dentro de uma ação Notificação. Isso é útil para monitorar o progresso enquanto o seu cenário está em + execução, ou para exibir um resumo no final.\n\nPara inserir um contador, pressione o botão Adicionar + contador na configuração da ação. Isso adiciona um marcador como {counterName} no seu texto. Em + tempo de execução, o marcador é substituído pelo valor atual do contador. Por exemplo, se um contador + chamado score tem o valor 42, o texto \"Pontuação atual: {score}\" se torna + \"Pontuação atual: 42\". + + Você também pode inserir o valor de um + contador em uma ação Escrever texto, para que o texto digitado inclua o valor atual no momento em que a + ação é executada.\n\nO marcador funciona da mesma forma que na ação Notificação: pressione o botão Adicionar + contador ou digite {counterName} diretamente. Por exemplo, se um contador chamado score tem + o valor 42, o texto \"Minha pontuação é {score}\" se torna \"Minha pontuação é 42\". + + Os valores dos contadores são registrados no + relatório de depuração. Se algo não estiver funcionando como esperado no seu cenário, capturar um relatório + de depuração mostrará exatamente como seus contadores mudaram ao longo do tempo, facilitando encontrar o + problema. + diff --git a/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_not_visible.xml index 973cf90c8..75dd6c54d 100644 --- a/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - Combinação de múltiplas condições - Crie e combine múltiplas condições para seu evento - Clique no botão azul apenas quando o botão vermelho estiver visível - - Vamos mudar as regras do jogo novamente. O alvo azul parou de se mover, - mas agora só deve ser clicado quando o alvo vermelho estiver visível.\n\nPrimeiro, inicie o jogo e veja se você consegue - vencer por conta própria. - - Mais uma vez, parece impossível vencer manualmente, então vamos usar o - Smart AutoClicker.\n\nSeu cenário do tutorial anterior foi mantido e carregado para este tutorial, mas precisaremos - alterar alguns parâmetros para vencer este novo jogo.\n\nClique no ícone de configuração de cenário para começar a - atualizar seu novo cenário. - - Ainda queremos clicar no alvo azul, mas apenas quando o vermelho estiver visível.\n - Então, precisamos adicionar uma condição para este alvo vermelho em nosso Evento.\n\nClique no evento criado anteriormente - para editá-lo. - - Vamos combinar várias condições, então precisamos verificar o Operador de Condição - para este evento.\n\nO Operador de Condição indica como múltiplas condições serão interpretadas juntas.\n - \'Um\' significa que apenas uma das Condições deste Evento deve ser cumprida para executar as Ações.\n\n\'Todos\' significa - que todas as Condições deste Evento devem ser cumpridas para executar as Ações.\n\nComo queremos detectar se dois - elementos estão sendo exibidos juntos, vamos usar \'Todos\'. - - Agora precisamos atualizar nossas Condições.\n\nClique na campo Condições para - exibir a lista de Condições. - - A Condição anterior de detecção do alvo azul ainda está correta, mas precisamos - de uma nova para o alvo vermelho.\n\nClique no botão de criar Condição para criar uma nova Condição para ele. - - Assim como para o alvo azul, inicie o jogo para mostrar o alvo vermelho. - Assim que ele estiver visível, tire uma captura de tela dele! - Use o botão de captura no menu flutuante para tirar a captura de tela. - - Sua captura de tela contém o alvo vermelho? Você pode recortá-la para obter apenas - a parte interessante para a detecção, o alvo vermelho. - Se sua captura de tela não contém o alvo vermelho, você pode - pressionar este botão para tirar uma nova. - - Sua imagem de Condição está agora registrada!\nComo o alvo vermelho não está se movendo, - podemos manter a configuração padrão.\nClique no botão Salvar para registrá-la e retornar à lista de condições. + Visibilidade de condições + Use a opção Visibilidade para acionar um + clique quando um alvo não estiver na tela + Toque no botão azul somente quando o + botão vermelho não estiver visível - Feche a lista de condições para retornar à configuração do evento. + Novas regras! O alvo azul parou de se + mover, mas só deve ser tocado quando o alvo vermelho não estiver visível. + \n\nInicie o jogo e veja se consegue vencer por conta própria. - Agora temos duas Condições, uma para cada alvo, e as Ações serão executadas - apenas se ambos forem detectados.\n\nClique na campo Ações para exibir a lista de Ações para nosso Evento. - - A ação já está configurada para clicar no personagem azul, e só será - executada quando os personagens azul e vermelho estiverem visíveis juntos.\n\nEste é exatamente o comportamento - que precisamos para vencer o jogo, então não há necessidade de editar nossa Ação de clique.\n\nClique no botão - Salvar para registrá-la e retornar à lista de ações. + Mais uma vez, parece impossível vencer + manualmente, então vamos usar o Klick\'r. \n\nAbra o menu de configuração do cenário, crie um novo Evento de + Tela e comece a adicionar condições para os alvos do jogo. - Clique no botão Salvar para salvar seu evento. + Primeiro, precisamos de uma condição + que verifique quando o alvo vermelho NÃO está visível na tela. \n\nCrie uma nova condição de imagem e capture + o alvo vermelho. + + Queremos tocar somente quando o alvo + vermelho não estiver visível, então defina a opção «Está visível» como Não. Assim, a condição só será atendida + quando o alvo vermelho estiver ausente da tela. + + As outras configurações estão certas + para o nosso caso — salve esta condição. + + Essa condição sozinha é suficiente para + vencer o jogo, mas ela também seria acionada quando o jogo não estiver em execução, o que não é ideal. + \n\nPara evitar isso, vamos combiná-la com uma segunda condição que verifique se o alvo azul está visível. + Crie uma nova Condição de Imagem e capture o alvo azul. + + Para esta condição queremos verificar + que o alvo azul está visível, então as configurações padrão estão todas corretas. Salve a condição e volte ao + Evento para continuar. + + Com várias condições, o operador de + condição é importante. Queremos que o evento seja acionado quando o alvo azul estiver visível E o vermelho não + estiver, então precisamos do operador E; e ele já é o padrão, então estamos bem. + \n\nAgora crie uma nova ação de clique para continuar. + + Queremos tocar no alvo azul, então + selecione o tipo de posição «Na Condição» e escolha a Condição de Imagem do alvo azul. + \n\nQuando terminar, salve o clique, depois seu evento e cenário, e volte ao jogo. + + Inicie seu cenário e comece o jogo + para vencer! \n\nSe não funcionar, verifique se suas condições foram capturadas corretamente e se a duração do + clique está definida como 1 ms. + + Parabéns! Você aprendeu a usar uma + condição «Não visível». Sempre combine-a com pelo menos uma outra condição para evitar acionar ações + involuntariamente durante todo o seu cenário. - Todas as mudanças devem ser salvas no seu cenário para serem registradas.\n - Clique no botão de salvar para salvar suas alterações. - - Estamos prontos para vencer este jogo!\n\nClique no botão de iniciar para iniciar - a detecção e, em seguida, inicie o jogo. - - Parabéns!\n\nAgora você sabe como combinar múltiplas Condições para um Evento, - mas há muito mais para aprender! diff --git a/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..2db83c721 --- /dev/null +++ b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,70 @@ + + + + + + Operador de condição E + Use o operador E para clicar apenas quando + vários alvos estiverem visíveis ao mesmo tempo + Toque no botão azul somente quando tanto o + alvo azul quanto o vermelho estiverem visíveis + + Novas regras! O jogo agora mostra dois + alvos. Você deve tocar no azul, mas somente quando os dois alvos, azul e vermelho, estiverem na tela ao mesmo + tempo. \n\nInicie o jogo e veja se consegue acompanhar o ritmo por conta própria. + + O tempo é muito apertado para gerenciar + manualmente, então vamos usar o Klick\'r. \n\nAbra o menu de configuração do cenário, crie um novo Evento de + Tela e comece a adicionar condições para os alvos do jogo. + + Precisamos de uma condição por alvo. + Vamos começar com o azul. \n\nCrie uma nova condição de imagem e capture o alvo azul. + + Queremos que esta condição seja atendida + quando o alvo azul estiver visível, então as configurações padrão estão todas corretas. Salve esta + condição. + + Agora vamos adicionar a segunda condição + para o alvo vermelho. \n\nCrie outra condição de imagem e capture o alvo vermelho. + + O mesmo aqui — o alvo vermelho deve estar + visível, então as configurações padrão estão corretas. Salve esta condição e volte ao Evento. + + Com duas condições definidas, o operador + de condição determina como elas são combinadas. Selecione o operador usando o seletor mostrado acima. + \n\n• E: o evento é ativado somente quando TODAS as condições são atendidas.\n• OU: o evento é ativado + assim que UMA condição for atendida.\n\nPara o nosso jogo, precisamos dos dois alvos na tela ao mesmo tempo, + então selecione E. + O seletor do operador de + condição + + E já é o operador padrão, então estamos + prontos. \n\nAgora abra a seção Ações e crie uma nova ação de clique. + + Queremos tocar no alvo azul, então + selecione o tipo de posição «Na Condição» e escolha a condição de imagem do alvo azul. + \n\nQuando terminar, salve o clique, depois seu evento e cenário, e volte ao jogo. + + Inicie seu cenário e comece o jogo para + vencer! \n\nSe não funcionar, verifique se ambas as condições foram capturadas corretamente e se a duração do + clique está definida como 1 ms. + + Parabéns! Você aprendeu a usar o operador + E. O evento agora é ativado apenas quando todas as suas condições são atendidas ao mesmo tempo. + + diff --git a/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..7adb473f3 --- /dev/null +++ b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,73 @@ + + + + + + Operador de condição OU + Use o operador OU para clicar no primeiro alvo + que aparecer na tela + Toque em qualquer alvo assim que ele aparecer + na tela + + Novo desafio! Dois alvos podem aparecer na + tela. O vermelho vale 2 pontos e o azul vale 1 ponto, então toque no que aparecer o mais rápido possível. + \n\nInicie o jogo e veja como você se sai. + + Rápido demais para gerenciar manualmente, + então vamos usar o Klick\'r. \n\nAbra o menu de configuração do cenário, crie um novo Evento de Tela e comece + a adicionar condições para os alvos do jogo. + + Precisamos de uma condição por alvo. Vamos + começar com o azul. \n\nCrie uma nova condição de imagem e capture o alvo azul. + + Esta condição deve ser ativada quando o alvo + azul estiver visível, então as configurações padrão estão todas corretas. Salve esta condição. + + Agora vamos adicionar a segunda condição para + o alvo vermelho. \n\nCrie outra condição de imagem e capture o alvo vermelho. + + O mesmo aqui, o alvo vermelho deve estar + visível, então as configurações padrão estão corretas. Salve esta condição. + + Com OU, as condições são verificadas em + ordem e o evento é ativado assim que a primeira corresponde, então a ordem das suas condições importa. + \n\nO alvo vermelho concede mais pontos, então queremos que ele seja verificado primeiro. Use o botão « para + movê-lo antes do azul, depois retorne ao diálogo Evento. + + Agora defina o operador de condição como OU. + O evento será ativado assim que qualquer um dos alvos aparecer. Se ambos estiverem visíveis ao mesmo tempo, a + condição vermelha será detectada primeiro, pois tem maior prioridade. \n\nSelecione OU. + + O operador OU está configurado. Abra a seção + Ações e crie uma nova ação de clique. + + Queremos clicar no alvo que ativou o evento. + Selecione o tipo de posição «Na Condição». Com OU, apenas uma condição pode ser detectada positivamente de + cada vez, então não é necessário selecionar uma condição específica. O Klick\'r clicará automaticamente na + localização da condição que correspondeu. \n\nQuando terminar, salve o clique, depois seu evento e cenário, + e volte ao jogo. + + Inicie seu cenário e comece o jogo para + vencer! \n\nSe não funcionar, verifique se suas condições foram capturadas corretamente e se a duração do + clique está definida como 1 ms. + + Parabéns! Você aprendeu a usar o operador + OU e por que a prioridade das condições é importante. Ao colocar a condição vermelha primeiro, o Klick\'r + sempre favorece o alvo de maior valor quando ambos estão visíveis ao mesmo tempo. + + diff --git a/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..4b0748668 --- /dev/null +++ b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_counters_basics.xml @@ -0,0 +1,129 @@ + + + + Noções básicas de contadores + Aprenda como usar a ação Alterar contador e a condição Quando o + contador for alcançado. + Clique 10 vezes no alvo azul, depois clique uma vez no alvo + vermelho + + Bem-vindo ao tutorial de Contadores! + \n\nAqui, você irá automatizar um jogo onde clica no alvo azul 10 vezes e depois clica no alvo vermelho uma vez + para validar sua contagem e ganhar 10 pontos. Você pode tentar o jogo primeiro ou ir direto para a configuração + do cenário. + + Primeiro, precisamos criar um Evento de Tela que detecta o + alvo azul e clica nele. \n\nClique em Criar Evento para começar. + + Vamos começar adicionando uma condição para detectar o alvo + azul. Clique no campo Condições para abrir a lista de condições e criar essa condição. \n\nO tutorial continuará + assim que sua condição for criada. + + Ótimo! Agora clique no campo Ações para adicionar as ações + que serão executadas quando o alvo azul for detectado. + + Primeiro precisamos de uma ação Clique para tocar no alvo + azul. Clique no botão criar para adicionar uma nova ação. + + Configure o clique para tocar no alvo azul e salve a ação. + \n\nO tutorial continuará assim que o clique for salvo. + + Também precisamos contar quantas vezes clicamos no alvo azul. + Isso pode ser feito com a ação Alterar contador, somando um a cada clique. \n\nClique no botão criar novamente + para adicionar uma segunda ação. + + Selecione a ação Alterar contador para incrementar um + contador a cada vez que o alvo azul for clicado. + + Primeiro, precisamos escolher qual contador atualizar. + Clique em Selecionar um contador para abrir a lista de contadores. + + A lista está vazia por enquanto. Clique no botão criar para + criar um novo contador. Dê um nome a ele (ex.: "Cliques azuis"), mantenha o valor inicial em 0, depois salve e + selecione-o. + + Agora configure como o contador muda a cada vez que o alvo + azul é clicado. \n\nDefina o operador como + e o valor como 1, para que o contador aumente em 1 a cada clique. + \n\nDepois salve a ação e volte ao diálogo do Evento. + O valor pode ser um número fixo ou o valor atual + de outro contador. + + Ótimo! Este Evento de Tela agora irá clicar no alvo azul e + incrementar seu contador a cada detecção. \n\nSalve o evento para voltar ao cenário. + + Agora precisamos de um evento que reaja quando o contador + chegar a 10. Esse tipo de evento não é acionado pela tela, então é um Evento de gatilho. + \n\nClique na aba Eventos de trigger para abrir a lista de Eventos de trigger. + + Clique no botão criar para adicionar um novo Evento de + gatilho. + + Assim como um Evento de Tela, um Evento de gatilho precisa + de condições. Clique no campo Condições para abrir a lista de condições e criar uma nova condição de + gatilho. + + Selecione o tipo de condição Quando o contador for + alcançado para acionar esse evento quando um contador atingir um valor específico. + + Selecione o contador que você criou anteriormente (o que + conta os cliques azuis) para usá-lo como gatilho. + + Agora defina a comparação para que a condição seja + satisfeita quando o contador for igual a 10. Há vários operadores de comparação, mas aqui precisamos verificar + a igualdade, então selecione \"=\". Depois insira 10 como valor, salve a condição e volte ao diálogo do + Evento. + O valor a comparar pode ser um número fixo ou o + valor atual de outro contador. + + Condição definida! Agora precisamos definir o que acontece + quando o contador chega a 10. Clique no campo Ações para abrir a lista de ações. + + Primeiro, crie uma ação Clique e posicione-a manualmente + sobre o alvo vermelho para validar a contagem. + + Configure o clique para tocar no alvo vermelho e salve a + ação. Observe que em um Evento de gatilho, a posição do clique deve sempre ser definida manualmente. + \n\nO tutorial continuará assim que o clique for salvo. + + Agora crie uma segunda ação para zerar o contador. Clique + no botão criar novamente e selecione a ação Alterar contador. + + Queremos definir o contador de cliques azuis como 0, então + primeiro selecione o contador de cliques azuis. + + Defina o operador como = e o valor como 0 para zerar o + contador após cada validação. Depois salve a ação e volte ao diálogo do Evento para continuar. + + Este Evento de gatilho irá clicar no alvo vermelho e zerar + o contador toda vez que 10 cliques azuis forem contados. A lista de Eventos de trigger é executada entre cada + quadro de tela, antes da lista de Eventos de tela, então assim que o contador chegar a 10, este evento é + executado imediatamente: o alvo vermelho é clicado e o contador zerado, pronto para recomeçar. + \n\nSalve o evento para voltar ao cenário. + + O cenário está completo! Ele irá clicar no alvo azul, + contar cada clique e depois validar com o alvo vermelho a cada 10 cliques e recomeçar. \n\nSalve o cenário para + aplicar sua configuração. + + Tudo pronto! Inicie o cenário, depois abra o jogo e veja o + Klick\'r cuidar da contagem por você. + + Muito bem! Você aprendeu como usar Contadores para + rastrear valores em múltiplos eventos. \n\nCombinados com a ação Alterar contador e a condição Quando o + contador for alcançado, agora você pode criar automações que reagem a padrões repetidos. + + diff --git a/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..371cdb885 --- /dev/null +++ b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_events_priority.xml @@ -0,0 +1,71 @@ + + + + + Priorizar um evento + Priorizar um Evento em relação a outro Evento + Clique o mais rápido possível nos alvos. Azul = 1 ponto; + Vermelho = 10 pontos + + Novo jogo! Precisamos clicar nos alvos o mais rápido + possível, mas o vermelho vale mais pontos. Você pode testar o jogo primeiro ou abrir o menu de configuração + do cenário para começar a automatizá-lo. + + Queremos detectar dois alvos diferentes, o azul e o + vermelho. Neste tutorial, criaremos dois eventos distintos: um para o alvo azul e outro para o alvo vermelho. + \n\nPrimeiro, crie o Evento para o alvo azul; ele deve clicar nele quando detectado. Não se esqueça de usar + os recursos de teste para garantir que sua condição seja detectada corretamente. \n\nO tutorial avançará + quando o seu Evento do alvo azul for salvo. + + Ótimo! Agora precisamos da mesma coisa, mas para o alvo + vermelho. Clique no botão Criar evento e crie um para o alvo vermelho; ele deve clicar nele quando detectado. + \n\nO tutorial avançará quando o seu Evento do alvo vermelho for salvo. + + Nossa lista agora tem dois eventos, um para cada alvo. + Salve seu Cenário e teste-o no jogo. + + Algo parece errado. O cenário só clica no alvo azul, + ignorando completamente o vermelho, o que nos impede de ganhar o jogo. \n\nPor que isso acontece? Porque o + evento azul está antes do vermelho, e como ele é sempre acionado, o quadro atual não é mais avaliado e o + próximo começa do início da lista de Eventos. \n\nHá várias formas de corrigir isso. Abra o diálogo de + configuração do cenário para aprender como. + + Podemos resolver o problema de duas formas: \n\nPodemos + alterar a opção \"Continuar executando\" do evento do alvo azul para continuar processando o mesmo quadro e + também executar o evento vermelho. Isso acionará os dois cliques quando ambos os alvos estiverem visíveis ao + mesmo tempo. \n\nOu podemos mover o evento do alvo vermelho para o topo da lista, para que seja verificado + primeiro e sempre clicado quando visível, mas o alvo azul não será mais clicado quando o vermelho também + estiver visível. \n\nA diferença principal entre as duas soluções é a velocidade: colocar o evento vermelho + primeiro significa que reagimos o mais rápido possível quando ele aparece, sendo ligeiramente mais lentos + quando apenas o alvo azul está visível. + + Como o jogo dá 10 pontos pelo alvo vermelho, queremos + reagir o mais rápido possível quando ele aparece, movendo o evento vermelho para o topo da lista. \n\nMova o + evento vermelho para o primeiro lugar e salve o cenário. Agora você deve conseguir vencer o jogo. + Você pode reordenar os Eventos pressionando + longamente neste ícone e arrastando o evento para o lugar correto. + + Como de costume, inicie seu cenário primeiro e depois o + jogo. \n\nSe ainda não conseguir vencer, certifique-se de que cada evento funciona individualmente usando os + recursos de teste. + + Ótimo! Agora você entende como funciona a prioridade de + eventos e como o loop de Eventos de Tela se comporta. Isso é fundamental para criar e gerenciar cenários + complexos. + + diff --git a/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_events_state.xml new file mode 100644 index 000000000..59fa1d095 --- /dev/null +++ b/feature/tutorial/src/main/res/values-pt-rBR/strings_tutorial_events_state.xml @@ -0,0 +1,145 @@ + + + + + Desativar eventos não utilizados + Altere o estado de vários eventos para otimizar um cenário complexo. + Clique nos alvos em ordem: azul, vermelho, verde e depois amarelo. + + Novo jogo! Desta vez você precisa clicar em quatro alvos + coloridos em ordem: primeiro azul, depois vermelho, depois verde e finalmente amarelo. \n\nVocê pode experimentar + o jogo primeiro para ver como funciona, ou abrir diretamente a configuração do cenário para começar a + automatizá-lo. + + Precisamos detectar quatro alvos diferentes, um para cada cor. + Vamos criar um Evento por alvo. \n\nComece com o alvo azul: crie um novo Evento que o detecte dentro da área de + jogo e clique nele. + + Ao usar vários eventos, é importante personalizar o nome de cada + um para se organizar. Dê a este Evento um nome claro, como \"Alvo azul\", para identificá-lo facilmente no seu + cenário. \n\nQuando terminar, crie uma nova condição de Imagem e capture o alvo azul. + + Como o alvo está se movendo, precisamos definir o tipo de + detecção como \"Área de detecção\" e selecionar a área de jogo. \n\nAssim que a área estiver corretamente + configurada, salve-a e volte ao diálogo Evento. + + Sua condição está definida. Agora precisamos de uma ação Clique + para que o Evento clique no alvo detectado. \n\nCrie uma nova ação Clique para continuar. + + O alvo está se movendo, então não podemos definir uma posição + fixa. Defina o campo \"Clique em\" para \"Clique na condição detectada\" e selecione sua condição de alvo azul. Assim, o clique sempre + cairá exatamente onde o alvo foi encontrado.\n\nAssim que a condição for selecionada, salve o clique e volte ao + diálogo Evento. + + O Evento do alvo azul está pronto! Agora crie um Evento para o + alvo vermelho da mesma forma: detecte-o na área de jogo e clique nele. O tutorial avançará quando seu Evento do + alvo vermelho estiver salvo. + + Ótimo! Agora crie o mesmo Evento para o alvo verde. O tutorial + avançará quando seu Evento do alvo verde estiver salvo. + + Quase lá! Crie um último Evento para o alvo amarelo. O tutorial + avançará quando seu Evento do alvo amarelo estiver salvo. + + Os quatro Eventos estão prontos. Como os definimos na ordem da + sequência do jogo, sua prioridade está correta. \n\nSalve seu Cenário e teste-o no jogo para ver como ele se + sai. + + O cenário está detectando e clicando nos alvos, mas + provavelmente é lento demais para vencer. \n\nAtualmente, os quatro Eventos estão ativos ao mesmo tempo, então + em cada quadro o cenário verifica azul, depois vermelho, depois verde, depois amarelo; independentemente de qual + alvo foi clicado por último. Isso desperdiça tempo precioso! \n\nAbra a configuração do cenário para aprender + como melhorar isso. + + Cada Evento tem um estado inicial: pode começar ativado ou + desativado. Agora, os quatro Eventos estão ativados, então todos são verificados em cada quadro. \n\nA solução + é manter ativo apenas o Evento do alvo atual e desativar os demais. Quando um alvo é clicado, seu Evento + ativará o próximo e desativará os outros. \n\nVamos começar editando o Evento do alvo azul. + + O alvo azul é o primeiro a ser clicado, então seu Evento deve + começar ativado; sem mudanças necessárias aqui. \n\nPrecisamos apenas adicionar uma ação \"Alterar estado do evento\" + para que, quando o alvo azul for clicado, o Evento do alvo vermelho seja ativado e os outros desativados. Toque + na área Ações para adicionar essa ação. + + Selecione o tipo de ação \"Alterar estado do evento\". + + Esta ação permite alterar o estado de qualquer Evento do seu + cenário quando este Evento for acionado. Toque no campo \"Nenhuma alteração\" para selecionar quais Eventos + alterar. + + Para cada Evento da lista, você pode definir um de três + estados: \n• Ativar: o Evento fica ativo e será verificado em cada quadro \n• Desativar: o Evento fica inativo + e é completamente ignorado \n• Inverter: alterna entre ativo e inativo a cada vez \n\nComo azul acabou de ser + clicado, ative o Evento do alvo vermelho e desative todos os outros. Toque em Próximo quando terminar. + Cada linha de Evento mostra três opções: Ativar, + Desativar e Alternar. Toque na que deseja aplicar quando esta ação for executada. + + Perfeito! Salve o Evento do alvo azul. + + Agora abra o Evento do alvo vermelho na lista para configurá-lo + da mesma forma. + + Ao contrário do Evento do alvo azul, este Evento não deve estar + ativo no início do cenário, pois seu alvo não é o primeiro. Mude seu estado inicial para Desativado. + + Agora adicione uma ação \"Alterar estado do evento\" para que, quando + este alvo for clicado, o Evento do próximo alvo seja ativado e os outros desativados. Toque na área Ações. + + Defina as alternâncias: ative o alvo verde e desative todos os + outros. Toque em Próximo quando terminar. + + Bom trabalho! Agora abra o Evento do alvo verde para + configurá-lo da mesma forma. + + O alvo verde também não deve estar ativo no início. Mude seu + estado inicial para Desativado. + + Agora adicione uma ação \"Alterar estado do evento\" para que, quando o + alvo verde for clicado, o Evento do alvo amarelo seja ativado e os outros desativados. Toque na área Ações. + + Defina as alternâncias: ative o alvo amarelo e desative todos + os outros. Toque em Próximo quando terminar. + + Quase pronto! Abra o Evento do alvo amarelo para concluir a + configuração. + + O alvo amarelo é o último da sequência, então também deve + começar desativado. Mude seu estado inicial para Desativado. + + Adicione também uma ação \"Alterar estado do evento\" ao Evento do alvo + amarelo. Quando amarelo for clicado, queremos voltar ao início: ative o alvo azul e desative todos os outros. + Toque na área Ações. + + Defina as alternâncias: ative o alvo azul e desative todos os + outros. Dessa forma, a sequência se repetirá indefinidamente. Toque em Próximo quando terminar. + + Todos os Eventos estão agora completamente configurados. Salve + seu Cenário para aplicar as alterações. + + Todos os Eventos estão configurados! Salve seu Cenário e então + inicie o jogo. Lembre-se de iniciar seu Cenário antes de lançar o jogo. \n\nComo nosso cenário tem um estado + interno, você precisa reiniciá-lo toda vez que reiniciar o jogo para garantir que ele não esteja esperando o + último alvo da sessão anterior. Isso pode ser facilmente automatizado detectando se o botão de início está + visível para redefinir os estados dos eventos. + + Você venceu! \n\nControlando quais Eventos estão ativos a + qualquer momento, o cenário sempre sabe exatamente qual alvo procurar a seguir — sem quadros desperdiçados + verificando alvos fora de sequência. \n\nÉ assim que a ação Alternar evento permite criar automações + sequenciais e baseadas em estado. + + diff --git a/feature/tutorial/src/main/res/values-ru/strings_categories.xml b/feature/tutorial/src/main/res/values-ru/strings_categories.xml index accbea341..7f88159df 100644 --- a/feature/tutorial/src/main/res/values-ru/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-ru/strings_categories.xml @@ -1,4 +1,4 @@ - + + Действие «Пауза» + Узнайте, как пауза влияет на выполнение действий и обнаружение + Действие «Пауза» приостанавливает весь сценарий на + заданное время: в этот период не выполняется ни одно действие и не происходит никакого обнаружения на + экране.\n\nОчень распространённый случай — добавить паузу в конец списка действий. Когда вы нажимаете + куда-либо, приложению нужно время, чтобы обработать нажатие и отобразить результат — и, как правило, + вы хотите подождать этого момента, прежде чем Klick\'r снова начнёт анализировать экран.\n\nПауза между + двумя действиями тоже уместна, но добавление паузы в конец списка обычно важнее. + + + Действие «Свайп» + Узнайте, как выполняется жест свайпа + Действие «Свайп» выполняет жест перетаскивания по + прямой линии из начальной точки в конечную. Обе координаты фиксированы и задаются в настройках + действия.\n\nДлительность определяет время, которое занимает жест от начала до конца: меньшая + длительность даёт более быстрый свайп, большая — более медленный и плавный. + + + Смещение клика + Узнайте, как скорректировать позицию клика по обнаруженному условию + При клике по обнаруженному условию нажатие по + умолчанию применяется к центру обнаруженной области.\n\nСмещение клика позволяет сдвинуть эту позицию + на фиксированное количество пикселей по осям X и Y относительно центра условия. Это удобно, когда + элемент, на который нужно нажать, находится близко к центру обнаруженной области, но не точно в нём. + + + Цель клика + Узнайте, как настроить место применения клика + Действие «Клик» может быть направлено на + два типа позиций: фиксированная позиция, которая всегда одинакова, или позиция обнаруженного условия. + \n\nВыберите метод прицеливания в селекторе цели в диалоге настройки действия. + При фиксированной позиции клик всегда + происходит в одних и тех же точных координатах, независимо от того, что отображается на экране.\n\nИмейте + в виду, что эти координаты чувствительны к повороту: если устройство повернётся, клик может оказаться + в неожиданном месте или за пределами экрана. + При позиции условия клик применяется к + центру обнаруженного условия изображения, следуя за целью, где бы она ни появилась на экране.\n\nС + оператором AND все условия должны быть выполнены, поэтому каждое условие изображения имеет доступную + позицию. Вы можете свободно выбрать любую и уточнить её с помощью смещения. + С оператором OR оценивается только первое + выполненное условие, остальные игнорируются. Поэтому Klick\'r не может заранее знать, какое условие + будет обнаружено.\n\nСледовательно, с оператором OR нельзя выбрать конкретное условие в качестве цели: + клик всегда будет применён к первому обнаруженному условию, каким бы оно ни оказалось во время + выполнения. + + + Порядок условий и скорость + Как порядок условий влияет на скорость проверки + события + + Порядок условий в списке влияет на + скорость проверки события.\n\nПри операторе И проверка останавливается, как только найдено первое невыполненное + условие. Размещение наименее вероятных условий первыми позволяет приложению пропустить остальные раньше, делая + событие быстрее. + + При операторе ИЛИ проверка + останавливается, как только найдено первое выполненное условие. Размещение наиболее вероятных условий первыми + позволяет приложению завершить проверку раньше, не проверяя остальные.\n\nВ обоих случаях размещение наиболее + важного условия в начале списка — простой способ поддерживать высокую скорость сценария. + + + + Состояние событий + Узнайте, как включать и отключать события во время + работы сценария + + Каждое событие в сценарии (События экрана и + События-триггеры) имеет состояние: оно либо включено, либо отключено.\n\nВо включённом состоянии + событие работает как обычно и проверяет свои условия. В отключённом — полностью пропускается, как если бы его + не существовало.\n\nПо умолчанию каждое событие запускается включённым. Это можно изменить через поле + Начальное состояние в настройках события. + + Во время работы сценария состояние любого события + можно изменить с помощью действия Изменить состояние события. Оно позволяет включить, отключить или + переключить состояние одного или нескольких событий.\n\nЭто открывает много возможностей: события, которые + включают друг друга по очереди, события, которые отключают себя после однократного срабатывания, или группы + событий, где только одно активно в один момент времени. + + Когда все события в сценарии отключены, + сценарий останавливается сам по себе. Делать больше нечего, и Klick\'r останавливается автоматически.\n\nЭто + простой способ завершить сценарий: пусть последнее событие отключит все остальные после выполнения своей + задачи, и всё остановится само. + + + + Список действий + Узнайте, как выполняется список действий + Действия выполняются по порядку, одно за другим. + Вы можете изменить порядок действия с помощью кнопок << и >> или нажав прямо на номер его + индекса.\n\nСтарайтесь держать списки действий короткими. Обычный автокликер выполняет одно действие на + событие — это и есть правильная модель. Если вы добавляете много действий в одно событие, это, как правило, + признак того, что работу следует разделить на несколько событий, каждое из которых реагирует на то, что + реально отображается на экране. Это философия «видеть и действовать» Klick\'r: сначала обнаружить, потом + действовать. + + + Действие «Написать текст» + Узнайте, как вставить текст в активное поле ввода + Прежде чем действие «Написать текст» выполнится, + целевое поле ввода уже должно быть в фокусе — так же, как если бы вы нажали на него, чтобы вызвать клавиатуру. + \n\nДля этого добавьте действие «Клик» по этому полю перед действием «Написать текст». Если после клика + воспроизводится анимация перехода, действие «Ожидание» между ними поможет убедиться, что поле готово. + \n\nДействие также имеет опцию «Подтвердить»: при включении она автоматически нажимает Enter после ввода + текста, подтверждая или отправляя значение. + Вы можете вставить значение счётчика в текст. + Нажмите кнопку «Добавить счётчик» в настройках действия, чтобы выбрать счётчик: это вставит заполнитель + {имяСчётчика} в текущую позицию курсора.\n\nВо время выполнения каждый заполнитель + {имяСчётчика} заменяется текущим значением счётчика до того, как текст будет вставлен в поле. Например, + если счётчик с именем яблоки имеет значение 18, текст «У меня {яблоки} яблок» становится + «У меня 18 яблок». + + + Системное действие + Узнайте, как вызывать системные действия навигации Android + Системное действие выполняет одно из встроенных + действий навигации Android: «Назад», «Домой» или «Последние приложения».\n\nЭто те же действия, что и кнопки + навигации в нижней части экрана. Они не требуют координат и работают на системном уровне, независимо от того, + какое приложение открыто. + + + Действие «Изменить счётчик» + Узнайте, как изменить значение счётчика + Действие «Изменить счётчик» применяет операцию + к счётчику, используя заданное статическое значение. Доступны три операции: добавить значение к счётчику (+), + вычесть из счётчика (−) или установить счётчик на это точное значение (=).\n\nЭто наиболее распространённый + способ обновить счётчик — например, прибавлять 1 каждый раз, когда условие обнаружено, или сбрасывать в 0 + при достижении цели. + Вместо статического значения можно использовать + текущее значение другого счётчика в качестве операнда. Применяются те же три операции (+, −, =), но величина + считывается из выбранного счётчика во время выполнения, а не задаётся при настройке.\n\nЭто позволяет строить + динамические сценарии, в которых счётчики взаимодействуют друг с другом. + + + Действие «Уведомление» + Узнайте, как показать уведомление во время сценария + Действие «Уведомление» отображает уведомление + Android с заголовком и сообщением на ваш выбор.\n\nВы можете вставить текущее значение счётчика в текст + уведомления с помощью кнопки «Добавить счётчик» или напрямую набрав заполнитель {имяСчётчика}. Во + время выполнения он заменяется значением счётчика — например, «У меня {яблоки} яблок» становится + «У меня 18 яблок». + Уровень важности уведомления контролирует + степень его навязчивости. Высокие уровни могут показывать всплывающий баннер и воспроизводить звук, тогда как + низкие доставляются тихо в панель уведомлений.\n\nТочное поведение зависит от устройства и может быть + дополнительно настроено в настройках уведомлений Android для Klick\'r. + + + Действие «Изменить состояние события» + Узнайте, как включать и отключать события во время выполнения + Отключённое событие полностью пропускается во + время цикла сценария — его условия никогда не проверяются, а действия никогда не выполняются. Это означает, + что оно не потребляет никакого времени обработки.\n\nОтключение неиспользуемых событий — отличный способ + повысить производительность. Например, в сценарии, чередующем фазу меню и фазу игры, отключение всех событий + меню во время игровой фазы (и наоборот) позволяет держать активными только нужные события в каждый момент. + При настройке действия можно выбрать изменение + состояния всех событий сценария сразу или задать новое состояние для каждого события по отдельности.\n\nДля + каждого события доступны три варианта изменения: включить, отключить или переключить из текущего значения — + включённое событие станет отключённым, а отключённое — включённым. + Если все события сценария окажутся отключены + одновременно, сценарий автоматически останавливается, так как выполнять больше нечего.\n\nЭто можно + использовать намеренно как чистый способ завершить сценарий после достижения цели: последнее действие + «Изменить состояние события», отключающее все события, остановит сценарий. + + + Действие «Intent» + Узнайте, как взаимодействовать с другими приложениями + Intent — это способ, которым приложения общаются + между собой в Android. Действие Intent позволяет задействовать эту систему прямо из вашего сценария.\n\nДля + удобства доступен набор готовых шаблонов. Самый распространённый — «Запустить приложение», которое открывает + другое приложение на устройстве точно так же, как если бы вы нажали на его иконку в лаунчере. + Вкладка «Расширенные» позволяет вручную определить + необработанный Intent, давая полный контроль над действием, категорией, данными и extras. Это не рекомендуется + для обычных пользователей — предназначено для Android-разработчиков, которые уже знают, как работают Intents. + \n\nВ будущих обновлениях будут добавлены новые готовые шаблоны, чтобы упростить распространённые сценарии + без необходимости прибегать к расширенным настройкам. + + + + Приоритет событий + Узнайте, как порядок событий в вашем списке влияет на их выполнение + Каждый кадр экрана обрабатывается путём проверки событий по одному, сверху вниз.\n\nПозиция события в списке определяет, когда оно получает возможность выполниться. По умолчанию, как только условия события выполнены и его действия запущены, кадр считается обработанным. Обработка останавливается для этого кадра, и следующий начинается с первого события в списке.\n\nЭто означает, что по умолчанию в каждом кадре может выполняться только одно событие. + Вы можете изменить это поведение, используя поле Продолжайте выполнять в настройках события. Когда оно включено, после выполнения этого события обработка продолжается со следующего события в списке вместо остановки.\n\nЭто позволяет нескольким событиям выполняться в одном кадре.\n\nПример: ваш список содержит Событие А, за которым следует Событие Б. Если Событие А продолжает обнаруживаться и у него не включено Продолжайте выполнять, оно будет выполняться в каждом кадре, а Событие Б никогда не получит возможности выполниться.\n\nВключите Продолжайте выполнять для События А, и оба события будут проверяться в каждом кадре.\n\nДля отработки этой концепции также доступен интерактивный обучающий материал. + + + + Перезарядка события + Узнайте, как работает перезарядка события в вашем сценарии + Параметр перезарядки события позволяет пропускать + событие в течение заданного времени после его срабатывания. \n\nСобытие в состоянии перезарядки по-прежнему + считается включённым: перезарядка и состояние события независимы друг от друга. \n\nЕсли событие будет + отключено во время перезарядки, таймер перезарядки будет сброшен, так что задержка больше не применяется при + повторном включении события. + + + + Использование значений счётчиков + Узнайте о разных способах отображения и использования значений счётчиков в вашем сценарии + + Вы можете отображать текущее значение + счётчика в действии «Уведомление». Это полезно для отслеживания прогресса во время выполнения сценария + или для показа итогов по его завершении.\n\nЧтобы вставить счётчик, нажмите кнопку «Добавить счётчик» + в настройках действия. Это добавит заполнитель вида {counterName} в ваш текст. Во время выполнения + заполнитель заменяется текущим значением счётчика. Например, если счётчик с именем score имеет + значение 42, текст «Текущий счёт: {score}» станет «Текущий счёт: 42». + + Вы также можете вставить значение счётчика + в действие «Написать текст», чтобы введённый текст содержал актуальное значение в момент выполнения + действия.\n\nЗаполнитель работает так же, как и в действии «Уведомление»: нажмите кнопку «Добавить + счётчик» или введите {counterName} напрямую. Например, если счётчик с именем score имеет + значение 42, текст «Мой счёт: {score}» станет «Мой счёт: 42». + + Значения счётчиков фиксируются в отчёте об + отладке. Если что-то работает не так, как ожидалось, создание отчёта об отладке покажет вам, как именно + изменялись ваши счётчики, и поможет найти причину проблемы. + diff --git a/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_not_visible.xml index 1f9ef501a..23819ff0e 100644 --- a/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - Комбинирование нескольких условий - Создайте и скомбинируйте несколько условий для вашего события - Кликните на синюю кнопку, только когда красная кнопка видна + Видимость условий + Используйте параметр «Видимость», чтобы + выполнять нажатие, когда цель отсутствует на экране + Нажимайте синюю кнопку только тогда, + когда красная кнопка не видна - Давайте снова изменим правила игры. Синяя цель перестала двигаться, - но теперь на нее следует кликать только тогда, когда красная цель видима.\n\nСначала запустите игру и проверьте, можете ли вы выиграть - самостоятельно. + Новые правила! Синяя цель перестала + двигаться, но нажимать на неё нужно только тогда, когда красная цель не видна на экране. + \n\nЗапустите игру и посмотрите, сможете ли выиграть самостоятельно. - Опять же кажется невозможным выиграть вручную, поэтому давайте используем Smart - AutoClicker.\n\nВаш сценарий предварительного обучения был сохранен и загружен для этого обучения, но нам - нужно будет изменить несколько параметров, чтобы выиграть эту новую игру.\n\nКликните на иконку настройки сценария, чтобы - начать обновление вашего нового сценария. + Снова кажется невозможным победить + вручную, поэтому воспользуемся Klick\'r. \n\nОткройте меню настройки сценария, создайте новое Экранное событие + и начните добавлять условия для целей игры. - Мы все еще хотим кликнуть на синюю цель, но только когда красная видимая.\n - Поэтому нам нужно добавить условие для этой красной цели в наше событие. + Сначала нам нужно условие, которое + проверяет, когда красная цель НЕ видна на экране. \n\nСоздайте новое условие изображения и захватите красную + цель. - Мы будем комбинировать несколько условий, поэтому нам нужно проверить оператор. - для этого события.\n\nОператор условия указывает, как несколько условий будут интерпретироваться вместе.\n - \'Одна\' означает, что только одно из условий для этого события должно быть выполнено, чтобы - выполнить действия.\n\n\'Все\' означает, что все условия для этого события должны быть выполнены, чтобы выполнить действия. - \n\nПоскольку мы хотим обнаружить, отображаются ли две вещи вместе, мы используем \'Все\' + Мы хотим нажимать только тогда, когда + красная цель не видна, поэтому установите параметр «Видимо» в значение Нет. Так условие будет выполняться + только при отсутствии красной цели на экране. - Теперь нам нужно обновить наши условия.\n\nКликните на поле условий, чтобы отобразить - список условий. + Остальные настройки подходят для + нашего случая — сохраните это условие. - Предварительное условие обнаружения синей цели все еще правильно, но нам нужно - новая для красной цели.\n\nКликните на кнопку создания условия, чтобы создать новое условие для нее. + Одного этого условия достаточно, чтобы + выиграть, но оно будет срабатывать даже когда игра не запущена, что нежелательно. + \n\nЧтобы этого избежать, дополним его вторым условием, которое проверяет, видна ли синяя цель. + Создайте новое Условие изображения и захватите синюю цель. - Так же как для синей цели, запустите игру, чтобы показать красную цель. - Когда она станет видимой, сделайте снимок экрана! - Используйте кнопку захвата в плавающем меню, чтобы сделать снимок экрана. + Для этого условия нам нужно убедиться, + что синяя цель видна, поэтому стандартные настройки полностью подходят. Сохраните условие и вернитесь к + событию, чтобы продолжить. - Содержит ли ваш снимок экрана красную цель? Вы можете обрезать его, чтобы получить только - часть, которая интересна для обнаружения – красную цель. - Если ваш снимок экрана не содержит красную цель, вы можете - нажать эту кнопку, чтобы сделать новый. + При наличии нескольких условий важен + оператор условия. Мы хотим, чтобы событие срабатывало, когда синяя цель видна И красная не видна, поэтому + нам нужен оператор И; он уже установлен по умолчанию, так что всё в порядке. + \n\nТеперь создайте новое действие нажатия, чтобы продолжить. - Изображение вашего условия теперь записано!\n\nПоскольку красная цель не двигается, мы - можем сохранить стандартную конфигурацию.\nКликните кнопку сохранения, чтобы зарегистрировать ее и вернуться в список условий. + Мы хотим нажимать на синюю цель, + поэтому выберите тип позиции «По условию» и укажите Условие изображения синей цели. + \n\nКогда закончите, сохраните нажатие, затем событие и сценарий, и вернитесь к игре. - Закройте список условий для возврата к настройке события. + Запустите сценарий и начните игру, + чтобы победить! \n\nЕсли что-то не работает, проверьте, что условия захвачены правильно и длительность + нажатия установлена на 1 мс. - Теперь у нас есть два условия, по одному для каждой цели, и действия будут исполнены - только если оба обнаружены.\n\nКликните на поле действий, чтобы отобразить список действий для нашего события. + Поздравляем! Вы научились + использовать условие «Не видно». Всегда сочетайте его хотя бы с одним другим условием, чтобы не вызывать + действия непреднамеренно на протяжении всего сценария. - Действие уже установлено для клика на синего персонажа, и оно будет выполнено только - когда синий и красный персонажи видны вместе.\n\nЭто именно то поведение, которое нам нужно для победы в - игре, поэтому нет необходимости редактировать наше действие клика.\n\nЗакройте список действий, чтобы вернуться к настройке события. - - Нажмите кнопку сохранения, чтобы сохранить событие. - - Все изменения должны быть сохранены в вашем сценарии, чтобы быть зарегистрированными.\n\nКликните - на кнопку сохранения, чтобы сохранить ваши изменения. - - Мы готовы выиграть эту игру!\n\nКликните на кнопку начала, чтобы начать - обнаружение, а затем запустите игру. - - Поздравляем!\n\nТеперь вы знаете, как комбинировать несколько условий для события, - но есть еще многое изучить! diff --git a/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..742495abe --- /dev/null +++ b/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,67 @@ + + + + + + Оператор условий И + Используйте оператор И, чтобы выполнять нажатие + только когда несколько целей видны одновременно + Нажимайте синюю кнопку только тогда, когда + видны и синяя, и красная цели + + Новые правила! Теперь в игре две цели. + Нажимайте на синюю, но только когда обе цели — синяя и красная — одновременно на экране. + \n\nЗапустите игру и посмотрите, справитесь ли самостоятельно. + + Слишком сложно делать это вручную, поэтому + воспользуемся Klick\'r. \n\nОткройте меню настройки сценария, создайте новое Экранное событие и начните + добавлять условия для целей игры. + + Нам нужно по одному условию на каждую + цель. Начнём с синей. \n\nСоздайте новое условие изображения и захватите синюю цель. + + Мы хотим, чтобы это условие выполнялось + когда синяя цель видна, поэтому стандартные настройки полностью подходят. Сохраните это условие. + + Теперь добавим второе условие для красной + цели. \n\nСоздайте ещё одно условие изображения и захватите красную цель. + + Здесь то же самое — красная цель должна + быть видна, поэтому стандартные настройки подходят. Сохраните это условие и вернитесь к событию. + + При двух заданных условиях оператор + условия определяет, как они объединяются. Выберите оператор с помощью селектора выше. + \n\n• И: событие срабатывает только когда ВСЕ условия выполнены.\n• ИЛИ: событие срабатывает как только + ОДНО условие выполнено.\n\nДля нашей игры нам нужны обе цели на экране одновременно, поэтому выберите И. + Селектор оператора условий + + И уже является оператором по умолчанию, + так что всё готово. \n\nТеперь откройте раздел Действия и создайте новое действие нажатия. + + Мы хотим нажимать на синюю цель, поэтому + выберите тип позиции «По условию» и укажите условие изображения синей цели. + \n\nКогда закончите, сохраните нажатие, затем событие и сценарий, и вернитесь к игре. + + Запустите сценарий и начните игру, чтобы + победить! \n\nЕсли что-то не работает, проверьте, что оба условия захвачены правильно и длительность + нажатия установлена на 1 мс. + + Поздравляем! Вы научились использовать + оператор И. Теперь событие срабатывает только когда все его условия выполнены одновременно. + + diff --git a/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..fb0714b91 --- /dev/null +++ b/feature/tutorial/src/main/res/values-ru/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,73 @@ + + + + + + Оператор условий ИЛИ + Используйте оператор ИЛИ, чтобы нажимать на + первую цель, которая появится на экране + Нажимайте на любую цель как только она + появится на экране + + Новый вызов! На экране могут появиться две + цели. Красная стоит 2 очка, а синяя — 1 очко, поэтому нажимайте на ту, что появится, как можно быстрее. + \n\nЗапустите игру и посмотрите, как справитесь. + + Слишком быстро для ручного управления, + поэтому воспользуемся Klick\'r. \n\nОткройте меню настройки сценария, создайте новое Экранное событие и + начните добавлять условия для целей игры. + + Нам нужно по одному условию на каждую цель. + Начнём с синей. \n\nСоздайте новое условие изображения и захватите синюю цель. + + Это условие должно срабатывать когда синяя + цель видна, поэтому стандартные настройки полностью подходят. Сохраните это условие. + + Теперь добавим второе условие для красной + цели. \n\nСоздайте ещё одно условие изображения и захватите красную цель. + + Здесь то же самое, красная цель должна быть + видна, поэтому стандартные настройки подходят. Сохраните это условие. + + При ИЛИ условия проверяются по порядку и + событие срабатывает как только первое из них совпадает, поэтому порядок условий важен. + \n\nКрасная цель приносит больше очков, поэтому мы хотим, чтобы она проверялась первой. Используйте кнопку + «, чтобы переместить её перед синей, затем вернитесь в диалог События. + + Теперь установите оператор условия на ИЛИ. + Событие будет срабатывать как только появится любая из целей. Если обе видны одновременно, красное условие + будет обнаружено первым, так как имеет более высокий приоритет. \n\nВыберите ИЛИ. + + Оператор ИЛИ теперь установлен. Откройте + раздел Действия и создайте новое действие нажатия. + + Мы хотим нажимать на цель, которая + вызвала событие. Выберите тип позиции «По условию». При ИЛИ одновременно может быть положительно обнаружено + только одно условие, поэтому выбирать конкретное условие не нужно. Klick\'r автоматически нажмёт в место + расположения совпавшего условия. \n\nКогда закончите, сохраните нажатие, затем событие и сценарий, и + вернитесь к игре. + + Запустите сценарий и начните игру, чтобы + победить! \n\nЕсли что-то не работает, проверьте, что ваши условия захвачены правильно и длительность + нажатия установлена на 1 мс. + + Поздравляем! Вы научились использовать + оператор ИЛИ и поняли, почему приоритет условий важен. Поместив красное условие первым, Klick\'r всегда + отдаёт предпочтение цели с более высокой ценностью, когда обе видны одновременно. + + diff --git a/feature/tutorial/src/main/res/values-ru/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-ru/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..9ed1c0eac --- /dev/null +++ b/feature/tutorial/src/main/res/values-ru/strings_tutorial_counters_basics.xml @@ -0,0 +1,127 @@ + + + + Основы счётчиков + Узнайте, как использовать действие «Изменить счётчик» и условие + «При достижении счётчика». + Нажмите на синюю мишень 10 раз, затем один раз нажмите на + красную мишень + + Добро пожаловать в учебник по счётчикам! + \n\nЗдесь вы автоматизируете игру, в которой нужно нажать на синюю мишень 10 раз, а затем нажать на красную + мишень один раз, чтобы подтвердить результат и заработать 10 очков. Вы можете сначала попробовать сыграть + самостоятельно или сразу перейти к настройке сценария. + + Сначала нам нужно создать Экранное событие, которое будет + обнаруживать синюю мишень и нажимать на неё. \n\nНажмите «Создать событие», чтобы начать. + + Начнём с добавления условия для обнаружения синей мишени. + Нажмите на поле «Условия», чтобы открыть список условий и создать нужное условие. \n\nУчебник продолжится, + как только условие будет создано. + + Отлично! Теперь нажмите на поле «Действия», чтобы добавить + действия, которые будут выполняться при обнаружении синей мишени. + + Сначала нам нужно действие «Нажатие», чтобы нажать на синюю + мишень. Нажмите кнопку «Создать», чтобы добавить новое действие. + + Настройте нажатие на синюю мишень, затем сохраните действие. + \n\nУчебник продолжится, как только нажатие будет сохранено. + + Нам также нужно считать, сколько раз мы нажимали на синюю + мишень. Это можно сделать с помощью действия «Изменить счётчик», прибавляя по единице при каждом нажатии. + \n\nНажмите кнопку «Создать» ещё раз, чтобы добавить второе действие. + + Выберите действие «Изменить счётчик», чтобы увеличивать + счётчик каждый раз, когда обнаруживается синяя мишень. + + Сначала нужно выбрать, какой счётчик обновлять. Нажмите + «Выбрать счётчик», чтобы открыть список счётчиков. + + Список пока пуст. Нажмите кнопку «Создать», чтобы создать + новый счётчик. Дайте ему название (например, «Синие нажатия»), оставьте начальное значение равным 0, затем + сохраните и выберите его. + + Теперь настройте, как счётчик изменяется при каждом нажатии + на синюю мишень. \n\nУстановите оператор «+» и значение «1», чтобы счётчик увеличивался на 1 при каждом + нажатии. \n\nЗатем сохраните действие и вернитесь к диалогу события. + Значение может быть фиксированным числом или + текущим значением другого счётчика. + + Отлично! Это Экранное событие теперь будет нажимать на синюю + мишень и увеличивать счётчик при каждом обнаружении. \n\nСохраните событие, чтобы вернуться к сценарию. + + Теперь нам нужно событие, которое реагирует, когда счётчик + достигает 10. Такой тип события запускается не экраном, а значит это Триггерное событие. + \n\nНажмите на вкладку «Триггеры», чтобы открыть список триггерных событий. + + Нажмите кнопку «Создать», чтобы добавить новое Триггерное + событие. + + Как и Экранное событие, Триггерное событие нуждается в + условиях. Нажмите на поле «Условия», чтобы открыть список условий и создать новое условие триггера. + + Выберите тип условия «При достижении счётчика», чтобы + запускать это событие, когда счётчик достигнет заданного значения. + + Выберите счётчик, созданный ранее (тот, что считает синие + нажатия), чтобы использовать его в качестве триггера. + + Теперь задайте сравнение так, чтобы условие выполнялось, + когда счётчик равен 10. Доступно несколько операторов сравнения, но здесь нам нужно проверить равенство, поэтому + выберите «=». Затем введите 10 в качестве значения, сохраните условие и вернитесь к диалогу события. + Значение для сравнения может быть фиксированным + числом или текущим значением другого счётчика. + + Условие задано! Теперь нужно определить, что происходит, + когда счётчик достигает 10. Нажмите на поле «Действия», чтобы открыть список действий. + + Сначала создайте действие «Нажатие» и вручную укажите его + позицию на красной мишени, чтобы подтвердить результат. + + Настройте нажатие на красную мишень, затем сохраните + действие. Обратите внимание: в Триггерном событии позиция нажатия всегда задаётся вручную. \n\nУчебник + продолжится, как только нажатие будет сохранено. + + Теперь создайте второе действие для сброса счётчика. Нажмите + кнопку «Создать» ещё раз и выберите действие «Изменить счётчик». + + Нам нужно установить счётчик синих нажатий на 0, поэтому + сначала выберите счётчик синих нажатий. + + Установите оператор «=» и значение «0», чтобы сбрасывать + счётчик после каждой проверки. Затем сохраните действие и вернитесь к диалогу события. + + Это Триггерное событие будет нажимать на красную мишень и + сбрасывать счётчик каждый раз, когда засчитано 10 синих нажатий. Список триггерных событий обрабатывается + между каждым кадром экрана, перед списком экранных событий, поэтому как только счётчик достигнет 10, это событие + немедленно выполнится: красная мишень будет нажата, а счётчик сброшен и готов начать заново. \n\nСохраните + событие, чтобы вернуться к сценарию. + + Сценарий готов! Он будет нажимать на синюю мишень, считать + каждое нажатие, затем подтверждать результат на красной мишени каждые 10 нажатий и начинать заново. \n\nСохраните + сценарий, чтобы применить настройки. + + Всё готово! Запустите сценарий, затем откройте игру и + наблюдайте, как Klick\'r считает за вас. + + Отлично! Вы научились использовать счётчики для отслеживания + значений в нескольких событиях. \n\nВместе с действием «Изменить счётчик» и условием «При достижении счётчика» + вы теперь можете создавать автоматизации, реагирующие на повторяющиеся паттерны. + + diff --git a/feature/tutorial/src/main/res/values-ru/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-ru/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..2be5e14ba --- /dev/null +++ b/feature/tutorial/src/main/res/values-ru/strings_tutorial_events_priority.xml @@ -0,0 +1,69 @@ + + + + + Определение приоритета события + Задать приоритет одного Cобытия над другим + Нажимайте на цели как можно быстрее. Синий = 1 очко; + Красный = 10 очков + + Новая игра! Нужно нажимать на цели как можно быстрее, но + красная цель приносит больше очков. Можете сначала попробовать игру или открыть меню настройки сценария, + чтобы начать автоматизацию. + + Мы хотим обнаруживать две разные цели: синюю и красную. + В этом уроке мы создадим два отдельных события: одно для синей цели и одно для красной. \n\nСначала создайте + Событие для синей цели; оно должно нажимать на неё при обнаружении. Не забудьте использовать функции + тестирования, чтобы убедиться, что условие определяется правильно. \n\nУрок продолжится после сохранения + Cобытия для синей цели. + + Отлично! Теперь нужно то же самое, но для красной цели. + Нажмите кнопку «Создать событие» и создайте событие для красной цели; оно должно нажимать на неё при + обнаружении. \n\nУрок продолжится после сохранения Cобытия для красной цели. + + В нашем списке теперь два события, по одному для каждой + цели. Сохраните Cценарий и проверьте его в игре. + + Что-то пошло не так. Сценарий нажимает только на синюю + цель, полностью игнорируя красную, что не даёт нам победить. \n\nПочему так происходит? Потому что синее + событие стоит перед красным, и поскольку оно всегда срабатывает, текущий кадр не оценивается дальше, а + следующий начинается с начала списка Cобытий. \n\nЕсть несколько способов это исправить. Откройте диалог + настройки сценария, чтобы узнать как. + + Проблему можно решить двумя способами: \n\nМожно изменить + параметр «Продолжить выполнение» события синей цели, чтобы продолжить обработку того же кадра и выполнить + красное событие тоже. Это вызовет оба нажатия, когда обе цели видны одновременно. \n\nИли можно переместить + событие красной цели в начало списка, чтобы оно проверялось первым и нажималось при появлении, но синяя + цель больше не будет нажиматься, когда красная тоже отображается. \n\nГлавное различие между решениями — + скорость: размещение красного события первым позволяет реагировать максимально быстро при его появлении, + будучи немного медленнее, когда видна только синяя цель. + + Поскольку игра даёт 10 очков за красную цель, мы хотим + реагировать на неё как можно быстрее, переместив красное событие в начало списка. \n\nПереместите красное + событие на первое место и сохраните сценарий. Теперь вы должны суметь победить в игре. + Вы можете изменить порядок Cобытий, удерживая + нажатой эту иконку и перетаскивая событие на нужное место. + + Как обычно, сначала запустите сценарий, а затем игру. + \n\nЕсли по-прежнему не удаётся победить, убедитесь, что каждое событие работает по отдельности с помощью + функций тестирования. + + Отлично! Теперь вы понимаете, как работает приоритет + событий и как ведёт себя цикл Cобытий Экрана. Это ключ к созданию и управлению сложными сценариями. + + diff --git a/feature/tutorial/src/main/res/values-ru/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-ru/strings_tutorial_events_state.xml new file mode 100644 index 000000000..2f3a65d2b --- /dev/null +++ b/feature/tutorial/src/main/res/values-ru/strings_tutorial_events_state.xml @@ -0,0 +1,145 @@ + + + + + Отключение неиспользуемых событий + Изменяйте состояние нескольких событий для оптимизации сложного сценария. + Нажимайте на цели по порядку: синяя, красная, зелёная, затем жёлтая. + + Новая игра! На этот раз нужно нажимать на четыре цветные цели по + порядку: сначала синяя, затем красная, затем зелёная и наконец жёлтая. \n\nВы можете сначала попробовать игру, + чтобы понять, как она работает, или сразу открыть настройки сценария и начать его автоматизацию. + + Нам нужно обнаруживать четыре разные цели, по одной на каждый + цвет. Мы создадим по одному Событию на цель. \n\nНачните с синей цели: создайте новое Событие, которое + обнаруживает её в игровой области и нажимает на неё. + + При использовании нескольких событий важно давать им понятные + имена, чтобы не запутаться. Дайте этому Событию чёткое имя, например «Синяя цель», чтобы легко находить его + в сценарии. \n\nПосле этого создайте новое условие Изображение и захватите синюю цель. + + Поскольку цель движется, нужно установить тип обнаружения + «Область обнаружения» и выбрать игровую зону. \n\nКогда область будет правильно настроена, сохраните её и вернитесь в + диалог Событие. + + Условие настроено. Теперь нам нужно действие Нажатие, чтобы + Событие нажимало на обнаруженную цель. \n\nСоздайте новое действие Нажатие, чтобы продолжить. + + Цель движется, поэтому мы не можем задать фиксированную + позицию. В поле «Нажать на» выберите «Нажать на обнаруженное условие» и выберите условие синей цели. Так нажатие всегда будет точно + там, где была найдена цель.\n\nПосле выбора условия сохраните нажатие и вернитесь в диалог Событие. + + Событие для синей цели готово! Теперь создайте Событие для + красной цели таким же образом: обнаруживайте её в игровой области и нажимайте на неё. Туториал продолжится + после сохранения вашего События для красной цели. + + Отлично! Теперь создайте такое же Событие для зелёной цели. + Туториал продолжится после сохранения вашего События для зелёной цели. + + Почти готово! Создайте последнее Событие для жёлтой цели. + Туториал продолжится после сохранения вашего События для жёлтой цели. + + Все четыре События готовы. Поскольку мы определили их в + порядке игровой последовательности, их приоритет настроен правильно. \n\nСохраните сценарий и проверьте его + в игре. + + Сценарий обнаруживает цели и нажимает на них, но он, + вероятно, слишком медленный, чтобы выиграть. \n\nСейчас все четыре События активны одновременно, поэтому в + каждом кадре сценарий проверяет синюю, затем красную, затем зелёную, затем жёлтую — независимо от того, на + какую цель только что нажали. Это впустую тратит время! \n\nОткройте настройки сценария, чтобы узнать, как + это исправить. + + Каждое Событие имеет начальное состояние: оно может + стартовать включённым или отключённым. Сейчас все четыре События включены, поэтому все проверяются в каждом + кадре. \n\nРешение: держать активным только Событие текущей цели, а остальные отключить. Когда цель нажата, + её Событие включит следующую и отключит остальные. \n\nНачнём с редактирования События синей цели. + + Синяя цель — первая для нажатия, поэтому её Событие должно + стартовать включённым; здесь ничего менять не нужно. \n\nНам нужно лишь добавить действие «Переключить + событие», чтобы при нажатии на синюю цель Событие красной цели включалось, а остальные отключались. Нажмите на + область Действия, чтобы добавить это действие. + + Выберите тип действия «Изменить состояние события». + + Это действие позволяет изменять состояние любого События в + сценарии при срабатывании данного События. Нажмите поле «Нет изменений», чтобы указать, какие События + изменить. + + Для каждого События в списке можно задать одно из трёх + состояний: \n• Включить: Событие становится активным и будет проверяться в каждом кадре \n• Отключить: + Событие становится неактивным и полностью пропускается \n• Инвертировать: каждый раз переключается между + активным и неактивным \n\nПоскольку синяя только что была нажата, включите Событие красной цели и отключите + все остальные. Нажмите Далее, когда закончите. + Каждая строка События показывает три варианта: + Включить, Отключить и Переключить. Нажмите тот, который хотите применить при выполнении этого действия. + + Отлично! Сохраните Событие синей цели. + + Теперь откройте Событие красной цели в списке и настройте + его таким же образом. + + В отличие от События синей цели, это Событие не должно быть + активным в начале сценария, так как его цель не первая. Измените начальное состояние на Отключено. + + Теперь добавьте действие «Изменить состояние события», чтобы при + нажатии на эту цель Событие следующей цели включалось, а остальные отключались. Нажмите на область + Действия. + + Настройте переключения: включите зелёную цель и отключите + все остальные. Нажмите Далее, когда закончите. + + Хорошая работа! Теперь откройте Событие зелёной цели и + настройте его таким же образом. + + Зелёная цель тоже не должна быть активной с самого начала. + Измените её начальное состояние на Отключено. + + Теперь добавьте действие «Изменить состояние события», чтобы при + нажатии на зелёную цель Событие жёлтой цели включалось, а остальные отключались. Нажмите на область + Действия. + + Настройте переключения: включите жёлтую цель и отключите все + остальные. Нажмите Далее, когда закончите. + + Почти готово! Откройте Событие жёлтой цели, чтобы завершить + настройку. + + Жёлтая цель — последняя в последовательности, поэтому она + тоже должна стартовать отключённой. Измените её начальное состояние на Отключено. + + Добавьте действие «Изменить состояние события» и в Событие жёлтой + цели. При нажатии на жёлтую мы хотим вернуться к началу: включите синюю цель и отключите все остальные. + Нажмите на область Действия. + + Настройте переключения: включите синюю цель и отключите все + остальные. Так последовательность будет повторяться бесконечно. Нажмите Далее, когда закончите. + + Все События полностью настроены. Сохраните сценарий, чтобы + применить изменения. + + Все События настроены! Сохраните сценарий и запустите игру. + Не забудьте запустить сценарий перед началом игры. \n\nПоскольку наш сценарий имеет внутреннее состояние, + его нужно перезапускать каждый раз при перезапуске игры, чтобы он не ждал последнюю цель предыдущей сессии. + Это легко автоматизировать, отслеживая видимость кнопки старта для сброса состояний событий. + + Вы победили! \n\nУправляя тем, какие События активны в + каждый момент, сценарий всегда точно знает, какую цель искать следующей — никаких лишних кадров на проверку + целей не в той очерёдности. \n\nИменно так действие Переключить событие позволяет создавать + последовательную автоматизацию, управляемую состоянием. + + diff --git a/feature/tutorial/src/main/res/values-uk/strings_categories.xml b/feature/tutorial/src/main/res/values-uk/strings_categories.xml index b41c20344..e4d796e6d 100644 --- a/feature/tutorial/src/main/res/values-uk/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-uk/strings_categories.xml @@ -1,4 +1,4 @@ - + + Дія «Пауза» + Дізнайтесь, як пауза впливає на виконання дій та виявлення + Дія «Пауза» призупиняє весь сценарій на заданий + час: протягом цього часу не виконується жодна дія і не відбувається виявлення на екрані.\n\nДуже + поширений випадок — додати паузу в кінець списку дій. Коли ви натискаєте десь, додатку потрібен час, + щоб обробити натискання та відобразити результат — і, як правило, ви хочете зачекати цього моменту, + перш ніж Klick\'r знову почне аналізувати екран.\n\nПауза між двома діями теж доречна, але додавання + паузи в кінець списку зазвичай важливіше. + + + Дія «Свайп» + Дізнайтесь, як виконується жест свайпу + Дія «Свайп» виконує жест перетягування по прямій + лінії від початкової точки до кінцевої. Обидві координати фіксовані і задаються в налаштуваннях + дії.\n\nТривалість визначає час, який займає жест від початку до кінця: менша тривалість дає швидший + свайп, більша — повільніший і плавніший. + + + Зміщення кліку + Дізнайтесь, як скоригувати позицію кліку по виявленій умові + При кліку по виявленій умові натискання за + замовчуванням застосовується до центру виявленої області.\n\nЗміщення кліку дозволяє перемістити цю + позицію на фіксовану кількість пікселів по осях X та Y відносно центру умови. Це зручно, коли елемент, + на який потрібно натиснути, знаходиться близько до центру виявленої області, але не точно в ньому. + + + Ціль кліку + Дізнайтесь, як налаштувати місце застосування кліку + Дія «Клік» може бути спрямована на два + типи позицій: фіксована позиція, яка завжди однакова, або позиція виявленої умови.\n\nВиберіть метод + прицілювання у селекторі цілі в діалозі налаштування дії. + При фіксованій позиції клік завжди + відбувається в одних і тих самих точних координатах, незалежно від того, що відображається на екрані. + \n\nМайте на увазі, що ці координати чутливі до повороту: якщо пристрій повернеться, клік може + опинитись у несподіваному місці або за межами екрана. + При позиції умови клік застосовується до + центру виявленої умови зображення, слідуючи за ціллю, де б вона не з\'явилась на екрані.\n\nЗ + оператором AND усі умови мають бути виконані, тому кожна умова зображення має доступну позицію. Ви + можете вільно обрати будь-яку і уточнити її за допомогою зміщення. + З оператором OR оцінюється тільки перша + виконана умова, решта ігнорується. Тому Klick\'r не може заздалегідь знати, яку умову буде виявлено. + \n\nОтже, з оператором OR не можна обрати конкретну умову як ціль: клік завжди буде застосований до + першої виявленої умови, якою б вона не виявилась під час виконання. + + + Порядок умов і швидкість + Як порядок умов впливає на швидкість перевірки + події + + Порядок умов у списку впливає на + швидкість перевірки події.\n\nПри операторі І перевірка зупиняється, щойно знайдено першу невиконану умову. + Розміщення найменш імовірних умов першими дозволяє додатку пропустити решту раніше, + роблячи подію швидшою. + + При операторі АБО перевірка зупиняється, + щойно знайдено першу виконану умову. Розміщення найбільш імовірних умов першими дозволяє додатку завершити + перевірку раніше, не перевіряючи решту.\n\nВ обох випадках розміщення найважливішої умови на початку списку — + простий спосіб підтримувати швидкість сценарію. + + + + Стан подій + Дізнайтеся, як вмикати та вимикати події під час роботи + сценарію + + Кожна подія у вашому сценарії (Події екрана та + Події-тригери) має стан: вона або увімкнена, або вимкнена.\n\nКоли увімкнена, подія працює як + звичайно та перевіряє свої умови. Коли вимкнена, вона повністю пропускається, ніби її не існує.\n\nЗа + замовчуванням кожна подія починається увімкненою. Це можна змінити через поле Початковий стан у + налаштуваннях події. + + Під час роботи сценарію стан будь-якої події + можна змінити за допомогою дії Змінити стан події. Вона дозволяє увімкнути, вимкнути або перемкнути стан + однієї чи кількох подій.\n\nЦе відкриває багато можливостей: події, що вмикають одна одну по черзі, події, що + вимикають себе після одного спрацювання, або групи подій, де лише одна активна одночасно. + + Коли всі події у сценарії вимкнені, + сценарій зупиняється сам по собі. Більше нічого робити, і Klick\'r зупиняється автоматично.\n\nЦе простий + спосіб завершити сценарій: нехай остання подія вимкне всі інші після виконання свого завдання, і все зупиниться + само. + + + + Список дій + Дізнайтесь, як виконується список дій + Дії виконуються по порядку, одна за одною. Ви можете + змінити порядок дії за допомогою кнопок << і >> або натиснувши безпосередньо на номер її індексу. + \n\nНамагайтеся тримати списки дій короткими. Звичайний автоклікер виконує одну дію на подію — це і є + правильна модель. Якщо ви додаєте багато дій до одної події, це зазвичай ознака того, що роботу слід + розподілити на кілька подій, кожна з яких реагуватиме на те, що реально відображається на екрані. Це + філософія «бачити і діяти» Klick\'r: спочатку виявити, потім діяти. + + + Дія «Написати текст» + Дізнайтесь, як вставити текст в активне поле введення + Перш ніж дія «Написати текст» виконається, цільове + поле введення вже має бути у фокусі — так само, як якби ви натиснули на нього, щоб викликати клавіатуру. + \n\nДля цього додайте дію «Клік» по цьому полю перед дією «Написати текст». Якщо після кліку відтворюється + анімація переходу, дія «Очікування» між ними допоможе переконатися, що поле готове.\n\nДія також має + параметр «Підтвердити»: при увімкненні вона автоматично натискає Enter після введення тексту, підтверджуючи + або надсилаючи значення. + Ви можете вставити значення лічильника в текст. + Натисніть кнопку «Додати лічильник» у налаштуваннях дії, щоб вибрати лічильник: це вставить замінник + {назваЛічильника} в поточну позицію курсора.\n\nПід час виконання кожен замінник + {назваЛічильника} замінюється поточним значенням лічильника до того, як текст буде вставлено в поле. + Наприклад, якщо лічильник з іменем яблука має значення 18, текст «У мене {яблука} яблук» стає + «У мене 18 яблук». + + + Системна дія + Дізнайтесь, як викликати системні дії навігації Android + Системна дія виконує одну з вбудованих дій навігації + Android: «Назад», «Додому» або «Останні програми».\n\nЦе ті самі дії, що й кнопки навігації в нижній частині + екрана. Вони не потребують координат і працюють на системному рівні, незалежно від того, яку програму + відкрито. + + + Дія «Змінити лічильник» + Дізнайтесь, як змінити значення лічильника + Дія «Змінити лічильник» застосовує операцію + до лічильника, використовуючи задане статичне значення. Доступні три операції: додати значення до лічильника + (+), відняти від лічильника (−) або встановити лічильник на це точне значення (=).\n\nЦе найпоширеніший спосіб + оновити лічильник — наприклад, додавати 1 щоразу, коли умову виявлено, або скидати до 0 при досягненні мети. + Замість статичного значення можна використовувати + поточне значення іншого лічильника як операнд. Застосовуються ті самі три операції (+, −, =), але величина + зчитується з вибраного лічильника під час виконання, а не задається при налаштуванні.\n\nЦе дозволяє будувати + динамічні сценарії, де лічильники взаємодіють між собою. + + + Дія «Сповіщення» + Дізнайтесь, як показати сповіщення під час сценарію + Дія «Сповіщення» відображає сповіщення Android + із заголовком і повідомленням на ваш вибір.\n\nВи можете вставити поточне значення лічильника в текст + сповіщення за допомогою кнопки «Додати лічильник» або безпосередньо ввівши замінник {назваЛічильника}. + Під час виконання він замінюється значенням лічильника — наприклад, «У мене {яблука} яблук» стає + «У мене 18 яблук». + Рівень важливості сповіщення контролює ступінь + його нав\'язливості. Високі рівні можуть показувати спливаючий банер і відтворювати звук, тоді як низькі + доставляються тихо на панель сповіщень.\n\nТочна поведінка залежить від пристрою і може бути додатково + налаштована в параметрах сповіщень Android для Klick\'r. + + + Дія «Змінити стан події» + Дізнайтесь, як вмикати та вимикати події під час виконання + Вимкнена подія повністю пропускається під час + циклу сценарію — її умови ніколи не перевіряються, а дії ніколи не виконуються. Це означає, що вона не + споживає жодного часу обробки.\n\nВимкнення невикористовуваних подій — чудовий спосіб підвищити + продуктивність. Наприклад, у сценарії, який чергує фазу меню та фазу гри, вимкнення всіх подій меню під час + ігрової фази (і навпаки) дозволяє тримати активними лише потрібні події в кожен момент. + При налаштуванні дії можна вибрати зміну стану + всіх подій сценарію одразу або задати новий стан для кожної події окремо.\n\nДля кожної події доступні три + варіанти зміни: увімкнути, вимкнути або перемкнути з поточного значення — увімкнена подія стане вимкненою, + а вимкнена — увімкненою. + Якщо всі події сценарію опиняться вимкненими + одночасно, сценарій автоматично зупиняється, оскільки більше нічого виконувати.\n\nЦе можна використовувати + навмисно як чистий спосіб завершити сценарій після досягнення мети: остання дія «Змінити стан події», що + вимикає всі події, зупинить сценарій. + + + Дія «Intent» + Дізнайтесь, як взаємодіяти з іншими програмами + Intent — це спосіб, яким програми спілкуються між + собою в Android. Дія Intent дозволяє задіяти цю систему безпосередньо з вашого сценарію.\n\nДля зручності + доступний набір готових шаблонів. Найпоширеніший — «Запустити програму», яке відкриває іншу програму на + пристрої так само, ніби ви натиснули на її іконку в лаунчері. + Вкладка «Розширені» дозволяє вручну визначити + необроблений Intent, надаючи повний контроль над дією, категорією, даними та extras. Це не рекомендується + для звичайних користувачів — призначено для Android-розробників, які вже знають, як працюють Intents. + \n\nУ майбутніх оновленнях буде додано нові готові шаблони, щоб спростити поширені сценарії без необхідності + вдаватися до розширених налаштувань. + + + + Пріоритет подій + Дізнайтеся, як порядок подій у вашому списку впливає на їх виконання + Кожен кадр екрана обробляється шляхом перевірки подій по одній, зверху вниз.\n\nПозиція події в списку визначає, коли вона отримає можливість виконатися. За замовчуванням, щойно умови події виконані та її дії запущені, кадр вважається обробленим. Обробка зупиняється для цього кадру, і наступний починається з першої події в списку.\n\nЦе означає, що за замовчуванням у кожному кадрі може виконуватися лише одна подія. + Ви можете змінити цю поведінку за допомогою поля Продовжувати виконання у налаштуваннях події. Коли воно увімкнено, після виконання цієї події обробка продовжується з наступної події у списку замість зупинки.\n\nЦе дозволяє кільком подіям виконуватися в одному кадрі.\n\nПриклад: ваш список містить Подію А, за якою іде Подія Б. Якщо Подія А продовжує виявлятися і для неї не увімкнено Продовжувати виконання, вона виконуватиметься в кожному кадрі, а Подія Б ніколи не отримає можливості виконатися.\n\nУвімкніть Продовжувати виконання для події А, і обидві події перевірятимуться в кожному кадрі.\n\nДля відпрацювання цієї концепції також доступний інтерактивний навчальний посібник. + + + + Перезарядка події + Дізнайтеся, як працює перезарядка події у вашому сценарії + Параметр перезарядки події дозволяє пропускати + подію протягом заданого часу після її виконання. \n\nПодія у стані перезарядки все одно вважається + увімкненою: перезарядка та стан події є незалежними. \n\nЯкщо подію вимкнено під час перезарядки, таймер + перезарядки буде скинуто, тому затримка більше не застосовується при повторному вмиканні події. + + + + Використання значень лічильників + Дізнайтеся про різні способи відображення та використання значень лічильників у вашому сценарії + + Ви можете відображати поточне значення + лічильника в дії «Сповіщення». Це корисно для відстеження прогресу під час виконання сценарію або для + показу підсумків після його завершення.\n\nЩоб вставити лічильник, натисніть кнопку «Додати лічильник» + у налаштуваннях дії. Це додасть у ваш текст заповнювач на кшталт {counterName}. Під час виконання + заповнювач замінюється фактичним значенням лічильника. Наприклад, якщо лічильник з іменем score + має значення 42, текст «Поточний рахунок: {score}» стане «Поточний рахунок: 42». + + Ви також можете вставити значення лічильника + в дію «Написати текст», щоб введений текст містив актуальне значення в момент виконання дії.\n\nЗаповнювач + працює так само, як і в дії «Сповіщення»: натисніть кнопку «Додати лічильник» або введіть + {counterName} безпосередньо. Наприклад, якщо лічильник з іменем score має значення 42, + текст «Мій рахунок: {score}» стане «Мій рахунок: 42». + + Значення лічильників фіксуються у звіті про + налагодження. Якщо щось не працює так, як очікувалося у вашому сценарії, створення звіту про налагодження + покаже, як саме змінювалися ваші лічильники, і допоможе знайти причину проблеми. + diff --git a/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_not_visible.xml index 7135e505c..3101e1237 100644 --- a/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - Комбінування кількох умов - Створіть та скомбінуйте кілька умов для вашої події - Клікніть на синю кнопку лише тоді, коли червона кнопка видима + Видимість умов + Використовуйте параметр «Видимість», щоб + виконувати натискання, коли ціль відсутня на екрані + Натискайте синю кнопку лише тоді, коли + червона кнопка не видима - Давайте знову змінимо правила гри. Синя ціль перестала рухатися, - але тепер на неї слід клікати лише тоді, коли червона ціль видима.\n\nСпочатку запустіть гру та перевірте, чи можете ви виграти - самостійно. + Нові правила! Синя ціль більше не + рухається, але натискати на неї потрібно лише тоді, коли червона ціль не видима на екрані. + \n\nЗапустіть гру і подивіться, чи зможете перемогти самостійно. - Знову ж таки, здається неможливим виграти вручну, тому давайте використаємо Smart - AutoClicker.\n\nВаш сценарій з попереднього навчання було збережено та завантажено для цього навчання, але нам - потрібно буде змінити кілька параметрів, щоб виграти цю нову гру.\n\nКлікніть на іконку налаштування сценарію, щоб - почати оновлення вашого нового сценарію. + Знову здається неможливим перемогти + вручну, тому скористаємося Klick\'r. \n\nВідкрийте меню налаштування сценарію, створіть нову Подію екрана + та почніть додавати умови для цілей гри. - Ми все ще хочемо клікнути на синю ціль, але лише коли червона видима.\n - Тому нам потрібно додати умову для цієї червоної цілі в нашу подію.\n\nКлікніть на вашу попередньо створену подію, щоб редагувати її. + Спочатку нам потрібна умова, яка + перевіряє, коли червона ціль НЕ видима на екрані. \n\nСтворіть нову умову зображення та захопіть червону + ціль. - Ми будемо комбінувати кілька умов, тому нам потрібно перевірити оператор умови - для цієї події.\n\nОператор умови вказує, як кілька умов будуть інтерпретуватися разом.\n - \'Одна\' означає, що лише одна з умов для цієї події повинна бути виконана, щоб - виконати дії.\n\n\'Всі\' означає, що всі умови для цієї події повинні бути виконані, щоб виконати дії. - \n\nОскільки ми хочемо виявити, чи дві речі відображаються разом, ми використаємо \'Всі\' + Ми хочемо натискати лише тоді, коли + червона ціль не видима, тому встановіть параметр «Видимо» у значення Ні. Так умова виконуватиметься лише + коли червона ціль відсутня на екрані. - Тепер нам потрібно оновити наші умови.\n\nКлікніть на поле умов, щоб відобразити - список умов. + Інші налаштування підходять для + нашого випадку — збережіть цю умову. - Попередня умова виявлення синьої цілі все ще правильна, але нам потрібна - нова для червоної цілі.\n\nКлікніть на кнопку створення умови, щоб створити нову умову для неї. + Цієї умови самої по собі достатньо, + щоб виграти, але вона також спрацьовуватиме, коли гра не запущена, що небажано. + \n\nЩоб уникнути цього, доповнимо її другою умовою, яка перевіряє, чи видима синя ціль. + Створіть нову Умову зображення та захопіть синю ціль. - Так само, як для синьої цілі, запустіть гру, щоб показати червону ціль. - Коли вона стане видимою, зробіть знімок екрана! - Використовуйте кнопку захоплення в плаваючому меню, щоб зробити знімок екрана. + Для цієї умови нам потрібно + переконатися, що синя ціль видима, тому стандартні налаштування повністю підходять. Збережіть умову та + поверніться до події, щоб продовжити. - Чи містить ваш знімок екрана червону ціль? Ви можете обрізати його, щоб отримати лише - частину, яка цікава для виявлення - червону ціль. - Якщо ваш знімок екрана не містить червону ціль, ви можете - натиснути цю кнопку, щоб зробити новий. + За наявності кількох умов оператор + умови важливий. Ми хочемо, щоб подія спрацьовувала, коли синя ціль видима І червона не видима, тому нам + потрібен оператор І; він вже встановлений за замовчуванням, тому все гаразд. + \n\nТепер створіть нову дію натискання, щоб продовжити. - Зображення вашої умови тепер записано!\n\nОскільки червона ціль не рухається, ми - можемо зберегти стандартну конфігурацію.\nКлікніть на кнопку збереження, щоб зареєструвати її та повернутися до списку умов. + Ми хочемо натискати на синю ціль, + тому виберіть тип позиції «За умовою» та вкажіть Умову зображення синьої цілі. + \n\nКоли закінчите, збережіть натискання, потім подію та сценарій, і поверніться до гри. - Закрийте список умов, щоб повернутися до налаштування події. + Запустіть сценарій і почніть гру, + щоб перемогти! \n\nЯкщо щось не працює, перевірте, що умови захоплені правильно і тривалість натискання + встановлена на 1 мс. - Тепер у нас є дві умови, по одній для кожної цілі, і дії будуть виконані - лише якщо обидві виявлені.\n\nКлікніть на поле дій, щоб відобразити список дій для нашої події. + Вітаємо! Ви навчилися використовувати + умову «Не видимо». Завжди поєднуйте її принаймні з однією іншою умовою, щоб не викликати дії ненавмисно + протягом усього сценарію. - Дія вже встановлена для кліку на синього персонажа, і вона буде виконана лише - коли синій та червоний персонажі видимі разом.\n\nЦе саме та поведінка, яка нам потрібна для перемоги в - грі, тому немає потреби редагувати нашу дію кліку.\n\nЗакрийте список дій, щоб повернутися до налаштування події. - - Клікніть на кнопку збереження, щоб зберегти вашу подію. - - Всі зміни повинні бути збережені у вашому сценарії, щоб бути зареєстрованими.\n\nКлікніть - на кнопку збереження, щоб зберегти ваші зміни. - - Ми готові виграти цю гру!\n\nКлікніть на кнопку початку, щоб почати - виявлення, а потім запустіть гру. - - Вітаємо!\n\nТепер ви знаєте, як комбінувати кілька умов для події, - але є ще багато чого вивчити! diff --git a/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..df53df509 --- /dev/null +++ b/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,67 @@ + + + + + + Оператор умов І + Використовуйте оператор І, щоб виконувати + натискання лише коли кілька цілей видимі одночасно + Натискайте синю кнопку лише тоді, коли видимі + і синя, і червона цілі + + Нові правила! Тепер у грі дві цілі. + Натискайте на синю, але лише коли обидві цілі — синя та червона — одночасно на екрані. + \n\nЗапустіть гру і подивіться, чи впораєтесь самостійно. + + Занадто складно робити це вручну, тому + скористаємося Klick\'r. \n\nВідкрийте меню налаштування сценарію, створіть нову Подію екрана і почніть + додавати умови для цілей гри. + + Нам потрібна одна умова на кожну ціль. + Почнемо з синьої. \n\nСтворіть нову умову зображення та захопіть синю ціль. + + Ми хочемо, щоб ця умова виконувалась + коли синя ціль видима, тому стандартні налаштування повністю підходять. Збережіть цю умову. + + Тепер додамо другу умову для червоної цілі. + \n\nСтворіть ще одну умову зображення та захопіть червону ціль. + + Тут те саме — червона ціль має бути + видимою, тому стандартні налаштування підходять. Збережіть цю умову і поверніться до події. + + При двох заданих умовах оператор умови + визначає, як вони поєднуються. Виберіть оператор за допомогою селектора вище. + \n\n• І: подія спрацьовує лише коли ВСІ умови виконані.\n• АБО: подія спрацьовує щойно ОДНА умова + виконана.\n\nДля нашої гри нам потрібні обидві цілі на екрані одночасно, тому виберіть І. + Селектор оператора умов + + І вже є оператором за замовчуванням, тому + все готово. \n\nТепер відкрийте розділ Дії та створіть нову дію натискання. + + Ми хочемо натискати на синю ціль, тому + виберіть тип позиції «За умовою» та вкажіть умову зображення синьої цілі. + \n\nКоли закінчите, збережіть натискання, потім подію та сценарій, і поверніться до гри. + + Запустіть сценарій і почніть гру, щоб + перемогти! \n\nЯкщо щось не працює, перевірте, що обидві умови захоплені правильно і тривалість натискання + встановлена на 1 мс. + + Вітаємо! Ви навчилися використовувати + оператор І. Тепер подія спрацьовує лише коли всі її умови виконані одночасно. + + diff --git a/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..53695ce2a --- /dev/null +++ b/feature/tutorial/src/main/res/values-uk/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,72 @@ + + + + + + Оператор умов АБО + Використовуйте оператор АБО, щоб натискати на + першу ціль, яка з\'явиться на екрані + Натискайте на будь-яку ціль щойно вона + з\'явиться на екрані + + Новий виклик! На екрані можуть з\'явитися + дві цілі. Червона коштує 2 очки, а синя — 1 очко, тому натискайте на ту, що з\'являється, якомога швидше. + \n\nЗапустіть гру і подивіться, як впораєтесь. + + Занадто швидко для ручного керування, тому + скористаємося Klick\'r. \n\nВідкрийте меню налаштування сценарію, створіть нову Подію екрана і почніть + додавати умови для цілей гри. + + Нам потрібна одна умова на кожну ціль. + Почнемо з синьої. \n\nСтворіть нову умову зображення та захопіть синю ціль. + + Ця умова має спрацьовувати коли синя ціль + видима, тому стандартні налаштування повністю підходять. Збережіть цю умову. + + Тепер додамо другу умову для червоної цілі. + \n\nСтворіть ще одну умову зображення та захопіть червону ціль. + + Тут те саме, червона ціль має бути видимою, + тому стандартні налаштування підходять. Збережіть цю умову. + + При АБО умови перевіряються по порядку і + подія спрацьовує щойно перша з них збігається, тому порядок умов важливий. + \n\nЧервона ціль приносить більше очок, тому ми хочемо, щоб вона перевірялася першою. Використовуйте кнопку + «, щоб перемістити її перед синьою, потім поверніться до діалогу Події. + + Тепер встановіть оператор умови на АБО. + Подія спрацьовуватиме щойно з\'явиться будь-яка з цілей. Якщо обидві видимі одночасно, червона умова буде + виявлена першою, оскільки має вищий пріоритет. \n\nВиберіть АБО. + + Оператор АБО тепер встановлено. Відкрийте + розділ Дії та створіть нову дію натискання. + + Ми хочемо натискати на ціль, яка + викликала подію. Виберіть тип позиції «За умовою». При АБО одночасно може бути позитивно виявлена лише одна + умова, тому вибирати конкретну умову не потрібно. Klick\'r автоматично натисне в місце розташування умови, + яка збіглася. \n\nКоли закінчите, збережіть натискання, потім подію та сценарій, і поверніться до гри. + + Запустіть сценарій і почніть гру, щоб + перемогти! \n\nЯкщо щось не працює, перевірте, що ваші умови захоплені правильно і тривалість натискання + встановлена на 1 мс. + + Вітаємо! Ви навчилися використовувати + оператор АБО і зрозуміли, чому пріоритет умов важливий. Помістивши червону умову першою, Klick\'r завжди + надає перевагу цілі з вищою цінністю, коли обидві видимі одночасно. + + diff --git a/feature/tutorial/src/main/res/values-uk/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-uk/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..58a6f4658 --- /dev/null +++ b/feature/tutorial/src/main/res/values-uk/strings_tutorial_counters_basics.xml @@ -0,0 +1,127 @@ + + + + Основи лічильників + Дізнайтеся, як використовувати дію «Змінити лічильник» та умову + «При досягненні лічильника». + Натисніть 10 разів на синю ціль, потім один раз на червону + ціль + + Ласкаво просимо до навчального посібника з лічильників! + \n\nТут ви автоматизуєте гру, де потрібно натиснути на синю ціль 10 разів, а потім один раз на червону ціль, + щоб підтвердити рахунок і отримати 10 очок. Ви можете спочатку спробувати гру або одразу перейти до + налаштування сценарію. + + Спочатку нам потрібно створити подію екрана, яка виявляє + синю ціль і натискає на неї. \n\nНатисніть «Створити подію», щоб почати. + + Почнемо з додавання умови для виявлення синьої цілі. + Натисніть на поле «Умови», щоб відкрити список умов і створити цю умову. \n\nНавчальний посібник продовжиться, + коли умову буде створено. + + Чудово! Тепер натисніть на поле «Дії», щоб додати дії, + які виконуватимуться при виявленні синьої цілі. + + Спочатку нам потрібна дія «Клік», щоб натиснути на синю + ціль. Натисніть кнопку «Створити», щоб додати нову дію. + + Налаштуйте клік на синю ціль, потім збережіть дію. + \n\nНавчальний посібник продовжиться, коли клік буде збережено. + + Нам також потрібно рахувати, скільки разів ми натиснули на + синю ціль. Це можна зробити за допомогою дії «Змінити лічильник», додаючи одиницю при кожному натисканні. + \n\nНатисніть кнопку «Створити» ще раз, щоб додати другу дію. + + Оберіть дію «Змінити лічильник», щоб збільшувати лічильник + кожного разу при натисканні на синю ціль. + + Спочатку нам потрібно вибрати, який лічильник оновлювати. + Натисніть «Вибрати лічильник», щоб відкрити список лічильників. + + Список наразі порожній. Натисніть кнопку «Створити», щоб + створити новий лічильник. Дайте йому назву (наприклад, «Сині кліки»), залиште початкове значення 0, потім + збережіть і виберіть його. + + Тепер налаштуйте, як змінюватиметься лічильник при кожному + натисканні на синю ціль. \n\nВстановіть оператор + і значення 1, щоб лічильник збільшувався на 1 при кожному + кліку. \n\nПотім збережіть дію та поверніться до діалогу події. + Значення може бути фіксованим числом або поточним + значенням іншого лічильника. + + Чудово! Ця подія екрана тепер натискатиме на синю ціль і + збільшуватиме лічильник при кожному виявленні. \n\nЗбережіть подію, щоб повернутися до сценарію. + + Тепер нам потрібна подія, яка реагує, коли лічильник + досягає 10. Такий тип події не запускається екраном, тому це тригерна подія. + \n\nНатисніть на вкладку «Тригери», щоб відкрити список тригерних подій. + + Натисніть кнопку «Створити», щоб додати нову тригерну + подію. + + Як і подія екрана, тригерна подія потребує умов. Натисніть + на поле «Умови», щоб відкрити список умов і створити нову умову тригера. + + Оберіть тип умови «При досягненні лічильника», щоб + запускати цю подію, коли лічильник досягне певного значення. + + Оберіть лічильник, який ви створили раніше (той, що рахує + кліки по синій цілі), щоб використати його як тригер. + + Тепер налаштуйте порівняння так, щоб умова виконувалась, + коли лічильник дорівнює 10. Є кілька операторів порівняння, але тут нам потрібно перевірити рівність, тому + оберіть «=». Потім введіть 10 як значення, збережіть умову та поверніться до діалогу події. + Значення для порівняння може бути фіксованим + числом або поточним значенням іншого лічильника. + + Умову встановлено! Тепер нам потрібно визначити, що + відбувається, коли лічильник досягає 10. Натисніть на поле «Дії», щоб відкрити список дій. + + Спочатку створіть дію «Клік» і вручну розмістіть її на + червоній цілі, щоб підтвердити рахунок. + + Налаштуйте клік на червону ціль, потім збережіть дію. + Зверніть увагу, що в тригерній події позицію кліка завжди потрібно вказувати вручну. \n\nНавчальний посібник + продовжиться, коли клік буде збережено. + + Тепер створіть другу дію для скидання лічильника. Натисніть + кнопку «Створити» ще раз і оберіть дію «Змінити лічильник». + + Ми хочемо встановити лічильник синіх кліків на 0, тому + спочатку виберіть лічильник синіх кліків. + + Встановіть оператор = і значення 0, щоб скидати лічильник + після кожного підтвердження. Потім збережіть дію та поверніться до діалогу події. + + Ця тригерна подія натискатиме на червону ціль і скидатиме + лічильник щоразу, коли нараховується 10 синіх кліків. Список тригерних подій виконується між кожним кадром + екрана, перед списком подій екрана, тому щойно лічильник досягає 10, ця подія запускається негайно: червона + ціль натискається і лічильник скидається, готовий до наступного циклу. \n\nЗбережіть подію, щоб повернутися + до сценарію. + + Сценарій готовий! Він натискатиме на синю ціль, рахуватиме + кожне натискання, потім підтверджуватиме червоною ціллю кожні 10 кліків і починатиме заново. \n\nЗбережіть + сценарій, щоб застосувати конфігурацію. + + Все готово! Запустіть сценарій, потім відкрийте гру і + спостерігайте, як Klick\'r виконує підрахунок замість вас. + + Чудово! Ви навчилися використовувати лічильники для + відстеження значень між кількома подіями. \n\nУ поєднанні з дією «Змінити лічильник» та умовою «При досягненні + лічильника» ви тепер можете створювати автоматизації, які реагують на повторювані дії. + + diff --git a/feature/tutorial/src/main/res/values-uk/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-uk/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..fbfb47f62 --- /dev/null +++ b/feature/tutorial/src/main/res/values-uk/strings_tutorial_events_priority.xml @@ -0,0 +1,69 @@ + + + + + Визначення пріоритету події + Надати пріоритет одній Події над іншою + Натискайте на цілі якомога швидше. Синій = 1 очко; + Червоний = 10 очок + + Нова гра! Потрібно натискати на цілі якомога швидше, але + червона ціль приносить більше очок. Можете спочатку спробувати гру або відкрити меню налаштування сценарію, + щоб почати автоматизацію. + + Ми хочемо визначати дві різні цілі: синю та червону. У + цьому уроці ми створимо дві окремі події: одну для синьої цілі та одну для червоної. \n\nСпочатку створіть + Подію для синьої цілі; вона має натискати на неї при виявленні. Не забудьте скористатися функціями + тестування, щоб переконатися, що умова визначається правильно. \n\nУрок продовжиться після збереження + Події для синьої цілі. + + Чудово! Тепер потрібне те саме, але для червоної цілі. + Натисніть кнопку «Створити подію» і створіть подію для червоної цілі; вона має натискати на неї при + виявленні. \n\nУрок продовжиться після збереження Події для червоної цілі. + + У нашому списку тепер дві події, по одній для кожної цілі. + Збережіть Сценарій і перевірте його в грі. + + Щось пішло не так. Сценарій натискає лише на синю ціль, + повністю ігноруючи червону, що не дає нам перемогти. \n\nЧому так відбувається? Тому що синя подія стоїть + перед червоною, і оскільки вона завжди спрацьовує, поточний кадр не оцінюється далі, а наступний починається + з початку списку Подій. \n\nЄ кілька способів це виправити. Відкрийте діалог налаштування сценарію, щоб + дізнатися як. + + Проблему можна вирішити двома способами: \n\nМожна змінити + параметр «Продовжити виконання» події синьої цілі, щоб продовжити обробку того самого кадру і виконати також + червону подію. Це спричинить обидва натискання, коли обидві цілі видимі одночасно. \n\nАбо можна перемістити + подію червоної цілі на початок списку, щоб вона перевірялася першою і натискалася при появі, але синя ціль + більше не натискатиметься, коли червона теж відображається. \n\nГоловна відмінність між рішеннями — швидкість: + розміщення червоної події першою дозволяє реагувати максимально швидко при її появі, будучи трохи повільнішим, + коли видима лише синя ціль. + + Оскільки гра дає 10 очок за червону ціль, ми хочемо + реагувати на неї якомога швидше, перемістивши червону подію на початок списку. \n\nПеремістіть червону подію + на перше місце і збережіть сценарій. Тепер ви зможете перемогти в грі. + Ви можете змінити порядок Подій, утримуючи цю + іконку і перетягуючи подію на потрібне місце. + + Як завжди, спочатку запустіть сценарій, а потім гру. + \n\nЯкщо все одно не вдається перемогти, переконайтеся, що кожна подія працює окремо за допомогою функцій + тестування. + + Чудово! Тепер ви розумієте, як працює пріоритет подій і + як поводиться цикл Подій Екрана. Це ключ до створення та управління складними сценаріями. + + diff --git a/feature/tutorial/src/main/res/values-uk/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-uk/strings_tutorial_events_state.xml new file mode 100644 index 000000000..9f57cc156 --- /dev/null +++ b/feature/tutorial/src/main/res/values-uk/strings_tutorial_events_state.xml @@ -0,0 +1,142 @@ + + + + + Вимкнення невикористовуваних подій + Змінюйте стан кількох подій для оптимізації складного сценарію. + Натискайте на цілі по порядку: синя, червона, зелена, потім жовта. + + Нова гра! Цього разу потрібно натискати на чотири кольорові цілі + по порядку: спочатку синя, потім червона, потім зелена і нарешті жовта. \n\nМожна спочатку спробувати гру, щоб + зрозуміти, як вона працює, або одразу відкрити налаштування сценарію і почати автоматизацію. + + Нам потрібно виявляти чотири різні цілі, по одній на кожен + колір. Ми створимо по одній Події на ціль. \n\nПочніть з синьої цілі: створіть нову Подію, яка виявляє її в + ігровій зоні та натискає на неї. + + При використанні кількох подій важливо давати їм зрозумілі + імена, щоб не заплутатися. Дайте цій Події чітке ім\'я, наприклад «Синя ціль», щоб легко знаходити її у + сценарії. \n\nПісля цього створіть нову умову Зображення та захопіть синю ціль. + + Оскільки ціль рухається, потрібно встановити тип виявлення + «Область виявлення» та вибрати ігрову область. \n\nКоли область буде правильно налаштована, збережіть її і поверніться + до діалогу Подія. + + Умову налаштовано. Тепер нам потрібна дія Натискання, щоб + Подія натискала на виявлену ціль. \n\nСтворіть нову дію Натискання, щоб продовжити. + + Ціль рухається, тому ми не можемо задати фіксовану позицію. + У полі «Клікнути на» виберіть «Клікнути на виявленій умові» та виберіть умову синьої цілі. Так натискання завжди потраплятиме + точно туди, де було знайдено ціль.\n\nПісля вибору умови збережіть натискання і поверніться до діалогу + Подія. + + Подія для синьої цілі готова! Тепер створіть Подію для + червоної цілі таким же чином: виявляйте її в ігровій зоні та натискайте на неї. Туторіал продовжиться після + збереження вашої Події для червоної цілі. + + Чудово! Тепер створіть таку саму Подію для зеленої цілі. + Туторіал продовжиться після збереження вашої Події для зеленої цілі. + + Майже готово! Створіть останню Подію для жовтої цілі. Туторіал + продовжиться після збереження вашої Події для жовтої цілі. + + Усі чотири Події готові. Оскільки ми визначили їх у порядку + ігрової послідовності, їхній пріоритет налаштовано правильно. \n\nЗбережіть сценарій і перевірте його в + грі. + + Сценарій виявляє цілі та натискає на них, але він, мабуть, + занадто повільний, щоб перемогти. \n\nЗараз усі чотири Події активні одночасно, тому в кожному кадрі + сценарій перевіряє синю, потім червону, потім зелену, потім жовту — незалежно від того, яку ціль щойно + натиснули. Це марнує дорогоцінний час! \n\nВідкрийте налаштування сценарію, щоб дізнатися, як це + виправити. + + Кожна Подія має початковий стан: вона може стартувати + увімкненою або вимкненою. Зараз усі чотири Події увімкнені, тому всі перевіряються в кожному кадрі. \n\nРішення: + тримати активною лише Подію поточної цілі, а решту вимкнути. Коли ціль натиснуто, її Подія увімкне наступну і + вимкне решту. \n\nПочнемо з редагування події синьої цілі. + + Синя ціль — перша для натискання, тому її Подія повинна + стартувати увімкненою; тут нічого змінювати не потрібно. \n\nНам лише потрібно додати дію «Змінити стан події», + щоб при натисканні на синю ціль Подія червоної цілі вмикалась, а решта вимикались. Натисніть на область Дії, + щоб додати цю дію. + + Виберіть тип дії «Змінити стан події». + + Ця дія дозволяє змінювати стан будь-якої Події у сценарії при + спрацюванні даної Події. Натисніть поле «Немає змін», щоб вказати, які Події змінити. + + Для кожної Події у списку можна задати один з трьох станів: + \n• Увімкнути: Подія стає активною і перевірятиметься в кожному кадрі \n• Вимкнути: Подія стає неактивною і + повністю пропускається \n• Інвертувати: щоразу перемикається між активним і неактивним \n\nОскільки синю щойно + натиснули, увімкніть Подію червоної цілі та вимкніть усі інші. Натисніть Далі, коли закінчите. + Кожен рядок Події показує три варіанти: Увімкнути, + Вимкнути та Переключити. Натисніть той, який хочете застосувати при виконанні цієї дії. + + Чудово! Збережіть Подію синьої цілі. + + Тепер відкрийте Подію червоної цілі у списку та налаштуйте + її таким самим чином. + + На відміну від Події синьої цілі, ця Подія не повинна бути + активною на початку сценарію, оскільки її ціль не перша. Змініть початковий стан на Вимкнено. + + Тепер додайте дію «Змінити стан події», щоб при натисканні + на цю ціль Подія наступної цілі вмикалась, а решта вимикались. Натисніть на область Дії. + + Налаштуйте перемикання: увімкніть зелену ціль і вимкніть усі + інші. Натисніть Далі, коли закінчите. + + Гарна робота! Тепер відкрийте Подію зеленої цілі та + налаштуйте її таким самим чином. + + Зелена ціль теж не повинна бути активною з самого початку. + Змініть її початковий стан на Вимкнено. + + Тепер додайте дію «Змінити стан події», щоб при натисканні на + зелену ціль Подія жовтої цілі вмикалась, а решта вимикались. Натисніть на область Дії. + + Налаштуйте перемикання: увімкніть жовту ціль і вимкніть усі + інші. Натисніть Далі, коли закінчите. + + Майже готово! Відкрийте Подію жовтої цілі, щоб завершити + налаштування. + + Жовта ціль — остання в послідовності, тому вона теж повинна + стартувати вимкненою. Змініть її початковий стан на Вимкнено. + + Додайте дію «Змінити стан події» і до Події жовтої цілі. При + натисканні на жовту ми хочемо повернутися до початку: увімкніть синю ціль і вимкніть усі інші. Натисніть на + область Дії. + + Налаштуйте перемикання: увімкніть синю ціль і вимкніть усі + інші. Так послідовність повторюватиметься нескінченно. Натисніть Далі, коли закінчите. + + Усі події повністю налаштовані. Збережіть сценарій, щоб + застосувати зміни. + + Усі події налаштовано! Збережіть сценарій і запустіть гру. + Не забудьте запустити сценарій перед початком гри. \n\nОскільки наш сценарій має внутрішній стан, його + потрібно перезапускати щоразу при перезапуску гри, щоб він не чекав останню ціль попередньої сесії. Це легко + автоматизувати, відстежуючи видимість кнопки старту для скидання станів подій. + + Ви перемогли! \n\nКеруючи тим, які Події активні в кожен + момент, сценарій завжди точно знає, яку ціль шукати наступною — жодних зайвих кадрів на перевірку цілей не в + тій черговості. \n\nСаме так дія Переключити подію дозволяє створювати послідовну автоматизацію, керовану + станом. + + diff --git a/feature/tutorial/src/main/res/values-zh-rCN/strings_categories.xml b/feature/tutorial/src/main/res/values-zh-rCN/strings_categories.xml index 08e46025a..6b9913d44 100644 --- a/feature/tutorial/src/main/res/values-zh-rCN/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-zh-rCN/strings_categories.xml @@ -1,4 +1,4 @@ - + + 暂停动作 + 了解暂停如何影响动作执行和检测 + 暂停动作会将整个场景暂停设定的时间:在此期间, + 不会执行任何动作,也不会进行任何屏幕检测。\n\n非常常见的用法是在动作列表末尾添加一个暂停。当您点击 + 某个地方时,被点击的应用程序需要时间来处理点击并显示结果——通常您会希望等待这个时刻,然后再让 + Klick\'r 重新开始分析屏幕。\n\n在两个动作之间添加暂停也是有效的,但在列表末尾添加暂停通常是更重要的 + 需求。 + + + 滑动动作 + 了解滑动手势的执行方式 + 滑动动作沿直线从起始位置到结束位置执行拖动手势。 + 两个坐标都是固定的,在动作配置中设定。\n\n持续时间控制手势从开始到结束所需的时间:较短的持续时间产生 + 更快的滑动,较长的持续时间产生更慢、更受控的滑动。 + + + 点击偏移 + 了解如何调整对检测到的条件的点击位置 + 点击检测到的条件时,默认情况下点击会应用于 + 检测区域的中心。\n\n点击偏移允许您将该位置相对于条件中心沿 X 轴和 Y 轴移动固定数量的像素。当您想要 + 点击的元素接近但不完全位于检测区域中心时,这非常有用。 + + + 点击目标 + 了解如何配置点击将应用的位置 + 点击动作可以针对两种位置:始终相同的静态 + 位置,或检测到的条件的位置。\n\n在动作配置对话框的目标选择器中选择您的瞄准方式。 + 使用静态位置时,无论屏幕上显示什么内容, + 点击都始终发生在相同的精确坐标处。\n\n请注意,这些坐标对旋转敏感:如果设备旋转,点击可能会落在意外 + 位置甚至超出屏幕边界。 + 使用条件位置时,点击会应用于检测到的图像 + 条件的中心,无论目标出现在屏幕的哪个位置都会跟踪它。\n\n使用 AND 运算符时,所有条件都必须满足,因此 + 每个图像条件都有一个可用位置。您可以自由选择任意一个并通过偏移量进行微调。 + 使用 OR 运算符时,只有第一个满足的条件会被 + 评估,其余条件将被忽略。因此,Klick\'r 无法提前知道哪个条件会被检测到。\n\n因此,使用 OR 运算符时无法 + 选择特定条件作为目标:点击始终会应用于运行时第一个检测到的条件,无论它是哪个。 + + + 条件顺序与速度 + 条件的顺序如何影响事件检查速度 + + 列表中条件的顺序会影响事件的检查速度。\n\n使用 AND + 运算符时,一旦找到第一个未满足的条件,检查就会停止。将最不可能满足的条件放在最前面,可以让应用更早跳过其余条件,使事件更快。 + + 使用 OR + 运算符时,一旦找到第一个满足的条件,检查就会停止。将最可能满足的条件放在最前面,可以让应用更早完成,而无需检查其余条件。\n\n在两种情况下,将最重要的条件放在列表顶部,都是保持场景高效运行的简单方法。 + + + + 事件状态 + 了解如何在场景运行时启用和禁用事件 + + 场景中的每个事件(屏幕事件和触发事件)都有一个状态:启用禁用。\n\ + n启用时,事件正常运行并检查其条件。禁用时,它会被完全跳过,就像不存在一样。\n\n默认情况下,每个事件都以启用状态开始。你可以通过事件设置中的初始状态字段来更改此设置。 + + 在场景运行时,可以使用更改事件状态动作来更改任何事件的状态。该动作可以启用、禁用或切 + 换一个或多个事件的状态。\n\n这开启了很多可能性:一个接一个相互开启的事件、运行一次后自动关闭的事件,或者同一时间只有一个处于活动状态的事件组。 + + 场景中的所有事件都被禁用时,场景会自动停止。没有更多事情要做,因此 + Klick\'r 会自动停止。\n\n这是结束场景的简单方法:让最后一个事件在完成任务后禁用所有其他事件,一切都会自动停止。 + + + + 动作列表 + 了解动作列表的执行方式 + 动作按顺序依次执行。您可以使用 << 和 >> + 按钮更改动作的顺序,或直接点击其索引编号。\n\n请尽量保持动作列表简短。普通自动点击器每个事件只执行一个动作——这就是 + 应该遵循的模式。如果您发现自己在单个事件中添加了很多动作,通常说明应该将工作拆分为多个事件,每个事件响应屏幕上 + 实际显示的内容。这就是 Klick\'r 的"看见即行动"理念:先检测,再行动。 + + + 输入文字动作 + 了解如何向已获焦点的输入框输入文字 + 在输入文字动作运行之前,目标输入框必须已获得焦点, + 就像您点击它以调出键盘一样。\n\n为此,在输入文字动作之前添加一个点击该输入框的点击动作。如果点击后有过渡动画, + 在两者之间添加一个等待动作可以确保输入框准备就绪。\n\n该动作还有一个"确认"选项:启用后,它会在设置文字后自动按 + Enter 键,确认或提交输入内容。 + 您可以将计数器的值插入要输入的文字中。在动作配置中 + 按"追加计数器"按钮选择一个计数器:它会在文字框当前光标位置插入占位符 {计数器名称}。\n\n在运行时,文字被 + 粘贴到输入框之前,每个 {计数器名称} 占位符都会被替换为计数器的当前值。例如,如果名为 苹果 的计数器 + 的值为 18,文字"我有 {苹果} 个苹果"就会变成"我有 18 个苹果"。 + + + 系统动作 + 了解如何触发 Android 导航动作 + 系统动作执行 Android 内置导航动作之一:返回、主页或最近 + 应用。\n\n这些与屏幕底部导航按钮的动作相同。它们不需要坐标,无论当前打开哪个应用都能在系统层面运行。 + + + 修改计数器动作 + 了解如何修改计数器的值 + 修改计数器动作使用预定义的静态值对计数器执行操作。 + 有三种操作可用:将该值加到计数器(+)、从计数器中减去它(−),或将计数器设置为该精确值(=)。\n\n这是更新计数器最 + 常见的方式——例如,每次检测到条件时加 1,或在达到目标时重置为 0。 + 除了静态值,您还可以使用另一个计数器的当前值作为 + 操作数。同样的三种操作(+、−、=)均适用,但操作量在运行时从所选计数器读取,而不是在配置时固定。\n\n这让您可以构建 + 计数器之间相互交互的动态场景。 + + + 通知动作 + 了解如何在场景运行时显示通知 + 通知动作显示带有您自定义标题和消息的 Android 通知。 + \n\n您可以使用"追加计数器"按钮,或直接输入占位符 {计数器名称},将计数器的当前值插入通知文字。运行时它会被 + 替换为计数器的值——例如,"我有 {苹果} 个苹果"变为"我有 18 个苹果"。 + 通知重要性级别控制通知显示的显眼程度。较高的重要性 + 级别可能显示横幅并播放声音,而较低级别则静默地发送到通知抽屉。\n\n确切行为取决于设备,可在 Android 通知设置中针对 + Klick\'r 进一步自定义。 + + + 更改事件状态动作 + 了解如何在运行时启用和禁用事件 + 禁用的事件在场景循环中被完全跳过——其条件从不检查, + 其动作也从不运行。这意味着它完全不消耗处理时间。\n\n禁用当前不使用的事件是提升性能的好方法。例如,在菜单阶段和游戏 + 阶段交替的场景中,在游戏阶段禁用所有菜单事件(反之亦然),可以在任何时刻只保持相关事件处于活动状态。 + 配置动作时,您可以选择一次性更改场景中所有事件的 + 状态,或分别为每个事件定义新状态。\n\n每个事件可用三种状态变更:启用它、禁用它,或从其当前值切换——已启用的事件变为 + 禁用,已禁用的事件变为启用。 + 如果场景中的所有事件同时被禁用,场景将自动停止, + 因为没有任何内容可以执行。\n\n这可以有意作为在达到目标后终止场景的干净方式:一个禁用所有事件的最终更改事件状态 + 动作将使场景停止运行。 + + + Intent 动作 + 了解如何与其他应用程序通信 + Intent 是 Android 上应用程序之间相互通信的方式。Intent + 动作让您可以直接从场景中利用这个系统。\n\n提供了一组预定义模板以简化操作。最常用的是"启动应用",它在您的设备上启动 + 另一个应用,就像您从启动器点击其图标一样。 + "高级"选项卡允许您手动定义原始 Intent,让您完全控制动作、 + 类别、数据和 extras。这不建议普通用户使用——面向已了解 Intent 工作原理的 Android 开发者。\n\n未来更新中将添加更多 + 开箱即用的模板,以便在不使用高级选项的情况下更轻松地设置常见用例。 + + + + 事件优先级 + 了解列表中事件的顺序如何影响哪些事件运行 + 从屏幕捕获的每一帧都通过从上到下逐一检查事件来处理。\n\n事件在列表中的位置决定了它何时有机会运行。默认情况下,一旦事件的条件满足并执行了其动作,该帧即视为处理完毕。该帧的处理停止,下一帧从列表中的第一个事件重新开始。\n\n这意味着默认情况下每帧只能运行一个事件。 + 你可以通过事件设置中的继续执行字段来改变此行为。启用后,该事件运行之后,处理会继续到列表中的下一个事件而不是停止。\n\n这允许多个事件在同一帧中运行。\n\n示例:你的列表包含事件A,后面是事件B。如果事件A持续被检测到且没有启用继续执行,它将在每帧运行,而事件B永远没有机会执行。\n\n在事件A上启用继续执行,两个事件将在每帧都被检查。\n\n还有一个互动教程可供练习此概念。 + + + + 事件重新装填 + 了解场景中事件重新装填的行为 + 事件重新装填参数允许您在事件触发后的一段时间内跳过该事件。 + \n\n处于重新装填状态的事件仍被视为启用:重新装填与事件状态相互独立。 \n\n如果事件在重新装填状态下被禁用,重新装填 + 计时器将被清除,因此当事件重新启用时冷却不再适用。 + + + + 使用计数器的值 + 了解在场景中显示和使用计数器值的不同方法 + + 您可以在通知动作中显示计数器的当前值。这对于在场景运行时监控进度,或在结束时显示摘要非常有用。\n\n要插入计数器,请在动作配置中按下"添加计数器"按钮。这会在您的文本中添加一个类似 {counterName} 的占位符。运行时,该占位符将被计数器的实际值替换。例如,如果名为 score 的计数器值为 42,则文本"当前分数:{score}"将变为"当前分数:42"。 + + 您也可以在写入文本动作中插入计数器的值,这样输入的文本将在动作执行时包含当前值。\n\n占位符的使用方式与通知动作相同:按下"添加计数器"按钮,或直接输入 {counterName}。例如,如果名为 score 的计数器值为 42,则文本"我的分数是 {score}"将变为"我的分数是 42"。 + + 计数器的值会被记录在调试报告中。如果您的场景出现了意外情况,生成调试报告将帮助您准确了解计数器的变化过程,从而更容易找到问题所在。 + diff --git a/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_not_visible.xml index 5b2222d1c..78570f90a 100644 --- a/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - 组合多个条件 - 为您的事件创建和组合多个条件 - 只有在红色按钮可见时才点击蓝色按钮 + 条件可见性 + 使用"可见性"选项,在目标不在屏幕上时触发点击 + 仅在红色按钮不可见时点击蓝色按钮 - 让我们再次改变游戏规则。蓝色目标停止移动,但现在只有在红色目标可见时才能点击。\n\n首先,开始游戏并检查是否能自己赢得比赛。 + 新规则!蓝色目标已停止移动,但只有在红色目标不可见时才能点击它。 + \n\n启动游戏,看看你能否自己获胜。 - 再次尝试手动赢得比赛似乎不可能,所以让我们使用Klick\'r。\n\n你之前教程的场景已经被保留并加载到这个教程中,但是为了赢得这场新比赛,我们需要更改一些参数。\n\n点击场景配置图标开始更新你的新场景。 + 再次看来,手动获胜似乎不可能,所以让我们使用 Klick\'r。 + \n\n打开场景配置菜单,创建一个新的屏幕事件,并开始为游戏目标添加条件。 - 我们仍然想要点击蓝色目标,但只有在红色目标可见时才能点击。\n -所以我们需要在事件中为这个红色目标添加一个条件。\n\n点击你之前创建的事件以进行编辑。 + 首先,我们需要一个条件来检测红色目标何时不在屏幕上。 + \n\n创建一个新的图像条件并捕获红色目标。 - 我们将结合多个条件,所以我们需要检查此事件的条件运算符。\n\n条件运算符表示如何一起解释多个条件。\n -‘单一’表示此事件的条件中只需满足一个条件即可执行操作。\n\n‘所有’表示此事件的所有条件必须满足才能执行操作。\n\n由于我们要检测两个事物是否同时显示,所以我们将使用「所有」 + 我们只想在红色目标不可见时点击,因此将"是否可见"选项设置为"否"。这样,只有当红色目标从屏幕上消失时,条件才会满足。 - 现在我们需要更新我们的条件。\n\n单击条件字段以显示 条件列表。 + 其他设置对我们的需求来说没问题——继续保存这个条件。 - 检测蓝色目标的先前条件仍然正确,但我们需要一个新的条件来检测红色目标。\n\n点击创建条件按钮以为其创建一个新条件。 + 仅此条件就足以赢得游戏,但在游戏未运行时它也会触发,这不太理想。 + \n\n为了避免这种情况,让我们将其与第二个条件配合使用,该条件检测蓝色目标是否可见。 + 创建一个新的图像条件并捕获蓝色目标。 - 就像蓝色目标一样,开始游戏以显示红色目标。一旦它可见,就拍摄一张屏幕截图! - 使用浮动菜单中的截屏按钮来拍摄截图。 + 对于此条件,我们要确认蓝色目标可见,因此默认设置完全正确。保存条件并返回事件以继续。 - 你的截图是否包含红色目标?您可以裁剪它,以便仅获得检测所需的红色目标部分。 - 如果你的截图不包含红色目标,你可以按此按钮拍摄新的截图。 + 有多个条件时,条件运算符很重要。我们希望事件在蓝色目标可见且红色目标不可见时触发,因此需要 AND 运算符;它已经是默认值了,所以一切正常。 + \n\n现在创建一个新的点击动作以继续。 - 你的条件图像现在已记录!由于红色目标不会移动,我们可以保留默认配置。\n单击保存 按钮进行注册,然后返回条件列表。 + 我们要点击蓝色目标,因此选择位置类型"按条件",并选择蓝色目标的图像条件。 + \n\n完成后,保存点击动作,然后保存事件和场景,并返回游戏。 - 关闭条件列表,返回事件配置。 + 启动你的场景并开始游戏以获胜! + \n\n如果无效,请检查条件是否正确捕获,以及点击时长是否设置为 1ms。 - 现在我们有了两个条件,一个用于每个目标,只有在两者都检测到时,操作才会执行。\n\n单击 “操作 ”字段,显示事件的操作列表。 + 恭喜!你已学会使用"不可见"条件。请始终将其与至少一个其他条件结合使用,以避免在整个场景运行过程中意外触发动作。 - 该操作已设置为点击蓝色角色,只有在蓝色和红色角色同时可见时才会执行。\n\n这正是我们赢得比赛所需的行为,因此无需编辑我们的点击操作。\n\n关闭操作列表,返回事件配置。 - - 点击保存按钮,保存您的活动 - - 所有更改都必须保存到你的场景中以进行注册。\n\n点击保存按钮以保存你的更改。 - - 我们准备好赢得这场比赛了!\n\n点击开始按钮以开始检测,然后开始游戏。 - - 恭喜!\n\n你现在知道如何为事件组合多个条件,但还有很多东西要学习! diff --git a/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..d12820d74 --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,57 @@ + + + + + + 条件运算符 AND + 使用 AND 运算符,仅在多个目标同时可见时触发点击 + 仅在蓝色和红色目标同时可见时点击蓝色按钮 + + 新规则!游戏现在显示两个目标。你需要点击蓝色目标,但只有在蓝色和红色目标同时出现在屏幕上时才能点击。 + \n\n启动游戏,看看你能否靠自己跟上节奏。 + + 手动操作时机太难把握,所以让我们使用 Klick\'r。 + \n\n打开场景配置菜单,创建一个新的屏幕事件,并开始为游戏目标添加条件。 + + 每个目标需要一个条件。先从蓝色目标开始。 + \n\n创建一个新的图像条件并捕获蓝色目标。 + + 我们希望在蓝色目标可见时满足此条件,因此默认设置完全正确。保存此条件。 + + 现在为红色目标添加第二个条件。 + \n\n再创建一个图像条件并捕获红色目标。 + + 这里也一样——红色目标应该可见,所以默认设置是正确的。保存此条件并返回事件。 + + 设置好两个条件后,条件运算符决定如何组合它们。使用上方显示的选择器来选择运算符。 + \n\n• AND:仅当所有条件都满足时,事件才会触发。\n• OR:只要有一个条件满足,事件就会立即触发。 + \n\n对于我们的游戏,需要两个目标同时在屏幕上,因此请选择 AND。 + 条件运算符选择器 + + AND 已经是默认运算符,所以我们准备好了。 + \n\n现在打开"动作"部分,创建一个新的点击动作。 + + 我们要点击蓝色目标,因此选择位置类型"按条件",并选择蓝色目标的图像条件。 + \n\n完成后,保存点击动作,然后保存事件和场景,并返回游戏。 + + 启动你的场景并开始游戏以获胜! + \n\n如果无效,请检查两个条件是否均已正确捕获,以及点击时长是否设置为 1ms。 + + 恭喜!你已学会使用 AND 运算符。事件现在只会在所有条件同时满足时才触发。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..4e05c5fe8 --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,57 @@ + + + + + + 条件运算符 OR + 使用 OR 运算符点击第一个出现在屏幕上的目标 + 一旦有目标出现在屏幕上就立即点击 + + 新挑战!屏幕上可能出现两个目标。红色目标值 2 分,蓝色目标值 1 分,所以要尽快点击出现的那个。 + \n\n启动游戏,看看你能发挥多好。 + + 手动操作太难跟上节奏,所以让我们使用 Klick\'r。 + \n\n打开场景配置菜单,创建一个新的屏幕事件,并开始为游戏目标添加条件。 + + 每个目标需要一个条件。先从蓝色目标开始。 + \n\n创建一个新的图像条件并捕获蓝色目标。 + + 此条件应在蓝色目标可见时触发,因此默认设置完全正确。保存此条件。 + + 现在为红色目标添加第二个条件。 + \n\n再创建一个图像条件并捕获红色目标。 + + 这里也一样,红色目标应该可见,所以默认设置是正确的。保存此条件。 + + 使用 OR 时,条件按顺序检查,一旦第一个匹配就触发事件,因此条件的顺序很重要。 + \n\n红色目标得分更高,所以我们希望它被优先检查。使用 « 按钮将其移到蓝色条件之前,然后返回事件对话框。 + + 现在将条件运算符设置为 OR。只要任一目标出现,事件就会触发。如果两个目标同时可见,红色条件将首先匹配,因为它的优先级更高。 + \n\n选择 OR。 + + OR 运算符已设置好。打开"动作"部分,创建一个新的点击动作。 + + 我们想点击触发事件的目标。选择位置类型"按条件"。使用 OR 时,每次只有一个条件能被正向检测到,因此无需选择特定条件。Klick\'r 会自动点击匹配条件的位置。 + \n\n完成后,保存点击动作,然后保存事件和场景,并返回游戏。 + + 启动你的场景并开始游戏以获胜! + \n\n如果无效,请检查你的条件是否正确捕获,以及点击时长是否设置为 1ms。 + + 恭喜!你已学会使用 OR 运算符,也明白了为什么条件优先级很重要。通过将红色条件排在第一位,当两个目标同时可见时,Klick\'r 始终优先选择得分更高的目标。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..aac47e656 --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_counters_basics.xml @@ -0,0 +1,83 @@ + + + + 计数器基础 + 学习如何使用"更改计数器"动作和"计数器达到时"条件。 + 点击蓝色目标10次,然后点击一次红色目标 + + 欢迎来到计数器教程! + \n\n在这里,您将自动化一个游戏:点击蓝色目标10次,然后点击红色目标一次以验证计数并获得10分。您可以先尝试游戏,或直接进入场景配置。 + + 首先,我们需要创建一个屏幕事件,用于检测蓝色目标并点击它。\n\n点击"创建事件"开始。 + + 先添加一个条件来检测蓝色目标。点击"条件"字段以打开条件列表并创建该条件。\n\n条件创建完成后教程将继续。 + + 很好!现在点击"动作"字段,添加检测到蓝色目标时要执行的动作。 + + 我们首先需要一个"单击"动作来点击蓝色目标。点击创建按钮添加新动作。 + + 配置单击以点击蓝色目标,然后保存动作。\n\n单击保存后教程将继续。 + + 我们还需要记录点击蓝色目标的次数。可以使用"更改计数器"动作,每次点击时将计数器加一。\n\n再次点击创建按钮添加第二个动作。 + + 选择"更改计数器"动作,以便每次点击蓝色目标时递增计数器。 + + 首先,我们需要选择要更新的计数器。点击"选择计数器"以打开计数器列表。 + + 列表目前为空。点击创建按钮新建一个计数器。为其命名(例如"蓝色点击次数"),保持初始值为0,然后保存并选择它。 + + 现在配置每次点击蓝色目标时计数器的变化方式。\n\n将运算符设为 + ,值设为 1,这样每次点击计数器加1。\n\n然后保存动作并返回事件对话框。 + 该值可以是固定数字,也可以是另一个计数器的当前值。 + + 太好了!这个屏幕事件现在将在每次检测到蓝色目标时点击它并递增计数器。\n\n保存事件以返回场景。 + + 现在我们需要一个在计数器达到10时做出响应的事件。这类事件不由屏幕触发,因此它是一个触发器事件。 + \n\n点击"触发器"标签页以打开触发事件列表。 + + 点击创建按钮添加新的触发器事件。 + + 与屏幕事件一样,触发器事件也需要条件。点击"条件"字段以打开条件列表并创建新的触发条件。 + + 选择"计数器达到时"条件类型,以便在计数器达到特定值时触发此事件。 + + 选择您之前创建的计数器(用于记录蓝色点击次数的那个)作为触发器。 + + 现在设置比较条件,使其在计数器等于10时满足。比较运算符有多种,但这里我们需要检测是否相等,请选择"="。然后输入10作为值,保存条件并返回事件对话框。 + 用于比较的值可以是固定数字,也可以是另一个计数器的当前值。 + + 条件已设置!现在我们需要定义计数器达到10时要执行的操作。点击"动作"字段以打开动作列表。 + + 首先,创建一个"单击"动作并手动将其放置在红色目标上以验证计数。 + + 配置单击以点击红色目标,然后保存动作。请注意,在触发器事件中,点击位置必须始终手动设置。\n\n单击保存后教程将继续。 + + 现在创建第二个动作来重置计数器。再次点击创建按钮并选择"更改计数器"动作。 + + 我们要将蓝色点击计数器重置为0,请先选择该计数器。 + + 将运算符设为 = ,值设为 0,以便每次验证后重置计数器。然后保存动作并返回事件对话框继续操作。 + + 这个触发器事件会在每次累计10次蓝色点击时点击红色目标并重置计数器。触发事件列表在每个屏幕帧之间、屏幕事件列表之前执行,因此一旦计数器等于10,该事件会立即运行:点击红色目标,计数器重置,然后重新开始。\n\n保存事件以返回场景。 + + 场景已完成!它将点击蓝色目标、记录每次点击,然后每10次点击用红色目标验证一次并重新开始。\n\n保存场景以应用您的配置。 + + 一切准备就绪!启动场景,然后打开游戏,看看 Klick\'r 为您自动完成计数。 + + 干得好!您已经学会了如何使用计数器跨多个事件追踪数值。\n\n结合"更改计数器"动作和"计数器达到时"条件,您现在可以构建能够响应重复模式的自动化流程。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..cd72b7eda --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_events_priority.xml @@ -0,0 +1,55 @@ + + + + + 设置事件优先级 + 让一个事件优先于另一个事件 + 尽快点击目标。蓝色 = 1分;红色 = 10分 + + 新游戏!我们需要尽快点击目标,但红色目标得分更高。您可以先试玩游戏, + 或打开场景配置菜单开始自动化。 + + 我们想检测两个不同的目标:蓝色和红色。在本教程中,我们将创建两个独立的事件: + 一个用于蓝色目标,一个用于红色目标。\n\n首先,创建蓝色目标的事件;检测到时必须点击它。不要忘记使用测试功能确保您的条件被正确检测。 + \n\n保存蓝色目标事件后,教程将继续。 + + 很好!现在需要对红色目标做同样的事情。点击创建事件按钮,为红色目标创建一个事件; + 检测到时必须点击它。\n\n保存红色目标事件后,教程将继续。 + + 我们的列表现在有两个事件,每个目标各一个。保存您的场景并在游戏中测试。 + + 似乎有些不对。场景只点击蓝色目标,完全忽视红色目标,导致我们无法获胜。\n\n + 为什么会这样?因为蓝色事件排在红色事件之前,由于它总是被触发,当前帧不再继续评估,下一帧从事件列表的开头重新开始。\n\n + 有几种方法可以修复这个问题。打开场景配置对话框了解如何操作。 + + 我们可以用两种方式解决这个问题:\n\n可以更改蓝色目标事件的「继续执行」选项, + 以继续处理同一帧并执行红色事件。当两个目标同时可见时,这将触发两次点击。\n\n或者可以将红色目标事件移到列表顶部,使其优先检查, + 可见时始终点击,但当红色目标也显示时,蓝色目标将不再被点击。\n\n两种解决方案的关键区别在于速度:将红色事件排在首位意味着红色目标 + 出现时我们能以最快速度响应,但只有蓝色目标可见时会稍慢一些。 + + 由于游戏中红色目标得10分,我们希望通过将红色事件移到列表顶部,在它出现时尽快响应。 + \n\n将红色事件移到第一位并保存场景。现在您应该能够赢得游戏了。 + 您可以长按此图标并将事件拖动到正确位置来重新排列事件。 + + 像往常一样,先启动场景,然后开始游戏。\n\n如果仍然无法获胜,请使用测试功能 + 确保每个事件单独运行正常。 + + 很好!您现在了解了事件优先级的工作原理以及屏幕事件循环的行为方式。这是构建和管理 + 复杂场景的关键。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_events_state.xml new file mode 100644 index 000000000..a40f8e5cf --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rCN/strings_tutorial_events_state.xml @@ -0,0 +1,123 @@ + + + + + 禁用未使用的事件 + 更改多个事件的状态以优化复杂场景。 + 按顺序点击目标:蓝色、红色、绿色,然后是黄色。 + + 新游戏!这次你需要按顺序点击四个彩色目标:先点蓝色,再点红色, + 再点绿色,最后点黄色。\n\n你可以先试玩游戏了解规则,也可以直接打开场景配置开始自动化。 + + 我们需要检测四个不同的目标,每种颜色一个。我们将为每个目标创建 + 一个事件。\n\n从蓝色目标开始:创建一个新事件,在游戏区域内检测蓝色目标并点击它。 + + 使用多个事件时,为每个事件起一个清晰的名称非常重要,方便后续管理。 + 给这个事件起一个清晰的名称,例如"蓝色目标",以便在场景中轻松识别。\n\n完成后,创建一个新的图像条件并捕获蓝色 + 目标。 + + 由于目标在移动,我们需要将检测类型设置为"检测区域",然后选择 + 游戏区域。\n\n区域配置完成后,保存并返回事件对话框。 + + 条件已设置完毕。现在我们需要一个点击动作,让事件点击检测到的目标。 + \n\n创建一个新的点击动作以继续。 + + 目标在移动,所以我们无法定义固定位置。将"点击位置"字段设置为"点击条件满足的对应位置坐标" + 并选择蓝色目标条件。这样点击总会落在目标被找到的确切位置。\n\n选择条件后,保存点击并返回事件对话框。 + + 蓝色目标事件完成!现在用同样的方式为红色目标创建一个事件:在游戏 + 区域内检测它并点击。保存红色目标事件后教程将继续。 + + 很好!现在为绿色目标创建同样的事件。保存绿色目标事件后教程将 + 继续。 + + 快完成了!为黄色目标创建最后一个事件。保存黄色目标事件后教程将 + 继续。 + + 四个事件都已准备就绪。因为我们按照游戏顺序定义了它们,优先级 + 是正确的。\n\n保存场景并在游戏中测试,看看效果如何。 + + 场景正在检测并点击目标,但可能太慢了无法获胜。\n\n目前四个事件 + 同时处于活动状态,所以每一帧场景都会依次检查蓝色、红色、绿色、黄色,无论刚才点击了哪个目标。这浪费了宝贵的时间! + \n\n打开场景配置了解如何改进。 + + 每个事件都有一个初始状态:可以从启用或禁用状态开始。目前四个事件 + 都处于启用状态,所以每一帧都会检查所有事件。\n\n解决方案是只保持当前目标的事件处于活动状态,禁用其余事件。当一个 + 目标被点击时,其事件将启用下一个目标并禁用其他事件。\n\n让我们从编辑蓝色目标事件开始。 + + 蓝色目标是第一个要点击的,所以它的事件应该从启用状态开始;这里 + 无需更改。\n\n我们只需要添加一个"更改事件状态"动作,使得点击蓝色目标时启用红色目标事件并禁用其他事件。点击动作区域 + 以添加此动作。 + + 选择动作类型"更改事件状态"。 + + 此动作允许你在该事件被触发时更改场景中任意事件的状态。点击 + "无变化"字段以选择要更改的事件。 + + 对于列表中的每个事件,可以设置以下三种状态之一:\n• 启用:事件 + 变为活动状态,每帧都会被检查 \n• 禁用:事件变为非活动状态,完全跳过 \n• 反转:每次在活动和非活动之间切换 + \n\n由于蓝色刚刚被点击,启用红色目标事件并禁用所有其他事件。完成后点击"下一步"。 + 每个事件行显示三个选项:启用、禁用和切换。点击你希望 + 在执行此动作时应用的选项。 + + 完美!保存蓝色目标事件。 + + 现在打开列表中的红色目标事件,以同样的方式进行配置。 + + 与蓝色目标事件不同,此事件在场景开始时不应处于活动状态,因为 + 它的目标不是第一个。将其初始状态更改为禁用。 + + 现在添加"更改事件状态"动作,使得点击此目标时启用下一个目标的事件 + 并禁用其他事件。点击动作区域。 + + 设置切换:启用绿色目标并禁用所有其他目标。完成后点击 + "下一步"。 + + 干得好!现在打开绿色目标事件,以同样的方式进行配置。 + + 绿色目标在开始时也不应处于活动状态。将其初始状态更改为 + 禁用。 + + 现在添加"更改事件状态"动作,使得点击绿色目标时启用黄色目标的事件 + 并禁用其他事件。点击动作区域。 + + 设置切换:启用黄色目标并禁用所有其他目标。完成后点击 + "下一步"。 + + 快完成了!打开黄色目标事件以完成配置。 + + 黄色目标是序列中的最后一个,所以它也应该从禁用状态开始。将其 + 初始状态更改为禁用。 + + 也为黄色目标事件添加"更改事件状态"动作。点击黄色后,我们想回到 + 起点:启用蓝色目标并禁用所有其他目标。点击动作区域。 + + 设置切换:启用蓝色目标并禁用所有其他目标。这样序列将无限循环。 + 完成后点击"下一步"。 + + 所有事件现在已完全配置完毕。保存场景以应用更改。 + + 所有事件已配置完成!保存场景,然后开始游戏。记得在启动游戏前 + 先启动场景。\n\n由于我们的场景有内部状态,每次重新开始游戏时都需要重启场景,以确保它不会等待上一局游戏的最后一个 + 目标。可以通过检测开始按钮是否可见来自动重置事件状态,从而轻松实现自动化。 + + 你赢了!\n\n通过控制哪些事件在任何时刻处于活动状态,场景始终 + 准确地知道下一个要寻找哪个目标——不会浪费任何帧来检查顺序之外的目标。\n\n这就是"更改事件状态"动作让你构建顺序化、 + 状态驱动自动化的方式。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rTW/strings_categories.xml b/feature/tutorial/src/main/res/values-zh-rTW/strings_categories.xml index 8b3f450b4..3bd3a187b 100644 --- a/feature/tutorial/src/main/res/values-zh-rTW/strings_categories.xml +++ b/feature/tutorial/src/main/res/values-zh-rTW/strings_categories.xml @@ -1,4 +1,4 @@ - + + 暫停動作 + 了解暫停如何影響動作執行和偵測 + 暫停動作會將整個情境暫停設定的時間:在此期間, + 不會執行任何動作,也不會進行任何螢幕偵測。\n\n非常常見的用法是在動作清單末尾新增一個暫停。當您點擊 + 某個地方時,被點擊的應用程式需要時間來處理點擊並顯示結果——通常您會希望等待這個時刻,然後再讓 + Klick\'r 重新開始分析螢幕。\n\n在兩個動作之間新增暫停也是有效的,但在清單末尾新增暫停通常是更重要的 + 需求。 + + + 滑動動作 + 了解滑動手勢的執行方式 + 滑動動作沿直線從起始位置到結束位置執行拖曳手勢。 + 兩個座標都是固定的,在動作設定中指定。\n\n持續時間控制手勢從開始到結束所需的時間:較短的持續時間產生 + 更快的滑動,較長的持續時間產生更慢、更受控的滑動。 + + + 點擊偏移 + 了解如何調整對偵測到的條件的點擊位置 + 點擊偵測到的條件時,預設情況下點擊會應用於 + 偵測區域的中心。\n\n點擊偏移允許您將該位置相對於條件中心沿 X 軸和 Y 軸移動固定數量的像素。當您想要 + 點擊的元素接近但不完全位於偵測區域中心時,這非常有用。 + + + 點擊目標 + 了解如何設定點擊將應用的位置 + 點擊動作可以針對兩種位置:始終相同的靜態 + 位置,或偵測到的條件的位置。\n\n在動作設定對話框的目標選擇器中選擇您的瞄準方式。 + 使用靜態位置時,無論螢幕上顯示什麼內容, + 點擊都始終發生在相同的精確座標處。\n\n請注意,這些座標對旋轉敏感:如果裝置旋轉,點擊可能會落在意外 + 位置甚至超出螢幕邊界。 + 使用條件位置時,點擊會應用於偵測到的圖片 + 條件的中心,無論目標出現在螢幕的哪個位置都會跟蹤它。\n\n使用 AND 運算子時,所有條件都必須滿足,因此 + 每個圖片條件都有一個可用位置。您可以自由選擇任意一個並透過偏移量進行微調。 + 使用 OR 運算子時,只有第一個滿足的條件會被 + 評估,其餘條件將被忽略。因此,Klick\'r 無法提前知道哪個條件會被偵測到。\n\n因此,使用 OR 運算子時無法 + 選擇特定條件作為目標:點擊始終會應用於執行時第一個偵測到的條件,無論它是哪個。 + + + 條件順序與速度 + 條件的順序如何影響事件檢查速度 + + 列表中條件的順序會影響事件的檢查速度。\n\n使用 AND + 運算子時,一旦找到第一個未滿足的條件,檢查就會停止。將最不可能滿足的條件放在最前面,可以讓應用程式更早跳過其餘條件,使事件更快。 + + 使用 OR + 運算子時,一旦找到第一個滿足的條件,檢查就會停止。將最可能滿足的條件放在最前面,可以讓應用程式更早完成,而無需檢查其餘條件。\n\n在兩種情況下,將最重要的條件放在列表頂部,都是保持場景快速運行的簡單方法。 + + + + 事件狀態 + 了解如何在場景執行時啟用和停用事件 + + 場景中的每個事件(螢幕事件和觸發事件)都有一個狀態:啟用停用。\n\ + n啟用時,事件正常執行並檢查其條件。停用時,它會被完全跳過,就像不存在一樣。\n\n預設情況下,每個事件都以啟用狀態開始。你可以透過事件設定中的初始狀態欄位來變更此設定。 + + 在場景執行時,可以使用變更事件狀態動作來變更任何事件的狀態。該動作可以啟用、停用或切 + 換一個或多個事件的狀態。\n\n這開啟了很多可能性:一個接一個相互開啟的事件、執行一次後自動關閉的事件,或者同一時間只有一個處於活動狀態的事件組。 + + 場景中的所有事件都被停用時,場景會自動停止。沒有更多事情要做,因此 + Klick\'r 會自動停止。\n\n這是結束場景的簡單方法:讓最後一個事件在完成任務後停用所有其他事件,一切都會自動停止。 + + + + 動作清單 + 了解動作清單的執行方式 + 動作按順序依次執行。您可以使用 << 和 >> + 按鈕更改動作的順序,或直接點擊其索引編號。\n\n請盡量保持動作清單簡短。一般自動點擊器每個事件只執行一個動作——這就是 + 應該遵循的模式。如果您發現自己在單一事件中添加了很多動作,通常表示應該將工作拆分為多個事件,每個事件回應螢幕上 + 實際顯示的內容。這就是 Klick\'r 的「看見即行動」理念:先偵測,再行動。 + + + 輸入文字動作 + 了解如何向已獲焦點的輸入欄位輸入文字 + 在輸入文字動作執行之前,目標輸入欄位必須已獲得焦點, + 就像您點擊它以調出鍵盤一樣。\n\n為此,在輸入文字動作之前新增一個點擊該輸入欄位的點擊動作。如果點擊後有過渡動畫, + 在兩者之間新增一個等待動作可以確保輸入欄位準備就緒。\n\n該動作還有一個「確認」選項:啟用後,它會在設定文字後自動按 + Enter 鍵,確認或提交輸入內容。 + 您可以將計數器的值插入要輸入的文字中。在動作設定中 + 按「附加計數器」按鈕選擇一個計數器:它會在文字欄位當前游標位置插入佔位符 {計數器名稱}。\n\n在執行時,文字 + 被貼上到輸入欄位之前,每個 {計數器名稱} 佔位符都會被替換為計數器的當前值。例如,如果名為 蘋果 的 + 計數器的值為 18,文字「我有 {蘋果} 個蘋果」就會變成「我有 18 個蘋果」。 + + + 系統動作 + 了解如何觸發 Android 導覽動作 + 系統動作執行 Android 內建導覽動作之一:返回、主畫面或最近 + 應用程式。\n\n這些與螢幕底部導覽按鈕的動作相同。它們不需要座標,無論目前開啟哪個應用程式都能在系統層面運作。 + + + 修改計數器動作 + 了解如何修改計數器的值 + 修改計數器動作使用預定義的靜態值對計數器執行操作。 + 有三種操作可用:將該值加到計數器(+)、從計數器中減去它(−),或將計數器設定為該精確值(=)。\n\n這是更新計數器最 + 常見的方式——例如,每次偵測到條件時加 1,或在達到目標時重置為 0。 + 除了靜態值,您還可以使用另一個計數器的當前值作為 + 運算元。同樣的三種操作(+、−、=)均適用,但操作量在執行時從所選計數器讀取,而不是在設定時固定。\n\n這讓您可以建構 + 計數器之間相互互動的動態情境。 + + + 通知動作 + 了解如何在情境執行時顯示通知 + 通知動作顯示帶有您自訂標題和訊息的 Android 通知。 + \n\n您可以使用「附加計數器」按鈕,或直接輸入佔位符 {計數器名稱},將計數器的當前值插入通知文字。執行時它會被 + 替換為計數器的值——例如,「我有 {蘋果} 個蘋果」變為「我有 18 個蘋果」。 + 通知重要性等級控制通知顯示的醒目程度。較高的重要性 + 等級可能顯示橫幅並播放聲音,而較低等級則靜默地傳送到通知抽屜。\n\n確切行為取決於裝置,可在 Android 通知設定中針對 + Klick\'r 進一步自訂。 + + + 變更事件狀態動作 + 了解如何在執行時啟用和停用事件 + 停用的事件在情境循環中被完全跳過——其條件從不檢查, + 其動作也從不執行。這意味著它完全不消耗處理時間。\n\n停用當前不使用的事件是提升效能的好方法。例如,在菜單階段和遊戲 + 階段交替的情境中,在遊戲階段停用所有菜單事件(反之亦然),可以在任何時刻只保持相關事件處於活動狀態。 + 設定動作時,您可以選擇一次性變更情境中所有事件的 + 狀態,或分別為每個事件定義新狀態。\n\n每個事件可用三種狀態變更:啟用它、停用它,或從其當前值切換——已啟用的事件變為 + 停用,已停用的事件變為啟用。 + 如果情境中的所有事件同時被停用,情境將自動停止, + 因為沒有任何內容可以執行。\n\n這可以有意作為在達到目標後終止情境的乾淨方式:一個停用所有事件的最終變更事件狀態 + 動作將使情境停止執行。 + + + Intent 動作 + 了解如何與其他應用程式通訊 + Intent 是 Android 上應用程式之間相互通訊的方式。Intent + 動作讓您可以直接從情境中利用這個系統。\n\n提供了一組預定義範本以簡化操作。最常用的是「啟動應用程式」,它在您的 + 裝置上啟動另一個應用程式,就像您從啟動器點擊其圖示一樣。 + 「進階」選項卡允許您手動定義原始 Intent,讓您完全控制 + 動作、類別、資料和 extras。這不建議一般使用者使用——面向已了解 Intent 運作方式的 Android 開發者。\n\n未來更新中將 + 新增更多開箱即用的範本,以便在不使用進階選項的情況下更輕鬆地設定常見用例。 + + + + 事件優先順序 + 了解清單中事件的順序如何影響哪些事件執行 + 從螢幕擷取的每一幀都透過由上到下逐一檢查事件來處理。\n\n事件在清單中的位置決定了它何時有機會執行。預設情況下,一旦事件的條件滿足並執行了其動作,該幀即視為處理完畢。該幀的處理停止,下一幀從清單中的第一個事件重新開始。\n\n這意味著預設情況下每幀只能執行一個事件。 + 你可以透過事件設定中的繼續執行欄位來改變此行為。啟用後,該事件執行之後,處理會繼續到清單中的下一個事件而不是停止。\n\n這允許多個事件在同一幀中執行。\n\n範例:你的清單包含事件A,後面是事件B。如果事件A持續被偵測到且沒有啟用繼續執行,它將在每幀執行,而事件B永遠沒有機會執行。\n\n在事件A上啟用繼續執行,兩個事件將在每幀都被檢查。\n\n還有一個互動教學可供練習此概念。 + + + + 事件重新裝填 + 了解情境中事件重新裝填的行為 + 事件重新裝填參數允許您在事件觸發後的一段時間內跳過該事件。 + \n\n處於重新裝填狀態的事件仍被視為啟用:重新裝填與事件狀態相互獨立。 \n\n如果事件在重新裝填狀態下被停用,重新裝填 + 計時器將被清除,因此當事件重新啟用時冷卻不再適用。 + + + + 使用計數器的值 + 了解在情境中顯示和使用計數器值的不同方法 + + 您可以在通知動作中顯示計數器的目前值。這對於在情境執行期間追蹤進度,或在結束時顯示摘要非常有用。\n\n要插入計數器,請在動作設定中按下「新增計數器」按鈕。這會在您的文字中加入類似 {counterName} 的占位符。執行時,該占位符將被計數器的實際值取代。例如,如果名為 score 的計數器值為 42,則文字「目前分數:{score}」將變為「目前分數:42」。 + + 您也可以在寫入文字動作中插入計數器的值,這樣輸入的文字將在動作執行時包含目前值。\n\n占位符的使用方式與通知動作相同:按下「新增計數器」按鈕,或直接輸入 {counterName}。例如,如果名為 score 的計數器值為 42,則文字「我的分數是 {score}」將變為「我的分數是 42」。 + + 計數器的值會被記錄在除錯報告中。如果您的情境出現了意外情況,擷取除錯報告將幫助您確切了解計數器的變化過程,從而更容易找到問題所在。 + diff --git a/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_not_visible.xml index b4a4fbde1..edeab4e11 100644 --- a/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ - 組合多個條件 - 為您的事件創建和組合多個條件 - 只有在紅色按鈕可見時才點擊藍色按鈕 + 條件可見性 + 使用「可見性」選項,在目標不在螢幕上時觸發點擊 + 僅在紅色按鈕不可見時點擊藍色按鈕 - 讓我們再次改變遊戲規則。藍色目標停止移動,但現在只有在紅色目標可見時才能點擊。\n\n首先,開始遊戲並檢查是否能自己贏得比賽。 + 新規則!藍色目標已停止移動,但只有在紅色目標不可見時才能點擊它。 + \n\n啟動遊戲,看看你能否自己獲勝。 - 再次嘗試手動贏得比賽似乎不可能,所以讓我們使用Klick\'r。\n\n你之前教程的場景已經被保留並加載到這個教程中,但是為了贏得這場新比賽,我們需要更改一些參數。\n\n點擊場景配置圖標開始更新你的新場景。 + 再次看來,手動獲勝似乎不可能,所以讓我們使用 Klick\'r。 + \n\n開啟場景設定選單,建立一個新的螢幕事件,並開始為遊戲目標新增條件。 - 我們仍然想要點擊藍色目標,但只有在紅色目標可見時才能點擊。\n -所以我們需要在事件中為這個紅色目標添加一個條件。\n\n點擊你之前創建的事件以進行編輯。 + 首先,我們需要一個條件來偵測紅色目標何時不在螢幕上。 + \n\n建立一個新的圖像條件並擷取紅色目標。 - 我們將結合多個條件,所以我們需要檢查此事件的條件運算符。\n\n條件運算符表示如何一起解釋多個條件。\n -『單一』表示此事件的條件中只需滿足一個條件即可執行操作。\n\n『所有』表示此事件的所有條件必須滿足才能執行操作。\n\n由於我們要檢測兩個事物是否同時顯示,所以我們將使用『所有』 + 我們只想在紅色目標不可見時點擊,因此將「是否可見」選項設定為「否」。這樣,只有當紅色目標從螢幕上消失時,條件才會滿足。 - 現在我們需要更新我們的條件。\n\n單擊條件欄位以顯示 條件列表。 + 其他設定對我們的需求來說沒問題——繼續儲存這個條件。 - 檢測藍色目標的先前條件仍然正確,但我們需要一個新的條件來檢測紅色目標。\n\n點擊創建條件按鈕以為其創建一個新條件。 + 僅此條件就足以贏得遊戲,但在遊戲未執行時它也會觸發,這不太理想。 + \n\n為了避免這種情況,讓我們將其與第二個條件搭配使用,該條件偵測藍色目標是否可見。 + 建立一個新的圖像條件並擷取藍色目標。 - 就像藍色目標一樣,開始遊戲以顯示紅色目標。一旦它可見,就拍攝一張螢幕截圖! - 使用浮動菜單中的截屏按鈕來拍攝截圖。 + 對於此條件,我們要確認藍色目標可見,因此預設設定完全正確。儲存條件並返回事件以繼續。 - 你的截圖是否包含紅色目標?您可以裁剪它,以便僅獲得檢測所需的紅色目標部分。 - 如果你的截圖不包含紅色目標,你可以按此按鈕拍攝新的截圖。 + 有多個條件時,條件運算子很重要。我們希望事件在藍色目標可見且紅色目標不可見時觸發,因此需要 AND 運算子;它已經是預設值了,所以一切正常。 + \n\n現在建立一個新的點擊動作以繼續。 - 你的條件圖像現在已記錄!由於紅色目標不會移動,我們可以保留默認配置。\n單擊保存 按鈕進行註冊,然後返回條件列表。 + 我們要點擊藍色目標,因此選擇位置類型「依條件」,並選擇藍色目標的圖像條件。 + \n\n完成後,儲存點擊動作,然後儲存事件和場景,並返回遊戲。 - 關閉條件列表,返回事件配置。 + 啟動你的場景並開始遊戲以獲勝! + \n\n如果無效,請檢查條件是否正確擷取,以及點擊時長是否設定為 1ms。 - 現在我們有了兩個條件,一個用於每個目標,只有在兩者都檢測到時,操作才會執行。\n\n單擊 「操作 」欄位,顯示事件的操作列表。 + 恭喜!你已學會使用「不可見」條件。請務必將其與至少一個其他條件結合使用,以避免在整個場景執行過程中意外觸發動作。 - 該操作已設置為點擊藍色角色,只有在藍色和紅色角色同時可見時才會執行。\n\n這正是我們贏得比賽所需的行為,因此無需編輯我們的點擊操作。\n\n關閉操作列表,返回事件配置。 - - 點擊保存按鈕,保存您的活動 - - 所有更改都必須保存到你的場景中以進行註冊。\n\n點擊保存按鈕以保存你的更改。 - - 我們準備好贏得這場比賽了!\n\n點擊開始按鈕以開始檢測,然後開始遊戲。 - - 恭喜!\n\n你現在知道如何為事件組合多個條件,但還有很多東西要學習! diff --git a/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..3467a223a --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,57 @@ + + + + + + 條件運算子 AND + 使用 AND 運算子,僅在多個目標同時可見時觸發點擊 + 僅在藍色和紅色目標同時可見時點擊藍色按鈕 + + 新規則!遊戲現在顯示兩個目標。你需要點擊藍色目標,但只有在藍色和紅色目標同時出現在螢幕上時才能點擊。 + \n\n啟動遊戲,看看你能否靠自己跟上節奏。 + + 手動操作時機太難掌握,所以讓我們使用 Klick\'r。 + \n\n開啟場景設定選單,建立一個新的螢幕事件,並開始為遊戲目標新增條件。 + + 每個目標需要一個條件。先從藍色目標開始。 + \n\n建立一個新的圖像條件並擷取藍色目標。 + + 我們希望在藍色目標可見時滿足此條件,因此預設設定完全正確。儲存此條件。 + + 現在為紅色目標新增第二個條件。 + \n\n再建立一個圖像條件並擷取紅色目標。 + + 這裡也一樣——紅色目標應該可見,所以預設設定是正確的。儲存此條件並返回事件。 + + 設定好兩個條件後,條件運算子決定如何組合它們。使用上方顯示的選擇器來選擇運算子。 + \n\n• AND:僅當所有條件都滿足時,事件才會觸發。\n• OR:只要有一個條件滿足,事件就會立即觸發。 + \n\n對於我們的遊戲,需要兩個目標同時在螢幕上,因此請選擇 AND。 + 條件運算子選擇器 + + AND 已經是預設運算子,所以我們準備好了。 + \n\n現在開啟「動作」部分,建立一個新的點擊動作。 + + 我們要點擊藍色目標,因此選擇位置類型「依條件」,並選擇藍色目標的圖像條件。 + \n\n完成後,儲存點擊動作,然後儲存事件和場景,並返回遊戲。 + + 啟動你的場景並開始遊戲以獲勝! + \n\n如果無效,請檢查兩個條件是否均已正確擷取,以及點擊時長是否設定為 1ms。 + + 恭喜!你已學會使用 AND 運算子。事件現在只會在所有條件同時滿足時才觸發。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..5d0199e0e --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,57 @@ + + + + + + 條件運算子 OR + 使用 OR 運算子點擊第一個出現在螢幕上的目標 + 一旦有目標出現在螢幕上就立即點擊 + + 新挑戰!螢幕上可能出現兩個目標。紅色目標值 2 分,藍色目標值 1 分,所以要盡快點擊出現的那個。 + \n\n啟動遊戲,看看你能發揮多好。 + + 手動操作太難跟上節奏,所以讓我們使用 Klick\'r。 + \n\n開啟場景設定選單,建立一個新的螢幕事件,並開始為遊戲目標新增條件。 + + 每個目標需要一個條件。先從藍色目標開始。 + \n\n建立一個新的圖像條件並擷取藍色目標。 + + 此條件應在藍色目標可見時觸發,因此預設設定完全正確。儲存此條件。 + + 現在為紅色目標新增第二個條件。 + \n\n再建立一個圖像條件並擷取紅色目標。 + + 這裡也一樣,紅色目標應該可見,所以預設設定是正確的。儲存此條件。 + + 使用 OR 時,條件按順序檢查,一旦第一個符合就觸發事件,因此條件的順序很重要。 + \n\n紅色目標得分更高,所以我們希望它被優先檢查。使用 « 按鈕將其移到藍色條件之前,然後返回事件對話框。 + + 現在將條件運算子設定為 OR。只要任一目標出現,事件就會觸發。如果兩個目標同時可見,紅色條件將首先符合,因為它的優先級更高。 + \n\n選擇 OR。 + + OR 運算子已設定好。開啟「動作」部分,建立一個新的點擊動作。 + + 我們想點擊觸發事件的目標。選擇位置類型「依條件」。使用 OR 時,每次只有一個條件能被正向偵測到,因此無需選擇特定條件。Klick\'r 會自動點擊符合條件的位置。 + \n\n完成後,儲存點擊動作,然後儲存事件和場景,並返回遊戲。 + + 啟動你的場景並開始遊戲以獲勝! + \n\n如果無效,請檢查你的條件是否正確擷取,以及點擊時長是否設定為 1ms。 + + 恭喜!你已學會使用 OR 運算子,也明白了為什麼條件優先級很重要。透過將紅色條件排在第一位,當兩個目標同時可見時,Klick\'r 始終優先選擇得分更高的目標。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..f9e1de4f0 --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_counters_basics.xml @@ -0,0 +1,83 @@ + + + + 計數器基礎 + 學習如何使用「更改計數器」動作與「計數器達到時」條件。 + 點擊藍色目標10次,再點擊紅色目標一次 + + 歡迎來到計數器教學! + \n\n在這裡,您將自動化一個遊戲:點擊藍色目標10次,再點擊紅色目標一次以驗證計數並獲得10分。您可以先試玩遊戲,或直接進入場景設定。 + + 首先,我們需要建立一個能偵測藍色目標並點擊它的螢幕事件。\n\n點擊「建立事件」開始。 + + 我們先新增一個條件來偵測藍色目標。點擊「條件」欄位以開啟條件清單並建立此條件。\n\n建立完成後教學將繼續。 + + 很好!現在點擊「動作」欄位,新增偵測到藍色目標時要執行的動作。 + + 我們首先需要一個點擊動作來點擊藍色目標。點擊建立按鈕新增動作。 + + 設定點擊位置為藍色目標,然後儲存動作。\n\n儲存後教學將繼續。 + + 我們還需要記錄點擊藍色目標的次數。可以使用「更改計數器」動作,每次點擊時將計數器加一。\n\n再次點擊建立按鈕以新增第二個動作。 + + 選擇「更改計數器」動作,讓每次點擊藍色目標時計數器遞增。 + + 首先,我們需要選擇要更新的計數器。點擊「選擇計數器」以開啟計數器清單。 + + 清單目前是空的。點擊建立按鈕建立新的計數器,為它命名(例如「藍色點擊」),保持初始值為0,然後儲存並選取它。 + + 現在設定每次點擊藍色目標時計數器的變化方式。\n\n將運算符設為「+」,數值設為「1」,這樣每次點擊計數器就會增加1。\n\n儲存動作後返回事件對話框。 + 數值可以是固定數字,也可以是另一個計數器的當前值。 + + 太好了!這個螢幕事件現在會在每次偵測到藍色目標時點擊它並遞增計數器。\n\n儲存事件以返回場景。 + + 現在我們需要一個在計數器達到10時做出反應的事件。這類事件不是由螢幕畫面觸發的,所以它是觸發器事件。 + \n\n點擊「觸發器事件」分頁以開啟觸發器事件清單。 + + 點擊建立按鈕新增一個新的觸發器事件。 + + 就像螢幕事件一樣,觸發器事件也需要條件。點擊「條件」欄位以開啟條件清單並建立新的觸發器條件。 + + 選擇「計數器達到時」條件類型,讓此事件在計數器達到特定值時觸發。 + + 選擇您先前建立的計數器(用來計算藍色點擊次數的那個)作為觸發依據。 + + 現在設定比較條件,使其在計數器等於10時滿足。有多種比較運算符,但這裡我們需要檢查相等,所以選擇「=」。然後輸入10作為數值,儲存條件並返回事件對話框。 + 要比較的數值可以是固定數字,也可以是另一個計數器的當前值。 + + 條件已設定!現在我們需要定義計數器達到10時要執行的動作。點擊「動作」欄位以開啟動作清單。 + + 首先,建立一個點擊動作並手動將位置設定在紅色目標上以驗證計數。 + + 設定點擊位置為紅色目標,然後儲存動作。請注意,在觸發器事件中,點擊位置必須手動設定。\n\n儲存後教學將繼續。 + + 現在建立第二個動作來重設計數器。再次點擊建立按鈕並選擇「更改計數器」動作。 + + 我們要將藍色點擊計數器重設為0,所以首先選取藍色點擊計數器。 + + 將運算符設為「=」,數值設為「0」,以便在每次驗證後重設計數器。然後儲存動作並返回事件對話框繼續。 + + 這個觸發器事件會在每次計算到10次藍色點擊時點擊紅色目標並重設計數器。觸發器事件清單在每個螢幕幀之間執行,且先於螢幕事件清單,因此一旦計數器等於10,此事件立即執行:點擊紅色目標並重設計數器,準備重新開始。\n\n儲存事件以返回場景。 + + 場景已完成!它將點擊藍色目標、記錄每次點擊,然後每10次點擊用紅色目標驗證一次並重新開始。\n\n儲存場景以套用您的設定。 + + 一切準備就緒!啟動場景,然後開啟遊戲,看著Klick\'r替您自動計數。 + + 做得好!您已學會如何使用計數器來追蹤多個事件之間的數值。\n\n結合「更改計數器」動作與「計數器達到時」條件,您現在可以建立能對重複模式做出反應的自動化場景了。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..c8a52e136 --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_events_priority.xml @@ -0,0 +1,55 @@ + + + + + 設定事件優先順序 + 讓一個事件優先於另一個事件 + 盡快點擊目標。藍色 = 1分;紅色 = 10分 + + 新遊戲!我們需要盡快點擊目標,但紅色目標得分更高。您可以先試玩遊戲, + 或開啟場景設定選單開始自動化。 + + 我們想偵測兩個不同的目標:藍色和紅色。在本教學中,我們將建立兩個獨立的事件: + 一個用於藍色目標,一個用於紅色目標。\n\n首先,建立藍色目標的事件;偵測到時必須點擊它。別忘了使用測試功能確認您的條件被正確偵測。 + \n\n儲存藍色目標事件後,教學將繼續。 + + 很好!現在需要對紅色目標做同樣的事。點擊建立事件按鈕,為紅色目標建立一個事件; + 偵測到時必須點擊它。\n\n儲存紅色目標事件後,教學將繼續。 + + 我們的清單現在有兩個事件,每個目標各一個。儲存您的場景並在遊戲中測試。 + + 似乎有些不對。場景只點擊藍色目標,完全忽視紅色目標,導致我們無法獲勝。\n\n + 為什麼會這樣?因為藍色事件排在紅色事件之前,由於它總是被觸發,目前影格不再繼續評估,下一個影格從事件清單的開頭重新開始。\n\n + 有幾種方法可以修正這個問題。開啟場景設定對話框了解如何操作。 + + 我們可以用兩種方式解決這個問題:\n\n可以變更藍色目標事件的「繼續執行」選項, + 以繼續處理同一影格並執行紅色事件。當兩個目標同時可見時,這將觸發兩次點擊。\n\n或者可以將紅色目標事件移到清單頂端,使其優先檢查, + 可見時始終點擊,但當紅色目標也顯示時,藍色目標將不再被點擊。\n\n兩種解決方案的關鍵差異在於速度:將紅色事件排在首位意味著紅色目標 + 出現時我們能以最快速度回應,但只有藍色目標可見時會稍慢一些。 + + 由於遊戲中紅色目標得10分,我們希望透過將紅色事件移到清單頂端,在它出現時盡快回應。 + \n\n將紅色事件移到第一位並儲存場景。現在您應該能夠贏得遊戲了。 + 您可以長按此圖示並將事件拖曳到正確位置來重新排列事件。 + + 和往常一樣,先啟動場景,然後開始遊戲。\n\n如果仍然無法獲勝,請使用測試功能 + 確認每個事件單獨運作正常。 + + 很好!您現在了解了事件優先順序的運作方式以及螢幕事件迴圈的行為。這是建立和管理 + 複雜場景的關鍵。 + + diff --git a/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_events_state.xml new file mode 100644 index 000000000..14f5d892c --- /dev/null +++ b/feature/tutorial/src/main/res/values-zh-rTW/strings_tutorial_events_state.xml @@ -0,0 +1,123 @@ + + + + + 停用未使用的事件 + 變更多個事件的狀態以最佳化複雜情景。 + 按順序點擊目標:藍色、紅色、綠色,然後是黃色。 + + 新遊戲!這次你需要按順序點擊四個彩色目標:先點藍色,再點紅色, + 再點綠色,最後點黃色。\n\n你可以先試玩遊戲了解規則,也可以直接開啟情景設定開始自動化。 + + 我們需要偵測四個不同的目標,每種顏色一個。我們將為每個目標建立 + 一個事件。\n\n從藍色目標開始:建立一個新事件,在遊戲區域內偵測藍色目標並點擊它。 + + 使用多個事件時,為每個事件取一個清晰的名稱非常重要,方便後續 + 管理。給這個事件取一個清晰的名稱,例如「藍色目標」,以便在情景中輕鬆識別。\n\n完成後,建立一個新的影像條件並 + 擷取藍色目標。 + + 由於目標在移動,我們需要將偵測類型設定為「檢測區域」,然後選擇 + 遊戲區域。\n\n區域設定完成後,儲存並返回事件對話框。 + + 條件已設定完畢。現在我們需要一個點擊動作,讓事件點擊偵測到的 + 目標。\n\n建立一個新的點擊動作以繼續。 + + 目標在移動,所以我們無法定義固定位置。將「點擊位置」欄位設定為「點擊條件滿足的對應位置坐標」 + 並選擇藍色目標條件。這樣點擊總會落在目標被找到的確切位置。\n\n選擇條件後,儲存點擊並返回事件對話框。 + + 藍色目標事件完成!現在用同樣的方式為紅色目標建立一個事件:在 + 遊戲區域內偵測它並點擊。儲存紅色目標事件後教學將繼續。 + + 很好!現在為綠色目標建立同樣的事件。儲存綠色目標事件後教學將 + 繼續。 + + 快完成了!為黃色目標建立最後一個事件。儲存黃色目標事件後教學將 + 繼續。 + + 四個事件都已準備就緒。因為我們按照遊戲順序定義了它們,優先順序 + 是正確的。\n\n儲存情景並在遊戲中測試,看看效果如何。 + + 情景正在偵測並點擊目標,但可能太慢了無法獲勝。\n\n目前四個事件 + 同時處於活動狀態,所以每一幀情景都會依序檢查藍色、紅色、綠色、黃色,無論剛才點擊了哪個目標。這浪費了寶貴的時間! + \n\n開啟情景設定了解如何改進。 + + 每個事件都有一個初始狀態:可以從啟用或停用狀態開始。目前四個 + 事件都處於啟用狀態,所以每一幀都會檢查所有事件。\n\n解決方案是只保持目前目標的事件處於活動狀態,停用其餘事件。 + 當一個目標被點擊時,其事件將啟用下一個目標並停用其他事件。\n\n讓我們從編輯藍色目標事件開始。 + + 藍色目標是第一個要點擊的,所以它的事件應該從啟用狀態開始;這 + 裡無需更改。\n\n我們只需要新增一個「變更事件狀態」動作,使得點擊藍色目標時啟用紅色目標事件並停用其他事件。點擊動作 + 區域以新增此動作。 + + 選擇動作類型「變更事件狀態」。 + + 此動作允許你在該事件被觸發時更改情景中任意事件的狀態。點擊 + 「無變化」欄位以選擇要更改的事件。 + + 對於清單中的每個事件,可以設定以下三種狀態之一:\n• 啟用:事件 + 變為活動狀態,每幀都會被檢查 \n• 停用:事件變為非活動狀態,完全跳過 \n• 反轉:每次在活動和非活動之間切換 + \n\n由於藍色剛剛被點擊,啟用紅色目標事件並停用所有其他事件。完成後點擊「下一步」。 + 每個事件列顯示三個選項:啟用、停用和切換。點擊你希望 + 在執行此動作時套用的選項。 + + 完美!儲存藍色目標事件。 + + 現在開啟清單中的紅色目標事件,以同樣的方式進行設定。 + + 與藍色目標事件不同,此事件在情景開始時不應處於活動狀態,因為 + 它的目標不是第一個。將其初始狀態更改為停用。 + + 現在新增「變更事件狀態」動作,使得點擊此目標時啟用下一個目標的事件 + 並停用其他事件。點擊動作區域。 + + 設定切換:啟用綠色目標並停用所有其他目標。完成後點擊 + 「下一步」。 + + 做得好!現在開啟綠色目標事件,以同樣的方式進行設定。 + + 綠色目標在開始時也不應處於活動狀態。將其初始狀態更改為 + 停用。 + + 現在新增「變更事件狀態」動作,使得點擊綠色目標時啟用黃色目標的事件 + 並停用其他事件。點擊動作區域。 + + 設定切換:啟用黃色目標並停用所有其他目標。完成後點擊 + 「下一步」。 + + 快完成了!開啟黃色目標事件以完成設定。 + + 黃色目標是序列中的最後一個,所以它也應該從停用狀態開始。將其 + 初始狀態更改為停用。 + + 也為黃色目標事件新增「變更事件狀態」動作。點擊黃色後,我們想回到 + 起點:啟用藍色目標並停用所有其他目標。點擊動作區域。 + + 設定切換:啟用藍色目標並停用所有其他目標。這樣序列將無限循環。 + 完成後點擊「下一步」。 + + 所有事件現在已完全設定完畢。儲存情景以套用變更。 + + 所有事件已設定完成!儲存情景,然後開始遊戲。記得在啟動遊戲前 + 先啟動情景。\n\n由於我們的情景有內部狀態,每次重新開始遊戲時都需要重啟情景,以確保它不會等待上一局遊戲的最後一個 + 目標。可以透過偵測開始按鈕是否可見來自動重置事件狀態,從而輕鬆實現自動化。 + + 你贏了!\n\n透過控制哪些事件在任何時刻處於活動狀態,情景始終 + 準確地知道下一個要尋找哪個目標——不會浪費任何幀來檢查順序之外的目標。\n\n這就是「變更事件狀態」動作讓你建構順序化、 + 狀態驅動自動化的方式。 + + diff --git a/feature/tutorial/src/main/res/values/colors.xml b/feature/tutorial/src/main/res/values/colors.xml index 0792ab761..c5841178f 100644 --- a/feature/tutorial/src/main/res/values/colors.xml +++ b/feature/tutorial/src/main/res/values/colors.xml @@ -18,6 +18,8 @@ #2196F3 #F44336 + #4CAF50 + #FFC107 #CDDC39 #4CAF50 #009688 diff --git a/feature/tutorial/src/main/res/values/strings_categories.xml b/feature/tutorial/src/main/res/values/strings_categories.xml index 06b833da0..9d7b4ff91 100644 --- a/feature/tutorial/src/main/res/values/strings_categories.xml +++ b/feature/tutorial/src/main/res/values/strings_categories.xml @@ -89,13 +89,6 @@ conditions to be fulfilled, while OR requires at least one. Mixing condition types and operators lets you handle complex real-world scenarios.\n\n Learn here how to combine conditions effectively. - Event State - Enable or disable Events dynamically. - Events can be enabled or disabled at runtime using the - ToggleEvent Action. This lets you build multistep automation flows where earlier steps gate later ones, or - where certain events are only active under specific conditions.\n\n Learn here how to control Event state to - build advanced Scenarios. - Trigger Conditions Verify the state of the Scenario A Trigger Condition is the \"when\" part of a Trigger @@ -109,4 +102,80 @@ Actions range from gestures (Click, Swipe) to flow control (ToggleEvent, ChangeCounter, Pause) and system interactions (Intent, Notification, SystemAction, SetText).\n\n Learn here how to use each Action type to build your automation scripts. + + Click + Tap at a fixed position or on a matched condition + A Click Action simulates a tap at a fixed coordinate or + at the center of a matched Condition. You can configure the press duration to simulate long presses. + \n\n Learn here how to use it to interact with your screen. + + Swipe + Slide from one point to another on the screen + A Swipe Action simulates a drag gesture from a start + coordinate to an end coordinate. You can configure the swipe duration to control the speed of the gesture. + \n\n Learn here how to use it to scroll or drag elements on your screen. + + Pause + Wait for a duration before executing the next action + A Pause Action delays execution for a configured amount + of time. It is useful to insert a wait between two actions when the app needs time to react. + \n\n Learn here how to use it to pace your automation scripts. + + Intent + Send an Android Intent to another app or component + An Intent Action sends an Android Intent, either as a + broadcast or to start an Activity or Service. You can attach extra key-value pairs to pass data along with + the Intent.\n\n Learn here how to use it to trigger actions in other applications. + + Change Counter + Set, add, or subtract a value on a Counter + A Change Counter Action modifies a named Counter + variable by setting it to a fixed value, adding to it, or subtracting from it. Counters can then be read by + Conditions or other Actions.\n\n Learn here how to use it to manage state across your Scenario. + + Change Event State + Enable, disable, or toggle one or more Events + A Change Event State Action enables, disables, + or toggles one or more Events at runtime. This lets you build multi-step flows where earlier steps gate later + ones.\n\n Learn here how to use it to control the flow of your Scenario. + + Notification + Post a system notification + A Notification Action posts an Android system + notification with a custom title and message. It is useful to alert the user when a specific condition is + detected.\n\n Learn here how to use it to surface information while your Scenario runs in the background. + + System Action + Invoke a global Android navigation action + A System Action invokes a global Android navigation + action such as pressing Back, Home or Recent. These actions do not require a + coordinate and act at the system level.\n\n Learn here how to use it to navigate the device during automation. + + Write Text + Paste text into the focused input field + A Write Text Action pastes a configured string into + the currently focused input field using the AccessibilityService. It is useful for filling forms or search + fields without simulating individual key presses.\n\n Learn here how to use it to enter text during automation. + + Combine Events + Use multiple events for complex logic control + Klick\'r lets you coordinate multiple Events to build + advanced automation flows. By controlling the order in which Events are evaluated and enabling or disabling + them at runtime, you can create complex, multi-step Scenarios.\n\n Learn here how to combine Events effectively + to take full control of your automation. + + Events priority + Control the importance of your events + Screen Events are evaluated in priority order during + each detection cycle. An Event higher in the list is checked before lower Events, letting you define which + Event take precedence when multiple Events could trigger at the same time.\n\n Learn here how to set Event + priorities to fine-tune the execution order of your Scenario. + + Events state + Enable or disable Events dynamically. + Events can be enabled or disabled at runtime using the + Change Event State Action. This lets you build multistep automation flows where earlier steps gate later ones, or + where certain events are only active under specific conditions.\n\n Learn here how to control Event state to + build advanced Scenarios. + \ No newline at end of file diff --git a/feature/tutorial/src/main/res/values/strings_slideshows.xml b/feature/tutorial/src/main/res/values/strings_slideshows.xml index ad3329ae0..ba02aa894 100644 --- a/feature/tutorial/src/main/res/values/strings_slideshows.xml +++ b/feature/tutorial/src/main/res/values/strings_slideshows.xml @@ -146,6 +146,7 @@ provided, but keep in mind that broadcast conditions are more for developers, as mastering them requires Android development knowledge. + On Counter Reached React to your scenario\'s counter values @@ -157,4 +158,266 @@ counter-related condition or action is often not enough to use them correctly. Interactive tutorials covering the Counter feature are available in their dedicated section. + + + Click offset + Learn how to fine-tune the click position on a detected condition + + When clicking on a detected condition, the click + is applied at the center of the matched area by default. \n\nThe click offset lets you shift that position by a + fixed number of pixels along the X and Y axes, relative to the condition\'s center. This is useful when the + element you want to tap is close to — but not exactly at — the center of the detected area. + + + + Click target + Learn how to configure where the click will be applied + + A Click Action can target two types of positions: + a static position that is always the same, or the position of a detected condition.\n\nChoose your targeting + method in the click target selector of the action configuration dialog. + + When using a static position, the click will + always occur at the exact same coordinates, regardless of what is currently on screen.\n\nKeep in mind that + those coordinates are screen-rotation-sensitive: if the device rotates, the click may end up at an unexpected + position or even outside the screen boundaries. + + When using a condition position, the click is + applied at the center of a detected Image Condition. This makes the click follow the target wherever it + appears on screen.\n\nWhen the event\'s operator is AND, all conditions must be fulfilled, so every Image + Condition has a detected position available. You can freely pick any of them as your click target, and + optionally refine it with a click offset. + + When the event\'s operator is OR, only one + condition will be fulfilled, and the next ones will be skipped. Because of this, Klick\'r cannot know + in advance which condition will be detected.\n\nAs a consequence, when using the OR operator, you cannot + choose a specific condition as the click target: the click will always be applied on the first detected + condition, whichever that turns out to be at runtime. + + + + Swipe action + Learn how the swipe gesture is performed + + A Swipe Action performs a straight-line drag gesture + from a start position to an end position. Both coordinates are fixed and set when configuring the action. + \n\nThe swipe duration controls how long the gesture takes to travel from start to end: a shorter duration + produces a faster swipe, while a longer one produces a slower, more controlled drag. + + + + Pause action + Learn how the pause affects action execution and detection + + A Pause Action suspends the entire scenario for a + configured duration: during that time, no action runs and no screen detection occurs.\n\nA very common use + case is to add a Pause at the end of your action list. When you click somewhere, the app you clicked on + needs time to process the click and display the result, and you usually want to wait during that moment + before Klick\'r starts looking at the screen again.\n\nA pause between two actions is also valid, but + adding one at the end of the list is often the more common use case. + + + + Write text action + Learn how to set text into a focused input field + + Before the Write Text action runs, the target + input field must already be focused, just as you would tap it to bring up the keyboard. \n\nTo achieve this, + add a Click action on that field before the Write Text action to focus it. If a transition animation plays + after the click, a Wait action between the two can help ensure the field is ready. \n\nThe action also has a + Validate option: when enabled, it will automatically press Enter after the text is set, confirming or submitting + the input. + + You can insert the value of a counter into + the text to write. Press the Append Counter button in the action configuration to pick a counter: it will + insert the placeholder {counterName} at the current cursor position in the text field.\n\nAt + runtime, every {counterName} placeholder is replaced by the counter\'s current value before the text + is pasted into the field. For example, if a counter named apples has the value 18, the text + \"I have {apples} apples\" becomes \"I have 18 apples\". + + + + System action + Learn how to trigger Android navigation actions + + A System Action executes one of Android\'s built-in + navigation actions: Back, Home, or Recents.\n\nThese are the same actions as the navigation buttons at the + bottom of your screen. They require no coordinates and work at the system level, regardless of which app is + currently open. + + + + Change counter action + Learn how to modify a counter value + + A Change Counter action applies an operation + to a counter using a predefined static value. Three operations are available: add the value to the counter + (+), subtract it from the counter (−), or set the counter to that exact value (=).\n\nThis is the most + common way to update a counter. For example, adding 1 each time a condition is detected, or resetting it + to 0 when a goal is reached. + + Instead of a static value, you can use the + current value of another counter as the operand. \n\nThe same three operations (+, −, =) apply, but the amount + is read from the selected counter at runtime rather than being fixed at configuration time.\n\nThis lets + you build dynamic scenarios where counters interact with each other. + + + + Notification action + Learn how to display a notification during your scenario + + A Notification action displays an Android + notification with a title and a message of your choice.\n\nYou can insert the current value of a counter + into the notification text using the Append Counter button, or by typing the {counterName} + placeholder directly. At runtime it is replaced by the counter\'s value — for example, + \"I have {apples} apples\" becomes \"I have 18 apples\". + + The notification importance level controls + how intrusively the notification is presented. Higher importance levels may show a heads-up banner and play + a sound, while lower ones are delivered silently to the notification drawer.\n\nThe exact behaviour depends + on the device and can be further customized in the Android notification settings for Klick\'r. + + + + Change event state action + Learn how to enable and disable events at runtime + + A disabled event is completely skipped during + the scenario loop; its conditions are never checked and its actions never run. This means it consumes no + processing time at all.\n\nDisabling events you are not currently using is a great way to improve + performance. For example, in a scenario that alternates between a menu phase and a game phase, disabling + all menu events while you are in the game phase (and vice versa) keeps only the relevant events active at + any given time. + + When configuring the action, you can choose + to change the state of all events in the scenario at once, or define a new state for each event + individually. \n\nThree state changes are available for each event: enable it, disable it, or toggle it + from its current value; so an enabled event becomes disabled and a disabled one becomes enabled. + + If every event in the scenario ends up + disabled at the same time, the scenario stops itself automatically, since there is nothing left to + execute.\n\nThis can be used intentionally as a clean way to terminate a scenario once a goal is reached: + a final Change Event State action that disables all events will bring the scenario to a halt. + + + + Intent action + Learn how to communicate with other applications + + Intents are the way applications communicate with + each other on Android. The Intent action lets you tap into this system directly from your scenario.\n\nA + set of predefined templates is available to make this easy. The most common one is Start Application, + which launches another app on your device exactly as if you had tapped its icon from the launcher. + + The Advanced tab lets you define a raw Intent + manually, giving you full control over the action, category, data, and extras. This is not recommended for + regular users; it is aimed at Android developers who already know how Intents work.\n\nMore ready-to-use + templates will be added in future updates to make common use cases easier to set up without going into the + advanced options. + + + + Action list + Learn how the action list is executed + + Actions are executed in order, one after the other. + You can change the order of an action using the << and >> buttons, or by tapping directly on + its index box.\n\nTry to keep your action lists short. A regular autoclicker taps one place per event; + that\'s the model to follow. If you find yourself adding many actions to a single event, it is usually a + sign that the work should be split across several events, each reacting to what is actually on the screen. + This is the see-and-act philosophy of Klick\'r: detect first, then act. + + + + Condition order and speed + How the order of your conditions affects how fast + your event is checked + + The order of conditions in the list + affects how fast your event is checked.\n\nWith the AND operator, the check stops as soon as the first + condition that is NOT met is found. Putting the least likely conditions first lets the app skip the rest + sooner, making your event faster. + + With the OR operator, the check stops as + soon as the first condition that IS met is found. Putting the most likely conditions first lets the app + finish sooner, without checking the rest.\n\nIn both cases, putting the most important condition at the top + of the list is an easy way to keep your scenario running fast. + + + + Event state + Learn how to enable and disable events while a + scenario is running + + Every event in your scenario (Screen Events and + Trigger Events) has a state: it is either enabled or disabled.\n\nWhen enabled, the event runs + normally and checks its conditions as usual. When disabled, it is completely skipped, as if it did not + exist.\n\nBy default, every event starts enabled. You can change this with the Initial State field in + the event settings. + + While a scenario is running, you can change the + state of any event using the Change Event State action. This action lets you enable, disable, or + toggle one or more events in your scenario.\n\nThis opens up many possibilities: events that turn each other + on one after another, events that turn themselves off after running once, or groups of events where only one + is active at a time. + + When all events in the scenario are + disabled, the scenario stops on its own. There is nothing left to do, so Klick\'r stops + automatically.\n\nThis is a simple way to end a scenario: have your last event disable all the others once + its job is done, and everything stops by itself. + + + + Event priority + Learn how the order of events in your list affects + which events run + + Every screen frame captured from your display + is processed by checking your events one by one, from top to bottom.\n\nThe position of an event in + your event list determines when it gets a chance to run. By default, as soon as an event\'s conditions + are met and its actions are executed, the frame is considered done. Processing stops for that frame, + and the next frame starts over from the first event in the list.\n\nThis means only one event can run per + frame by default. + + You can change this behavior using the + Keep executing field in the event settings. When enabled, after that event runs, processing + continues to the next event in the list instead of stopping.\n\nThis lets multiple events run on the + same frame.\n\nExample: your list contains Event A followed by Event B. If Event A keeps being detected + and does not have Keep executing enabled, it will run every frame and Event B will never get a chance + to execute.\n\nEnable Keep executing on Event A, and both events will be checked on every frame. \n\nAn + interactive tutorial is also available to practice this concept. + + + + Event reloading + Learn how the reloading of an Event behaves in your scenario + + The event reloading parameter allows you to skip an + event for a given amount of time once it is fulfilled. \n\nEven if skipped, an event in reloading state is + still considered enabled: reloading and the event state are independent. \n\nIf the Event is disabled while in + reloading state, the reloading timer will be cleared, so the cooldown no longer applies when the event is + re-enabled. + + + + Using counter values + Learn the different ways to display and use counter values in your scenario + + You can show the current value of a counter + inside a Notification action. This is useful to monitor progress while your scenario is running, or to + display a summary at the end.\n\nTo insert a counter, press the Append Counter button in the action + configuration. This adds a placeholder like {counterName} into your text. At runtime, the placeholder + is replaced by the counter\'s actual value. \n\nFor example, if a counter named score has the value 42, + the text \"Current score: {score}\" becomes \"Current score: 42\". + + You can also insert a counter\'s value into a + Write Text action, so the typed text includes the current value at the moment the action runs.\n\nThe + placeholder works the same way as in the Notification action: press the Append Counter button or type + {counterName} directly. \n\nFor example, if a counter named score has the value 42, the text + \"My score is {score}\" becomes \"My score is 42\". + + Counter values are tracked in the debug report. + If something is not working as expected in your scenario, capturing a debug report will show you exactly how + your counters changed over time, making it easier to find the issue. + \ No newline at end of file diff --git a/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_not_visible.xml b/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_not_visible.xml index 0c8195f2d..d86214373 100644 --- a/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_not_visible.xml +++ b/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_not_visible.xml @@ -1,6 +1,6 @@ Condition visibility - Use the Visibility option to click when the target is not displayed - Click on the blue button only when the red button is not visible + Use the Visibility option to trigger a click + when a target is not on screen + Click the blue button only when the red + button is not visible - Let\'s change the rules of the game again. The blue target has stopped moving, - but now it should only be clicked when the red target is not visible.\n\nFirst, start the game and check if you can win - by yourself. + New rules! The blue target has stopped + moving, but it should only be clicked when the red target is not visible. + \n\nStart the game and see if you can win on your own. - Once again, it seems impossible to win manually, so let\'s use Klick\'r. - \n\nClick on the Scenario configuration button to start automating this game. + Once again, this seems impossible to + win manually, so let\'s use Klick\'r. \n\nOpen the scenario configuration menu, create a new Screen Event, and + start adding conditions for the game targets. - We want to click at the same spot when the red target is not displayed.\n - We need to create an Event that will handle that, click on the create Event button to continue. + First, we need a condition that checks + when the red target is NOT visible on the screen. \n\nCreate a new image condition and capture the red target. + - First, we need to add an Image Condition. Click on the Conditions field to display - the Conditions list. + We want to click only when the red + target is not visible, so set the "Is visible" option to No. This way the condition will only be met when the + red target is absent from the screen. - Then, click on create a new Screen Condition. + The other settings look good for our + needs — go ahead and save this condition. - In this tutorial, we want to learn how to detect if an image is not on the screen, - so select Image Condition + This condition alone is enough to win + the game, but it would also trigger while the game is not even running, which is not ideal. \n\nTo prevent that, + let\'s pair it with a second condition that checks whether the blue target is visible. Create a new Image + Condition and capture the blue target. - We need to take a screenshot of the red target, so start the game to make it visible. - Once it is visible, take a screenshot of it! - Use the capture button in the floating menu to take the screenshot. + For this condition, we want to check + that the blue target is visible, so the default settings are all correct. Save the condition and go back to the + Event to continue. - Is your screenshot containing the red target? You can crop it in order to only - get the part that is interesting for the detection, the red target. - If your screenshot does not contain the red target, you can - press this button to take a new one. + With multiple conditions, the condition + operator matters. We want the event to trigger when the blue target is visible AND the red target is not, so the + AND operator is what we need; and it\'s already the default, so we\'re good. + \n\nNow create a new click action to continue. - Your Condition image is now recorded!\n\nAs the red target isn\'t moving, we - can keep the default area configuration, which will verify only at the capture position. + We want to click on the blue target, + so select the \"On Condition\" position type and pick the blue target Image Condition. + \n\nWhen you\'re done, save the click, then save your event and scenario, and head back to the game. - We want to verify if the target is NOT displayed, so we need to uncheck the - \"Visible\" option. With this, the Image Condition will be fulfilled for each screen frames that does not display the red target. + Start your scenario and launch the + game to win! \n\nIf it doesn\'t work, double-check that your conditions are captured correctly and that the + click duration is set to 1ms. - The Image Condition is now correctly configured. - Click on the save button to register it and return to the Conditions list. + Congratulations! You\'ve learned how + to use a \"Not visible\" condition. Always combine it with at least one other condition to avoid triggering + actions unintentionally throughout your entire scenario. - Close the Conditions list to return to the Event configuration. - - The condition will be fulfilled when the red target is not visible, - now we need to define the action to trigger when this happens. Click on the Action field to display the Action list. - - For now, we have no Action. Click on create a new Action. - - We need to click on the blue target, so select Click. - - The blue target is never moving, so we can simply define a static position for our Click.\n\n - \n\nClick on the position picker to select the Click position. - - You need to select the exact position to be clicked, so you need to start - the game again to display the blue character, and then select its position.\n\nOnce the position is correct, click on the validate button to save it. - You can\'t interact with the game while the position selector is - visible, but you can use this button to show and hide it, allowing you to remove that restriction at will. - - As we want to click as quickly as possible, we can keep the default press duration of 1ms, - which is the lowest possible value. The click is now correctly configured!\n\nClick on the save button to register it and return to the Actions list. - - Close the Actions list to return to the Event configuration. - - Your Event now have a Condition and an Action, which means it knows what - to execute and when to execute it.\n\nClick on the save button to register it and return to the Scenario dialog. - - All changes must be saved in your scenario in order to be registered.\n\nClick - on the save button to save your changes. - - We are ready to win this game!\n\nClick on the start button to start the - detection and then, start the game. - - Congratulations!\n\n - You now know how to execute something when an Image is not visible on the screen! diff --git a/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_operator_and.xml b/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_operator_and.xml new file mode 100644 index 000000000..74ae21fa4 --- /dev/null +++ b/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_operator_and.xml @@ -0,0 +1,70 @@ + + + + + + Condition operator AND + Use the AND operator to click only when + multiple targets are visible at the same time + Click the blue button only when both the + blue and red targets are visible + + New rules! The game now shows two targets. + You should click the blue one, but only when both the blue and red targets are on screen at the same time. + \n\nStart the game and see if you can keep up on your own. + + The timing is too tight to handle manually, + so let\'s use Klick\'r. \n\nOpen the scenario configuration menu, create a new Screen Event, and start adding + conditions for the game targets. + + We need one condition per target. Let\'s + start with the blue one. \n\nCreate a new image condition and capture the blue target. + + We want this condition to be met when the + blue target is visible, so the default settings are all correct. Save this condition. + + Now let\'s add the second condition for the + red target. \n\nCreate another image condition and capture the red target. + + Same here; the red target should be + visible, so the default settings are correct. Save this condition and go back to the Event. + + With two conditions set up, the condition + operator decides how they are combined. Select the operator using the selector shown above. + \n\n• AND: the event triggers only when ALL conditions are met.\n• OR: the event triggers as soon as the + ONE condition is met.\n\nFor our game, we need both targets on screen at the same time, so select + AND. + The condition operator + selector + + AND is already the default operator, so + we\'re all set. \n\nNow open the Actions section and create a new click action. + + We want to click on the blue target, so + select the \"On Condition\" position type and pick the blue target image condition. + \n\nWhen you\'re done, save the click, then your event and scenario, and head back to the game. + + Start your scenario and launch the game + to win! \n\nIf it doesn\'t work, double-check that both conditions are captured correctly and that the click + duration is set to 1ms. + + Congratulations! You\'ve learned how to + use the AND operator. The event now triggers only when all of its conditions are satisfied at the same + time. + + \ No newline at end of file diff --git a/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_operator_or.xml b/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_operator_or.xml new file mode 100644 index 000000000..9c11abc7d --- /dev/null +++ b/feature/tutorial/src/main/res/values/strings_tutorial_combine_conditions_operator_or.xml @@ -0,0 +1,75 @@ + + + + + + Condition operator OR + Use the OR operator to click on the first + target that appears on screen + Click on any target as soon as it appears + on screen + + New challenge! Two targets can appear on + screen. The red one is worth 2 points and the blue one is worth 1 point, so click on whichever shows up + as fast as possible. \n\nStart the game and see how you do on your own. + + Too fast to handle manually, so let\'s use + Klick\'r. \n\nOpen the scenario configuration menu, create a new Screen Event, and start adding conditions + for the game targets. + + We need one condition per target. Let\'s + start with the blue one. \n\nCreate a new image condition and capture the blue target. + + This condition should trigger when the blue + target is visible, so the default settings are all correct. Save this condition. + + Now let\'s add the second condition for the + red target. \n\nCreate another image condition and capture the red target. + + Same here, the red target should be + visible, so the default settings are correct. Save this condition. + + With OR, conditions are checked in order + and the event triggers as soon as the first one matches, so the order of your conditions matters. + \n\nThe red target grants more points, so we want it to be checked first. Use the « button to move it + before the blue one, then return to the Event dialog. + + Now set the condition operator to OR. The + event will trigger as soon as either target appears. If both are visible at the same time, the red + condition will be matched first since it has the higher priority. \n\nSelect OR. + + The OR operator is now set. Open the + Actions section and create a new click action. + + We want to click on whichever target + triggered the event. Select the \"On Condition\" position type. With OR, only one condition can be + positively detected at a time, so no specific condition needs to be selected. Klick\'r will automatically + click on the location of whichever condition matched. \n\nWhen you\'re done, save the click, then your + event and scenario, and head back to the game. + + Start your scenario and launch the game + to win! \n\nIf it doesn\'t work, double-check that your conditions are captured correctly and that the + click duration is set to 1ms. + + Congratulations! You\'ve learned how to + use the OR operator and why condition priority matters. By placing the red condition first, Klick\'r always + favours the higher-value target when both are visible at the same time. + + + + \ No newline at end of file diff --git a/feature/tutorial/src/main/res/values/strings_tutorial_counters_basics.xml b/feature/tutorial/src/main/res/values/strings_tutorial_counters_basics.xml new file mode 100644 index 000000000..eb95bebd9 --- /dev/null +++ b/feature/tutorial/src/main/res/values/strings_tutorial_counters_basics.xml @@ -0,0 +1,124 @@ + + + + Counters basics + Learn how to use the Set Counter action and the Counter Reached + condition. + Click 10 times on the blue target, then click once on the red + target + + Welcome to the Counters tutorial! + \n\nHere, you will automate a game where you click the blue target 10 times, then click the red target once to + validate your count and earn 10 points. You can try the game first, or jump straight into the scenario + configuration. + + First, we need to create a Screen Event that detects the blue + target and clicks on it. \n\nClick on Create Event to get started. + + Let\'s start by adding a condition to detect the blue target. + Click on the Conditions field to open the condition list and create this condition. \n\nTutorial will proceed + once your condition is created. + + Good! Now click on the Actions field to add the actions that + will run when the blue target is detected. + + We first need a Click action to tap the blue target. Click + on the create button to add a new action. + + Configure the click to tap the blue target, then save the + action. \n\nTutorial will proceed once the click is saved. + + We also need to count how many times we have clicked on the + blue target. This can be achieved with a Change Counter action, by adding one every time we click. \n\nClick on + the create button again to add a second action. + + Select the Change Counter action to increment a counter each + time the blue target is clicked. + + First, we need to choose which counter to update. Click on + Select a counter to open the counter list. + + The list is empty for now. Click the create button to create + a new counter. Give it a name (e.g. "Blue clicks"), keep the starting value at 0, then save and select it. + + Now configure how the counter changes each time the blue + target is clicked. \n\nSet the operator to + and the value to 1, so the counter increases by 1 on each click. + \n\nThen save the action and return to the Event dialog. + The value can be a fixed number, or the current + value of another counter. + + Great! This Screen Event will now click the blue target and + increment your counter on every detection. \n\nSave the event to return to the scenario. + + Now we need an event that reacts when the counter reaches + 10. That kind of event is not triggered by the screen, so it\'s a Trigger Event. + \n\nClick on the Trigger Events tab to open the Trigger Events list. + + Click on the create button to add a new Trigger Event. + + Just like a Screen Event, a Trigger Event needs conditions. + Click on the Conditions field to open the condition list and create a new trigger condition. + + Select the Counter Reached condition type to trigger this + event when a counter hits a specific value. + + Select the counter you created earlier (the one counting + blue clicks) to use it as the trigger. + + Now set the comparison so the condition is fulfilled when + the counter equals 10. There are several comparison operators, but here we need to check when it is equal, so + select \"=\". Then enter 10 as value, save the condition and return to the Event dialog. + The value to compare against can be a fixed number, + or the current value of another counter. + + Condition is set! Now we need to define what happens when + the counter reaches 10. Click on the Actions field to open the action list. + + First, create a Click action and manually place it on the + red target to validate the count. + + Configure the click to tap the red target, then save the + action. Note that in a Trigger Event, the click position must always be set manually. \n\nTutorial will proceed + once the click is saved. + + Now create a second action to reset the counter. Click the + create button again and select the Change Counter action. + + We want to set the blue click counter to 0, so first, + select the blue click counter. + + Set the operator to = and the value to 0 to reset the + counter after each validation. Then save the action and return to the Event dialog to proceed. + + This Trigger Event will click the red target and reset the + counter every time 10 blue clicks are counted. The Trigger Event list is executed between each screen frame, + before the Screen Event list, so once the counter equals 10, this event runs immediately: the red target is + clicked and the counter reset, ready to start over. \n\nSave the event to return to the scenario. + + The scenario is complete! It will click the blue target, + count each click, then validate with the red target every 10 clicks and start over. \n\nSave the scenario to + apply your configuration. + + Everything is ready! Start the scenario, then launch the + game and watch Klick\'r handle the counting for you. + + Well done! You\'ve learned how to use Counters to track + values across multiple events. \n\nCombined with the Change Counter action and the Counter Reached condition, + you can now build automations that react to repeated patterns. + + \ No newline at end of file diff --git a/feature/tutorial/src/main/res/values/strings_tutorial_events_priority.xml b/feature/tutorial/src/main/res/values/strings_tutorial_events_priority.xml new file mode 100644 index 000000000..f9267f533 --- /dev/null +++ b/feature/tutorial/src/main/res/values/strings_tutorial_events_priority.xml @@ -0,0 +1,68 @@ + + + + + Prioritizing an Event + Prioritize an Event over another Event + Click as fast as possible on the targets. Blue = 1 point; + Red = 10 points + + New game, we need to click on any targets as fast as + possible, but the red one is more rewarding. You can test the game first or open the scenario configuration menu + to start automating this game. + + We want to detect two different targets, the blue and the red. + For this tutorial, we will create two distinct events: a first one for the blue target and a second one + for the red target. \n\nFirst, create the Event for the blue target; it must click on it when detected. + Don\'t forget to use the test features to make sure your condition is correctly detected. \n\nThe tutorial will + proceed once your blue target Event is saved. + + Great! Now we need the same thing, but for the red target. + Click on the create Event button and create one for the red target; it must click on it when detected. + \n\nThe tutorial will proceed once your red target Event is saved. + + Our list now has two events, one for each target. Save your + Scenario and test it against the game. + + Something seems wrong. The scenario only clicks on the blue + target, completely ignoring the red one, which prevents us from winning the game. \n\nWhy is this happening? + Because the blue event is before the red one, and since it\'s always triggered, the current frame is evaluated + no further and the next frame starts from the beginning of the Event list. \n\nThere are multiple ways to fix + this. Open the scenario configuration dialog to learn how. + + We can fix the problem in two ways: \n\nWe can change the + \"Keep executing\" option of the blue target event to continue processing the same frame and also execute the + red event. This will trigger both clicks when both targets are visible at the same time. \n\nOr we can move the + red target event to the top of the event list, so it is checked first and always clicked when visible, but the + blue target won\'t be clicked anymore when the red target is also displayed. \n\nThe key difference between both + solutions is speed: putting the red event first means we react as fast as possible when it appears, while being + slightly slower when only the blue target is visible. + + Since the game gives 10 points for the red target, we want + to react as fast as possible when it appears by moving the red event to the top of the event list. \n\nMove the + red event first and save the scenario. You should be able to beat the game now. + You can reorder Events by long pressing on this + icon and dragging the event to the correct place. + + As usual, start your scenario first, and then start the game. + \n\nIf you still can\'t beat it, make sure each event works on its own using the test features. + + Great! You now understand how event priority works and how + the Screen Event loop behaves. This is key to building and managing complex scenarios. + + \ No newline at end of file diff --git a/feature/tutorial/src/main/res/values/strings_tutorial_events_state.xml b/feature/tutorial/src/main/res/values/strings_tutorial_events_state.xml new file mode 100644 index 000000000..f53fb9c26 --- /dev/null +++ b/feature/tutorial/src/main/res/values/strings_tutorial_events_state.xml @@ -0,0 +1,142 @@ + + + + + Disable unused events + Change the state of multiple events to optimize a complex scenario. + Click on the targets in order: blue, red, green and then yellow. + + New game! This time you need to click on four colored targets + in order: blue first, then red, then green, and finally yellow. \n\nYou can try the game first to see how it + works, or open the scenario configuration right away to start automating it. + + We need to detect four different targets, one for each color. + We will create one Event per target. \n\nStart with the blue target: create a new Event that detects it within + the game area and clicks on it. + + When using multiple events, it is important to customize the name + of your events to keep track of what you are doing. Give this Event a clear name, like \"Blue target\", so you can + easily identify it later in your scenario. \n\nOnce you are done, create a new Image condition and capture the + blue target. + + As the target is moving, we need to set the detection type to + \"Detection Area\" and then select the game area. \n\nOnce the area is correctly configured, save it and return + to the Event dialog. + + Your condition is set, now we need a Click action so the Event + clicks on the detected target. \n\nCreate a new Click action to proceed. + + The target is moving, so we can\'t define a static position. + Set the \"Click on\" field to \"Click on the detected condition\" and select your blue target condition. This way, the click will always + land exactly where the target was found on screen.\n\nOnce the condition is selected, save the click and return + to the Event dialog. + + Blue target Event is done! Now create an Event for the red + target the same way: detect it in the game area and click on it. The tutorial will proceed once your red target + Event is saved. + + Great! Now create the same Event for the green target. The + tutorial will proceed once your green target Event is saved. + + Almost there! Create one last Event for the yellow target. The + tutorial will proceed once your yellow target Event is saved. + + All four Events are ready. As we defined them in the game + sequence order, their priority are OK. \n\nSave your Scenario and test it against the game to see how it + performs. + + The scenario is detecting and clicking on targets, but it\'s + probably too slow to win. \n\nCurrently, all four Events are active at the same time, so every frame the scenario + checks blue, then red, then green, then yellow; no matter which target was just clicked. This wastes precious + time! \n\nOpen the scenario configuration to learn how to improve this. + + Each Event has an initial state: it can start enabled or + disabled. Right now all four Events are enabled, so they are all checked on every frame. \n\nThe solution is to + keep only the current target\'s Event active and disable the rest. When a target is clicked, its Event will + enable the next target and disable al others. \n\nLet\'s start by editing the blue target Event. + + The blue target is the first to click, so its Event should + start enabled; no change needed here. \n\nWe just need to add a \"Change event state\" action so that when the blue + target is clicked, the red target Event is enabled and the others are disabled. Tap on the Actions area to + add this action. + + Select the \"Change event state\" action type. + + This action lets you change the state of any Event in your + scenario when this Event is triggered. Tap the \"No changes\" field to select which Events to change. + + For each Event in the list, you can set one of three states: + \n• Enable: the Event becomes active and will be checked on every frame \n• Disable: the Event becomes inactive + and is skipped entirely \n• Invert: switches between active and inactive each time \n\nSince blue was just + clicked, enable the red target Event and disable all the others. Tap Next when you are done. + Each Event row shows three options: Enable, Disable, + and Toggle. Tap the one you want to apply when this action is executed. + + Perfect! Save the blue target Event. + + Now open the red target Event in the list to configure it the + same way. + + Unlike the blue target Event, this Event should not be active + at the start of the scenario, since its target is not the first one. Change its initial state to Disabled. + + Now add a \"Change event state\" action so that when this target is + clicked, the next target\'s Event is enabled and the others are disabled. Tap the Actions area. + + Set the toggles: enable the green target and disable all the + others. Tap Next when you are done. + + Good job! Now open the green target Event to configure it the + same way. + + The green target should not be active at the start either. + Change its initial state to Disabled. + + Now add a \"Change event state\" action so that when the green target + is clicked, the yellow target\'s Event is enabled and the others are disabled. Tap the Actions area. + + Set the toggles: enable the yellow target and disable all the + others. Tap Next when you are done. + + Almost done! Open the yellow target Event to finish the + configuration. + + The yellow target is the last in the sequence, so it should + also start disabled. Change its initial state to Disabled. + + Add a \"Change event state\" action to the yellow target Event as + well. When yellow is clicked, we want to loop back to the beginning: enable the blue target and disable all the + others. Tap the Actions area. + + Set the toggles: enable the blue target and disable all the + others. This way, the sequence will loop indefinitely. Tap Next when you are done. + + All Events are now fully configured. Save your Scenario to + apply the changes. + + All Events are configured! Save your Scenario and then start + the game. Remember to start your Scenario before launching the game. \n\nAs our scenario has an internal state, + you need to restart it every time you restart the game to ensure it won\'t be waiting for the last target of the + previous game session. This can be easily automated by detecting if the start button is visible to reset the + events states. + + You won! \n\nBy controlling which Events are active at any + given time, the scenario always knows exactly which target to look for next — no wasted frames checking targets + out of sequence. \n\nThis is how the Toggle Event action lets you build sequential and state-driven + automation. + \ No newline at end of file diff --git a/feature/tutorial/src/test/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/GetTutorialCategoryUseCaseTest.kt b/feature/tutorial/src/test/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/GetTutorialCategoryUseCaseTest.kt index a07b68172..a9b94476b 100644 --- a/feature/tutorial/src/test/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/GetTutorialCategoryUseCaseTest.kt +++ b/feature/tutorial/src/test/java/com/buzbuz/smartautoclicker/feature/tutorial/domain/GetTutorialCategoryUseCaseTest.kt @@ -87,14 +87,14 @@ class GetTutorialCategoryUseCaseTest { val header = state.items[0] as TutorialCategoryUiItems.Header assertEquals(R.string.tutorial_category_root_name, header.categoryNameRes) - // Header + SectionDivider + BASICS + COMBINE_CONDITIONS + EVENT_STATE + COUNTERS + // Header + Divider + BASICS + COMBINE_CONDITIONS + EVENT_STATE + COUNTERS assertEquals(6, state.items.size) assertTrue(state.items[1] is TutorialCategoryUiItems.SectionDivider) assertEquals( listOf( TutorialCategory.Type.BASICS, TutorialCategory.Type.COMBINE_CONDITIONS, - TutorialCategory.Type.EVENT_STATE, + TutorialCategory.Type.COMBINE_EVENTS, TutorialCategory.Type.COUNTERS, ), state.items.filterIsInstance().map { it.type }, diff --git a/smartautoclicker/src/main/res/layout/fragment_settings.xml b/smartautoclicker/src/main/res/layout/fragment_settings.xml index d51e2afca..cefd6620e 100644 --- a/smartautoclicker/src/main/res/layout/fragment_settings.xml +++ b/smartautoclicker/src/main/res/layout/fragment_settings.xml @@ -29,11 +29,6 @@ android:layout_marginHorizontal="@dimen/margin_horizontal_default" android:orientation="vertical"> - -