diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index de24089..ee650f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -79,7 +79,7 @@ jobs: - name: Gradle Build id: gradle-build - run: ./gradlew repackageUberJar package -PSENTRY_ENDPOINT=${{ env.SENTRY_ENDPOINT }} -PSENTRY_DEBUG=${{ env.SENTRY_DEBUG }} + run: ./gradlew repackageUberJar package -PSENTRY_ENDPOINT=${{ env.SENTRY_ENDPOINT }} -PSENTRY_DEBUG=${{ env.SENTRY_DEBUG }} -PAPP_VERSION=${{github.ref_name}} - name: Uploading ${{ matrix.os }} uber jar if: steps.gradle-build.outcome == 'success' diff --git a/.github/workflows/buildPreProd.yml b/.github/workflows/buildPreProd.yml index 279f2fe..65415e7 100644 --- a/.github/workflows/buildPreProd.yml +++ b/.github/workflows/buildPreProd.yml @@ -71,7 +71,7 @@ jobs: - name: Gradle Build id: gradle-build - run: ./gradlew package -PSENTRY_ENDPOINT=${{ env.SENTRY_ENDPOINT }} + run: ./gradlew repackageUberJar package -PSENTRY_ENDPOINT=${{ env.SENTRY_ENDPOINT }} - name: Uploading ${{ matrix.os }} uber jar if: steps.gradle-build.outcome == 'success' diff --git a/.idea/runConfigurations/logvue__run_.xml b/.idea/runConfigurations/logvue__run_.xml index b9ae7b3..2727d01 100644 --- a/.idea/runConfigurations/logvue__run_.xml +++ b/.idea/runConfigurations/logvue__run_.xml @@ -4,7 +4,7 @@ diff --git a/build.gradle.kts b/build.gradle.kts index 83c16f7..ef19dd1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,9 +9,28 @@ plugins { } val r8: Configuration by configurations.creating +fun appVersion() : String { + val key = "APP_VERSION" + return if (project.hasProperty(key)) { + val version = project.property("APP_VERSION").toString() + println("Version = $version") + if (version.isBlank()) { + return "1.0.0" + } + if (version.matches(Regex("^[\\d]{1,3}.[\\d]{1,3}.[\\d]{1,4}"))) { + return version + } + if (version.matches(Regex("^v[\\d]{1,3}.[\\d]{1,3}.[\\d]{1,4}"))) { + return version.removePrefix("v") + } + "1.0.0" + } else { + "1.0.0" + } +} group = "com.voxfinite" -version = "1.0.0" +version = appVersion() repositories { google() diff --git a/src/main/kotlin/app/Main.kt b/src/main/kotlin/app/Main.kt index 6ce6dc6..6e6c4a5 100644 --- a/src/main/kotlin/app/Main.kt +++ b/src/main/kotlin/app/Main.kt @@ -3,8 +3,8 @@ package app import androidx.compose.ui.window.application fun main() = application(false) { - val environment = System.getenv("SKIKO_RENDER_API") - val property = System.getProperty("skiko.renderApi") - println("env: $environment render: $property") +// val environment = System.getenv("SKIKO_RENDER_API") +// val property = System.getProperty("skiko.renderApi") +// println("env: $environment render: $property") appWindow() } diff --git a/src/main/kotlin/models/SessionInfo.kt b/src/main/kotlin/models/SessionInfo.kt index f1d7e03..4f2bf3e 100644 --- a/src/main/kotlin/models/SessionInfo.kt +++ b/src/main/kotlin/models/SessionInfo.kt @@ -4,7 +4,8 @@ import java.io.Serializable data class SessionInfo( val description: String, - val appPackage: String + val appPackage: String, + val configs: HashMap? = hashMapOf() ) : Serializable { companion object { private const val serialVersionUID = 1L diff --git a/src/main/kotlin/processor/MainProcessor.kt b/src/main/kotlin/processor/MainProcessor.kt index 9ba55a6..d2a447a 100644 --- a/src/main/kotlin/processor/MainProcessor.kt +++ b/src/main/kotlin/processor/MainProcessor.kt @@ -130,7 +130,9 @@ class MainProcessor { val sentryTransaction = Sentry.startTransaction("filterLogs", "filter", true) sentryTransaction.setData("query", filterQuery ?: "") try { - filterLogs(indexedCollection, list, parser, fQuery) + val fl = filterLogs(indexedCollection, list, parser, fQuery) + sentryTransaction.status = SpanStatus.OK + fl } catch (e: Exception) { e.reportException() sentryTransaction.throwable = e diff --git a/src/main/kotlin/processor/QueryHelper.kt b/src/main/kotlin/processor/QueryHelper.kt index 0bc54d0..fa7d323 100644 --- a/src/main/kotlin/processor/QueryHelper.kt +++ b/src/main/kotlin/processor/QueryHelper.kt @@ -10,7 +10,9 @@ import com.googlecode.cqengine.index.radixinverted.InvertedRadixTreeIndex import com.googlecode.cqengine.index.radixreversed.ReversedRadixTreeIndex import com.googlecode.cqengine.query.parser.sql.SQLParser import models.LogItem +import storage.SessionConfig import utils.AppLog +import utils.ConfigConstants import utils.reportException import kotlin.reflect.KProperty1 import kotlin.time.ExperimentalTime @@ -66,9 +68,10 @@ fun registerPropertiesInParser( parser: SQLParser, indexedCollection: ConcurrentIndexedCollection ) { + val addIndex = SessionConfig.boolDefaultOn(ConfigConstants.QUERY_INDEX) val propertySet = hashSetOf() list.forEach { - registerMapPropertiesInParser(it.properties, propertySet, parser, indexedCollection) + registerMapPropertiesInParser(it.properties, propertySet, parser, indexedCollection, addIndex) } } @@ -77,18 +80,19 @@ private fun registerMapPropertiesInParser( propertySet: HashSet, parser: SQLParser, indexedCollection: ConcurrentIndexedCollection, + addIndex: Boolean, parentKey: String = "" ) { properties.forEach { (k, v) -> if (!propertySet.contains(k)) { if (v is Map<*, *>) { @Suppress("UNCHECKED_CAST") registerMapPropertiesInParser( - v as Map, propertySet, parser, indexedCollection, "$parentKey$k." + v as Map, propertySet, parser, indexedCollection, addIndex, "$parentKey$k." ) } else { // println("Attribute : ${att.attributeName} with first value = $v and v class = ${v.javaClass.name}") val key = "$parentKey$k" - registerAndAddIndex(v, key, parser, indexedCollection) + registerAndAddIndex(v, key, parser, indexedCollection, addIndex) propertySet.add(k) } } else { @@ -101,11 +105,17 @@ fun registerAndAddIndex( value: Any, key: String, parser: SQLParser, - indexedCollection: ConcurrentIndexedCollection + indexedCollection: ConcurrentIndexedCollection, + addIndex: Boolean ) { with(indexedCollection) { + if (!addIndex) { + addGenericAttribute(key, value, parser, false) + return + } if (key.isBlank()) { addGenericAttribute(key, value, parser) + return } when (value) { is String -> { @@ -147,14 +157,17 @@ fun registerAndAddIndex( private fun ConcurrentIndexedCollection.addGenericAttribute( key: String, value: Any, - parser: SQLParser + parser: SQLParser, + addIndex: Boolean = true ) { val att: ParameterizedAttribute = ParameterizedAttribute(key, value.javaClass) - try { - addIndex(HashIndex.onAttribute(att)) - } catch (e: IllegalStateException) { - // Maybe the index is already added - AppLog.d(e.message.orEmpty()) + if (addIndex) { + try { + addIndex(HashIndex.onAttribute(att)) + } catch (e: IllegalStateException) { + // Maybe the index is already added + AppLog.d(e.message.orEmpty()) + } } parser.registerAttribute(att) } diff --git a/src/main/kotlin/storage/Db.kt b/src/main/kotlin/storage/Db.kt index 00f6fcf..30d09ad 100644 --- a/src/main/kotlin/storage/Db.kt +++ b/src/main/kotlin/storage/Db.kt @@ -36,6 +36,10 @@ object Db { return sessionInfoMap[sessionId] } + fun updateSessionInfo(sessionId: String, sessionInfo: SessionInfo) { + sessionInfoMap[sessionId] = sessionInfo + } + fun getAllSessions() = diskDb.getAllNames().filter { it.startsWith(PREFIX) }.sortedBy { getSessionNumber(it) } private fun getLastSessionNumber(): Int { diff --git a/src/main/kotlin/storage/SessionConfig.kt b/src/main/kotlin/storage/SessionConfig.kt new file mode 100644 index 0000000..288bd3b --- /dev/null +++ b/src/main/kotlin/storage/SessionConfig.kt @@ -0,0 +1,57 @@ +package storage + +import models.SessionInfo + +/** + * Operations for config related to session. + * These are stored in sessionInfo so that it is tied to session and will be deleted along with it. + */ +object SessionConfig { + + private val currentSessionId + get() = Db.sessionId() + + fun string(key: String, sessionId: String? = currentSessionId): String? = getConfig(key, sessionId) + + fun boolDefaultOn(key: String, sessionId: String? = currentSessionId): Boolean { + return getConfig(key, sessionId)?.toBooleanStrictOrNull() ?: true + } + + fun bool(key: String, sessionId: String? = currentSessionId, default: Boolean = false): Boolean { + return getConfig(key, sessionId)?.toBooleanStrictOrNull() ?: default + } + + fun int(key: String, sessionId: String? = currentSessionId): Long? { + return getConfig(key, sessionId)?.toLongOrNull() + } + + fun double(key: String, sessionId: String? = currentSessionId): Double? { + return getConfig(key, sessionId)?.toDoubleOrNull() + } + + /** + * Updates config in db and returns updated [SessionInfo] + * If [sessionId] is null or blank or there is no config in db, this is a no-op and return null. + * If value is null, we will remove that key from db or put. + * This function creates a copy of session info and updates it + */ + fun set(key: String, value: Any?, sessionId: String? = currentSessionId): SessionInfo? { + if (sessionId.isNullOrBlank()) return null + val sInfo = Db.getSessionInfo(sessionId) ?: return null + val sInfoConfig = HashMap(sInfo.configs ?: emptyMap()) + if (value == null) { + sInfoConfig.remove(key) + } else { + sInfoConfig[key] = value.toString() + } + val copy = sInfo.copy(configs = sInfoConfig) + Db.updateSessionInfo(sessionId, copy) + return copy + } + + private fun getConfig(key: String, sessionId: String?): String? { + if (sessionId.isNullOrBlank()) return null + return Db.getSessionInfo(sessionId)?.configs?.get(key) + } + +} diff --git a/src/main/kotlin/ui/components/ListItemInternalContent.kt b/src/main/kotlin/ui/components/ListItemInternalContent.kt index d79225e..af26f8d 100644 --- a/src/main/kotlin/ui/components/ListItemInternalContent.kt +++ b/src/main/kotlin/ui/components/ListItemInternalContent.kt @@ -1,25 +1,29 @@ package ui.components +import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.text.selection.DisableSelection import androidx.compose.foundation.text.selection.SelectionContainer -import androidx.compose.material.Card -import androidx.compose.material.Text +import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import models.ErrorContent import models.InternalContent import models.NoLogsContent -import org.apache.logging.log4j.core.util.StringBuilderWriter import storage.Db +import storage.SessionConfig import ui.CustomTheme -import java.io.PrintWriter +import utils.ConfigConstants @Composable fun ListItemInternalContent(internalContent: InternalContent?, modifier: Modifier = Modifier) { @@ -39,37 +43,70 @@ private fun ListItemEmptyContent(noLogsContent: NoLogsContent, modifier: Modifie noLogsContent.msg } Column(Modifier.padding(24.dp), horizontalAlignment = Alignment.CenterHorizontally) { - Image(painterResource("icons/empty_state.svg"), "Use start to log events", + Image(painterResource("icons/empty_state.svg"), + "Use start to log events", Modifier.fillMaxWidth(0.5f).graphicsLayer { rotationY = 180f }) Spacer(Modifier.height(16.dp)) Text( - text, textAlign = TextAlign.Center, - style = CustomTheme.typography.headings.h5 + text, textAlign = TextAlign.Center, style = CustomTheme.typography.headings.h5 ) } } } +@OptIn(ExperimentalComposeUiApi::class) @Composable private fun ListErrorContent(errorContent: ErrorContent, modifier: Modifier = Modifier) { Card(modifier) { - SelectionContainer { - Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { - Text(errorContent.error, style = CustomTheme.typography.headings.h3) - Text("Exception:", style = CustomTheme.typography.headings.h6Medium) - val throwable = errorContent.throwable - if (throwable != null) { - val errorString = StringBuilderWriter() - val printWriter = PrintWriter(errorString) - throwable.printStackTrace(printWriter) - printWriter.flush() - Text( - errorString.toString(), - fontFamily = FontFamily.Monospace, - style = CustomTheme.typography.bodySmall - ) + Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { + Text(errorContent.error, style = CustomTheme.typography.headings.h3) + Divider() + Column( + Modifier.fillMaxWidth().background(CustomTheme.colors.componentOutline, CustomTheme.shapes.large) + .padding(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text("Technical Exception:", style = CustomTheme.typography.headings.h6Medium) + val errorString = createExceptionString(errorContent.throwable) + SelectionContainer { + if (!errorString.isNullOrBlank()) { + Text( + errorString, fontFamily = FontFamily.Monospace, style = CustomTheme.typography.bodySmall + ) + } } } + DisableSelection { + if (SessionConfig.boolDefaultOn(ConfigConstants.QUERY_INDEX)) { + val colors = + ButtonDefaults.textButtonColors(contentColor = CustomTheme.colors.alertColors.danger) + TextButton({ + SessionConfig.set(ConfigConstants.QUERY_INDEX, false) + }, colors = colors) { + Text(CustomTheme.strings.turnOffFilterIndexText, textDecoration = TextDecoration.Underline) + } + } + } + } } } + +@Preview +@Composable +fun ListError() { + val exception = Exception("Testing error") + ListErrorContent(ErrorContent("There is some error in this query", exception)) +} + +private fun createExceptionString(throwable: Throwable?): String? { + if (throwable == null) return null + val sb = StringBuilder() + sb.append(throwable.message) + val cause = throwable.cause?.message + if (!cause.isNullOrBlank()) { + sb.append(System.lineSeparator()) + sb.append(cause) + } + return sb.toString() +} diff --git a/src/main/kotlin/ui/components/dialogs/CustomDialog.kt b/src/main/kotlin/ui/components/dialogs/CustomDialog.kt index f84a189..8f15a5d 100644 --- a/src/main/kotlin/ui/components/dialogs/CustomDialog.kt +++ b/src/main/kotlin/ui/components/dialogs/CustomDialog.kt @@ -91,39 +91,35 @@ fun CustomDialog( Floats.constrainToRange(backgroundAlpha, 0.0f, 1.0f) Floats.constrainToRange(dialogWidthRatio, 0.1f, 1.0f) Floats.constrainToRange(dialogHeightRatio, 0.1f, 1.0f) - with(PopupAlertDialogProvider) { - AlertDialog(onDismissRequest) { - Dialog( - onCloseRequest = onDismissRequest, - state = rememberDialogState(width = Dp.Unspecified, height = Dp.Unspecified), - undecorated = true, - resizable = false, - transparent = true, - onKeyEvent = { - if (it.key == Key.Escape) { - onDismissRequest() - true - } else { - false - } - }, + Dialog( + onCloseRequest = onDismissRequest, + state = rememberDialogState(width = Dp.Unspecified, height = Dp.Unspecified), + undecorated = true, + resizable = true, + transparent = true, + onKeyEvent = { + if (it.key == Key.Escape) { + onDismissRequest() + true + } else { + false + } + }, + ) { + Box( + Modifier + .fillMaxSize() + .background(Color.DarkGray.copy(backgroundAlpha)) + .clickable(MutableInteractionSource(), null) { onDismissRequest() }, + contentAlignment = Alignment.Center + ) { + Surface( + Modifier + .fillMaxWidth(dialogWidthRatio) + .fillMaxHeight(dialogHeightRatio) + .clickable(MutableInteractionSource(), null) {}, dialogShape, elevation = dialogElevation ) { - Box( - Modifier - .fillMaxSize() - .background(Color.DarkGray.copy(backgroundAlpha)) - .clickable(MutableInteractionSource(), null) { onDismissRequest() }, - contentAlignment = Alignment.Center - ) { - Surface( - Modifier - .fillMaxWidth(dialogWidthRatio) - .fillMaxHeight(dialogHeightRatio) - .clickable(MutableInteractionSource(), null) {}, dialogShape, elevation = dialogElevation - ) { - content() - } - } + content() } } } diff --git a/src/main/kotlin/ui/components/dialogs/SettingsDialog.kt b/src/main/kotlin/ui/components/dialogs/SettingsDialog.kt index fed639e..b6092fd 100644 --- a/src/main/kotlin/ui/components/dialogs/SettingsDialog.kt +++ b/src/main/kotlin/ui/components/dialogs/SettingsDialog.kt @@ -1,10 +1,13 @@ package ui.components.dialogs +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.IconButton +import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -15,6 +18,7 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp +import com.voxfinite.logvue.APP_VERSION import models.SocialIcons import ui.CustomTheme import ui.components.ItemHeader @@ -23,116 +27,139 @@ import utils.AppSettings import utils.Helpers import utils.SentryHelper +@OptIn(ExperimentalFoundationApi::class) @Composable fun SettingsDialog(onDismissRequest: () -> Unit) { SimpleVerticalDialog(header = "Settings", onDismissRequest = onDismissRequest) { LazyColumn(verticalArrangement = Arrangement.spacedBy(16.dp)) { - item { - GeneralSettingBlock(Modifier.fillMaxWidth()) + stickyHeader("h1-General") { + ItemHeader("General", Modifier.fillMaxWidth().background(CustomTheme.colors.componentBackground)) } - item { + item("darkMode") { + DarkModeSwitch() + } + item("autoScroll") { + AutoScrollSwitch() + } + item("divider-1") { + Divider(color = CustomTheme.colors.componentOutline, thickness = (0.5).dp) + } + stickyHeader("h1-other") { + ItemHeader("Other", Modifier.fillMaxWidth().background(CustomTheme.colors.componentBackground)) + } + item("feedback") { + Feedback() + } + item("aboutUs") { + AboutUsBlock() + } + item("divider-2") { Divider(color = CustomTheme.colors.componentOutline, thickness = (0.5).dp) } item { - OtherSettingBlock(Modifier.fillMaxWidth()) + GeneralInfoBlock(Modifier.fillMaxWidth().padding(8.dp)) } } } } @Composable -fun GeneralSettingBlock(modifier: Modifier = Modifier) { - Column(modifier, verticalArrangement = Arrangement.spacedBy(16.dp)) { - ItemHeader("General") - var isDarkMode by remember { mutableStateOf(!Helpers.isThemeLightMode.value) } - DarkModeSwitchItem( - isDarkMode, "Dark Mode", Modifier.fillMaxWidth(), - "Enable dark mode for less strain on eyes" - ) { - isDarkMode = it - Helpers.switchThemes(!it) - } - var isAutoScroll by remember { mutableStateOf(AppSettings.getFlag(AppSettings.AUTO_SCROLL)) } - SwitchItem( - isAutoScroll, "Auto Scroll logs", Modifier.fillMaxWidth(), - "When recording, auto-scroll to the latest incoming analytics logs", - painterResource("icons/Tornado.svg") +private fun DarkModeSwitch() { + var isDarkMode by remember { mutableStateOf(!Helpers.isThemeLightMode.value) } + DarkModeSwitchItem( + isDarkMode, "Dark Mode", Modifier.fillMaxWidth(), + "Enable dark mode for less strain on eyes" + ) { + isDarkMode = it + Helpers.switchThemes(!it) + } +} + +@Composable +private fun AutoScrollSwitch() { + var isAutoScroll by remember { mutableStateOf(AppSettings.getFlag(AppSettings.AUTO_SCROLL)) } + SwitchItem( + isAutoScroll, "Auto Scroll logs", Modifier.fillMaxWidth(), + "When recording, auto-scroll to the latest incoming analytics logs", + painterResource("icons/Tornado.svg") + ) { + isAutoScroll = it + AppSettings.setFlag(AppSettings.AUTO_SCROLL, it) + } +} + +@Composable +private fun Feedback() { + Column { + SimpleListItem( + "Feedback / Issues", Modifier.fillMaxWidth(), + "If you have any feedback or issues, we would love to hear it from you", + painterResource("icons/ico-email.svg") + ) + Row( + Modifier.padding(start = 32.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceEvenly ) { - isAutoScroll = it - AppSettings.setFlag(AppSettings.AUTO_SCROLL, it) - } - if (SentryHelper.isEnabled()) { - var reportCrash by remember { mutableStateOf(AppSettings.getFlag("reportCrash")) } - SwitchItem( - reportCrash, "Report Crashes", Modifier.fillMaxWidth(), - "Should we report crashes? We use it to make sure our app stays healthy. " + - "No private information is shared with us.", - painterResource("icons/bug.svg") - ) { - reportCrash = it - AppSettings.setFlag("reportCrash", it) - } + WebLinkButton(SocialIcons.GithubIssues, "Create new issue") + WebLinkButton(SocialIcons.Email, "Mail Us") } } } @Composable -fun OtherSettingBlock(modifier: Modifier = Modifier) { - Column(modifier, verticalArrangement = Arrangement.spacedBy(12.dp)) { - ItemHeader("Other") - Column { - SimpleListItem( - "Feedback / Issues", Modifier.fillMaxWidth(), - "If you have any feedback or issues, we would love to hear it from you", - painterResource("icons/ico-email.svg") - ) - Row( - Modifier.padding(start = 32.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceEvenly +private fun AboutUsBlock() { + val aboutUsText = buildAnnotatedString { + withStyle(SpanStyle(color = CustomTheme.colors.mediumContrast)) { + append("This ") + pushStringAnnotation("gitProjectLink", "https://github.com/amank22/LogVue") + withStyle( + SpanStyle( + textDecoration = TextDecoration.Underline, + color = CustomTheme.colors.highContrast + ) ) { - WebLinkButton(SocialIcons.GithubIssues, "Create new issue") - WebLinkButton(SocialIcons.Email, "Mail Us") + append("open-source project") } + pop() + append(" is created by Aman Kapoor. Connect with him below.") } - val aboutUsText = buildAnnotatedString { - withStyle(SpanStyle(color = CustomTheme.colors.mediumContrast)) { - append("This ") - pushStringAnnotation("gitProjectLink", "https://github.com/amank22/LogVue") - withStyle( - SpanStyle( - textDecoration = TextDecoration.Underline, - color = CustomTheme.colors.highContrast - ) - ) { - append("open-source project") - } - pop() - append(" is created by Aman Kapoor. Connect with him below.") + } + Column { + ClickableListItem( + AnnotatedString("About us"), Modifier.fillMaxWidth(), + aboutUsText, + painterResource("icons/ico_info.svg") + ) { offset -> + aboutUsText.getStringAnnotations( + tag = "gitProjectLink", start = offset, + end = offset + ).firstOrNull()?.let { + openBrowser(it.item) } } - Column { - ClickableListItem( - AnnotatedString("About us"), Modifier.fillMaxWidth(), - aboutUsText, - painterResource("icons/ico_info.svg") - ) { offset -> - aboutUsText.getStringAnnotations( - tag = "gitProjectLink", start = offset, - end = offset - ).firstOrNull()?.let { - openBrowser(it.item) - } - } - Row(Modifier.padding(start = 32.dp)) { - SocialIcons.DefaultIcons.forEach { - SocialIcon(it) - } + Row(Modifier.padding(start = 32.dp)) { + SocialIcons.DefaultIcons.forEach { + SocialIcon(it) } } } } +@Composable +fun GeneralInfoBlock(modifier: Modifier = Modifier) { + // Replace with a single view with app version, bug reporting enabled etc description + Column( + modifier, verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Version : $APP_VERSION", style = CustomTheme.typography.headings.caption) + if (SentryHelper.isEnabled()) { + Text("Crash reporting enabled", style = CustomTheme.typography.bodySmall) + } + } +} + @Composable private fun SocialIcon(icon: SocialIcons) { IconButton({ openBrowser(icon.url) }) { diff --git a/src/main/kotlin/utils/AppResources.kt b/src/main/kotlin/utils/AppResources.kt index 68439ca..b1aa956 100644 --- a/src/main/kotlin/utils/AppResources.kt +++ b/src/main/kotlin/utils/AppResources.kt @@ -5,6 +5,7 @@ interface StringRes { val appName: String val filterFaqTitle: String val appCrashText: String + val turnOffFilterIndexText: String } class EnglishStringRes : StringRes { @@ -13,5 +14,7 @@ class EnglishStringRes : StringRes { override val appCrashText: String = "Unfortunately the app was crashed last time. " + "While we look into this, you can also report this issue to us on github or through " + "mail describing the scenario that caused this crash." + override val turnOffFilterIndexText: String = "If you are facing repeated issues with filter, " + + "click here and re-run query for filter. This is one time setting per session" } diff --git a/src/main/kotlin/utils/ConfigConstants.kt b/src/main/kotlin/utils/ConfigConstants.kt new file mode 100644 index 0000000..3381d72 --- /dev/null +++ b/src/main/kotlin/utils/ConfigConstants.kt @@ -0,0 +1,7 @@ +package utils + +object ConfigConstants { + + const val QUERY_INDEX = "indexQueryParams" + +} diff --git a/src/main/kotlin/utils/CustomExceptionHandler.kt b/src/main/kotlin/utils/CustomExceptionHandler.kt index 434200c..998b3b3 100644 --- a/src/main/kotlin/utils/CustomExceptionHandler.kt +++ b/src/main/kotlin/utils/CustomExceptionHandler.kt @@ -5,7 +5,6 @@ class CustomExceptionHandler : Thread.UncaughtExceptionHandler { override fun uncaughtException(t: Thread?, e: Throwable?) { e?.printStackTrace() setCrashed() - throw e ?: Exception("Unknown exception") } companion object {