Промежуточный результат для 1.0.4 версии

This commit is contained in:
2026-02-22 08:54:46 +05:00
parent 3aa18fa9ac
commit 5b9b3f83f7
37 changed files with 5643 additions and 928 deletions

View File

@@ -0,0 +1,104 @@
package com.rosetta.messenger.data
import android.content.Context
import android.content.SharedPreferences
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/**
* 📝 Менеджер черновиков сообщений (как в Telegram)
* Хранит текст из инпута для каждого диалога.
* При возврате в список чатов показывает "Draft: текст" красным цветом.
*
* Использует SharedPreferences для персистентности между перезапусками.
* Ключ: "draft_{account}_{opponentKey}" -> текст черновика
*/
object DraftManager {
private const val PREFS_NAME = "rosetta_drafts"
private const val KEY_PREFIX = "draft_"
private var prefs: SharedPreferences? = null
// 🔥 Реактивный Map: opponentKey -> draftText
// Обновляется при каждом изменении черновика для мгновенного обновления UI списка чатов
private val _drafts = MutableStateFlow<Map<String, String>>(emptyMap())
val drafts: StateFlow<Map<String, String>> = _drafts.asStateFlow()
private var currentAccount: String = ""
/** Инициализация с контекстом приложения */
fun init(context: Context) {
if (prefs == null) {
prefs = context.applicationContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
}
}
/** Установить текущий аккаунт и загрузить его черновики */
fun setAccount(account: String) {
if (currentAccount == account) return
currentAccount = account
loadDraftsFromPrefs()
}
/** Сохранить черновик для диалога */
fun saveDraft(opponentKey: String, text: String) {
if (currentAccount.isEmpty()) return
val trimmed = text.trim()
val currentDrafts = _drafts.value.toMutableMap()
if (trimmed.isEmpty()) {
// Удаляем черновик если текст пустой
currentDrafts.remove(opponentKey)
prefs?.edit()?.remove(prefKey(opponentKey))?.apply()
} else {
currentDrafts[opponentKey] = trimmed
prefs?.edit()?.putString(prefKey(opponentKey), trimmed)?.apply()
}
_drafts.value = currentDrafts
}
/** Получить черновик для диалога */
fun getDraft(opponentKey: String): String? {
return _drafts.value[opponentKey]
}
/** Очистить черновик для диалога (после отправки сообщения) */
fun clearDraft(opponentKey: String) {
if (currentAccount.isEmpty()) return
val currentDrafts = _drafts.value.toMutableMap()
currentDrafts.remove(opponentKey)
_drafts.value = currentDrafts
prefs?.edit()?.remove(prefKey(opponentKey))?.apply()
}
/** Очистить все черновики (при смене аккаунта / логауте) */
fun clearAll() {
_drafts.value = emptyMap()
}
/** Загрузить черновики текущего аккаунта из SharedPreferences */
private fun loadDraftsFromPrefs() {
val allPrefs = prefs?.all ?: return
val prefix = "${KEY_PREFIX}${currentAccount}_"
val loaded = mutableMapOf<String, String>()
allPrefs.forEach { (key, value) ->
if (key.startsWith(prefix) && value is String && value.isNotEmpty()) {
val opponentKey = key.removePrefix(prefix)
loaded[opponentKey] = value
}
}
_drafts.value = loaded
}
private fun prefKey(opponentKey: String): String {
return "${KEY_PREFIX}${currentAccount}_${opponentKey}"
}
}