diff --git a/app/src/main/java/com/jocmp/capyreader/common/AppPreferences.kt b/app/src/main/java/com/jocmp/capyreader/common/AppPreferences.kt index 595e18db..e5c9a00e 100644 --- a/app/src/main/java/com/jocmp/capyreader/common/AppPreferences.kt +++ b/app/src/main/java/com/jocmp/capyreader/common/AppPreferences.kt @@ -33,6 +33,9 @@ class AppPreferences(context: Context) { val articleID: Preference get() = preferenceStore.getString("article_id") + val crashReporting: Preference + get() = preferenceStore.getBoolean("enable_crash_reporting", false) + fun clearAll() { accountID.delete() articleID.delete() diff --git a/app/src/main/java/com/jocmp/capyreader/ui/components/CrashReportingCheckbox.kt b/app/src/main/java/com/jocmp/capyreader/ui/components/CrashReportingCheckbox.kt new file mode 100644 index 00000000..4da52639 --- /dev/null +++ b/app/src/main/java/com/jocmp/capyreader/ui/components/CrashReportingCheckbox.kt @@ -0,0 +1,60 @@ +package com.jocmp.capyreader.ui.components + +import androidx.compose.foundation.layout.Row +import androidx.compose.material3.Checkbox +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.google.firebase.crashlytics.ktx.crashlytics +import com.google.firebase.ktx.Firebase +import com.jocmp.capyreader.R +import com.jocmp.capyreader.common.AppPreferences +import com.jocmp.capyreader.setupCommonModules +import com.jocmp.capyreader.ui.theme.CapyTheme +import org.koin.android.ext.koin.androidContext +import org.koin.compose.KoinApplication +import org.koin.compose.koinInject + +@Composable +fun CrashReportingCheckbox( + appPreferences: AppPreferences = koinInject() +) { + val (enableCrashReporting, setCrashReportingEnabled) = rememberSaveable { + mutableStateOf(appPreferences.crashReporting.get()) + } + + val updateCrashReporting = { enabled: Boolean -> + setCrashReportingEnabled(enabled) + Firebase.crashlytics.setCrashlyticsCollectionEnabled(enabled) + appPreferences.crashReporting.set(enabled) + } + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox(checked = enableCrashReporting, onCheckedChange = updateCrashReporting) + Text(text = stringResource(R.string.crash_reporting_checkbox_title)) + } +} + +@Preview +@Composable +private fun CrashReportingCheckboxPreview() { + val context = LocalContext.current + + KoinApplication( + application = { + androidContext(context) + setupCommonModules() + } + ) { + CapyTheme { + CrashReportingCheckbox() + } + } +} diff --git a/app/src/main/java/com/jocmp/capyreader/ui/login/LoginView.kt b/app/src/main/java/com/jocmp/capyreader/ui/login/LoginView.kt index a5f38ec1..2d4acbec 100644 --- a/app/src/main/java/com/jocmp/capyreader/ui/login/LoginView.kt +++ b/app/src/main/java/com/jocmp/capyreader/ui/login/LoginView.kt @@ -3,6 +3,7 @@ package com.jocmp.capyreader.ui.login import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.widthIn @@ -12,10 +13,19 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.jocmp.capyreader.R +import com.jocmp.capyreader.common +import com.jocmp.capyreader.common.AppPreferences +import com.jocmp.capyreader.setupCommonModules +import com.jocmp.capyreader.ui.components.CrashReportingCheckbox +import org.koin.android.ext.koin.androidContext +import org.koin.compose.KoinApplication +import org.koin.dsl.module +import kotlin.math.sin @Composable fun LoginView( @@ -41,24 +51,30 @@ fun LoginView( .padding(padding) ) { Column( - verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier .widthIn(max = 400.dp) - .padding(horizontal = 16.dp) ) { - Text( - text = stringResource(R.string.login_title), - style = typography.headlineMedium, - ) - AuthFields( - username = username, - password = password, - onUsernameChange = onUsernameChange, - onPasswordChange = onPasswordChange, - onSubmit = onSubmit, - loading = loading, - errorMessage = errorMessage - ) + Column( + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(horizontal = 16.dp) + ) { + Text( + text = stringResource(R.string.login_title), + style = typography.headlineMedium, + ) + AuthFields( + username = username, + password = password, + onUsernameChange = onUsernameChange, + onPasswordChange = onPasswordChange, + onSubmit = onSubmit, + loading = loading, + errorMessage = errorMessage + ) + } + Row(Modifier.padding(horizontal = 8.dp)) { + CrashReportingCheckbox() + } } } } @@ -67,8 +83,17 @@ fun LoginView( @Preview @Composable private fun LoginViewPreview() { - LoginView( - username = "test@example.com", - password = "", - ) + val context = LocalContext.current + + KoinApplication( + application = { + androidContext(context) + setupCommonModules() + } + ) { + LoginView( + username = "test@example.com", + password = "", + ) + } } diff --git a/app/src/main/java/com/jocmp/capyreader/ui/settings/SettingsView.kt b/app/src/main/java/com/jocmp/capyreader/ui/settings/SettingsView.kt index 46f6716c..ed5e405f 100644 --- a/app/src/main/java/com/jocmp/capyreader/ui/settings/SettingsView.kt +++ b/app/src/main/java/com/jocmp/capyreader/ui/settings/SettingsView.kt @@ -2,6 +2,7 @@ package com.jocmp.capyreader.ui.settings import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -13,6 +14,7 @@ import androidx.compose.material.icons.filled.Close import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -26,14 +28,19 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.jocmp.capyreader.R import com.jocmp.capyreader.refresher.RefreshInterval +import com.jocmp.capyreader.setupCommonModules import com.jocmp.capyreader.ui.LocalWindowWidth +import com.jocmp.capyreader.ui.components.CrashReportingCheckbox import com.jocmp.capyreader.ui.isCompact +import org.koin.android.ext.koin.androidContext +import org.koin.compose.KoinApplication @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -75,7 +82,7 @@ fun SettingsView( }, ) { contentPadding -> Column( - verticalArrangement = Arrangement.SpaceBetween, + verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier .padding(contentPadding) .fillMaxHeight() @@ -107,13 +114,20 @@ fun SettingsView( updateRefreshInterval = updateRefreshInterval, ) } + + Row(Modifier.padding(start = 8.dp)) { + CrashReportingCheckbox() + } + } Column( horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier - .padding(16.dp) + .padding(horizontal = 16.dp) ) { + HorizontalDivider() Button( onClick = { setRemoveDialogOpen(true) }, Modifier.fillMaxWidth() @@ -157,11 +171,20 @@ private fun backButton(): ImageVector { @Preview @Composable fun AccountSettingsViewPreview() { - SettingsView( - refreshInterval = RefreshInterval.EVERY_HOUR, - updateRefreshInterval = {}, - onRequestLogout = {}, - onNavigateBack = {}, - accountName = "hello@example.com" - ) + val context = LocalContext.current + + KoinApplication( + application = { + androidContext(context) + setupCommonModules() + } + ) { + SettingsView( + refreshInterval = RefreshInterval.EVERY_HOUR, + updateRefreshInterval = {}, + onRequestLogout = {}, + onNavigateBack = {}, + accountName = "hello@example.com" + ) + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2dbe630c..7d783651 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -72,4 +72,5 @@ Invalid email or password Successfully logged in Log in to Feedbin + Enable crash reporting