diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index 3f3a58e4..6af3b540 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -13,9 +13,6 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index daa45ce4..04bba921 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -4,15 +4,19 @@
+
+
+
+
@@ -28,21 +32,27 @@
+
+
+
+
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 59216037..45f87c6f 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -125,6 +125,21 @@ android {
}
}
+ /**
+ * Code shrinking and obfuscation are intentionally disabled for the `release` build.
+ *
+ * This application embeds Android Studio–like tooling (editor/runtime features) that rely on:
+ * - reflection
+ * - dynamic class loading
+ * - stable class and method names
+ *
+ * Enabling `isMinifyEnabled` or `isShrinkResources` may break these mechanisms,
+ * leading to runtime instability or non-functional tooling inside the app.
+ *
+ * Note:
+ * If minification is ever enabled, extensive keep rules will be required to preserve
+ * all dynamically accessed APIs and internal tooling components.
+ */
buildTypes {
release {
val signingFile = rootProject.file("signing.properties")
@@ -133,8 +148,8 @@ android {
} else {
null
}
- isMinifyEnabled = true
- isShrinkResources = true
+ isMinifyEnabled = false
+ isShrinkResources = false
proguardFiles(getDefaultProguardFile(name = "proguard-android-optimize.txt"), "proguard-rules.pro")
if (hasGoogleServicesConfig) {
configure {
@@ -170,7 +185,7 @@ android {
dependencies {
// App Core
- implementation(dependencyNotation = "com.github.MihaiCristianCondrea:App-Toolkit-for-Android:2.0.8") {
+ implementation(dependencyNotation = "com.github.MihaiCristianCondrea:App-Toolkit-for-Android:2.0.10") {
isTransitive = true
}
diff --git a/app/src/androidTest/kotlin/com/d4rk/androidtutorials/app/codestudio/onboarding/ui/IdeOnboardingScreenTest.kt b/app/src/androidTest/kotlin/com/d4rk/androidtutorials/app/codestudio/onboarding/ui/IdeOnboardingScreenTest.kt
new file mode 100644
index 00000000..7374fbc3
--- /dev/null
+++ b/app/src/androidTest/kotlin/com/d4rk/androidtutorials/app/codestudio/onboarding/ui/IdeOnboardingScreenTest.kt
@@ -0,0 +1,124 @@
+package com.d4rk.androidtutorials.app.codestudio.onboarding.ui
+
+import androidx.activity.ComponentActivity
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.d4rk.android.libs.apptoolkit.core.ui.window.AppWindowWidthSizeClass
+import com.d4rk.androidtutorials.app.codestudio.onboarding.domain.model.CodeStudioOnboardingStep
+import com.d4rk.androidtutorials.app.codestudio.onboarding.domain.model.CodeStudioProjectForm
+import com.d4rk.androidtutorials.app.codestudio.onboarding.domain.reducer.IdeOnboardingReducer
+import com.d4rk.androidtutorials.app.codestudio.onboarding.domain.validation.IdeProjectFormValidator
+import com.d4rk.androidtutorials.app.codestudio.onboarding.ui.contract.CodeStudioOnboardingAction
+import com.d4rk.androidtutorials.app.codestudio.onboarding.ui.state.CodeStudioOnboardingUiState
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+// FIXME: FIX THE UNIT TESTS
+@RunWith(AndroidJUnit4::class)
+class IdeOnboardingScreenTest {
+
+ @get:Rule
+ val composeRule = createAndroidComposeRule()
+
+ @Test
+ fun stepNavigation_nextAndBack_updatesStepCounter() {
+ composeRule.setContent {
+ var state by mutableStateOf(CodeStudioOnboardingUiState())
+ CodeStudioOnboardingScreen(
+ state = state,
+ windowWidthSizeClass = AppWindowWidthSizeClass.Compact,
+ paddingValues = androidx.compose.foundation.layout.PaddingValues(),
+ onAction = { action -> state = IdeOnboardingReducer.reduce(state, action).state },
+ onRequestPermissionCapability = {},
+ onRunEnvironmentChecks = {},
+ )
+ }
+
+ composeRule.onNodeWithText("Step 1 of 7").assertIsDisplayed()
+ composeRule.onNodeWithText("Next").performClick()
+ composeRule.onNodeWithText("Step 2 of 7").assertIsDisplayed()
+ composeRule.onNodeWithText("Next").performClick()
+ composeRule.onNodeWithText("Step 3 of 7").assertIsDisplayed()
+ composeRule.onNodeWithText("Back").performClick()
+ composeRule.onNodeWithText("Step 2 of 7").assertIsDisplayed()
+ }
+
+ @Test
+ fun nextDisabled_whenPermissionStepNotGranted() {
+ composeRule.setContent {
+ val state = CodeStudioOnboardingUiState(currentStep = CodeStudioOnboardingStep.PERMISSIONS)
+ IdeOnboardingScreen(
+ state = state,
+ windowWidthSizeClass = AppWindowWidthSizeClass.Compact,
+ paddingValues = androidx.compose.foundation.layout.PaddingValues(),
+ onAction = {},
+ onRequestPermissionCapability = {},
+ onRunEnvironmentChecks = {},
+ )
+ }
+
+ composeRule.onNodeWithText("Next").assertIsNotEnabled()
+ }
+
+ @Test
+ fun errorMessage_isRenderedWithLiveRegionCard() {
+ composeRule.setContent {
+ val state = CodeStudioOnboardingUiState(errorMessage = "Project cannot be created yet.")
+ IdeOnboardingScreen(
+ state = state,
+ windowWidthSizeClass = AppWindowWidthSizeClass.Compact,
+ paddingValues = androidx.compose.foundation.layout.PaddingValues(),
+ onAction = {},
+ onRequestPermissionCapability = {},
+ onRunEnvironmentChecks = {},
+ )
+ }
+
+ composeRule.onNodeWithText("Project cannot be created yet.").assertIsDisplayed()
+ }
+
+ @Test
+ fun createButton_enabledOnValidReview_andDispatchesAction() {
+ var lastAction: CodeStudioOnboardingAction? = null
+
+ composeRule.setContent {
+ val form = CodeStudioProjectForm(
+ projectName = "MyProject",
+ packageName = "com.example.project",
+ saveLocation = "/tmp",
+ selectedTemplateId = "empty_activity",
+ )
+ val state = CodeStudioOnboardingUiState(
+ currentStep = CodeStudioOnboardingStep.REVIEW_AND_CREATE,
+ projectForm = form,
+ validationResult = IdeProjectFormValidator.validate(form),
+ isPermissionGranted = true,
+ isEnvironmentReady = true,
+ )
+ IdeOnboardingScreen(
+ state = state,
+ windowWidthSizeClass = AppWindowWidthSizeClass.Compact,
+ paddingValues = androidx.compose.foundation.layout.PaddingValues(),
+ onAction = { action -> lastAction = action },
+ onRequestPermissionCapability = {},
+ onRunEnvironmentChecks = {},
+ )
+ }
+
+ composeRule.onNodeWithText("Create Project").assertIsEnabled().performClick()
+ composeRule.runOnIdle {
+ assertEquals(CodeStudioOnboardingAction.CreateProjectClicked, lastAction)
+ }
+ composeRule.onNodeWithText("Next").assertDoesNotExist()
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 50bb27b3..bf524445 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,6 +20,8 @@
android:installLocation="auto">
+
+
+
+
+
+
+
+