Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ passkeys, and credit card information encrypted entirely on your local device.
### Driven by a modern & intuitive design

<div align="center">
<img src="docs/assets/phone-1.png" width="32%" alt="Vault List Screenshot"/>
<img src="docs/assets/phone-2.png" width="32%" alt="Item Detail Screenshot"/>
<img src="docs/assets/phone-3.png" width="32%" alt="Password Generator Screenshot"/>
<img src="docs/assets/phone/01_hero.png" width="32%" alt="Vault List Screenshot"/>
<img src="docs/assets/phone/02_password_health.png" width="32%" alt="Password Health Screenshot"/>
<img src="docs/assets/phone/03_2fa.png" width="32%" alt="Two-Factor Authenticator Screenshot"/>
</div>

## Features
Expand All @@ -22,17 +22,17 @@ passkeys, and credit card information encrypted entirely on your local device.
* **Local-Only Storage:** Your data will never leave your device.
* **Comprehensive Management:** Store passwords, passkeys, and credit cards.
* **MFA Support:** Built-in authenticator for TOTP tokens.
* **Advanced Security:** Per-item, industry-standard encryption.
* **Advanced Security:** Per-item, industry-standard encryption & password health scanning.
* **Seamless Integration:** System-wide autofill service for all your credentials.

## Download

Get the latest version of KeyGo directly from the Play Store or GitHub:
|Platform|Status|
|:------:|:----:|
| Google Play
Store | [<img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" alt="Download from Google Play" height="80">](https://play.google.com/store/apps/details?id=de.davis.passwordmanager) |
|GitHub. | [![GitHub tag](https://img.shields.io/github/release/OffRange/KeyGo?include_prereleases=&sort=semver)](https://github.com/OffRange/KeyGo/releases/)|

| Platform | Status |
|:-----------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| Google Play Store | [<img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" alt="Download from Google Play" height="80">](https://play.google.com/store/apps/details?id=de.davis.passwordmanager) |
| GitHub | [![GitHub tag](https://img.shields.io/github/release/OffRange/KeyGo?include_prereleases=&sort=semver)](https://github.com/OffRange/KeyGo/releases/) |

## Build it Yourself

Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ plugins {
}

versioning {
minVersion = Version(major = 2, minor = 1)
minVersion = Version(major = 2, minor = 2)
}

android versionedBy versioning
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.davis.keygo.core.ui.components

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.SelectableMenuItemColors
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color

object KeyGoMenuDefaults {

val containerColor: Color
@Composable get() = MaterialTheme.colorScheme.surfaceContainerHighest

/** Item colors matching [containerColor]; the M3 defaults paint items `surfaceContainerLow`. */
val selectableItemColors: SelectableMenuItemColors
@Composable
get() = MenuDefaults.selectableItemColors(containerColor = containerColor)
}
Binary file removed docs/assets/desktop.png
Binary file not shown.
Binary file modified docs/assets/feature-graphic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/assets/phone-1.png
Binary file not shown.
Binary file removed docs/assets/phone-2.png
Binary file not shown.
Binary file removed docs/assets/phone-3.png
Binary file not shown.
Binary file removed docs/assets/phone-4.png
Binary file not shown.
Binary file removed docs/assets/phone-5.png
Binary file not shown.
Binary file removed docs/assets/phone-6.png
Binary file not shown.
Binary file added docs/assets/phone/01_hero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/phone/02_password_health.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/phone/03_2fa.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/phone/04_generator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/phone/05_vaults.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/phone/06_privacy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/assets/tablet-1.png
Binary file not shown.
Binary file added docs/assets/tablet-10in/01_hero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/tablet-10in/02_password_health.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/tablet-10in/03_2fa_generator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/tablet-10in/04_privacy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/assets/tablet-2.png
Binary file not shown.
Binary file added docs/assets/tablet-7in/01_hero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/tablet-7in/02_password_health.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/tablet-7in/03_2fa_generator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/tablet-7in/04_privacy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
Expand All @@ -31,7 +30,6 @@ import androidx.compose.material.icons.filled.DeleteSweep
import androidx.compose.material.icons.filled.Remove
import androidx.compose.material.icons.filled.Schedule
import androidx.compose.material3.ButtonGroupDefaults
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
Expand Down Expand Up @@ -78,7 +76,6 @@ import de.davis.keygo.feature.backup.presentation.label
import kotlinx.coroutines.delay
import kotlin.time.Duration.Companion.milliseconds

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
internal fun IntervalPicker(
interval: BackupInterval,
Expand Down Expand Up @@ -115,7 +112,7 @@ internal fun IntervalPicker(
0 -> ButtonGroupDefaults.connectedLeadingButtonShapes()
else -> ButtonGroupDefaults.connectedTrailingButtonShapes()
},
colors = OutlinedToggleButtonDefaults.outlinedToggleButtonColors(
colors = OutlinedToggleButtonDefaults.colors(
checkedContainerColor = MaterialTheme.colorScheme.primaryContainer,
checkedContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
)
Expand All @@ -127,7 +124,6 @@ internal fun IntervalPicker(
}
}

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
internal fun RetentionPicker(
keepCount: Int,
Expand Down Expand Up @@ -314,7 +310,6 @@ private fun StepperButton(
}
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun StepperValueField(
value: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.TableChart
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenu
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
Expand All @@ -22,6 +21,7 @@ import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.SegmentedListItem
import androidx.compose.material3.SelectableDropdownMenuItem
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -193,7 +193,6 @@ private fun SourceSegment(columnIndex: Int, header: String) {
* since all three segments carry the same weight of leading icon. This is the only segment of the
* three that is genuinely interactive.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TypeSegment(
selectedType: CsvColumnType?,
Expand Down Expand Up @@ -254,18 +253,26 @@ private fun TypeSegment(
shape = MenuDefaults.standaloneGroupShape,
) {
TYPE_OPTIONS.forEachIndexed { index, option ->
DropdownMenuItem(
SelectableDropdownMenuItem(
selected = selectedType == option,
onClick = {
onTypeChange(option)
expanded = false
},
text = { Text(text = option.displayName) },
leadingIcon = {
Icon(imageVector = option.icon, contentDescription = null)
Icon(
imageVector = option.icon,
modifier = Modifier.size(MenuDefaults.LeadingIconSize),
contentDescription = null,
)
},
selectedLeadingIcon = {
Icon(imageVector = Icons.Default.Check, contentDescription = null)
Icon(
imageVector = Icons.Default.Check,
modifier = Modifier.size(MenuDefaults.LeadingIconSize),
contentDescription = null,
)
},
shapes = MenuDefaults.itemShape(index, TYPE_OPTIONS.size)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.clearText
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ExposedDropdownMenu
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
Expand All @@ -23,8 +21,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.ImeAction
import de.davis.keygo.core.ui.components.KeyGoMenuDefaults

@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun KeyGoFormSuggestionField(
suggestions: Set<String>,
Expand Down Expand Up @@ -70,7 +68,9 @@ fun KeyGoFormSuggestionField(

ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { setExpanded(false) }
onDismissRequest = { setExpanded(false) },
containerColor = KeyGoMenuDefaults.containerColor,
shape = MenuDefaults.standaloneGroupShape,
) {
suggestions.forEachIndexed { index, suggestion ->
DropdownMenuItem(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.InputChip
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -25,9 +23,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import de.davis.keygo.core.ui.components.KeyGoMenuDefaults
import de.davis.keygo.feature.item.core.R

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun MenuChip(
chipText: String,
Expand Down Expand Up @@ -56,7 +54,7 @@ fun MenuChip(
) {
DropdownMenuGroup(
shapes = MenuDefaults.groupShape(0, 1),
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
containerColor = KeyGoMenuDefaults.containerColor,
) {
onModifyClick?.let { onModify ->
DropdownMenuItem(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ExposedDropdownMenu
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
Expand All @@ -15,6 +12,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.SelectableDropdownMenuItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
Expand All @@ -25,10 +23,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import de.davis.keygo.core.item.domain.alias.VaultId
import de.davis.keygo.core.item.presentation.toImageVector
import de.davis.keygo.core.ui.components.KeyGoMenuDefaults
import de.davis.keygo.feature.item.create.R
import de.davis.keygo.feature.item.create.presentation.model.VaultsState

@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun VaultDropDownMenu(
vaultsState: VaultsState,
Expand Down Expand Up @@ -68,15 +66,14 @@ fun VaultDropDownMenu(
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
containerColor = KeyGoMenuDefaults.containerColor,
shape = MenuDefaults.standaloneGroupShape,
) {
val optionCount = vaultsState.vaults.size
vaultsState.vaults.forEachIndexed { index, metadata ->
DropdownMenuItem(
SelectableDropdownMenuItem(
shapes = MenuDefaults.itemShape(index, optionCount),
colors = MenuDefaults.selectableItemColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
),
colors = KeyGoMenuDefaults.selectableItemColors,
text = {
Text(
metadata.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ fun GeneratePasswordContent(
.fillMaxWidth(),
properties = cardProp,
) {
Slider(state = viewModel.sliderState)
Slider(
state = viewModel.sliderState,
onValueChange = { viewModel.sliderState.value = it },
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.davis.keygo.feature.item.create.presentation.password

import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SliderState
import androidx.compose.runtime.snapshotFlow
import androidx.lifecycle.ViewModel
Expand Down Expand Up @@ -28,14 +27,13 @@ import org.koin.core.annotation.KoinViewModel
import kotlin.time.Duration.Companion.milliseconds

@KoinViewModel
@OptIn(ExperimentalMaterial3Api::class, FlowPreview::class)
@OptIn(FlowPreview::class)
internal class GeneratePasswordViewModel(
private val passwordGenerator: PasswordGenerator,
private val passwordStrengthEstimator: PasswordStrengthEstimator,
) : ViewModel() {

@OptIn(ExperimentalMaterial3Api::class)
val sliderState = SliderState(value = 10f, valueRange = 8f..100f)
val sliderState = SliderState(value = 10f, trackRange = 8f..100f)

private val finalPasswordChannel = Channel<String>()
val finalPassword = finalPasswordChannel.receiveAsFlow()
Expand Down Expand Up @@ -73,7 +71,6 @@ internal class GeneratePasswordViewModel(
initialValue = GeneratePasswordUiState(),
)

@OptIn(ExperimentalMaterial3Api::class)
fun onEvent(event: GeneratePasswordUiEvent) {
when (event) {
is GeneratePasswordUiEvent.OnCharacterSetClick -> {
Expand Down
Loading
Loading