feat: add app version in settings (#839)

* feat: add app version in settings

* feat: add about app section

* feat: change icon
This commit is contained in:
Yogesh Choudhary Paliyal
2024-05-12 14:29:59 +05:30
committed by GitHub
parent c139cad899
commit 29fd5ab8b2
11 changed files with 252 additions and 3 deletions

View File

@@ -0,0 +1,153 @@
package com.yogeshpaliyal.keypass.ui.about
import android.content.res.Configuration
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
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.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.yogeshpaliyal.common.utils.openLink
import com.yogeshpaliyal.keypass.BuildConfig
import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.ui.commonComponents.DefaultBottomAppBar
import com.yogeshpaliyal.keypass.ui.commonComponents.PreferenceItem
@Composable
fun AboutScreen() {
Scaffold(bottomBar = { DefaultBottomAppBar() }) { contentPadding ->
Surface(
modifier = Modifier
.padding(contentPadding)
.fillMaxWidth()
) {
MainContent()
}
}
}
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true)
@Composable
fun MainContentDarkPreview() {
MainContent()
}
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, showBackground = true)
@Composable
fun MainContentLightPreview() {
MainContent()
}
@Composable
private fun MainContent() {
val context = LocalContext.current
Column(
modifier = Modifier
.fillMaxSize(1f)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
Column(
modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier.border(
1.dp,
MaterialTheme.colorScheme.onBackground,
shape = androidx.compose.foundation.shape.AbsoluteRoundedCornerShape(8.dp)
)
) {
Image(
painter = painterResource(id = R.mipmap.ic_launcher_foreground),
contentDescription = "App Icon"
)
}
Spacer(modifier = Modifier.size(16.dp))
Text(
stringResource(id = R.string.app_name),
style = MaterialTheme.typography.headlineSmall
)
Spacer(modifier = Modifier.size(8.dp))
Text(BuildConfig.VERSION_NAME)
HorizontalDivider(modifier = Modifier.padding(vertical = 16.dp))
Text(
stringResource(id = R.string.app_desc),
style = MaterialTheme.typography.bodyMedium
)
Text(
text = stringResource(R.string.source_code),
modifier = Modifier
.fillMaxWidth()
.clickable {
context.openLink("https://github.com/yogeshpaliyal/KeyPass")
},
fontStyle = androidx.compose.ui.text.font.FontStyle.Italic,
style = MaterialTheme.typography.labelMedium,
textDecoration = TextDecoration.Underline,
textAlign = TextAlign.Center
)
HorizontalDivider(modifier = Modifier.padding(vertical = 16.dp))
}
Text(
stringResource(id = R.string.app_developer),
style = MaterialTheme.typography.headlineSmall
)
Spacer(modifier = Modifier.size(16.dp))
Column(modifier = Modifier.fillMaxWidth()) {
PreferenceItem(
painter = painterResource(id = R.drawable.ic_twitter),
title = R.string.app_developer_x
) {
context.openLink("https://twitter.com/yogeshpaliyal")
}
}
PreferenceItem(
painter = painterResource(id = R.drawable.ic_github),
title = R.string.app_developer_github
) {
context.openLink("https://github.com/yogeshpaliyal")
}
PreferenceItem(
painter = painterResource(id = R.drawable.ic_linkedin),
title = R.string.app_developer_linkedin
) {
context.openLink("https://linkedin.com/in/yogeshpaliyal")
}
}
}

View File

@@ -24,6 +24,7 @@ import com.yogeshpaliyal.common.utils.getUserSettingsFlow
import com.yogeshpaliyal.common.utils.migrateOldDataToNewerDataStore
import com.yogeshpaliyal.common.utils.setUserSettings
import com.yogeshpaliyal.keypass.BuildConfig
import com.yogeshpaliyal.keypass.ui.about.AboutScreen
import com.yogeshpaliyal.keypass.ui.auth.AuthScreen
import com.yogeshpaliyal.keypass.ui.backup.BackupScreen
import com.yogeshpaliyal.keypass.ui.backupsImport.BackupImporter
@@ -36,6 +37,7 @@ import com.yogeshpaliyal.keypass.ui.nav.components.KeyPassBottomBar
import com.yogeshpaliyal.keypass.ui.redux.KeyPassRedux
import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction
import com.yogeshpaliyal.keypass.ui.redux.actions.UpdateContextAction
import com.yogeshpaliyal.keypass.ui.redux.states.AboutState
import com.yogeshpaliyal.keypass.ui.redux.states.AccountDetailState
import com.yogeshpaliyal.keypass.ui.redux.states.AuthState
import com.yogeshpaliyal.keypass.ui.redux.states.BackupImporterState
@@ -166,6 +168,7 @@ fun CurrentPage() {
}
is BackupImporterState -> BackupImporter(state = it)
is AboutState -> AboutScreen()
}
}
}

View File

@@ -0,0 +1,3 @@
package com.yogeshpaliyal.keypass.ui.redux.states
class AboutState : ScreenState()

View File

@@ -6,15 +6,24 @@ import android.provider.Settings
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.rounded.Feedback
import androidx.compose.material.icons.rounded.Fingerprint
import androidx.compose.material.icons.rounded.Password
import androidx.compose.material.icons.rounded.Share
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -22,13 +31,14 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.yogeshpaliyal.common.utils.email
import com.yogeshpaliyal.common.utils.setBiometricEnable
import com.yogeshpaliyal.keypass.BuildConfig
import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.ui.commonComponents.PreferenceItem
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
@@ -37,6 +47,7 @@ import com.yogeshpaliyal.keypass.ui.redux.actions.Action
import com.yogeshpaliyal.keypass.ui.redux.actions.IntentNavigation
import com.yogeshpaliyal.keypass.ui.redux.actions.NavigationAction
import com.yogeshpaliyal.keypass.ui.redux.actions.ToastAction
import com.yogeshpaliyal.keypass.ui.redux.states.AboutState
import com.yogeshpaliyal.keypass.ui.redux.states.BackupImporterState
import com.yogeshpaliyal.keypass.ui.redux.states.BackupScreenState
import com.yogeshpaliyal.keypass.ui.redux.states.ChangeAppPasswordState
@@ -44,7 +55,6 @@ import com.yogeshpaliyal.keypass.ui.redux.states.ChangeDefaultPasswordLengthStat
import kotlinx.coroutines.launch
import org.reduxkotlin.compose.rememberTypedDispatcher
@Preview(showSystemUi = true)
@Composable
fun MySettingCompose() {
val dispatchAction = rememberTypedDispatcher<Action>()
@@ -57,7 +67,7 @@ fun MySettingCompose() {
userSettings.defaultPasswordLength.let { value -> savedPasswordLength = value }
}
Column {
Column(modifier = Modifier.fillMaxSize(1f).verticalScroll(rememberScrollState())) {
PreferenceItem(title = R.string.security, isCategory = true)
PreferenceItem(
painter = painterResource(id = R.drawable.credentials_backup),
@@ -113,6 +123,27 @@ fun MySettingCompose() {
) {
dispatchAction(IntentNavigation.ShareApp)
}
PreferenceItem(
title = R.string.about_us,
summary = R.string.about_us,
icon = Icons.Outlined.Info
) {
dispatchAction(NavigationAction(AboutState()))
}
Row(
modifier = Modifier
.fillMaxWidth(1f)
.padding(16.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "App Version ${BuildConfig.VERSION_NAME}",
style = MaterialTheme.typography.labelSmall
)
}
}
}

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M69.12,94.15 L28.5,128l40.62,33.85a8,8 0,1 1,-10.24 12.29l-48,-40a8,8 0,0 1,0 -12.29l48,-40a8,8 0,0 1,10.24 12.3ZM245.12,121.85 L197.12,81.85a8,8 0,1 0,-10.24 12.3L227.5,128l-40.62,33.85a8,8 0,1 0,10.24 12.29l48,-40a8,8 0,0 0,0 -12.29ZM162.73,32.48a8,8 0,0 0,-10.25 4.79l-64,176a8,8 0,0 0,4.79 10.26A8.14,8.14 0,0 0,96 224a8,8 0,0 0,7.52 -5.27l64,-176A8,8 0,0 0,162.73 32.48Z"
android:fillColor="#ffffff"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M208.31,75.68A59.78,59.78 0,0 0,202.93 28,8 8,0 0,0 196,24a59.75,59.75 0,0 0,-48 24H124A59.75,59.75 0,0 0,76 24a8,8 0,0 0,-6.93 4,59.78 59.78,0 0,0 -5.38,47.68A58.14,58.14 0,0 0,56 104v8a56.06,56.06 0,0 0,48.44 55.47A39.8,39.8 0,0 0,96 192v8H72a24,24 0,0 1,-24 -24A40,40 0,0 0,8 136a8,8 0,0 0,0 16,24 24,0 0,1 24,24 40,40 0,0 0,40 40H96v16a8,8 0,0 0,16 0V192a24,24 0,0 1,48 0v40a8,8 0,0 0,16 0V192a39.8,39.8 0,0 0,-8.44 -24.53A56.06,56.06 0,0 0,216 112v-8A58.14,58.14 0,0 0,208.31 75.68ZM200,112a40,40 0,0 1,-40 40H112a40,40 0,0 1,-40 -40v-8a41.74,41.74 0,0 1,6.9 -22.48A8,8 0,0 0,80 73.83a43.81,43.81 0,0 1,0.79 -33.58,43.88 43.88,0 0,1 32.32,20.06A8,8 0,0 0,119.82 64h32.35a8,8 0,0 0,6.74 -3.69,43.87 43.87,0 0,1 32.32,-20.06A43.81,43.81 0,0 1,192 73.83a8.09,8.09 0,0 0,1 7.65A41.72,41.72 0,0 1,200 104Z"
android:fillColor="#ffffff"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M216,24L40,24A16,16 0,0 0,24 40L24,216a16,16 0,0 0,16 16L216,232a16,16 0,0 0,16 -16L232,40A16,16 0,0 0,216 24ZM216,216L40,216L40,40L216,40L216,216ZM96,112v64a8,8 0,0 1,-16 0L80,112a8,8 0,0 1,16 0ZM184,140v36a8,8 0,0 1,-16 0L168,140a20,20 0,0 0,-40 0v36a8,8 0,0 1,-16 0L112,112a8,8 0,0 1,15.79 -1.78A36,36 0,0 1,184 140ZM100,84A12,12 0,1 1,88 72,12 12,0 0,1 100,84Z"
android:fillColor="#ffffff"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M5.92,6L20.582,27.375L6.23,44L9.41,44L21.986,29.422L31.986,44L44,44L28.682,21.67L42.199,6L39.029,6L27.275,19.617L17.934,6L5.92,6zM9.717,8L16.881,8L40.203,42L33.039,42L9.717,8z"/>
</vector>

View File

@@ -2,6 +2,7 @@
<string name="generate_password">Generate Password</string>
<string name="app_desc">Open-source &amp; offline password manager. Store, manage, take control securely.</string>
<string name="home">Home</string>
<string name="delete">Delete</string>
@@ -21,7 +22,14 @@
<string name="send_feedback">Send feedback</string>
<string name="send_feedback_desc">Report technical issues or suggest new features</string>
<string name="share">Share</string>
<string name="about_us">About Us</string>
<string name="share_desc">Share app with others</string>
<string name="about_us_desc">About us Desc</string>
<string name="app_developer">Developer</string>
<string name="app_developer_x">X (previously Twitter)</string>
<string name="app_developer_linkedin">LinkedIn</string>
<string name="source_code">Source Code</string>
<string name="app_developer_github">Github</string>
<string name="password">Password</string>
<string name="copied_to_clipboard">Copied to clipboard</string>
<string name="login_to_enter_keypass">Login to enter KeyPass</string>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">KeyPass Pro</string>
</resources>

View File

@@ -61,6 +61,17 @@ fun Context.sendSMS(chooserTitle: String, number: String, text: String = ""): Bo
}
}
fun Context.openLink(link: String): Boolean {
try {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("$link?utm_source=KeyPass&utm_medium=app&utm_campaign=KeyPass"))
startActivity(intent)
return true
} catch (e: Exception) {
e.printStackTrace()
return false
}
}
fun Context.share(chooserTitle: String, text: String): Boolean {
try {
val intent = Intent(Intent.ACTION_SEND)