Skip to content

Release/3.0.3 - #98

Merged
amirisback merged 3 commits into
masterfrom
release/3.0.3
Jun 21, 2026
Merged

Release/3.0.3#98
amirisback merged 3 commits into
masterfrom
release/3.0.3

Conversation

@amirisback

Copy link
Copy Markdown
Member

No description provided.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@amirisback
amirisback merged commit 4334350 into master Jun 21, 2026
1 check failed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the project version to 3.0.3, bumps the compile SDK to 37, and introduces Jetpack Compose support for Fragments and Navigation (including FrogoComposeFragment and FrogoComposeNavActivity) along with unit tests and sample implementations. The review feedback highlights several improvement opportunities: avoiding the use of a protected lateinit var for the NavController, removing an unused and directly instantiated ViewModel in SampleFragment, using LocalContext.current instead of the nullable Fragment context inside Composables, removing a redundant onCreateExt override, and centralizing the navigation-compose version in the Version Catalog.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +7 to +15
abstract class FrogoComposeNavActivity : FrogoComposeActivity() {

protected lateinit var navController: NavHostController

@Composable
override fun SetupCompose() {
navController = rememberNavController()
SetupNavigation(navController)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Storing navController as a protected lateinit var in the Activity class is risky and can lead to UninitializedPropertyAccessException if accessed before composition occurs (e.g., during onCreate or other lifecycle methods). Additionally, keeping a reference to NavController in the Activity can lead to state inconsistencies or memory leaks.

Since SetupNavigation already receives the navController as a parameter, we can completely eliminate the class property and use a local variable inside SetupCompose.

abstract class FrogoComposeNavActivity : FrogoComposeActivity() {

    @Composable
    override fun SetupCompose() {
        val navController = rememberNavController()
        SetupNavigation(navController)
    }

Comment on lines +24 to +29
private lateinit var sampleViewModel: SampleViewModel

override fun setupViewModel() {
super.setupViewModel()
sampleViewModel = SampleViewModel()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The sampleViewModel property is declared and directly instantiated via SampleViewModel(), which is an anti-pattern in Android (ViewModels should be managed by the lifecycle/ViewModelStore, not instantiated directly). Furthermore, this property is completely unused because setupCompose correctly retrieves the ViewModel using the viewModel() delegate. We should remove this redundant and incorrect initialization.

Comment on lines +31 to +56
@Composable
override fun setupCompose() {
val vm: SampleViewModel = viewModel()
val state by vm.uiState.collectAsState()

Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Sample Fragment Compose", style = MaterialTheme.typography.headlineMedium)
Spacer(modifier = Modifier.height(8.dp))
Text(text = state.description, style = MaterialTheme.typography.bodyMedium)
Spacer(modifier = Modifier.height(16.dp))
Text(text = "Counter: ${state.counter}", style = MaterialTheme.typography.titleLarge)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = {
vm.incrementCounter()
Toast.makeText(context, "Clicked from Compose Fragment!", Toast.LENGTH_SHORT).show()
}) {
Text("Increment Counter")
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In Jetpack Compose, the idiomatic way to obtain the Android Context is by using LocalContext.current. Relying on the Fragment's context property directly can be unsafe because it is nullable (Context?) and can lead to crashes if the Fragment is detached when the click action is triggered.

    @Composable
    override fun setupCompose() {
        val vm: SampleViewModel = viewModel()
        val state by vm.uiState.collectAsState()
        val context = androidx.compose.ui.platform.LocalContext.current

        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Sample Fragment Compose", style = MaterialTheme.typography.headlineMedium)
            Spacer(modifier = Modifier.height(8.dp))
            Text(text = state.description, style = MaterialTheme.typography.bodyMedium)
            Spacer(modifier = Modifier.height(16.dp))
            Text(text = "Counter: ${state.counter}", style = MaterialTheme.typography.titleLarge)
            Spacer(modifier = Modifier.height(16.dp))
            Button(onClick = {
                vm.incrementCounter()
                Toast.makeText(context, "Clicked from Compose Fragment!", Toast.LENGTH_SHORT).show()
            }) {
                Text("Increment Counter")
            }
        }
    }

Comment on lines +22 to +53
@Composable
override fun setupCompose() {
Column(
modifier = Modifier
.fillMaxWidth()
.background(
color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
)
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Sample Bottom Sheet Fragment",
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSurface
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "This bottom sheet UI is built entirely using Jetpack Compose hosted inside a BottomSheetDialogFragment.",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = {
Toast.makeText(context, "Action from Bottom Sheet!", Toast.LENGTH_SHORT).show()
dismiss()
}) {
Text("Dismiss Sheet")
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the Fragment's nullable context property directly inside a Composable is discouraged. Instead, use LocalContext.current to safely retrieve the non-null Context associated with the composition tree.

    @Composable
    override fun setupCompose() {
        val context = androidx.compose.ui.platform.LocalContext.current
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .background(
                    color = MaterialTheme.colorScheme.surface,
                    shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
                )
                .padding(24.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = "Sample Bottom Sheet Fragment",
                style = MaterialTheme.typography.titleLarge,
                color = MaterialTheme.colorScheme.onSurface
            )
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                text = "This bottom sheet UI is built entirely using Jetpack Compose hosted inside a BottomSheetDialogFragment.",
                style = MaterialTheme.typography.bodyMedium,
                color = MaterialTheme.colorScheme.onSurfaceVariant
            )
            Spacer(modifier = Modifier.height(16.dp))
            Button(onClick = {
                Toast.makeText(context, "Action from Bottom Sheet!", Toast.LENGTH_SHORT).show()
                dismiss()
            }) {
                Text("Dismiss Sheet")
            }
        }
    }

Comment on lines +23 to +31
class SampleNavComposeActivity : FrogoComposeNavActivity() {

override fun onCreateExt(savedInstanceState: Bundle?) {
super.onCreateExt(savedInstanceState)
// Additional configuration during onCreate if needed
}

@Composable
override fun SetupNavigation(navController: NavHostController) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The onCreateExt method is overridden but only calls super.onCreateExt(savedInstanceState) without adding any custom logic. This redundant override can be safely removed to keep the codebase clean.

Suggested change
class SampleNavComposeActivity : FrogoComposeNavActivity() {
override fun onCreateExt(savedInstanceState: Bundle?) {
super.onCreateExt(savedInstanceState)
// Additional configuration during onCreate if needed
}
@Composable
override fun SetupNavigation(navController: NavHostController) {
class SampleNavComposeActivity : FrogoComposeNavActivity() {
@Composable
override fun SetupNavigation(navController: NavHostController) {

Comment thread gradle/libs.versions.toml
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "liveCycle" }
androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" }
androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" }
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version = "2.8.5" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It is best practice to define all dependency versions in the [versions] block of the Version Catalog (libs.versions.toml) rather than hardcoding them directly in the [libraries] block. This ensures centralized version management.

Suggested change
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version = "2.8.5" }
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant