diff --git a/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt b/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt index 2916d8a3..65e2ee8e 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt @@ -152,11 +152,17 @@ fun ChatHeaderContent( when { selectedPrivatePeer != null -> { - // Private chat header + // Private chat header - ensure state synchronization + val favoritePeers by viewModel.favoritePeers.observeAsState(emptySet()) + val fingerprint = viewModel.privateChatManager.getPeerFingerprint(selectedPrivatePeer) + val isFavorite = favoritePeers.contains(fingerprint) + + Log.d("ChatHeader", "Header recomposing: peer=$selectedPrivatePeer, fingerprint=$fingerprint, isFav=$isFavorite") + PrivateChatHeader( peerID = selectedPrivatePeer, peerNicknames = viewModel.meshService.getPeerNicknames(), - isFavorite = viewModel.isFavorite(selectedPrivatePeer), + isFavorite = isFavorite, onBackClick = onBackClick, onToggleFavorite = { viewModel.toggleFavorite(selectedPrivatePeer) } ) diff --git a/app/src/main/java/com/bitchat/android/ui/ChatState.kt b/app/src/main/java/com/bitchat/android/ui/ChatState.kt index 7309d2fc..748062b1 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatState.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatState.kt @@ -189,8 +189,17 @@ class ChatState { } fun setFavoritePeers(favorites: Set) { + val currentValue = _favoritePeers.value ?: emptySet() Log.d("ChatState", "setFavoritePeers called with ${favorites.size} favorites: $favorites") + Log.d("ChatState", "Current value: $currentValue") + Log.d("ChatState", "Values equal: ${currentValue == favorites}") + Log.d("ChatState", "Setting on thread: ${Thread.currentThread().name}") + + // Always set the value - even if equal, this ensures observers are triggered _favoritePeers.value = favorites + + Log.d("ChatState", "LiveData value after set: ${_favoritePeers.value}") + Log.d("ChatState", "LiveData has active observers: ${_favoritePeers.hasActiveObservers()}") } } diff --git a/app/src/main/java/com/bitchat/android/ui/PrivateChatManager.kt b/app/src/main/java/com/bitchat/android/ui/PrivateChatManager.kt index ceead27f..6c70241e 100644 --- a/app/src/main/java/com/bitchat/android/ui/PrivateChatManager.kt +++ b/app/src/main/java/com/bitchat/android/ui/PrivateChatManager.kt @@ -109,6 +109,9 @@ class PrivateChatManager( val wasFavorite = dataManager.isFavorite(fingerprint) Log.d(TAG, "Current favorite status: $wasFavorite") + val currentFavorites = state.getFavoritePeersValue() + Log.d(TAG, "Current UI state favorites: $currentFavorites") + if (wasFavorite) { dataManager.removeFavorite(fingerprint) Log.d(TAG, "Removed from favorites: $fingerprint") @@ -117,10 +120,11 @@ class PrivateChatManager( Log.d(TAG, "Added to favorites: $fingerprint") } - // Update state to trigger UI refresh - state.setFavoritePeers(dataManager.favoritePeers) + // Always update state to trigger UI refresh - create new set to ensure change detection + val newFavorites = dataManager.favoritePeers.toSet() + state.setFavoritePeers(newFavorites) - Log.d(TAG, "Updated favorite peers state. New favorites: ${dataManager.favoritePeers}") + Log.d(TAG, "Force updated favorite peers state. New favorites: $newFavorites") Log.d(TAG, "All peer fingerprints: $peerIDToPublicKeyFingerprint") } diff --git a/app/src/main/java/com/bitchat/android/ui/SidebarComponents.kt b/app/src/main/java/com/bitchat/android/ui/SidebarComponents.kt index 2bc7750d..4186a76f 100644 --- a/app/src/main/java/com/bitchat/android/ui/SidebarComponents.kt +++ b/app/src/main/java/com/bitchat/android/ui/SidebarComponents.kt @@ -264,20 +264,26 @@ fun PeopleSection( val privateChats by viewModel.privateChats.observeAsState(emptyMap()) val favoritePeers by viewModel.favoritePeers.observeAsState(emptySet()) + // Pre-calculate all favorite states to ensure proper state synchronization + val peerFavoriteStates = remember(favoritePeers, connectedPeers) { + connectedPeers.associateWith { peerID -> + val fingerprint = viewModel.privateChatManager.getPeerFingerprint(peerID) + favoritePeers.contains(fingerprint) + } + } + + Log.d("SidebarComponents", "Recomposing with ${favoritePeers.size} favorites, peer states: $peerFavoriteStates") + // Smart sorting: unread DMs first, then by most recent DM, then favorites, then alphabetical val sortedPeers = connectedPeers.sortedWith( compareBy { !hasUnreadPrivateMessages.contains(it) } // Unread DM senders first .thenByDescending { privateChats[it]?.maxByOrNull { msg -> msg.timestamp }?.timestamp?.time ?: 0L } // Most recent DM (convert Date to Long) - .thenBy { - val fingerprint = viewModel.privateChatManager.getPeerFingerprint(it) - fingerprint == null || !favoritePeers.contains(fingerprint) - } // Favorites + .thenBy { !(peerFavoriteStates[it] ?: false) } // Favorites first .thenBy { (if (it == nickname) "You" else (peerNicknames[it] ?: it)).lowercase() } // Alphabetical ) sortedPeers.forEach { peerID -> - val fingerprint = viewModel.privateChatManager.getPeerFingerprint(peerID) - val isFavorite = favoritePeers.contains(fingerprint) + val isFavorite = peerFavoriteStates[peerID] ?: false PeerItem( peerID = peerID, @@ -289,7 +295,7 @@ fun PeopleSection( colorScheme = colorScheme, onItemClick = { onPrivateChatStart(peerID) }, onToggleFavorite = { - Log.d("SidebarComponents", "Sidebar toggle favorite: peerID=$peerID, fingerprint=$fingerprint, currentFavorite=$isFavorite") + Log.d("SidebarComponents", "Sidebar toggle favorite: peerID=$peerID, currentFavorite=$isFavorite") viewModel.toggleFavorite(peerID) } )