diff --git a/app/src/main/java/app/closer/data/repository/CoupleRepositoryImpl.kt b/app/src/main/java/app/closer/data/repository/CoupleRepositoryImpl.kt index de7a6a79..1baba4fc 100644 --- a/app/src/main/java/app/closer/data/repository/CoupleRepositoryImpl.kt +++ b/app/src/main/java/app/closer/data/repository/CoupleRepositoryImpl.kt @@ -1,5 +1,6 @@ package app.closer.data.repository +import app.closer.core.crash.CrashReporter import app.closer.data.remote.FirestoreCoupleDataSource import app.closer.data.remote.FirestoreUserDataSource import app.closer.domain.model.Couple @@ -10,12 +11,17 @@ import javax.inject.Singleton @Singleton class CoupleRepositoryImpl @Inject constructor( private val coupleDataSource: FirestoreCoupleDataSource, - private val userDataSource: FirestoreUserDataSource + private val userDataSource: FirestoreUserDataSource, + private val crashReporter: CrashReporter ) : CoupleRepository { override suspend fun getCoupleForUser(userId: String): Couple? { - val coupleId = runCatching { userDataSource.getUser(userId)?.coupleId }.getOrNull() ?: return null - return runCatching { coupleDataSource.getCoupleById(coupleId) }.getOrNull() + val coupleId = runCatching { userDataSource.getUser(userId)?.coupleId } + .onFailure { crashReporter.recordException(it) } + .getOrNull() ?: return null + return runCatching { coupleDataSource.getCoupleById(coupleId) } + .onFailure { crashReporter.recordException(it) } + .getOrNull() } override suspend fun createCouple(inviterUserId: String, acceptorUserId: String, inviteCode: String): Result = runCatching { diff --git a/app/src/main/java/app/closer/data/repository/QuestionSessionRepositoryImpl.kt b/app/src/main/java/app/closer/data/repository/QuestionSessionRepositoryImpl.kt index 52f48372..1d617d0e 100644 --- a/app/src/main/java/app/closer/data/repository/QuestionSessionRepositoryImpl.kt +++ b/app/src/main/java/app/closer/data/repository/QuestionSessionRepositoryImpl.kt @@ -1,5 +1,6 @@ package app.closer.data.repository +import app.closer.core.crash.CrashReporter import app.closer.data.remote.FirestoreCollections import app.closer.domain.model.QuestionSession import app.closer.domain.repository.QuestionSessionRepository @@ -10,7 +11,8 @@ import javax.inject.Singleton @Singleton class QuestionSessionRepositoryImpl @Inject constructor( - private val firestore: FirebaseFirestore + private val firestore: FirebaseFirestore, + private val crashReporter: CrashReporter ) : QuestionSessionRepository { override suspend fun saveSession(session: QuestionSession): Result = runCatching { @@ -64,7 +66,9 @@ class QuestionSessionRepositoryImpl @Inject constructor( isPremium = doc.getBoolean("isPremium") ?: false, status = doc.getString("status") ?: "completed" ) - }.getOrNull() + } + .onFailure { crashReporter.recordException(it) } + .getOrNull() } } } diff --git a/app/src/main/java/app/closer/ui/dates/DateMatchViewModel.kt b/app/src/main/java/app/closer/ui/dates/DateMatchViewModel.kt index 626addaa..90c9de6e 100644 --- a/app/src/main/java/app/closer/ui/dates/DateMatchViewModel.kt +++ b/app/src/main/java/app/closer/ui/dates/DateMatchViewModel.kt @@ -1,5 +1,6 @@ package app.closer.ui.dates +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.closer.domain.model.DateIdea @@ -62,7 +63,9 @@ class DateMatchViewModel @Inject constructor( val uid = authRepository.currentUserId val couple = uid?.let { runCatching { coupleRepository.getCoupleForUser(it) }.getOrNull() } val partnerName = couple?.userIds?.firstOrNull { it != uid }?.let { partnerId -> - runCatching { userRepository.getUser(partnerId)?.displayName }.getOrNull() + runCatching { userRepository.getUser(partnerId)?.displayName } + .onFailure { Log.w(TAG, "Could not load partner display name", it) } + .getOrNull() } val ideas = repository.getDateIdeas() _uiState.value = DateMatchUiState( @@ -145,4 +148,8 @@ class DateMatchViewModel @Inject constructor( } fun retry() = loadDateMatch() + + companion object { + private const val TAG = "DateMatchViewModel" + } } diff --git a/app/src/main/java/app/closer/ui/dates/DateMatchesViewModel.kt b/app/src/main/java/app/closer/ui/dates/DateMatchesViewModel.kt index c1f965db..90996771 100644 --- a/app/src/main/java/app/closer/ui/dates/DateMatchesViewModel.kt +++ b/app/src/main/java/app/closer/ui/dates/DateMatchesViewModel.kt @@ -1,5 +1,6 @@ package app.closer.ui.dates +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.closer.data.repository.DateIdeaSeed @@ -59,7 +60,9 @@ class DateMatchesViewModel @Inject constructor( val couple = uid?.let { runCatching { coupleRepository.getCoupleForUser(it) }.getOrNull() } val partnerId = couple?.userIds?.firstOrNull { it != uid } val partnerName = partnerId?.let { id -> - runCatching { userRepository.getUser(id)?.displayName }.getOrNull() + runCatching { userRepository.getUser(id)?.displayName } + .onFailure { Log.w(TAG, "Could not load partner display name", it) } + .getOrNull() } _uiState.value = DateMatchesUiState( @@ -132,4 +135,8 @@ class DateMatchesViewModel @Inject constructor( } fun retry() = loadMatches() + + companion object { + private const val TAG = "DateMatchesViewModel" + } } diff --git a/app/src/main/java/app/closer/ui/home/HomeViewModel.kt b/app/src/main/java/app/closer/ui/home/HomeViewModel.kt index 808c5534..bf97e01c 100644 --- a/app/src/main/java/app/closer/ui/home/HomeViewModel.kt +++ b/app/src/main/java/app/closer/ui/home/HomeViewModel.kt @@ -1,5 +1,6 @@ package app.closer.ui.home +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.closer.domain.model.LocalAnswer @@ -106,7 +107,9 @@ class HomeViewModel @Inject constructor( val uid = authRepository.currentUserId val couple = uid?.let { runCatching { coupleRepository.getCoupleForUser(it) }.getOrNull() } val partnerName = couple?.userIds?.firstOrNull { it != uid }?.let { partnerId -> - runCatching { userRepository.getUser(partnerId)?.displayName }.getOrNull() + runCatching { userRepository.getUser(partnerId)?.displayName } + .onFailure { Log.w(TAG, "Could not load partner display name", it) } + .getOrNull() } _uiState.update { it.copy( @@ -261,4 +264,8 @@ class HomeViewModel @Inject constructor( split("_", "-") .filter { part -> part.isNotBlank() } .joinToString(" ") { part -> part.replaceFirstChar { it.uppercaseChar() } } + + companion object { + private const val TAG = "HomeViewModel" + } } diff --git a/app/src/main/java/app/closer/ui/onboarding/OnboardingViewModel.kt b/app/src/main/java/app/closer/ui/onboarding/OnboardingViewModel.kt index d64816fa..8b279b04 100644 --- a/app/src/main/java/app/closer/ui/onboarding/OnboardingViewModel.kt +++ b/app/src/main/java/app/closer/ui/onboarding/OnboardingViewModel.kt @@ -1,5 +1,6 @@ package app.closer.ui.onboarding +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.closer.domain.model.AuthState @@ -34,7 +35,9 @@ class OnboardingViewModel @Inject constructor( is AuthState.Loading -> _uiState.update { it.copy(isCheckingAuth = true) } is AuthState.Unauthenticated -> _uiState.update { it.copy(isCheckingAuth = false, navigateTo = null) } is AuthState.Authenticated -> { - val user = runCatching { userRepository.getUser(authState.userId) }.getOrNull() + val user = runCatching { userRepository.getUser(authState.userId) } + .onFailure { Log.w(TAG, "Could not load user profile during onboarding", it) } + .getOrNull() val destination = when { user == null || user.displayName.isBlank() -> "create_profile" else -> "home" @@ -47,4 +50,8 @@ class OnboardingViewModel @Inject constructor( } fun onNavigated() = _uiState.update { it.copy(navigateTo = null) } + + companion object { + private const val TAG = "OnboardingViewModel" + } } diff --git a/app/src/main/java/app/closer/ui/pairing/InviteConfirmViewModel.kt b/app/src/main/java/app/closer/ui/pairing/InviteConfirmViewModel.kt index 75108bf6..9d565fe3 100644 --- a/app/src/main/java/app/closer/ui/pairing/InviteConfirmViewModel.kt +++ b/app/src/main/java/app/closer/ui/pairing/InviteConfirmViewModel.kt @@ -1,5 +1,6 @@ package app.closer.ui.pairing +import android.util.Log import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -46,7 +47,9 @@ class InviteConfirmViewModel @Inject constructor( .onSuccess { invite -> loadedInvite = invite val inviterName = invite?.let { - runCatching { userRepository.getUser(it.inviterUserId)?.displayName }.getOrNull() + runCatching { userRepository.getUser(it.inviterUserId)?.displayName } + .onFailure { e -> Log.w(TAG, "Could not load inviter display name", e) } + .getOrNull() } _uiState.update { it.copy(isLoading = false, inviterName = inviterName ?: "your partner") } } @@ -80,4 +83,8 @@ class InviteConfirmViewModel @Inject constructor( fun onNavigated() = _uiState.update { it.copy(navigateTo = null) } fun dismissError() = _uiState.update { it.copy(error = null) } + + companion object { + private const val TAG = "InviteConfirmViewModel" + } } diff --git a/app/src/main/java/app/closer/ui/settings/SettingsViewModel.kt b/app/src/main/java/app/closer/ui/settings/SettingsViewModel.kt index 486523f3..6e061740 100644 --- a/app/src/main/java/app/closer/ui/settings/SettingsViewModel.kt +++ b/app/src/main/java/app/closer/ui/settings/SettingsViewModel.kt @@ -1,5 +1,6 @@ package app.closer.ui.settings +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.closer.core.navigation.AppRoute @@ -45,11 +46,15 @@ class SettingsViewModel @Inject constructor( return@launch } val email = authRepository.currentUserEmail ?: "" - val user = runCatching { userRepository.getUser(userId) }.getOrNull() + val user = runCatching { userRepository.getUser(userId) } + .onFailure { Log.w(TAG, "Could not load current user profile", it) } + .getOrNull() val couple = coupleRepository.getCoupleForUser(userId) val partnerId = couple?.userIds?.firstOrNull { it != userId } val partnerName = partnerId?.let { - runCatching { userRepository.getUser(it)?.displayName }.getOrNull() + runCatching { userRepository.getUser(it)?.displayName } + .onFailure { e -> Log.w(TAG, "Could not load partner display name", e) } + .getOrNull() } _uiState.update { it.copy( @@ -72,4 +77,8 @@ class SettingsViewModel @Inject constructor( } fun onNavigated() = _uiState.update { it.copy(navigateTo = null) } + + companion object { + private const val TAG = "SettingsViewModel" + } } diff --git a/app/src/main/java/app/closer/ui/wheel/SpinWheelViewModel.kt b/app/src/main/java/app/closer/ui/wheel/SpinWheelViewModel.kt index a1f6919e..18f19077 100644 --- a/app/src/main/java/app/closer/ui/wheel/SpinWheelViewModel.kt +++ b/app/src/main/java/app/closer/ui/wheel/SpinWheelViewModel.kt @@ -1,5 +1,6 @@ package app.closer.ui.wheel +import android.util.Log import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -40,7 +41,9 @@ class SpinWheelViewModel @Inject constructor( private fun loadCategory() { viewModelScope.launch { - val category = runCatching { repository.getCategoryById(categoryId) }.getOrNull() + val category = runCatching { repository.getCategoryById(categoryId) } + .onFailure { Log.w(TAG, "Could not load wheel category", it) } + .getOrNull() _uiState.update { it.copy( isLoading = false, @@ -56,7 +59,9 @@ class SpinWheelViewModel @Inject constructor( _uiState.update { it.copy(isSpinning = true, error = null) } val questions = runCatching { repository.getQuestionsByCategory(categoryId).shuffled().take(SESSION_SIZE) - }.getOrElse { emptyList() } + } + .onFailure { Log.w(TAG, "Could not load wheel questions", it) } + .getOrElse { emptyList() } if (questions.isEmpty()) { _uiState.update { @@ -65,7 +70,9 @@ class SpinWheelViewModel @Inject constructor( return@launch } - val category = runCatching { repository.getCategoryById(categoryId) }.getOrNull() + val category = runCatching { repository.getCategoryById(categoryId) } + .onFailure { Log.w(TAG, "Could not load wheel category for session", it) } + .getOrNull() sessionStore.activeSession = LocalWheelSession( categoryId = categoryId, categoryName = category?.displayName ?: categoryId, @@ -85,5 +92,6 @@ class SpinWheelViewModel @Inject constructor( companion object { const val SESSION_SIZE = 10 + private const val TAG = "SpinWheelViewModel" } }