diff --git a/app/build.gradle b/app/build.gradle index 394b47f7..c1f42353 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/DashboardViewModel.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/DashboardViewModel.kt index 2dec7640..ce7f52a2 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/DashboardViewModel.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/DashboardViewModel.kt @@ -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("") - } - val tag by lazy { - MutableLiveData() - } - private val appDao = appDb.getDao() val mediator = MediatorLiveData>() - 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)) } } } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/Homepage.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/Homepage.kt new file mode 100644 index 00000000..1d9f077f --- /dev/null +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/Homepage.kt @@ -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) + } +} diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/SortingOrders.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/SortingOrders.kt new file mode 100644 index 00000000..a51995d0 --- /dev/null +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/SortingOrders.kt @@ -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 +) { + object Title : SortingField(R.string.account_name, "title", getSortingOrderOptions()) + object Username : SortingField(R.string.username_email_phone, "username", getSortingOrderOptions()) +} diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/HomeFragment.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/AccountsList.kt similarity index 68% rename from app/src/main/java/com/yogeshpaliyal/keypass/ui/home/HomeFragment.kt rename to app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/AccountsList.kt index acea9f7e..5fa99d36 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/AccountsList.kt @@ -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? = null) { val dispatch = rememberDispatcher() @@ -167,18 +80,6 @@ fun AccountsList(accounts: List? = 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 + ) +} diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/SearchBar.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/SearchBar.kt new file mode 100644 index 00000000..ecf5e005 --- /dev/null +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/SearchBar.kt @@ -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) + } + } + ) +} diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/SortingMenu.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/SortingMenu.kt new file mode 100644 index 00000000..29141775 --- /dev/null +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/home/components/SortingMenu.kt @@ -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) + } + ) + } + } + ) + } + } +} diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt index b3fe5db5..bd72b6a6 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt @@ -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)) } } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/State.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/State.kt index 23618b1f..08cf046b 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/State.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/State.kt @@ -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) diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 05d800e5..48e361c3 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -82,5 +82,7 @@ पुनर्स्थापित करना कृपया वह कीफ़्रेज़ दर्ज करें जो आपके द्वारा बैक अप लेने पर प्राप्त होता है क्या आप बैकअप के लिए अपना खुद का कीफ्रेज बनाना चाहते हैं या मुझे आपके लिए जनरेट करना चाहिए? + आरोही + अवरोही \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index d41c1155..572870e8 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -80,5 +80,7 @@ Restaurar Insira a frase-chave que você obteve ao fazer backup Deseja criar sua própria frase-chave para backups ou devo gerar para você? + Ascendente + descendente diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index e12778cc..8d35e9c3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -81,5 +81,7 @@ 恢复 请输入您备份时获得的关键词 您想创建自己的备份关键字还是我应该为您生成? + 上升 + 降序 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d5ebdfd0..d32ad7d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -80,4 +80,7 @@ Please enter keyphrase you get when you backed up Do you want to create your own keyphrase for backups or should I generate for you? + Ascending + Descending + diff --git a/common/src/main/java/com/yogeshpaliyal/common/db/DbDao.kt b/common/src/main/java/com/yogeshpaliyal/common/db/DbDao.kt index 1fefa020..0afd660d 100644 --- a/common/src/main/java/com/yogeshpaliyal/common/db/DbDao.kt +++ b/common/src/main/java/com/yogeshpaliyal/common/db/DbDao.kt @@ -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 + fun getAllAccountsAscending( + query: String?, + tag: String?, + sortingField: String? + ): List + + @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 @Query("SELECT * FROM account WHERE id = :id") suspend fun getAccount(id: Long?): AccountModel?