Skip to content

Commit

Permalink
Added functionality to search data (#116)
Browse files Browse the repository at this point in the history
* started with search in all info frag

Signed-off-by: Nitin Verma <canvas.nv@gmail.com>

* removed add data success snackbar

Signed-off-by: Nitin Verma <canvas.nv@gmail.com>

* added search in all screens

Signed-off-by: Nitin Verma <canvas.nv@gmail.com>

* minor lint fix

Signed-off-by: Nitin Verma <canvas.nv@gmail.com>

* Updated readme

Signed-off-by: Nitin Verma <canvas.nv@gmail.com>

* increased version

Signed-off-by: Nitin Verma <canvas.nv@gmail.com>

* extracted string res

Signed-off-by: Nitin Verma <canvas.nv@gmail.com>
  • Loading branch information
Ni3verma authored Dec 5, 2021
1 parent c92484a commit 036428d
Show file tree
Hide file tree
Showing 25 changed files with 220 additions and 72 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Safe Box is an easy to use, secure app which will store all your data in a super
</br></br>

<img src="./screenshots/readme/backupAndRestore.png" height="400px" width = "200px"/>&emsp;
<img src="./screenshots/readme/searchData.png" height="400px" width = "200px"/>&emsp;

<hr>

Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ android {
applicationId "com.andryoga.safebox"
minSdkVersion 23
targetSdkVersion 30
versionCode 6
versionCode 7
// majorVersion.minorVersion.dbVersion.fixVersion
versionName "1.4.4.0"
versionName "1.5.4.0"

//room.incremental: Enables Gradle incremental annotation processor
//room.expandProjection: Configures Room to rewrite queries such that their top star projection is expanded to only contain the columns defined in the DAO method return type.
Expand Down
12 changes: 11 additions & 1 deletion app/src/main/java/com/andryoga/safebox/ui/view/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class MainActivity : AppCompatActivity() {
drawerLayout = binding.drawerLayout
binding.lifecycleOwner = this

setSupportActionBar(findViewById(R.id.my_toolbar))

// top level navigation for which back button should not appear
appBarConfiguration = AppBarConfiguration(
drawerLayoutTopLevelNavigationIds,
Expand Down Expand Up @@ -150,7 +152,15 @@ class MainActivity : AppCompatActivity() {

fun setSupportActionBarVisibility(isVisible: Boolean) {
Timber.i("setting support action bar visibility to $isVisible")
if (isVisible) supportActionBar?.show() else supportActionBar?.hide()
if (isVisible) {
supportActionBar?.show()
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
} else {
supportActionBar?.hide()
// doing below so that even sliding from screen start to end
// doesn't open the drawer
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
}
}

// this is directly called from xml so view input param is required
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.andryoga.safebox.ui.view.home.child.all

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.*
import androidx.appcompat.widget.SearchView
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
Expand Down Expand Up @@ -48,8 +47,10 @@ class AllInfoFragment : Fragment() {
savedInstanceState: Bundle?
): View {
Timber.i("on create view of all info fragment")
setHasOptionsMenu(true)
return ComposeView(requireContext()).apply {
setContent {
val searchTextFilter by viewModel.searchTextFilter.collectAsState()
val listData by viewModel.allData.collectAsState(
initial = Resource.loading(
emptyList()
Expand All @@ -64,11 +65,12 @@ class AllInfoFragment : Fragment() {
}
UserDataList(
listResource = listData,
searchTextFilter = searchTextFilter,
onItemClick = { onListItemClick(it) },
onDeleteItemClick = { viewModel.onDeleteItemClick(it) }
)
}
AddNewDataFab() {
AddNewDataFab {
findNavController()
.navigate(R.id.action_nav_all_info_to_addNewUserPersonalDataDialogFragment)
}
Expand All @@ -89,6 +91,22 @@ class AllInfoFragment : Fragment() {
}
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.home_info_screen, menu)
val searchView = menu.findItem(R.id.action_search).actionView as SearchView

searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}

override fun onQueryTextChange(newText: String?): Boolean {
viewModel.setSearchText(newText)
return true
}
})
}

private fun onListItemClick(item: UserListItemData) {
val id = item.id
Timber.i("clicked $id - ${item.type.name}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ class AllInfoViewModel @Inject constructor(
private val secureNoteDataRepository: SecureNoteDataRepository,
private val backupMetadataRepository: BackupMetadataRepository
) : ViewModel() {
private val _isBackupPathSet = MutableStateFlow<Boolean>(true)
private val _isBackupPathSet = MutableStateFlow(true)
val isBackupPathSet: StateFlow<Boolean> = _isBackupPathSet

private val _searchTextFilter = MutableStateFlow<String?>(null)
val searchTextFilter: StateFlow<String?> = _searchTextFilter

init {
viewModelScope.launch(Dispatchers.IO) {
backupMetadataRepository.getBackupMetadata().collect {
Expand Down Expand Up @@ -158,6 +161,10 @@ class AllInfoViewModel @Inject constructor(
}
}

fun setSearchText(searchText: String?) {
_searchTextFilter.value = searchText
}

// This method is for test purpose only
// should never be called in production code
fun insertDummyData() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.andryoga.safebox.ui.view.home.child.bankAccountInfo

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.*
import androidx.appcompat.widget.SearchView
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
Expand All @@ -30,9 +29,10 @@ class BankAccountInfoFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
setHasOptionsMenu(true)
return ComposeView(requireContext()).apply {

setContent {
val searchTextFilter by viewModel.searchTextFilter.collectAsState()
val listData by viewModel.listData.collectAsState(
initial = Resource.loading(
emptyList()
Expand All @@ -41,10 +41,11 @@ class BankAccountInfoFragment : Fragment() {
BasicSafeBoxTheme {
UserDataList(
listResource = listData,
searchTextFilter = searchTextFilter,
onItemClick = { onListItemClick(it) },
onDeleteItemClick = { viewModel.onDeleteItemClick(it) }
)
AddNewDataFab() {
AddNewDataFab {
findNavController()
.navigate(R.id.action_nav_bank_account_info_to_addNewUserPersonalDataDialogFragment)
}
Expand All @@ -53,6 +54,22 @@ class BankAccountInfoFragment : Fragment() {
}
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.home_info_screen, menu)
val searchView = menu.findItem(R.id.action_search).actionView as SearchView

searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}

override fun onQueryTextChange(newText: String?): Boolean {
viewModel.setSearchText(newText)
return true
}
})
}

private fun onListItemClick(item: UserListItemData) {
Timber.i("clicked ${item.id}")
findNavController().navigate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ import com.andryoga.safebox.ui.common.UserDataType
import com.andryoga.safebox.ui.view.home.child.common.UserListItemData
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class BankAccountInfoViewModel @Inject constructor(
private val bankAccountDataRepository: BankAccountDataRepository
) : ViewModel() {

private val _searchTextFilter = MutableStateFlow<String?>(null)
val searchTextFilter: StateFlow<String?> = _searchTextFilter

val listData = flow<Resource<List<UserListItemData>>> {
bankAccountDataRepository
.getAllBankAccountData()
Expand Down Expand Up @@ -48,4 +49,8 @@ class BankAccountInfoViewModel @Inject constructor(
bankAccountDataRepository.deleteBankAccountDataByKey(key)
}
}

fun setSearchText(searchText: String?) {
_searchTextFilter.value = searchText
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.andryoga.safebox.ui.view.home.child.bankCardInfo

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.*
import androidx.appcompat.widget.SearchView
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
Expand All @@ -30,9 +29,10 @@ class BankCardInfoFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
setHasOptionsMenu(true)
return ComposeView(requireContext()).apply {

setContent {
val searchTextFilter by viewModel.searchTextFilter.collectAsState()
val listData by viewModel.listData.collectAsState(
initial = Resource.loading(
emptyList()
Expand All @@ -41,10 +41,11 @@ class BankCardInfoFragment : Fragment() {
BasicSafeBoxTheme {
UserDataList(
listResource = listData,
searchTextFilter = searchTextFilter,
onItemClick = { onListItemClick(it) },
onDeleteItemClick = { viewModel.onDeleteItemClick(it) }
)
AddNewDataFab() {
AddNewDataFab {
findNavController()
.navigate(R.id.action_nav_bank_card_info_to_addNewUserPersonalDataDialogFragment)
}
Expand All @@ -53,6 +54,22 @@ class BankCardInfoFragment : Fragment() {
}
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.home_info_screen, menu)
val searchView = menu.findItem(R.id.action_search).actionView as SearchView

searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}

override fun onQueryTextChange(newText: String?): Boolean {
viewModel.setSearchText(newText)
return true
}
})
}

private fun onListItemClick(item: UserListItemData) {
Timber.i("clicked ${item.id}")
findNavController().navigate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ import com.andryoga.safebox.ui.common.UserDataType
import com.andryoga.safebox.ui.view.home.child.common.UserListItemData
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class BankCardInfoViewModel @Inject constructor(
private val bankCardDataRepository: BankCardDataRepository
) : ViewModel() {

private val _searchTextFilter = MutableStateFlow<String?>(null)
val searchTextFilter: StateFlow<String?> = _searchTextFilter

val listData = flow<Resource<List<UserListItemData>>> {
bankCardDataRepository
.getAllBankCardData()
Expand Down Expand Up @@ -48,4 +49,8 @@ class BankCardInfoViewModel @Inject constructor(
bankCardDataRepository.deleteBankCardDataByKey(key)
}
}

fun setSearchText(searchText: String?) {
_searchTextFilter.value = searchText
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ private val typeToTextMap = mapOf(
@Composable
fun UserDataList(
listResource: Resource<List<UserListItemData>>,
searchTextFilter: String?,
onItemClick: (item: UserListItemData) -> Unit,
onDeleteItemClick: (id: UserListItemData) -> Unit
) {
Expand All @@ -58,8 +59,15 @@ fun UserDataList(
}
}
Status.SUCCESS -> {
// In success state, if there was no data then show empty view other show list of data
val list = listResource.data
// In success state, if there was no data then show empty view otherwise show list of data
val list = if (searchTextFilter == null) {
listResource.data
} else {
listResource.data?.filter {
it.title.contains(searchTextFilter, ignoreCase = true) ||
it.subTitle?.contains(searchTextFilter, ignoreCase = true) == true
}
}
if (list.isNullOrEmpty()) {
EmptyUserData()
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.andryoga.safebox.ui.view.home.child.loginInfo

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.*
import androidx.appcompat.widget.SearchView
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
Expand All @@ -30,8 +29,10 @@ class LoginInfoFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
setHasOptionsMenu(true)
return ComposeView(requireContext()).apply {
setContent {
val searchTextFilter by viewModel.searchTextFilter.collectAsState()
val listData by viewModel.listData.collectAsState(
initial = Resource.loading(
emptyList()
Expand All @@ -40,10 +41,11 @@ class LoginInfoFragment : Fragment() {
BasicSafeBoxTheme {
UserDataList(
listResource = listData,
searchTextFilter = searchTextFilter,
onItemClick = { onListItemClick(it) },
onDeleteItemClick = { viewModel.onDeleteItemClick(it) }
)
AddNewDataFab() {
AddNewDataFab {
findNavController()
.navigate(R.id.action_nav_login_info_to_addNewUserPersonalDataDialogFragment)
}
Expand All @@ -52,6 +54,22 @@ class LoginInfoFragment : Fragment() {
}
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.home_info_screen, menu)
val searchView = menu.findItem(R.id.action_search).actionView as SearchView

searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}

override fun onQueryTextChange(newText: String?): Boolean {
viewModel.setSearchText(newText)
return true
}
})
}

private fun onListItemClick(item: UserListItemData) {
Timber.i("clicked ${item.id}")
findNavController().navigate(
Expand Down
Loading

0 comments on commit 036428d

Please sign in to comment.