Загрузка данных
package ru.notesapp.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import ru.notesapp.data.NotesRepository
import ru.notesapp.data.remote.NetworkResult
import ru.notesapp.domain.Note
import ru.notesapp.domain.NoteType
import javax.inject.Inject
@HiltViewModel
class NotesViewModel @Inject constructor(
private val repository: NotesRepository,
) : ViewModel() {
private val _uiState = MutableStateFlow<NotesUiState>(NotesUiState.Loading)
val uiState: StateFlow<NotesUiState> = _uiState.asStateFlow()
private val _isRefreshing = MutableStateFlow(false)
val isRefreshing: StateFlow<Boolean> = _isRefreshing.asStateFlow()
private val _snackbarMessage = MutableStateFlow<String?>(null)
val snackbarMessage: StateFlow<String?> = _snackbarMessage.asStateFlow()
// --- Состояние поиска живёт в ViewModel и переживает навигацию ---
private val _searchMode = MutableStateFlow(false)
val searchMode: StateFlow<Boolean> = _searchMode.asStateFlow()
private val _searchQuery = MutableStateFlow("")
val searchQuery: StateFlow<String> = _searchQuery.asStateFlow()
private var notesJob: Job? = null
init {
loadNotes()
}
fun loadNotes() {
notesJob?.cancel()
notesJob = viewModelScope.launch {
_uiState.value = NotesUiState.Loading
repository.observeAll().collect { notes ->
_uiState.value = if (notes.isEmpty()) NotesUiState.Empty
else NotesUiState.Success(notes)
}
}
}
fun refresh() {
viewModelScope.launch {
_isRefreshing.value = true
when (val result = repository.refresh()) {
is NetworkResult.Success -> {
val count = (uiState.value as? NotesUiState.Success)?.notes?.size ?: 0
_snackbarMessage.value = "Обновлено: $count заметок"
}
is NetworkResult.Error -> {
_snackbarMessage.value = "Ошибка сервера: ${result.code}"
}
is NetworkResult.NetworkError -> {
_snackbarMessage.value = "Нет соединения с интернетом"
}
}
_isRefreshing.value = false
}
}
fun addNote(
title: String,
content: String,
type: NoteType,
imageUrl: String? = null,
) {
viewModelScope.launch {
repository.add(
Note(
id = 0L,
title = title,
content = content,
createdAt = System.currentTimeMillis(),
type = type,
imageUrl = imageUrl,
)
)
}
}
fun deleteNote(id: Long) {
viewModelScope.launch {
repository.delete(id)
}
}
// --- Поиск ---
fun openSearch() {
_searchMode.value = true
}
fun closeSearch() {
_searchMode.value = false
_searchQuery.value = ""
loadNotes()
}
fun searchNotes(query: String) {
_searchQuery.value = query
notesJob?.cancel()
if (query.isBlank()) {
loadNotes()
return
}
notesJob = viewModelScope.launch {
repository.search(query).collect { notes ->
_uiState.value = if (notes.isEmpty()) NotesUiState.Empty
else NotesUiState.Success(notes)
}
}
}
fun clearSnackbarMessage() {
_snackbarMessage.value = null
}
}