back gesture works

This commit is contained in:
callebtc
2025-07-12 17:32:08 +02:00
parent b623519dd7
commit d490393de6
4 changed files with 91 additions and 6 deletions
@@ -18,6 +18,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback
import com.bitchat.android.mesh.BluetoothMeshService import com.bitchat.android.mesh.BluetoothMeshService
import com.bitchat.android.onboarding.* import com.bitchat.android.onboarding.*
import com.bitchat.android.ui.ChatScreen import com.bitchat.android.ui.ChatScreen
@@ -138,6 +140,24 @@ class MainActivity : ComponentActivity() {
} }
OnboardingState.COMPLETE -> { OnboardingState.COMPLETE -> {
// Set up back navigation handling for the chat screen
val backCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Let ChatViewModel handle navigation state
val handled = chatViewModel.handleBackPressed()
if (!handled) {
// If ChatViewModel doesn't handle it, disable this callback
// and let the system handle it (which will exit the app)
this.isEnabled = false
onBackPressedDispatcher.onBackPressed()
this.isEnabled = true
}
}
}
// Add the callback - this will be automatically removed when the activity is destroyed
onBackPressedDispatcher.addCallback(this, backCallback)
ChatScreen(viewModel = chatViewModel) ChatScreen(viewModel = chatViewModel)
} }
@@ -60,15 +60,15 @@ fun ChatScreen(viewModel: ChatViewModel) {
val hasUnreadPrivateMessages by viewModel.unreadPrivateMessages.observeAsState(emptySet()) val hasUnreadPrivateMessages by viewModel.unreadPrivateMessages.observeAsState(emptySet())
val privateChats by viewModel.privateChats.observeAsState(emptyMap()) val privateChats by viewModel.privateChats.observeAsState(emptyMap())
val channelMessages by viewModel.channelMessages.observeAsState(emptyMap()) val channelMessages by viewModel.channelMessages.observeAsState(emptyMap())
var showSidebar by remember { mutableStateOf(false) } val showSidebar by viewModel.showSidebar.observeAsState(false)
val showCommandSuggestions by viewModel.showCommandSuggestions.observeAsState(false) val showCommandSuggestions by viewModel.showCommandSuggestions.observeAsState(false)
val commandSuggestions by viewModel.commandSuggestions.observeAsState(emptyList()) val commandSuggestions by viewModel.commandSuggestions.observeAsState(emptyList())
val showAppInfo by viewModel.showAppInfo.observeAsState(false)
var messageText by remember { mutableStateOf("") } var messageText by remember { mutableStateOf("") }
var showPasswordPrompt by remember { mutableStateOf(false) } var showPasswordPrompt by remember { mutableStateOf(false) }
var showPasswordDialog by remember { mutableStateOf(false) } var showPasswordDialog by remember { mutableStateOf(false) }
var passwordInput by remember { mutableStateOf("") } var passwordInput by remember { mutableStateOf("") }
var showAppInfo by remember { mutableStateOf(false) }
// Show password dialog when needed // Show password dialog when needed
LaunchedEffect(showPasswordPrompt) { LaunchedEffect(showPasswordPrompt) {
@@ -142,8 +142,8 @@ fun ChatScreen(viewModel: ChatViewModel) {
nickname = nickname, nickname = nickname,
viewModel = viewModel, viewModel = viewModel,
colorScheme = colorScheme, colorScheme = colorScheme,
onSidebarToggle = { showSidebar = true }, onSidebarToggle = { viewModel.showSidebar() },
onShowAppInfo = { showAppInfo = true }, onShowAppInfo = { viewModel.showAppInfo() },
onPanicClear = { viewModel.panicClearAllData() } onPanicClear = { viewModel.panicClearAllData() }
) )
@@ -162,7 +162,7 @@ fun ChatScreen(viewModel: ChatViewModel) {
) { ) {
SidebarOverlay( SidebarOverlay(
viewModel = viewModel, viewModel = viewModel,
onDismiss = { showSidebar = false }, onDismiss = { viewModel.hideSidebar() },
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )
} }
@@ -188,7 +188,7 @@ fun ChatScreen(viewModel: ChatViewModel) {
passwordInput = "" passwordInput = ""
}, },
showAppInfo = showAppInfo, showAppInfo = showAppInfo,
onAppInfoDismiss = { showAppInfo = false } onAppInfoDismiss = { viewModel.hideAppInfo() }
) )
} }
@@ -85,6 +85,10 @@ class ChatState {
val peerIDToPublicKeyFingerprint = mutableMapOf<String, String>() val peerIDToPublicKeyFingerprint = mutableMapOf<String, String>()
// Navigation state
private val _showAppInfo = MutableLiveData<Boolean>(false)
val showAppInfo: LiveData<Boolean> = _showAppInfo
// Unread state computed properties // Unread state computed properties
val hasUnreadChannels: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>() val hasUnreadChannels: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>()
val hasUnreadPrivateMessages: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>() val hasUnreadPrivateMessages: MediatorLiveData<Boolean> = MediatorLiveData<Boolean>()
@@ -118,6 +122,7 @@ class ChatState {
fun getShowCommandSuggestionsValue() = _showCommandSuggestions.value ?: false fun getShowCommandSuggestionsValue() = _showCommandSuggestions.value ?: false
fun getCommandSuggestionsValue() = _commandSuggestions.value ?: emptyList() fun getCommandSuggestionsValue() = _commandSuggestions.value ?: emptyList()
fun getFavoritePeersValue() = _favoritePeers.value ?: emptySet() fun getFavoritePeersValue() = _favoritePeers.value ?: emptySet()
fun getShowAppInfoValue() = _showAppInfo.value ?: false
// Setters for state updates // Setters for state updates
fun setMessages(messages: List<BitchatMessage>) { fun setMessages(messages: List<BitchatMessage>) {
@@ -201,5 +206,9 @@ class ChatState {
Log.d("ChatState", "LiveData value after set: ${_favoritePeers.value}") Log.d("ChatState", "LiveData value after set: ${_favoritePeers.value}")
Log.d("ChatState", "LiveData has active observers: ${_favoritePeers.hasActiveObservers()}") Log.d("ChatState", "LiveData has active observers: ${_favoritePeers.hasActiveObservers()}")
} }
fun setShowAppInfo(show: Boolean) {
_showAppInfo.value = show
}
} }
@@ -71,6 +71,7 @@ class ChatViewModel(
val showCommandSuggestions: LiveData<Boolean> = state.showCommandSuggestions val showCommandSuggestions: LiveData<Boolean> = state.showCommandSuggestions
val commandSuggestions: LiveData<List<CommandSuggestion>> = state.commandSuggestions val commandSuggestions: LiveData<List<CommandSuggestion>> = state.commandSuggestions
val favoritePeers: LiveData<Set<String>> = state.favoritePeers val favoritePeers: LiveData<Set<String>> = state.favoritePeers
val showAppInfo: LiveData<Boolean> = state.showAppInfo
init { init {
// Note: Mesh service delegate is now set by MainActivity // Note: Mesh service delegate is now set by MainActivity
@@ -366,4 +367,59 @@ class ChatViewModel(
// Note: Mesh service restart is now handled by MainActivity // Note: Mesh service restart is now handled by MainActivity
// This method now only clears data, not mesh service lifecycle // This method now only clears data, not mesh service lifecycle
} }
// MARK: - Navigation Management
fun showAppInfo() {
state.setShowAppInfo(true)
}
fun hideAppInfo() {
state.setShowAppInfo(false)
}
fun showSidebar() {
state.setShowSidebar(true)
}
fun hideSidebar() {
state.setShowSidebar(false)
}
/**
* Handle Android back navigation
* Returns true if the back press was handled, false if it should be passed to the system
*/
fun handleBackPressed(): Boolean {
return when {
// Close app info dialog
state.getShowAppInfoValue() -> {
hideAppInfo()
true
}
// Close sidebar
state.getShowSidebarValue() -> {
hideSidebar()
true
}
// Close password dialog
state.getShowPasswordPromptValue() -> {
state.setShowPasswordPrompt(false)
state.setPasswordPromptChannel(null)
true
}
// Exit private chat
state.getSelectedPrivateChatPeerValue() != null -> {
endPrivateChat()
true
}
// Exit channel view
state.getCurrentChannelValue() != null -> {
switchToChannel(null)
true
}
// No special navigation state - let system handle (usually exits app)
else -> false
}
}
} }