diff --git a/screen/reports/src/main/java/com/ivy/reports/FilterOverlay.kt b/screen/reports/src/main/java/com/ivy/reports/FilterOverlay.kt index 8aad381444..63ac3391fe 100644 --- a/screen/reports/src/main/java/com/ivy/reports/FilterOverlay.kt +++ b/screen/reports/src/main/java/com/ivy/reports/FilterOverlay.kt @@ -132,10 +132,16 @@ fun BoxWithConstraintsScope.FilterOverlay( var maxAmountModalShown by remember { mutableStateOf(false) } var includeKeywordModalShown by remember { mutableStateOf(false) } var excludeKeywordModalShown by remember { mutableStateOf(false) } - var tagModalVisible by remember { mutableStateOf(false) } - val selectedTags by remember(localFilter) { + var includedTagModalVisible by remember { mutableStateOf(false) } + var excludedTagModalVisible by remember { mutableStateOf(false) } + val includedTags by remember(localFilter) { derivedStateOf { - localFilter?.selectedTags?.toImmutableList() ?: persistentListOf() + localFilter?.includedTags?.toImmutableList() ?: persistentListOf() + } + } + val excludedTags by remember(localFilter) { + derivedStateOf { + localFilter?.excludedTags?.toImmutableList() ?: persistentListOf() } } @@ -272,10 +278,13 @@ fun BoxWithConstraintsScope.FilterOverlay( FilterDivider() - OthersFilter( + TagsFilter( filter = localFilter, - onTagButtonClick = { - tagModalVisible = true + onIncludesTagButtonClick = { + includedTagModalVisible = true + }, + onExcludesTagButtonClick = { + excludedTagModalVisible = true } ) @@ -396,15 +405,49 @@ fun BoxWithConstraintsScope.FilterOverlay( } ShowTagModal( - visible = tagModalVisible, + visible = includedTagModalVisible, + selectOnlyMode = true, + onDismiss = { + includedTagModalVisible = false + // Reset TagList, avoids showing incorrect tag list if user had searched for a tag previously + onTagSearch("") + }, + allTagList = allTags, + selectedTagList = includedTags, + onTagAdd = { + // Do Nothing + }, + onTagEdit = { oldTag, newTag -> + // Do Nothing + }, + onTagDelete = { + // Do Nothing + }, + onTagSelected = { + localFilter = nonNullFilter(localFilter).copy( + includedTags = nonNullFilter(localFilter).includedTags.plus(it.id) + ) + }, + onTagDeSelected = { + localFilter = nonNullFilter(localFilter).copy( + includedTags = nonNullFilter(localFilter).includedTags.minus(it.id) + ) + }, + onTagSearch = { + onTagSearch(it) + } + ) + + ShowTagModal( + visible = excludedTagModalVisible, selectOnlyMode = true, onDismiss = { - tagModalVisible = false + excludedTagModalVisible = false // Reset TagList, avoids showing incorrect tag list if user had searched for a tag previously onTagSearch("") }, allTagList = allTags, - selectedTagList = selectedTags, + selectedTagList = excludedTags, onTagAdd = { // Do Nothing }, @@ -416,12 +459,12 @@ fun BoxWithConstraintsScope.FilterOverlay( }, onTagSelected = { localFilter = nonNullFilter(localFilter).copy( - selectedTags = nonNullFilter(localFilter).selectedTags.plus(it.id) + excludedTags = nonNullFilter(localFilter).excludedTags.plus(it.id) ) }, onTagDeSelected = { localFilter = nonNullFilter(localFilter).copy( - selectedTags = nonNullFilter(localFilter).selectedTags.minus(it.id) + excludedTags = nonNullFilter(localFilter).excludedTags.minus(it.id) ) }, onTagSearch = { @@ -431,18 +474,45 @@ fun BoxWithConstraintsScope.FilterOverlay( } @Composable -fun ColumnScope.OthersFilter( +fun ColumnScope.TagsFilter( filter: ReportFilter?, - onTagButtonClick: () -> Unit, + onIncludesTagButtonClick: () -> Unit, + onExcludesTagButtonClick: () -> Unit, + @Suppress("UnusedParameter") modifier: Modifier = Modifier ) { FilterTitleText( - text = stringResource(R.string.others_optional), + text = stringResource(R.string.tags_optional), active = false ) + Spacer(Modifier.height(12.dp)) + + Text( + modifier = Modifier.padding(start = 32.dp), + text = stringResource(R.string.includes_uppercase), + style = UI.typo.b2.style( + fontWeight = FontWeight.ExtraBold + ) + ) + + TagFilter( + selectedTags = filter?.includedTags?.toImmutableList() ?: persistentListOf(), + onTagButtonClick = onIncludesTagButtonClick, + ) + + Spacer(Modifier.height(20.dp)) + + Text( + modifier = Modifier.padding(start = 32.dp), + text = stringResource(R.string.excludes_uppercase), + style = UI.typo.b2.style( + fontWeight = FontWeight.ExtraBold + ) + ) + TagFilter( - selectedTags = filter?.selectedTags?.toImmutableList() ?: persistentListOf(), - onTagButtonClick = onTagButtonClick, + selectedTags = filter?.excludedTags?.toImmutableList() ?: persistentListOf(), + onTagButtonClick = onExcludesTagButtonClick, ) } @@ -452,14 +522,6 @@ fun ColumnScope.TagFilter( onTagButtonClick: () -> Unit, @Suppress("UnusedParameter") modifier: Modifier = Modifier ) { - Text( - modifier = Modifier.padding(start = 32.dp, top = 16.dp), - text = stringResource(R.string.tags), - style = UI.typo.b2.style( - fontWeight = FontWeight.ExtraBold - ) - ) - Spacer(Modifier.height(12.dp)) if (selectedTags.isEmpty()) { diff --git a/screen/reports/src/main/java/com/ivy/reports/ReportFilter.kt b/screen/reports/src/main/java/com/ivy/reports/ReportFilter.kt index 35c4abc52e..33bad9d880 100644 --- a/screen/reports/src/main/java/com/ivy/reports/ReportFilter.kt +++ b/screen/reports/src/main/java/com/ivy/reports/ReportFilter.kt @@ -18,7 +18,9 @@ data class ReportFilter( val maxAmount: Double?, val includeKeywords: List, val excludeKeywords: List, - val selectedTags: List + val includedTags: List, + val excludedTags: List, + ) { companion object { fun emptyFilter( @@ -33,7 +35,8 @@ data class ReportFilter( excludeKeywords = emptyList(), minAmount = null, maxAmount = null, - selectedTags = emptyList() + includedTags = emptyList(), + excludedTags = emptyList() ) } diff --git a/screen/reports/src/main/java/com/ivy/reports/ReportViewModel.kt b/screen/reports/src/main/java/com/ivy/reports/ReportViewModel.kt index 968c18ba27..0febff6874 100644 --- a/screen/reports/src/main/java/com/ivy/reports/ReportViewModel.kt +++ b/screen/reports/src/main/java/com/ivy/reports/ReportViewModel.kt @@ -111,9 +111,9 @@ class ReportViewModel @Inject constructor( private var overdueExpenses by mutableDoubleStateOf(0.0) private var history by mutableStateOf>(persistentListOf()) private var upcomingTransactions by - mutableStateOf>(persistentListOf()) + mutableStateOf>(persistentListOf()) private var overdueTransactions by - mutableStateOf>(persistentListOf()) + mutableStateOf>(persistentListOf()) private var accounts by mutableStateOf>(persistentListOf()) private var upcomingExpanded by mutableStateOf(false) private var overdueExpanded by mutableStateOf(false) @@ -375,8 +375,8 @@ class ReportViewModel @Inject constructor( val filterRange = filter.period?.toRange(ivyContext.startDayOfMonth, timeConverter, timeProvider) - val transactions = if (filter.selectedTags.isNotEmpty()) { - tagRepository.findByAllAssociatedIdForTagId(filter.selectedTags) + val transactions = if (filter.includedTags.isNotEmpty()) { + tagRepository.findByAllAssociatedIdForTagId(filter.includedTags) .asSequence() .flatMap { it.value } .map { TransactionId(it.associatedId.value) } @@ -389,7 +389,24 @@ class ReportViewModel @Inject constructor( transactionRepository.findAll() } + val excludeableByTagTransactionsIds = if (filter.excludedTags.isNotEmpty()) { + tagRepository.findByAllAssociatedIdForTagId(filter.excludedTags) + .asSequence() + .flatMap { it.value } + .distinct() + .map { TransactionId(it.associatedId.value) } + .toList() + .let { + transactionRepository.findByIds(it) + }.map { + it.id + } + } else { + emptyList() + } + return transactions + .filter { !excludeableByTagTransactionsIds.contains(it.id) } .filter { with(transactionMapper) { filter.trnTypes.contains(it.getTransactionType()) diff --git a/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen no filter[Dark].png b/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen no filter[Dark].png index 1e8097f0fa..2cb02e579b 100644 Binary files a/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen no filter[Dark].png and b/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen no filter[Dark].png differ diff --git a/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen no filter[Light].png b/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen no filter[Light].png index f613991216..ed3f774020 100644 Binary files a/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen no filter[Light].png and b/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen no filter[Light].png differ diff --git a/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen[Dark].png b/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen[Dark].png index 284c34c880..9499ab9d66 100644 Binary files a/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen[Dark].png and b/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen[Dark].png differ diff --git a/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen[Light].png b/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen[Light].png index 1988435d01..3f1ded06c6 100644 Binary files a/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen[Light].png and b/screen/reports/src/test/snapshots/images/com.ivy.report_ReportPaparazziTest_snapshot Report Screen[Light].png differ diff --git a/shared/ui/core/src/main/res/values-de/strings.xml b/shared/ui/core/src/main/res/values-de/strings.xml index b2fb198b0e..c5340a4a65 100644 --- a/shared/ui/core/src/main/res/values-de/strings.xml +++ b/shared/ui/core/src/main/res/values-de/strings.xml @@ -448,7 +448,7 @@ Verringern Wähle das Ziel für den Übertrag Wählen ein anders Ziel-Konto für den Übertrag - Andere (optional) + Tags (optional) Tags Tags durchsuchen Wechselkurse diff --git a/shared/ui/core/src/main/res/values-it/strings.xml b/shared/ui/core/src/main/res/values-it/strings.xml index 3d5ea47da4..7265398c84 100644 --- a/shared/ui/core/src/main/res/values-it/strings.xml +++ b/shared/ui/core/src/main/res/values-it/strings.xml @@ -450,7 +450,7 @@ Diminuzione Seleziona la destinazione del trasferimento Selezionare un altro conto come destinazione per il trasferimento - Altro (opzionale) + Tags (optional) Etichette Tag di Ricerca Tassi di cambio diff --git a/shared/ui/core/src/main/res/values-pt-rBR/strings.xml b/shared/ui/core/src/main/res/values-pt-rBR/strings.xml index dc1e8e1fc0..58661ec336 100644 --- a/shared/ui/core/src/main/res/values-pt-rBR/strings.xml +++ b/shared/ui/core/src/main/res/values-pt-rBR/strings.xml @@ -450,7 +450,7 @@ Diminuir Selecione o destino da transferência Selecione uma conta de destino diferente para a transferência - Outro (opcional) + Tags (optional) Tags Pesquisar Tags Taxas de câmbio diff --git a/shared/ui/core/src/main/res/values-vi/strings.xml b/shared/ui/core/src/main/res/values-vi/strings.xml index 39e11f2f9a..11088cdee5 100644 --- a/shared/ui/core/src/main/res/values-vi/strings.xml +++ b/shared/ui/core/src/main/res/values-vi/strings.xml @@ -449,7 +449,7 @@ Giảm Chọn tài khoản đích Chọn một tài khoản đích khác để chuyển - Khác (tùy chọn) + Tags (optional) Thẻ Tìm thẻ Các tỷ giá hối đoái diff --git a/shared/ui/core/src/main/res/values-zh-rCN/strings.xml b/shared/ui/core/src/main/res/values-zh-rCN/strings.xml index dcb0025bdc..6d83d63675 100644 --- a/shared/ui/core/src/main/res/values-zh-rCN/strings.xml +++ b/shared/ui/core/src/main/res/values-zh-rCN/strings.xml @@ -450,7 +450,7 @@ 减少 选择转账目标账户 请选择不同的目标账户进行转账 - 其他(可选) + Tags (optional) 标签 搜索标签 汇率 diff --git a/shared/ui/core/src/main/res/values-zh-rTW/strings.xml b/shared/ui/core/src/main/res/values-zh-rTW/strings.xml index cbad635d01..30db2b29cb 100644 --- a/shared/ui/core/src/main/res/values-zh-rTW/strings.xml +++ b/shared/ui/core/src/main/res/values-zh-rTW/strings.xml @@ -453,7 +453,7 @@ 減少 選擇傳輸目的地 選擇不同的目標帳戶進行轉帳 - 其他 (可選) + Tags (optional) 標籤 搜尋標籤 匯率 diff --git a/shared/ui/core/src/main/res/values/strings.xml b/shared/ui/core/src/main/res/values/strings.xml index 4b9184a7e1..8fb0dc95c0 100644 --- a/shared/ui/core/src/main/res/values/strings.xml +++ b/shared/ui/core/src/main/res/values/strings.xml @@ -453,7 +453,7 @@ Decrease Select the transfer destination Select a different destination account for the transfer - Other (optional) + Tags (optional) Tags Search Tags Exchange rates