Untitled
unknown
kotlin
7 days ago
12 kB
20
Indexable
package ru.space.irminsul.models import android.annotation.SuppressLint import android.content.Context import android.util.Log import androidx.activity.ComponentActivity import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.firebase.messaging.FirebaseMessaging import com.google.gson.Gson import io.appwrite.Client import io.appwrite.Query import io.appwrite.enums.OAuthProvider import io.appwrite.services.Account import io.appwrite.services.Databases import io.appwrite.services.Realtime import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.tasks.await import kotlinx.coroutines.withContext import ru.space.irminsul.screens.createUser class AuthViewModel(private val client: Client, private val context: Context) : ViewModel() { private val account = Account(client) private val databases = Databases(client) private val realtime = Realtime(client) private val _user = MutableStateFlow<AppUser?>(null) val user: StateFlow<AppUser?> = _user private val _isAuth = MutableStateFlow(false) val isAuth: StateFlow<Boolean> = _isAuth companion object { private const val DATABASE_ID = "." private const val COLLECTION_ID = "." private const val PREFS_NAME = "user_prefs" private const val PREF_USER_KEY = "cached_user" } init { loadCachedUser() // Загружаем сохраненные данные checkAuth() subscribeToUserUpdates() } /** * Загружает кэшированные данные пользователя при старте */ private fun loadCachedUser() { val sharedPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) val userJson = sharedPrefs.getString(PREF_USER_KEY, null) userJson?.let { val cachedUser = Gson().fromJson(it, AppUser::class.java) _user.value = cachedUser } } /** * Сохраняет данные пользователя в SharedPreferences */ private fun saveUserToCache(user: AppUser) { val sharedPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) sharedPrefs.edit().putString(PREF_USER_KEY, Gson().toJson(user)).apply() } /** * Проверка авторизации пользователя и загрузка его данных */ fun checkAuth() { viewModelScope.launch { try { val userData = account.get() val dbUser = fetchUserFromDatabase(userData.id) if (dbUser != null) { _user.value = dbUser saveUserToCache(dbUser) // Сохраняем данные } else { val newUser = AppUser(userData.id, userData.name, userData.email, "", rating = 1) createUser(newUser, client) _user.value = newUser saveUserToCache(newUser) } _isAuth.value = true } catch (e: Exception) { _isAuth.value = false Log.e("AuthViewModel", "Ошибка проверки авторизации: ${e.message}") } } } /** * Получение данных пользователя из базы данных */ private suspend fun fetchUserFromDatabase(userId: String): AppUser? { return try { Log.d("AuthViewModel", "📥 Запрос пользователя с ID: $userId") val response = databases.listDocuments( databaseId = DATABASE_ID, collectionId = COLLECTION_ID, queries = listOf(Query.equal("userId", userId)) ) val document = response.documents.firstOrNull() if (document == null) { Log.d("AuthViewModel", "❌ Пользователь не найден в базе") return null } Log.d("AuthViewModel", "✅ Найден документ: ${document.id}") Log.d("AuthViewModel", "📜 Данные документа: ${document.data}") // Проверяем, что именно приходит в "balance" val user = AppUser( id = document.data["\$id"] as String, name = document.data["name"]?.toString() ?: "", email = document.data["email"]?.toString() ?: "", description = document.data["description"]?.toString() ?: "", avatarUrl = document.data["avatarUrl"]?.toString() ?: "", rating = document.data["rating"]?.toString()?.toIntOrNull() ?: 1, balance = (document.data["balance"] as Long).toInt(), deviceIds = document.data["deviceIds"] as List<String> ) Log.d("AuthViewModel", "✅ Итоговый объект AppUser: $user") withContext(Dispatchers.Main) { _user.value = user } user } catch (e: Exception) { Log.e("AuthViewModel", "❌ Ошибка получения данных: ${e.message}", e) null } } /** * Подписка на обновления данных пользователя в реальном времени */ private fun subscribeToUserUpdates() { Log.d("AuthViewModel", "🔔 Подписка на обновления пользователя...") val subscription = realtime.subscribe( "databases.$DATABASE_ID.collections.$COLLECTION_ID.documents" ) { event -> viewModelScope.launch { try { Log.d("AuthViewModel", "⚡ Изменения в БД: ${event.payload}") val gson = Gson() val jsonPayload = gson.toJson(event.payload) val updatedUser = gson.fromJson(jsonPayload, AppUser::class.java) if (updatedUser.id == _user.value?.id) { _user.value = updatedUser saveUserToCache(updatedUser) Log.d("AuthViewModel", "✅ Данные пользователя обновлены!") } } catch (e: Exception) { Log.e("AuthViewModel", "❌ Ошибка при обработке обновлений: ${e.message}", e) } } } Log.d("AuthViewModel", "✅ Подписка создана: $subscription") } /** * Авторизация через Yandex OAuth */ @SuppressLint("CommitPrefEdits") fun login( activity: ComponentActivity, onAuthSuccess: () -> Unit = {}, onAuthFail: () -> Unit = {} ) { viewModelScope.launch { withContext(Dispatchers.IO) { try { Log.d("AuthViewModel", "Начинаем OAuth авторизацию...") // Создание OAuth2 сессии с Yandex account.createOAuth2Session(activity, OAuthProvider.YANDEX) Log.d("AuthViewModel", "OAuth сессия создана") // Получаем данные пользователя val userData = account.get() // Проверяем, существует ли пользователь в базе данных val dbUser = fetchUserFromDatabase(userData.id) ?: run { Log.d("AuthViewModel", "Пользователь не найден в БД, создаем нового") // Получаем FCM токен устройства val deviceIds = try { FirebaseMessaging.getInstance().token.await() } catch (e: Exception) { Log.e("AuthViewModel", "Ошибка получения FCM токена: ${e.message}", e) "" // Возвращаем пустую строку в случае ошибки } val newUser = AppUser( userData.id, userData.name, userData.email, avatarUrl = "", // Здесь можно добавить URL аватара, если нужно rating = 1, deviceIds = listOfNotNull(deviceIds).filter { it.isNotEmpty() } ) // Создаем пользователя в базе данных createUser(newUser, client) newUser } withContext(Dispatchers.Main){ // Устанавливаем пользователя в state _user.value = dbUser } // Сохраняем пользователя в кэш saveUserToCache(dbUser) // Устанавливаем флаг успешной авторизации withContext(Dispatchers.Main){ _isAuth.value = true Log.d("AuthViewModel", "Авторизация успешна!") // Вызов успешной авторизации onAuthSuccess() } } catch (e: Exception) { Log.e("AuthViewModel", "Ошибка авторизации: ${e.message}", e) // Если ошибка при авторизации, устанавливаем флаг неудачи withContext(Dispatchers.Main) { _isAuth.value = false onAuthFail() } } } } } fun logout(onLogoutSuccess: () -> Unit = {}, onLogoutFail: (Exception) -> Unit = {}) { viewModelScope.launch { try { account.deleteSession("current") // Завершаем текущую сессию _user.value = null _isAuth.value = false // Очистка данных из SharedPreferences val sharedPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) sharedPrefs.edit().remove(PREF_USER_KEY).apply() Log.d("AuthViewModel", "Выход выполнен успешно") onLogoutSuccess() } catch (e: Exception) { Log.e("AuthViewModel", "Ошибка при выходе: ${e.message}", e) onLogoutFail(e) } } } }
Editor is loading...
Leave a Comment