mirror of
https://github.com/yogeshpaliyal/KeyPass.git
synced 2025-12-31 00:59:51 -06:00
KEYPASS-237 | Add sorting options (#475)
This commit is contained in:
committed by
GitHub
parent
321e0d020b
commit
2e6df18677
@@ -15,7 +15,7 @@ android {
|
||||
defaultConfig {
|
||||
|
||||
applicationId appPackageId
|
||||
minSdk 22
|
||||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 1411
|
||||
versionName "1.4.11"
|
||||
@@ -41,8 +41,8 @@ android {
|
||||
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
@@ -171,7 +171,6 @@ dependencies {
|
||||
// ...with Kotlin.
|
||||
kaptTest("com.google.dagger:hilt-android-compiler:$hilt_version")
|
||||
|
||||
|
||||
implementation "org.reduxkotlin:redux-kotlin-compose-jvm:0.6.0"
|
||||
|
||||
implementation "me.saket.cascade:cascade-compose:2.0.0-rc02"
|
||||
}
|
||||
|
||||
@@ -3,12 +3,10 @@ package com.yogeshpaliyal.keypass.ui.home
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.yogeshpaliyal.common.data.AccountModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -25,40 +23,16 @@ class DashboardViewModel @Inject constructor(
|
||||
) :
|
||||
AndroidViewModel(application) {
|
||||
|
||||
val keyword by lazy {
|
||||
MutableLiveData<String>("")
|
||||
}
|
||||
val tag by lazy {
|
||||
MutableLiveData<String?>()
|
||||
}
|
||||
|
||||
private val appDao = appDb.getDao()
|
||||
|
||||
val mediator = MediatorLiveData<List<AccountModel>>()
|
||||
|
||||
init {
|
||||
mediator.addSource(keyword) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
mediator.postValue(appDao.getAllAccounts(keyword.value, tag.value))
|
||||
}
|
||||
}
|
||||
mediator.addSource(tag) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
mediator.postValue(appDao.getAllAccounts(keyword.value, tag.value))
|
||||
}
|
||||
}
|
||||
|
||||
fun queryUpdated(keyword: String?, tag: String?, sortField: String?, sortAscending: Boolean = true) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
mediator.postValue(appDao.getAllAccounts(keyword.value, tag.value))
|
||||
}
|
||||
reloadData()
|
||||
}
|
||||
|
||||
private fun reloadData() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
while (true) {
|
||||
delay(1000)
|
||||
mediator.postValue(appDao.getAllAccounts(keyword.value, tag.value))
|
||||
if (sortAscending) {
|
||||
mediator.postValue(appDao.getAllAccountsAscending(keyword ?: "", tag, sortField))
|
||||
} else {
|
||||
mediator.postValue(appDao.getAllAccountsDescending(keyword ?: "", tag, sortField))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.yogeshpaliyal.keypass.ui.home
|
||||
|
||||
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.lazy.LazyRow
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Close
|
||||
import androidx.compose.material3.AssistChip
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.yogeshpaliyal.keypass.ui.home.components.AccountsList
|
||||
import com.yogeshpaliyal.keypass.ui.home.components.SearchBar
|
||||
import com.yogeshpaliyal.keypass.ui.redux.HomeState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.NavigationAction
|
||||
import com.yogeshpaliyal.keypass.ui.redux.StateUpdateAction
|
||||
import org.reduxkotlin.compose.rememberDispatcher
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
* https://techpaliyal.com
|
||||
* created on 31-01-2021 09:25
|
||||
*/
|
||||
|
||||
@Composable()
|
||||
fun Homepage(
|
||||
mViewModel: DashboardViewModel = viewModel(),
|
||||
homeState: HomeState
|
||||
) {
|
||||
val tag = homeState.tag
|
||||
val keyword = homeState.keyword
|
||||
val sortField = homeState.sortField
|
||||
val sortAscendingOrder = homeState.sortAscending
|
||||
|
||||
val listOfAccountsLiveData by mViewModel.mediator.observeAsState()
|
||||
|
||||
val dispatchAction = rememberDispatcher()
|
||||
|
||||
LaunchedEffect(tag, keyword, sortField, sortAscendingOrder, block = {
|
||||
mViewModel.queryUpdated(keyword, tag, sortField, sortAscendingOrder)
|
||||
})
|
||||
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
SearchBar(keyword, {
|
||||
dispatchAction(StateUpdateAction(homeState.copy(keyword = it)))
|
||||
}) { field, order ->
|
||||
dispatchAction(
|
||||
|
||||
StateUpdateAction(
|
||||
homeState.copy(
|
||||
sortField = field.value,
|
||||
sortAscending = order == SortingOrder.Ascending
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
if (tag != null) {
|
||||
LazyRow(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
content = {
|
||||
item {
|
||||
AssistChip(onClick = { }, label = {
|
||||
Text(text = tag)
|
||||
}, trailingIcon = {
|
||||
IconButton(onClick = {
|
||||
dispatchAction(NavigationAction(HomeState(), true))
|
||||
}) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(image = Icons.Rounded.Close),
|
||||
contentDescription = ""
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
AccountsList(listOfAccountsLiveData)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.yogeshpaliyal.keypass.ui.home
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import com.yogeshpaliyal.keypass.R
|
||||
|
||||
sealed class SortingOrder(@StringRes val label: Int) {
|
||||
object Ascending : SortingOrder(R.string.ascending)
|
||||
object Descending : SortingOrder(R.string.descending)
|
||||
}
|
||||
|
||||
fun getSortingOrderOptions() = mutableListOf(SortingOrder.Ascending, SortingOrder.Descending)
|
||||
|
||||
sealed class SortingField(
|
||||
@StringRes val label: Int,
|
||||
val value: String,
|
||||
val sortingOrders: List<SortingOrder>
|
||||
) {
|
||||
object Title : SortingField(R.string.account_name, "title", getSortingOrderOptions())
|
||||
object Username : SortingField(R.string.username_email_phone, "username", getSortingOrderOptions())
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.yogeshpaliyal.keypass.ui.home
|
||||
package com.yogeshpaliyal.keypass.ui.home.components
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -14,24 +13,19 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Close
|
||||
import androidx.compose.material.icons.twotone.ContentCopy
|
||||
import androidx.compose.material3.AssistChip
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -41,100 +35,19 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.yogeshpaliyal.common.constants.AccountType
|
||||
import com.yogeshpaliyal.common.data.AccountModel
|
||||
import com.yogeshpaliyal.keypass.R
|
||||
import com.yogeshpaliyal.keypass.ui.redux.AccountDetailState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.CopyToClipboard
|
||||
import com.yogeshpaliyal.keypass.ui.redux.HomeState
|
||||
import com.yogeshpaliyal.keypass.ui.redux.IntentNavigation
|
||||
import com.yogeshpaliyal.keypass.ui.redux.NavigationAction
|
||||
import com.yogeshpaliyal.keypass.ui.style.KeyPassTheme
|
||||
import kotlinx.coroutines.delay
|
||||
import org.reduxkotlin.compose.rememberDispatcher
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
/*
|
||||
* @author Yogesh Paliyal
|
||||
* techpaliyal@gmail.com
|
||||
* https://techpaliyal.com
|
||||
* created on 31-01-2021 09:25
|
||||
*/
|
||||
private fun getPassword(model: AccountModel): String {
|
||||
if (model.type == AccountType.TOTP) {
|
||||
return model.getOtp()
|
||||
}
|
||||
return model.password.orEmpty()
|
||||
}
|
||||
|
||||
@Composable()
|
||||
fun Homepage(mViewModel: DashboardViewModel = viewModel(), selectedTag: String?) {
|
||||
val listOfAccountsLiveData by mViewModel.mediator.observeAsState()
|
||||
|
||||
val keyword by mViewModel.keyword.observeAsState()
|
||||
val dispatchAction = rememberDispatcher()
|
||||
|
||||
LaunchedEffect(key1 = selectedTag, block = {
|
||||
if (selectedTag.isNullOrBlank()) {
|
||||
mViewModel.tag.postValue(null)
|
||||
} else {
|
||||
mViewModel.tag.postValue(selectedTag)
|
||||
}
|
||||
})
|
||||
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(1f)
|
||||
.padding(16.dp),
|
||||
value = keyword ?: "",
|
||||
placeholder = {
|
||||
Text(text = "Search Account")
|
||||
},
|
||||
onValueChange = { newValue -> mViewModel.keyword.value = newValue },
|
||||
trailingIcon = {
|
||||
if (keyword.isNullOrBlank().not()) {
|
||||
IconButton(onClick = { mViewModel.keyword.value = "" }) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(image = Icons.Rounded.Close),
|
||||
contentDescription = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (selectedTag != null) {
|
||||
LazyRow(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||
content = {
|
||||
item {
|
||||
AssistChip(onClick = { }, label = {
|
||||
Text(text = selectedTag)
|
||||
}, trailingIcon = {
|
||||
IconButton(onClick = {
|
||||
dispatchAction(NavigationAction(HomeState(), true))
|
||||
}) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(image = Icons.Rounded.Close),
|
||||
contentDescription = ""
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
AccountsList(listOfAccountsLiveData)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AccountsList(accounts: List<AccountModel>? = null) {
|
||||
val dispatch = rememberDispatcher()
|
||||
@@ -167,18 +80,6 @@ fun AccountsList(accounts: List<AccountModel>? = null) {
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewAccount() {
|
||||
KeyPassTheme {
|
||||
Account(
|
||||
accountModel = AccountModel(),
|
||||
onClick = {
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Account(
|
||||
accountModel: AccountModel,
|
||||
@@ -187,7 +88,7 @@ fun Account(
|
||||
val dispatch = rememberDispatcher()
|
||||
|
||||
Card(
|
||||
elevation = androidx.compose.material3.CardDefaults.cardElevation(defaultElevation = 1.dp),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 1.dp),
|
||||
onClick = { onClick(accountModel) }
|
||||
) {
|
||||
Row(modifier = Modifier.padding(12.dp)) {
|
||||
@@ -242,26 +143,6 @@ fun Account(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WrapWithProgress(accountModel: AccountModel) {
|
||||
val (progress, setProgress) = remember { mutableStateOf(0f) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (accountModel.type == AccountType.TOTP) {
|
||||
while (true) {
|
||||
val newProgress = accountModel.getTOtpProgress().toFloat() / 30
|
||||
setProgress(newProgress)
|
||||
delay(1.seconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
progress = progress
|
||||
)
|
||||
}
|
||||
|
||||
private fun getUsernameOrOtp(accountModel: AccountModel): String? {
|
||||
return if (accountModel.type == AccountType.TOTP) accountModel.getOtp() else accountModel.username
|
||||
}
|
||||
@@ -282,7 +163,7 @@ fun RenderUserName(accountModel: AccountModel) {
|
||||
}
|
||||
|
||||
Text(
|
||||
text = username ?: "",
|
||||
text = username,
|
||||
style = MaterialTheme.typography.bodyMedium.merge(
|
||||
TextStyle(
|
||||
fontSize = 14.sp
|
||||
@@ -318,3 +199,30 @@ fun NoDataFound() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPassword(model: AccountModel): String {
|
||||
if (model.type == AccountType.TOTP) {
|
||||
return model.getOtp()
|
||||
}
|
||||
return model.password.orEmpty()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WrapWithProgress(accountModel: AccountModel) {
|
||||
val (progress, setProgress) = remember { mutableStateOf(0f) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (accountModel.type == AccountType.TOTP) {
|
||||
while (true) {
|
||||
val newProgress = accountModel.getTOtpProgress().toFloat() / 30
|
||||
setProgress(newProgress)
|
||||
delay(1.seconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
progress = progress
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.yogeshpaliyal.keypass.ui.home.components
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Close
|
||||
import androidx.compose.material.icons.rounded.Sort
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
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.Modifier
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.yogeshpaliyal.keypass.ui.home.SortingField
|
||||
import com.yogeshpaliyal.keypass.ui.home.SortingOrder
|
||||
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
keyword: String?,
|
||||
updateKeyword: (keyword: String) -> Unit,
|
||||
updateSorting: (SortingField, SortingOrder) -> Unit
|
||||
) {
|
||||
val (isMenuVisible, setMenuVisible) = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(1f)
|
||||
.padding(16.dp),
|
||||
value = keyword ?: "",
|
||||
placeholder = {
|
||||
Text(text = "Search Account")
|
||||
},
|
||||
onValueChange = { newValue ->
|
||||
updateKeyword(newValue)
|
||||
},
|
||||
trailingIcon = {
|
||||
Row {
|
||||
if (keyword.isNullOrBlank().not()) {
|
||||
IconButton(onClick = { updateKeyword("") }) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(image = Icons.Rounded.Close),
|
||||
contentDescription = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(onClick = {
|
||||
setMenuVisible(!isMenuVisible)
|
||||
}) {
|
||||
Icon(
|
||||
painter = rememberVectorPainter(image = Icons.Rounded.Sort),
|
||||
contentDescription = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SortingMenu(isMenuVisible, setMenuVisible) { sortingField, order ->
|
||||
updateSorting(sortingField, order)
|
||||
setMenuVisible(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.yogeshpaliyal.keypass.ui.home.components
|
||||
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.yogeshpaliyal.keypass.ui.home.SortingField
|
||||
import com.yogeshpaliyal.keypass.ui.home.SortingOrder
|
||||
import me.saket.cascade.CascadeDropdownMenu
|
||||
import me.saket.cascade.rememberCascadeState
|
||||
|
||||
@Composable
|
||||
fun SortingMenu(
|
||||
isMenuVisible: Boolean,
|
||||
setMenuVisible: (Boolean) -> Unit,
|
||||
onOptionSelected: (SortingField, SortingOrder) -> Unit
|
||||
) {
|
||||
val state = rememberCascadeState()
|
||||
|
||||
val sortingOptions =
|
||||
remember { mutableListOf(SortingField.Title, SortingField.Username) }
|
||||
|
||||
CascadeDropdownMenu(
|
||||
state = state,
|
||||
expanded = isMenuVisible,
|
||||
onDismissRequest = { setMenuVisible(false) }
|
||||
) {
|
||||
sortingOptions.forEach { sortingField ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = sortingField.label)) },
|
||||
children = {
|
||||
sortingField.sortingOrders.forEach {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = it.label)) },
|
||||
onClick = {
|
||||
onOptionSelected(sortingField, it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ fun CurrentPage() {
|
||||
|
||||
when (currentScreen) {
|
||||
is HomeState -> {
|
||||
Homepage(selectedTag = (currentScreen as HomeState).type)
|
||||
Homepage(homeState = (currentScreen as HomeState))
|
||||
}
|
||||
|
||||
is SettingsState -> {
|
||||
@@ -179,7 +179,7 @@ fun OptionBottomBar(
|
||||
|
||||
is NavigationModelItem.NavTagItem -> {
|
||||
NavMenuFolder(folder = it) {
|
||||
dispatchAction(NavigationAction(HomeState(it.tag), false))
|
||||
dispatchAction(NavigationAction(HomeState(tag = it.tag), false))
|
||||
dispatchAction(BottomSheetAction.HomeNavigationMenu(false))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ data class KeyPassState(
|
||||
|
||||
sealed class ScreenState(val showMainBottomAppBar: Boolean = false)
|
||||
|
||||
data class HomeState(val type: String? = null) : ScreenState(true)
|
||||
data class HomeState(val keyword: String? = null, val tag: String? = null, val sortField: String? = null, val sortAscending: Boolean = true) : ScreenState(true)
|
||||
data class AccountDetailState(val accountId: Long? = null) : ScreenState()
|
||||
data class TotpDetailState(val accountId: String? = null) : ScreenState()
|
||||
object SettingsState : ScreenState(true)
|
||||
|
||||
@@ -82,5 +82,7 @@
|
||||
<string name="restore">पुनर्स्थापित करना</string>
|
||||
<string name="keyphrase_restore_info">कृपया वह कीफ़्रेज़ दर्ज करें जो आपके द्वारा बैक अप लेने पर प्राप्त होता है</string>
|
||||
<string name="custom_generated_keyphrase_info">क्या आप बैकअप के लिए अपना खुद का कीफ्रेज बनाना चाहते हैं या मुझे आपके लिए जनरेट करना चाहिए?</string>
|
||||
<string name="ascending">आरोही</string>
|
||||
<string name="descending">अवरोही</string>
|
||||
|
||||
</resources>
|
||||
@@ -80,5 +80,7 @@
|
||||
<string name="restore">Restaurar</string>
|
||||
<string name="keyphrase_restore_info">Insira a frase-chave que você obteve ao fazer backup</string>
|
||||
<string name="custom_generated_keyphrase_info">Deseja criar sua própria frase-chave para backups ou devo gerar para você?</string>
|
||||
<string name="ascending">Ascendente</string>
|
||||
<string name="descending">descendente</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -81,5 +81,7 @@
|
||||
<string name="restore">恢复</string>
|
||||
<string name="keyphrase_restore_info">请输入您备份时获得的关键词</string>
|
||||
<string name="custom_generated_keyphrase_info">您想创建自己的备份关键字还是我应该为您生成?</string>
|
||||
<string name="ascending">上升</string>
|
||||
<string name="descending">降序</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -80,4 +80,7 @@
|
||||
<string name="keyphrase_restore_info">Please enter keyphrase you get when you backed up</string>
|
||||
<string name="custom_generated_keyphrase_info">Do you want to create your own keyphrase for backups or should I generate for you?</string>
|
||||
|
||||
<string name="ascending">Ascending</string>
|
||||
<string name="descending">Descending</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -40,9 +40,40 @@ interface DbDao {
|
||||
"AND ((username LIKE '%'||:query||'%' ) " +
|
||||
"OR (title LIKE '%'||:query||'%' ) " +
|
||||
"OR (notes LIKE '%'||:query||'%' )) " +
|
||||
"ORDER BY title ASC"
|
||||
"ORDER BY" +
|
||||
" CASE" +
|
||||
" WHEN :sortingField = 'username' THEN username" +
|
||||
" WHEN :sortingField = 'title' THEN title" +
|
||||
" WHEN :sortingField = 'notes' THEN notes" +
|
||||
" END ASC"
|
||||
)
|
||||
fun getAllAccounts(query: String?, tag: String?): List<AccountModel>
|
||||
fun getAllAccountsAscending(
|
||||
query: String?,
|
||||
tag: String?,
|
||||
sortingField: String?
|
||||
): List<AccountModel>
|
||||
|
||||
@Query(
|
||||
"SELECT * FROM account " +
|
||||
"WHERE " +
|
||||
"CASE WHEN :tag IS NOT NULL " +
|
||||
"THEN tags = :tag " +
|
||||
"ELSE 1 END " +
|
||||
"AND ((username LIKE '%'||:query||'%' ) " +
|
||||
"OR (title LIKE '%'||:query||'%' ) " +
|
||||
"OR (notes LIKE '%'||:query||'%' )) " +
|
||||
"ORDER BY" +
|
||||
" CASE" +
|
||||
" WHEN :sortingField = 'username' THEN username" +
|
||||
" WHEN :sortingField = 'title' THEN title" +
|
||||
" WHEN :sortingField = 'notes' THEN notes" +
|
||||
" END DESC"
|
||||
)
|
||||
fun getAllAccountsDescending(
|
||||
query: String?,
|
||||
tag: String?,
|
||||
sortingField: String?
|
||||
): List<AccountModel>
|
||||
|
||||
@Query("SELECT * FROM account WHERE id = :id")
|
||||
suspend fun getAccount(id: Long?): AccountModel?
|
||||
|
||||
Reference in New Issue
Block a user