Skip to content

Commit 51a5cae

Browse files
authored
Merge pull request #442 from AppDevNext/MainActivityCompose
Compose MainActivity
2 parents 210944e + f4b58ee commit 51a5cae

File tree

180 files changed

+311
-105
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

180 files changed

+311
-105
lines changed

app/build.gradle.kts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
55
plugins {
66
id("com.android.application")
77
id("kotlin-android")
8+
id("org.jetbrains.kotlin.plugin.compose") version "2.2.21"
89
}
910

1011
android {
@@ -34,6 +35,7 @@ android {
3435
}
3536
buildFeatures {
3637
viewBinding = true
38+
compose = true
3739
}
3840
buildTypes {
3941
release {
@@ -52,6 +54,23 @@ dependencies {
5254
implementation("com.google.android.material:material:1.13.0")
5355
implementation(project(":MPChartLib"))
5456

57+
// Compose BOM
58+
val composeBom = platform("androidx.compose:compose-bom:2024.11.00")
59+
implementation(composeBom)
60+
androidTestImplementation(composeBom)
61+
62+
// Compose dependencies
63+
implementation("androidx.compose.material3:material3")
64+
implementation("androidx.compose.ui:ui")
65+
implementation("androidx.compose.ui:ui-tooling-preview")
66+
implementation("androidx.activity:activity-compose:1.9.3")
67+
implementation("androidx.compose.material:material-icons-extended")
68+
debugImplementation("androidx.compose.ui:ui-tooling")
69+
70+
// Compose testing
71+
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
72+
debugImplementation("androidx.compose.ui:ui-test-manifest")
73+
5574
androidTestImplementation("androidx.test.ext:junit-ktx:1.3.0")
5675
androidTestImplementation("com.github.AppDevNext.Logcat:LogcatCoreLib:3.4")
5776
androidTestUtil("androidx.test.services:test-services:1.6.0")

app/src/androidTest/java/info/appdev/chartexample/StartTest.kt

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
package info.appdev.chartexample
22

33
import android.graphics.Bitmap
4+
import androidx.compose.ui.test.assertIsDisplayed
5+
import androidx.compose.ui.test.junit4.createEmptyComposeRule
6+
import androidx.compose.ui.test.onNodeWithTag
7+
import androidx.compose.ui.test.onNodeWithText
8+
import androidx.compose.ui.test.performClick
9+
import androidx.compose.ui.test.performScrollToIndex
410
import androidx.test.core.graphics.writeToTestStorage
511
import androidx.test.espresso.Espresso
6-
import androidx.test.espresso.Espresso.onData
712
import androidx.test.espresso.Espresso.onView
813
import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
914
import androidx.test.espresso.action.ViewActions.captureToBitmap
1015
import androidx.test.espresso.action.ViewActions.click
1116
import androidx.test.espresso.intent.Intents
1217
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
1318
import androidx.test.espresso.matcher.ViewMatchers
14-
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
15-
import androidx.test.espresso.matcher.ViewMatchers.withId
1619
import androidx.test.espresso.matcher.ViewMatchers.withText
1720
import androidx.test.ext.junit.rules.activityScenarioRule
1821
import androidx.test.ext.junit.runners.AndroidJUnit4
1922
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
2023
import info.appdev.chartexample.notimportant.DemoBase.Companion.optionMenus
2124
import info.appdev.chartexample.notimportant.MainActivity
2225
import info.hannes.timber.DebugFormatTree
23-
import org.hamcrest.CoreMatchers.allOf
24-
import org.hamcrest.CoreMatchers.anything
2526
import org.junit.After
2627
import org.junit.Before
2728
import org.junit.Rule
@@ -37,6 +38,9 @@ class StartTest {
3738
@get:Rule
3839
val activityScenarioRule = activityScenarioRule<MainActivity>()
3940

41+
@get:Rule
42+
val composeTestRule = createEmptyComposeRule()
43+
4044
@get:Rule
4145
var nameRule = TestName()
4246

@@ -53,19 +57,47 @@ class StartTest {
5357

5458
@Test
5559
fun smokeTestStart() {
60+
// Wait for Compose to be ready
61+
composeTestRule.waitForIdle()
62+
5663
onView(ViewMatchers.isRoot())
5764
.perform(captureToBitmap { bitmap: Bitmap -> bitmap.writeToTestStorage("${javaClass.simpleName}_${nameRule.methodName}") })
5865

5966
var optionMenu = ""
60-
// iterate samples
67+
// iterate samples - only items with classes (not section headers)
6168
MainActivity.menuItems.forEachIndexed { index, contentItem ->
6269
contentItem.clazz?.let {
63-
Timber.d("Intended ${index}-${it.simpleName}")
70+
Timber.d("Intended ${index}-${it.simpleName}: ${contentItem.name}")
6471

6572
try {
66-
onData(anything())
67-
.inAdapterView(allOf(withId(R.id.listViewMain), isCompletelyDisplayed()))
68-
.atPosition(index).perform(click())
73+
// Use description to uniquely identify items since names can be duplicated
74+
// If description exists, use it; otherwise fall back to name
75+
val searchText = if (contentItem.desc.isNotEmpty()) {
76+
contentItem.desc
77+
} else {
78+
contentItem.name
79+
}
80+
81+
Timber.d("Searching for index $index: $searchText")
82+
83+
// Scroll to the item in the LazyColumn by index
84+
// This ensures the item is composed and visible
85+
try {
86+
composeTestRule.onNodeWithTag("menuList")
87+
.performScrollToIndex(index)
88+
composeTestRule.waitForIdle()
89+
} catch (e: Exception) {
90+
Timber.w("Could not scroll to index $index: ${e.message}")
91+
}
92+
93+
// Now click the item using its test tag
94+
composeTestRule.onNodeWithTag("menuItem_$index")
95+
.assertExists("Could not find menu item at index $index")
96+
.performClick()
97+
98+
// Wait for the new activity to start
99+
composeTestRule.waitForIdle()
100+
Thread.sleep(300) // Increased delay for activity transition
69101

70102
Intents.intended(hasComponent(it.name))
71103
onView(ViewMatchers.isRoot())
@@ -80,8 +112,12 @@ class StartTest {
80112

81113
//Thread.sleep(100)
82114
Espresso.pressBack()
115+
116+
// Wait for MainActivity to be visible again
117+
composeTestRule.waitForIdle()
118+
Thread.sleep(200) // Small delay for back navigation
83119
} catch (e: Exception) {
84-
Timber.e(optionMenu + e.message!!)
120+
Timber.e("Error at index $index: $optionMenu - ${e.message}", e)
85121
onView(ViewMatchers.isRoot())
86122
.perform(captureToBitmap { bitmap: Bitmap -> bitmap.writeToTestStorage("${javaClass.simpleName}_${nameRule.methodName}-${index}-${it.simpleName}-Error") })
87123
}

app/src/main/kotlin/info/appdev/chartexample/notimportant/DemoBase.kt

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import android.os.Bundle
77
import android.view.Menu
88
import android.view.MenuItem
99
import android.view.View
10-
import android.view.WindowInsets
11-
import android.view.WindowInsetsController
12-
import android.view.WindowManager
1310
import android.widget.Toast
1411
import androidx.activity.OnBackPressedCallback
1512
import androidx.appcompat.app.AppCompatActivity
1613
import androidx.core.app.ActivityCompat
14+
import androidx.core.view.WindowCompat
15+
import androidx.core.view.WindowInsetsCompat
16+
import androidx.core.view.WindowInsetsControllerCompat
1717
import com.github.mikephil.charting.charts.Chart
1818
import com.google.android.material.snackbar.Snackbar
1919
import info.appdev.chartexample.R
@@ -40,20 +40,6 @@ abstract class DemoBase : AppCompatActivity(), ActivityCompat.OnRequestPermissio
4040
override fun onCreate(savedInstanceState: Bundle?) {
4141
super.onCreate(savedInstanceState)
4242

43-
// Enable fullscreen mode using modern API
44-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
45-
window.insetsController?.let {
46-
it.hide(WindowInsets.Type.statusBars())
47-
it.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
48-
}
49-
} else {
50-
@Suppress("DEPRECATION")
51-
window.setFlags(
52-
WindowManager.LayoutParams.FLAG_FULLSCREEN,
53-
WindowManager.LayoutParams.FLAG_FULLSCREEN
54-
)
55-
}
56-
5743
optionMenus.clear()
5844

5945
tfRegular = Typeface.createFromAsset(assets, "OpenSans-Regular.ttf")
@@ -62,6 +48,18 @@ abstract class DemoBase : AppCompatActivity(), ActivityCompat.OnRequestPermissio
6248
onBackPressedDispatcher.addCallback(this, backPressedCallback)
6349
}
6450

51+
override fun onStart() {
52+
super.onStart()
53+
54+
// Hide status bars using modern WindowCompat API
55+
// Note: We don't call setDecorFitsSystemWindows(false) because these activities
56+
// use traditional AppCompat ActionBar which needs to fit within system windows
57+
WindowCompat.getInsetsController(window, window.decorView).apply {
58+
hide(WindowInsetsCompat.Type.statusBars())
59+
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
60+
}
61+
}
62+
6563
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
6664
menu?.let {
6765
for (i in 0 until menu.size) {

0 commit comments

Comments
 (0)