Skip to content

Commit

Permalink
Favorite Support
Browse files Browse the repository at this point in the history
  • Loading branch information
Shade authored and Shade committed Nov 24, 2024
1 parent 3b3e1b4 commit 34f7ce2
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 25 deletions.
8 changes: 8 additions & 0 deletions src/main/kotlin/core/models/SelectedCredential.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,12 @@ data class SelectedCredential(
return password != null || creditCard != null
}

fun isFavorite(): Boolean {
return (password != null || creditCard != null) && (password?.favorite == true || creditCard?.favorite == true)
}

fun getId(): UUID? {
return password?.id?.value ?: creditCard?.id?.value
}

}
3 changes: 2 additions & 1 deletion src/main/kotlin/core/models/UiModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ data class CredentialDisplay(
val id: UUID,
val title: String,
val description: String,
val favorite: Boolean
val favorite: Boolean,
val isSelected: Boolean
)

enum class CredentialSort(val value: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,11 @@ class CreditCard(id: EntityID<UUID>) : UUIDEntity(id) {
var lastUpdateDateTime by CreditCardTable.lastUpdateDateTime
var lastUpdatedBy by CreditCardTable.lastUpdatedBy
var version by CreditCardTable.version

fun favorite(): CreditCard {
return this.apply {
favorite = true
}
}

}
2 changes: 2 additions & 0 deletions src/main/kotlin/repository/creditcard/CreditCardRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ interface CreditCardRepository {

suspend fun update(id: UUID, user: String, creditCardDto: CreditCardDto): Result<Boolean>

suspend fun favorite(id: UUID, user: String): Result<Boolean>

}
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,24 @@ class CreditCardRepositoryImpl(
}
}

override suspend fun favorite(id: UUID, user: String): Result<Boolean> {
return try {
return transaction(db) {
CreditCard.findById(id)?.let {
it.favorite = !it.favorite
it.lastUpdateDateTime = LocalDateTime.now()
it.lastUpdatedBy = user
it.version += 1
}
}.let {
Result.Success(true)
}
} catch (e: Exception) {
logger.error(e.message, e)
Result.Error(DatabaseError.fromException(e).extractMessage())
}
}

private fun toSort(sort: CredentialSort): Expression<*> {
return when (sort) {
CredentialSort.NAME -> CreditCardTable.name
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/repository/password/PasswordRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ interface PasswordRepository {

suspend fun update(id: UUID, user: String, password: PasswordDto): Result<Boolean>

suspend fun favorite(id: UUID, user: String): Result<Boolean>

}
18 changes: 18 additions & 0 deletions src/main/kotlin/repository/password/impl/PasswordRepositoryImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,24 @@ class PasswordRepositoryImpl(
}
}

override suspend fun favorite(id: UUID, user: String): Result<Boolean> {
return try {
return transaction(db) {
Password.findById(id)?.let {
it.favorite = !it.favorite
it.lastUpdatedBy = user
it.lastUpdateDateTime = LocalDateTime.now()
it.version += 1
}
}.let {
Result.Success(true)
}
} catch (e: Exception) {
logger.error(e.message, e)
Result.Error(DatabaseError.fromException(e).extractMessage())
}
}

private fun toSort(sort: CredentialSort): Expression<*> {
return when (sort) {
CredentialSort.NAME -> PasswordsTable.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -94,9 +91,9 @@ fun PasswordInfoHeader(screenModel: SecVaultScreenModel) {

Column(
modifier = Modifier.weight(3f)
.fillMaxHeight()
.fillMaxWidth()
.padding(PaddingValues(top = 4.dp)),
.fillMaxHeight()
.fillMaxWidth()
.padding(PaddingValues(top = 4.dp)),
horizontalAlignment = Alignment.End
)
{
Expand All @@ -106,12 +103,26 @@ fun PasswordInfoHeader(screenModel: SecVaultScreenModel) {
)
{
Column() {
Icon(
imageVector = Icons.Default.Star,
contentDescription = "User Icon",
modifier = Modifier.size(24.dp),
tint = Color.White
IconButton(
onClick = {
when (selectedMenu) {
DefaultMenuItem.PASSWORDS,
DefaultMenuItem.CREDIT_CARD,
DefaultMenuItem.NOTES -> {
screenModel.favorite(selectedCredential.getId()!!)
}
}
},
enabled = selectedCredential.isSelected()
)
{
Icon(
imageVector = Icons.Default.Star,
contentDescription = "Favorite Icon",
modifier = Modifier.size(24.dp),
tint = if (selectedCredential.isFavorite()) Color.Yellow else Color.White
)
}
}

Column() {
Expand All @@ -120,14 +131,22 @@ fun PasswordInfoHeader(screenModel: SecVaultScreenModel) {
val navigator = LocalNavigator.current

OutlinedButton(
onClick = { when(selectedMenu) {
DefaultMenuItem.PASSWORDS -> {navigator?.push(PasswordMgntScreen(selectedCredential.password, MODIFIATION))}
DefaultMenuItem.CREDIT_CARD -> {navigator?.push(CreditCardForm(selectedCredential.creditCard, MODIFIATION))}
DefaultMenuItem.NOTES -> TODO()
} },
onClick = {
when (selectedMenu) {
DefaultMenuItem.PASSWORDS -> {
navigator?.push(PasswordMgntScreen(selectedCredential.password, MODIFIATION))
}

DefaultMenuItem.CREDIT_CARD -> {
navigator?.push(CreditCardForm(selectedCredential.creditCard, MODIFIATION))
}

DefaultMenuItem.NOTES -> TODO()
}
},
enabled = selectedCredential.isSelected(),
modifier = Modifier.size(height = 28.dp, width = 62.dp)
.hoverable(interactionSource),
.hoverable(interactionSource),
shape = RoundedCornerShape(size = 4.dp),
contentPadding = PaddingValues(4.dp),
border = BorderStroke(2.dp, color = Color.White),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fun PasswordItem(credentialDisplay: CredentialDisplay, onClick: (id: UUID) -> Un
Row(
modifier = Modifier.height(60.dp).fillMaxWidth()
.background(
if (isHovered) PasswordColors.tertiary else Color.Transparent,
if (isHovered || credentialDisplay.isSelected) PasswordColors.tertiary else Color.Transparent,
shape = RoundedCornerShape(6.dp)
)
.padding(PaddingValues(start = 5.dp, end = 5.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fun PasswordLayout(screenModel: SecVaultScreenModel) {
val creditCards by screenModel.creditCardItems.collectAsState()
val passwordItems by screenModel.passwordItems.collectAsState()
val secVaultState by screenModel.secVaultState.collectAsState()
val selectedCredential by screenModel.selectedCredential.collectAsState()

Column(
modifier = Modifier.padding(PaddingValues(start = 20.dp, end = 20.dp, top = 24.dp, bottom = 20.dp))
Expand Down Expand Up @@ -67,7 +68,8 @@ fun PasswordLayout(screenModel: SecVaultScreenModel) {
id = item.id,
title = item.name,
description = item.email?.takeIf { it.isNotEmpty() } ?: item.username!!,
favorite = item.favorite
favorite = item.favorite,
isSelected = selectedCredential.getId() == item.id
)
},
screenModel
Expand All @@ -83,6 +85,7 @@ fun PasswordLayout(screenModel: SecVaultScreenModel) {
title = item.name,
description = item.number,
favorite = item.favorite,
isSelected = selectedCredential.getId() == item.id
)
},
screenModel
Expand Down
29 changes: 25 additions & 4 deletions src/main/kotlin/viewmodel/SecVaultScreenModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.launch
import repository.creditcard.CreditCard
import repository.creditcard.CreditCardRepository
import repository.creditcard.projection.CreditCardSummary
import repository.password.Password
import repository.password.PasswordRepository
import repository.password.projection.PasswordSummary
import java.util.*
Expand Down Expand Up @@ -72,6 +74,8 @@ class SecVaultScreenModel(
fun loadCredentials() {
screenModelScope.launch(dispatcher) {
_secVaultState.value = UiState.Loading
selectedCredential.value.getId()?.let { loadSelectedCredential(it)}

when (_selectedMenuItem.value) {
DefaultMenuItem.PASSWORDS -> loadPasswords(_selectedSortItem.value)
DefaultMenuItem.CREDIT_CARD -> loadCreditCards(_selectedSortItem.value)
Expand All @@ -91,16 +95,18 @@ class SecVaultScreenModel(
when (_selectedMenuItem.value) {
DefaultMenuItem.PASSWORDS -> {
passwordRepository.findById(id).let { result ->
if (result is Result.Success) {
_selectedCredential.value = SelectedCredential(result.data, null)
when (result) {
is Result.Error -> UiState.Error(result.message)
is Result.Success<Password> -> _selectedCredential.value = SelectedCredential(result.data, null)
}
}
}

DefaultMenuItem.CREDIT_CARD -> {
creditCardRepository.findById(id).let { result ->
if (result is Result.Success) {
_selectedCredential.value = SelectedCredential(null, result.data)
when (result) {
is Result.Error -> UiState.Error(result.message)
is Result.Success<CreditCard> -> _selectedCredential.value = SelectedCredential(null, result.data)
}
}
}
Expand All @@ -110,6 +116,21 @@ class SecVaultScreenModel(
}
}

fun favorite(id: UUID) {
screenModelScope.launch(dispatcher) {
val result = when (selectedMenuItem.value) {
DefaultMenuItem.PASSWORDS -> passwordRepository.favorite(id, appState.userName)
DefaultMenuItem.CREDIT_CARD -> creditCardRepository.favorite(id, appState.userName)
DefaultMenuItem.NOTES -> TODO()
}

when (result) {
is Result.Error -> UiState.Error(result.message)
is Result.Success -> onScreenShown()
}
}
}

private suspend fun loadPasswords(sort: CredentialSort) {
val criteria = CredentialSearchCriteria(appState.getAuthenticatedUser?.id?.value, sort)
_passwordItems.value = when (val passwords = passwordRepository.findSummaries(criteria)) {
Expand Down

0 comments on commit 34f7ce2

Please sign in to comment.