diff --git a/app/src/main/kotlin/dev/meloda/fast/MainViewModel.kt b/app/src/main/kotlin/dev/meloda/fast/MainViewModel.kt index 52796b70..a10fc6b4 100644 --- a/app/src/main/kotlin/dev/meloda/fast/MainViewModel.kt +++ b/app/src/main/kotlin/dev/meloda/fast/MainViewModel.kt @@ -2,7 +2,6 @@ package dev.meloda.fast import android.content.Intent import android.os.Build -import android.util.Log import androidx.appcompat.app.AppCompatDelegate import androidx.core.app.NotificationCompat import androidx.core.os.LocaleListCompat @@ -38,6 +37,7 @@ interface MainViewModel { val startDestination: StateFlow val isNeedToReplaceWithAuth: StateFlow val currentUser: StateFlow + val baseError: StateFlow val isNeedToShowNotificationsDeniedDialog: StateFlow val isNeedToShowNotificationsRationaleDialog: StateFlow @@ -45,6 +45,7 @@ interface MainViewModel { val isNeedToRequestNotifications: StateFlow fun onError(error: BaseError) + fun onErrorConsumed() fun onNavigatedToAuth() @@ -73,6 +74,7 @@ class MainViewModelImpl( override val startDestination = MutableStateFlow(null) override val isNeedToReplaceWithAuth = MutableStateFlow(false) override val currentUser = MutableStateFlow(null) + override val baseError = MutableStateFlow(null) override val isNeedToShowNotificationsDeniedDialog = MutableStateFlow(false) override val isNeedToShowNotificationsRationaleDialog = MutableStateFlow(false) @@ -93,10 +95,16 @@ class MainViewModelImpl( isNeedToReplaceWithAuth.update { true } } - else -> Unit // TODO: 21-Mar-25, Danil Nikolaev: show error in ui + else -> { + baseError.update { error } + } } } + override fun onErrorConsumed() { + baseError.update { null } + } + override fun onNavigatedToAuth() { isNeedToReplaceWithAuth.update { false } } @@ -207,8 +215,6 @@ class MainViewModelImpl( viewModelScope.launch(Dispatchers.IO) { val currentAccount = getCurrentAccountUseCase() - Log.d("MainViewModel", "currentAccount: $currentAccount") - if (currentAccount != null) { UserConfig.apply { this.userId = currentAccount.userId diff --git a/app/src/main/kotlin/dev/meloda/fast/presentation/MainActivity.kt b/app/src/main/kotlin/dev/meloda/fast/presentation/MainActivity.kt index 15dda193..0eee2a17 100644 --- a/app/src/main/kotlin/dev/meloda/fast/presentation/MainActivity.kt +++ b/app/src/main/kotlin/dev/meloda/fast/presentation/MainActivity.kt @@ -9,7 +9,6 @@ import android.content.res.Configuration import android.os.Build import android.os.Bundle import android.provider.Settings -import android.util.Log import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge @@ -65,9 +64,6 @@ class MainActivity : AppCompatActivity() { setContent { val viewModel: MainViewModel = koinViewModel() - LaunchedEffect(viewModel) { - Log.d("VM_CREATE", "onCreate: viewModel: $viewModel") - } LifecycleResumeEffect(true) { viewModel.onAppResumed(intent) diff --git a/app/src/main/kotlin/dev/meloda/fast/presentation/RootErrorDialog.kt b/app/src/main/kotlin/dev/meloda/fast/presentation/RootErrorDialog.kt new file mode 100644 index 00000000..d9accefa --- /dev/null +++ b/app/src/main/kotlin/dev/meloda/fast/presentation/RootErrorDialog.kt @@ -0,0 +1,38 @@ +package dev.meloda.fast.presentation + +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import dev.meloda.fast.model.BaseError +import dev.meloda.fast.ui.R + +@Composable +fun RootErrorDialog( + baseError: BaseError?, + onDismiss: () -> Unit, + onConfirm: () -> Unit, +) { + if (baseError == null) return + + val errorText = when (baseError) { + BaseError.ConnectionError -> "Connection error" + BaseError.InternalError -> "Internal error" + BaseError.UnknownError -> "Unknown error" + is BaseError.SimpleError -> baseError.message + BaseError.SessionExpired -> "Session expired" + BaseError.AccountBlocked -> "Account blocked" + } + + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(text = stringResource(id = R.string.warning)) }, + text = { Text(text = errorText) }, + confirmButton = { + TextButton(onClick = onConfirm) { + Text(text = stringResource(id = R.string.try_again)) + } + } + ) +} diff --git a/app/src/main/kotlin/dev/meloda/fast/presentation/RootScreen.kt b/app/src/main/kotlin/dev/meloda/fast/presentation/RootScreen.kt index c0ef5bc4..2e0e2629 100644 --- a/app/src/main/kotlin/dev/meloda/fast/presentation/RootScreen.kt +++ b/app/src/main/kotlin/dev/meloda/fast/presentation/RootScreen.kt @@ -4,16 +4,12 @@ import android.Manifest import android.content.Intent import android.net.Uri import android.provider.Settings -import android.util.Log import androidx.activity.compose.LocalActivity import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect @@ -91,10 +87,7 @@ fun RootScreen( val longPollCurrentState by longPollController.currentState.collectAsStateWithLifecycle() val longPollStateToApply by longPollController.stateToApply.collectAsStateWithLifecycle() - val viewModel: MainViewModel = koinViewModel() - LaunchedEffect(viewModel) { - Log.d("VM_CREATE", "RootScreen(): viewModel: $viewModel") - } + val viewModel: MainViewModel = koinViewModel() val currentUser: VkUser? by viewModel.currentUser.collectAsStateWithLifecycle() @@ -125,14 +118,12 @@ fun RootScreen( } } - LifecycleResumeEffect(longPollStateToApply) { - Log.d("LongPollMainActivity", "longPollStateToApply: $longPollStateToApply") + LifecycleResumeEffect(longPollStateToApply) { if (longPollStateToApply != LongPollState.Background) { if (longPollStateToApply.isLaunched() && longPollCurrentState.isLaunched() && longPollCurrentState != longPollStateToApply ) { toggleLongPollService(false, null) - Log.d("LongPoll", "recreate()") } toggleLongPollService( @@ -241,6 +232,7 @@ fun RootScreen( val context = LocalContext.current val startDestination by viewModel.startDestination.collectAsStateWithLifecycle() val isNeedToOpenAuth by viewModel.isNeedToReplaceWithAuth.collectAsStateWithLifecycle() + val baseError by viewModel.baseError.collectAsStateWithLifecycle() val isNeedToShowDeniedDialog by viewModel.isNeedToShowNotificationsDeniedDialog.collectAsStateWithLifecycle() val isNeedToShowRationaleDialog by viewModel.isNeedToShowNotificationsRationaleDialog.collectAsStateWithLifecycle() @@ -304,6 +296,12 @@ fun RootScreen( ) } + RootErrorDialog( + baseError = baseError, + onDismiss = viewModel::onErrorConsumed, + onConfirm = viewModel::onErrorConsumed + ) + if (startDestination != null) { CompositionLocalProvider( LocalNavRootController provides navController, diff --git a/build-logic/convention/src/main/kotlin/dev/meloda/fast/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/dev/meloda/fast/KotlinAndroid.kt index 71840190..e1098056 100644 --- a/build-logic/convention/src/main/kotlin/dev/meloda/fast/KotlinAndroid.kt +++ b/build-logic/convention/src/main/kotlin/dev/meloda/fast/KotlinAndroid.kt @@ -25,6 +25,7 @@ internal fun Project.configureKotlinAndroid( commonExtension.apply { compileSdk = getVersionInt("compileSdk") + buildToolsVersion = "36.1.0" } configureKotlin()