feat: enhance image viewer navigation with tap animations and controls visibility
This commit is contained in:
@@ -10,6 +10,7 @@ import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringSetPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
private val Context.dataStore: DataStore<Preferences> by
|
||||
@@ -49,6 +50,9 @@ class PreferencesManager(private val context: Context) {
|
||||
|
||||
// Pinned Chats (max 3)
|
||||
val PINNED_CHATS = stringSetPreferencesKey("pinned_chats") // Set of opponent public keys
|
||||
|
||||
// Muted Chats (stored as "account::opponentKey")
|
||||
val MUTED_CHATS = stringSetPreferencesKey("muted_chats")
|
||||
}
|
||||
|
||||
// ═════════════════════════════════════════════════════════════
|
||||
@@ -238,4 +242,63 @@ class PreferencesManager(private val context: Context) {
|
||||
}
|
||||
return wasPinned
|
||||
}
|
||||
|
||||
// ═════════════════════════════════════════════════════════════
|
||||
// 🔕 MUTED CHATS
|
||||
// ═════════════════════════════════════════════════════════════
|
||||
|
||||
private fun buildMutedKey(account: String, opponentKey: String): String {
|
||||
val trimmedAccount = account.trim()
|
||||
val trimmedOpponent = opponentKey.trim()
|
||||
return if (trimmedAccount.isBlank()) trimmedOpponent else "$trimmedAccount::$trimmedOpponent"
|
||||
}
|
||||
|
||||
private fun parseMutedKeyForAccount(rawKey: String, account: String): String? {
|
||||
val trimmedAccount = account.trim()
|
||||
if (rawKey.isBlank()) return null
|
||||
|
||||
// Legacy format support: plain opponentKey without account prefix.
|
||||
if ("::" !in rawKey) return rawKey
|
||||
|
||||
val parts = rawKey.split("::", limit = 2)
|
||||
if (parts.size != 2) return null
|
||||
val keyAccount = parts[0]
|
||||
val opponentKey = parts[1]
|
||||
return if (trimmedAccount.isBlank() || keyAccount == trimmedAccount) opponentKey else null
|
||||
}
|
||||
|
||||
val mutedChats: Flow<Set<String>> =
|
||||
context.dataStore.data.map { preferences -> preferences[MUTED_CHATS] ?: emptySet() }
|
||||
|
||||
fun mutedChatsForAccount(account: String): Flow<Set<String>> =
|
||||
mutedChats.map { muted ->
|
||||
muted.mapNotNull { parseMutedKeyForAccount(it, account) }.toSet()
|
||||
}
|
||||
|
||||
suspend fun isChatMuted(account: String, opponentKey: String): Boolean {
|
||||
if (opponentKey.isBlank()) return false
|
||||
val current = mutedChats.first()
|
||||
return current.contains(buildMutedKey(account, opponentKey)) || current.contains(opponentKey)
|
||||
}
|
||||
|
||||
suspend fun setChatMuted(account: String, opponentKey: String, muted: Boolean) {
|
||||
if (opponentKey.isBlank()) return
|
||||
val scopedKey = buildMutedKey(account, opponentKey)
|
||||
context.dataStore.edit { preferences ->
|
||||
val current = preferences[MUTED_CHATS] ?: emptySet()
|
||||
preferences[MUTED_CHATS] =
|
||||
if (muted) {
|
||||
current + scopedKey
|
||||
} else {
|
||||
current - scopedKey - opponentKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun toggleMuteChat(account: String, opponentKey: String): Boolean {
|
||||
if (opponentKey.isBlank()) return false
|
||||
val mutedNow = !isChatMuted(account, opponentKey)
|
||||
setChatMuted(account, opponentKey, mutedNow)
|
||||
return mutedNow
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user