Skip to content

feat: double-back-to-exit on root tab screens#457

Merged
torlando-tech merged 2 commits intotorlando-tech:mainfrom
MatthieuTexier:feature/back-press-confirm
Feb 17, 2026
Merged

feat: double-back-to-exit on root tab screens#457
torlando-tech merged 2 commits intotorlando-tech:mainfrom
MatthieuTexier:feature/back-press-confirm

Conversation

@MatthieuTexier
Copy link
Copy Markdown
Contributor

Summary

Prevents accidental exits and annoying back-navigation between tabs. When on a root tab screen (Chats, Contacts, Map, Settings), pressing the system back button now shows a "Press back again to exit" toast instead of navigating to the previous tab. A second press within 2 seconds closes the app.

How it works

  • BackHandler is enabled only on root tab screens
  • First press → shows a Toast and sets a flag
  • LaunchedEffect auto-resets the flag after 2 seconds
  • Second press within the window → finish() on the activity

Files changed

  • app/src/main/java/com/lxmf/messenger/MainActivity.kt — added BackHandler + LaunchedEffect in ColumbaNavigation()

Testing

  • Build succeeds (compileNoSentryDebugKotlin)
  • detekt passes
  • ktlint passes
  • Manual test: back on root tab shows toast, double-back exits
  • Manual test: back on nested screens (messaging, settings sub-pages) still navigates normally

When on a root tab (Chats, Contacts, Map, Settings), pressing back
shows a "Press back again to exit" toast instead of navigating between
tabs. A second press within 2 seconds finishes the activity.

Uses BackHandler with LaunchedEffect for lifecycle-aware timer reset.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 13, 2026

Greptile Summary

This PR adds a double-back-to-exit pattern for root tab screens (Chats, Contacts, Map, Settings) in ColumbaNavigation. When on a root screen, the first back press shows a "Press back again to exit" toast, and a second press within 2 seconds calls finish() to close the app. The implementation uses Compose BackHandler (enabled only on root routes), a remember state flag keyed on currentRoute to reset when switching tabs, and a LaunchedEffect to auto-reset after 2 seconds.

  • The core logic is clean and correctly handles edge cases (tab switching resets state, BackHandler is disabled on nested screens so normal navigation is unaffected)
  • The second commit (c316aa71) fixes the previously-reviewed issue where backPressedOnce persisted across tab switches by keying remember on currentRoute
  • Two minor style items: a fully-qualified kotlinx.coroutines.delay call and a non-alphabetical import ordering

Confidence Score: 4/5

  • This PR is safe to merge — it adds a well-scoped UX improvement with no functional regressions.
  • Score of 4 reflects a clean, focused change with correct logic, proper edge case handling (tab switching resets state), and no impact on nested screen navigation. Only minor style issues prevent a 5.
  • No files require special attention. The single changed file has been thoroughly reviewed.

Important Files Changed

Filename Overview
app/src/main/java/com/lxmf/messenger/MainActivity.kt Adds BackHandler with double-back-to-exit logic for root tab screens. Logic is sound; two minor style issues (FQ delay call, import ordering).

Sequence Diagram

sequenceDiagram
    participant User
    participant BackHandler
    participant State as backPressedOnce State
    participant Toast
    participant LaunchedEffect
    participant Activity as ComponentActivity

    User->>BackHandler: Press back (on root tab)
    BackHandler->>State: Check backPressedOnce
    alt First press (backPressedOnce = false)
        State-->>BackHandler: false
        BackHandler->>State: Set backPressedOnce = true
        BackHandler->>Toast: Show "Press back again to exit"
        BackHandler->>LaunchedEffect: Triggered (key changed)
        LaunchedEffect->>LaunchedEffect: delay(2000ms)
        LaunchedEffect->>State: Reset backPressedOnce = false
    else Second press within 2s (backPressedOnce = true)
        State-->>BackHandler: true
        BackHandler->>Activity: finish()
    end

    Note over User,Activity: Tab switch resets state via remember(currentRoute)
Loading

Last reviewed commit: c316aa7

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@sentry
Copy link
Copy Markdown
Contributor

sentry bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 0% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...p/src/main/java/com/lxmf/messenger/MainActivity.kt 0.00% 12 Missing ⚠️

📢 Thoughts on this report? Let us know!

Key remember on currentRoute so the "press back again" flag resets
when the user navigates to a different tab.
@torlando-tech
Copy link
Copy Markdown
Owner

@greptileai

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

// Auto-reset the flag after 2 seconds
LaunchedEffect(backPressedOnce) {
if (backPressedOnce) {
kotlinx.coroutines.delay(2000)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use an import for delay
kotlinx.coroutines.delay is used with a fully-qualified name here, while kotlinx.coroutines.launch is already imported at line 109. For consistency, add import kotlinx.coroutines.delay and use the short name.

Suggested change
kotlinx.coroutines.delay(2000)
delay(2000)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/com/lxmf/messenger/MainActivity.kt
Line: 896:896

Comment:
**Use an import for `delay`**
`kotlinx.coroutines.delay` is used with a fully-qualified name here, while `kotlinx.coroutines.launch` is already imported at line 109. For consistency, add `import kotlinx.coroutines.delay` and use the short name.

```suggestion
            delay(2000)
```

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +13 to 14
import android.widget.Toast
import android.provider.Settings
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Import ordering is non-alphabetical
android.widget.Toast should come after android.provider.Settings to maintain alphabetical ordering within the android.* import group.

Suggested change
import android.widget.Toast
import android.provider.Settings
import android.provider.Settings
import android.widget.Toast

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/com/lxmf/messenger/MainActivity.kt
Line: 13:14

Comment:
**Import ordering is non-alphabetical**
`android.widget.Toast` should come after `android.provider.Settings` to maintain alphabetical ordering within the `android.*` import group.

```suggestion
import android.provider.Settings
import android.widget.Toast
```

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@torlando-tech torlando-tech merged commit b705425 into torlando-tech:main Feb 17, 2026
10 of 11 checks passed
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.

2 participants