mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 18:05:20 +00:00
back gesture works
This commit is contained in:
@@ -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>) {
|
||||||
@@ -202,4 +207,8 @@ class ChatState {
|
|||||||
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user