diff --git a/app/src/main/java/com/electricdreams/numo/feature/history/DateFilterBottomSheet.kt b/app/src/main/java/com/electricdreams/numo/feature/history/DateFilterBottomSheet.kt new file mode 100644 index 000000000..050fcfbb5 --- /dev/null +++ b/app/src/main/java/com/electricdreams/numo/feature/history/DateFilterBottomSheet.kt @@ -0,0 +1,119 @@ +package com.electricdreams.numo.feature.history + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.core.content.ContextCompat +import androidx.core.os.bundleOf +import androidx.fragment.app.setFragmentResult +import com.electricdreams.numo.R +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import java.util.Calendar + +class DateFilterBottomSheet : BottomSheetDialogFragment() { + + override fun getTheme(): Int = R.style.Theme_Numo_BottomSheet + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? = inflater.inflate(R.layout.bottom_sheet_date_filter, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val currentStart = arguments?.getLong(ARG_CURRENT_START, 0L) ?: 0L + val currentEnd = arguments?.getLong(ARG_CURRENT_END, 0L) ?: 0L + if (currentStart == 0L && currentEnd == 0L) { + view.findViewById(R.id.check_all_time).visibility = View.VISIBLE + } + + view.findViewById(R.id.row_all_time).setOnClickListener { send(0L, 0L) } + view.findViewById(R.id.row_last_7).setOnClickListener { + val (s, e) = preset(daysBack = 7) + send(s, e) + } + view.findViewById(R.id.row_last_30).setOnClickListener { + val (s, e) = preset(daysBack = 30) + send(s, e) + } + view.findViewById(R.id.row_this_month).setOnClickListener { + send(startOfThisMonthLocal(), System.currentTimeMillis()) + } + view.findViewById(R.id.row_custom).setOnClickListener { + send(SENTINEL_CUSTOM, 0L) + } + + setupBottomSheetBehavior() + } + + private fun setupBottomSheetBehavior() { + dialog?.setOnShowListener { dialogInterface -> + val bottomSheetDialog = dialogInterface as BottomSheetDialog + val bottomSheet = bottomSheetDialog.findViewById( + com.google.android.material.R.id.design_bottom_sheet + ) ?: return@setOnShowListener + bottomSheet.setBackgroundColor( + ContextCompat.getColor(requireContext(), R.color.color_bg_white) + ) + BottomSheetBehavior.from(bottomSheet).apply { + state = BottomSheetBehavior.STATE_EXPANDED + skipCollapsed = true + isDraggable = true + } + } + } + + private fun send(start: Long, end: Long) { + setFragmentResult( + RESULT_KEY, + bundleOf(RESULT_START to start, RESULT_END to end) + ) + dismiss() + } + + private fun preset(daysBack: Int): Pair { + val now = System.currentTimeMillis() + val start = Calendar.getInstance().apply { + timeInMillis = now + add(Calendar.DAY_OF_YEAR, -daysBack) + set(Calendar.HOUR_OF_DAY, 0) + clear(Calendar.MINUTE) + clear(Calendar.SECOND) + clear(Calendar.MILLISECOND) + }.timeInMillis + return start to now + } + + private fun startOfThisMonthLocal(): Long = Calendar.getInstance().apply { + set(Calendar.DAY_OF_MONTH, 1) + set(Calendar.HOUR_OF_DAY, 0) + clear(Calendar.MINUTE) + clear(Calendar.SECOND) + clear(Calendar.MILLISECOND) + }.timeInMillis + + companion object { + const val TAG = "DateFilterBottomSheet" + const val RESULT_KEY = "date_filter_result" + const val RESULT_START = "start" + const val RESULT_END = "end" + const val SENTINEL_CUSTOM = -1L + + private const val ARG_CURRENT_START = "current_start" + private const val ARG_CURRENT_END = "current_end" + + fun newInstance(currentStart: Long, currentEnd: Long): DateFilterBottomSheet = + DateFilterBottomSheet().apply { + arguments = bundleOf( + ARG_CURRENT_START to currentStart, + ARG_CURRENT_END to currentEnd, + ) + } + } +} diff --git a/app/src/main/java/com/electricdreams/numo/feature/history/PaymentsHistoryActivity.kt b/app/src/main/java/com/electricdreams/numo/feature/history/PaymentsHistoryActivity.kt index 8753fc9fa..b63ee5d03 100644 --- a/app/src/main/java/com/electricdreams/numo/feature/history/PaymentsHistoryActivity.kt +++ b/app/src/main/java/com/electricdreams/numo/feature/history/PaymentsHistoryActivity.kt @@ -12,6 +12,7 @@ import com.electricdreams.numo.util.createProgressDialog import com.electricdreams.numo.util.startActivityForResultCompat import android.view.View import android.widget.Toast +import com.google.android.material.chip.Chip import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog @@ -66,8 +67,6 @@ class PaymentsHistoryActivity : AppCompatActivity() { } } - private var isFiltersExpanded = false - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityHistoryBinding.inflate(layoutInflater) @@ -95,7 +94,13 @@ class PaymentsHistoryActivity : AppCompatActivity() { binding.historyRecyclerView.adapter = adapter binding.historyRecyclerView.layoutManager = LinearLayoutManager(this) - setupFilterBar() + migrateLegacyFilterStateIfNeeded() + registerDateFilterResultListener() + findViewById(R.id.active_filter_indicator).apply { + setOnClickListener { clearAllFilters() } + setOnCloseIconClickListener { clearAllFilters() } + } + updateActiveFilterIndicator() // Load and display history loadHistory() @@ -333,75 +338,90 @@ class PaymentsHistoryActivity : AppCompatActivity() { .show() } - private fun setupFilterBar() { + private fun migrateLegacyFilterStateIfNeeded() { val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE) - updateFilterButtonTexts() + if (!prefs.contains(LEGACY_KEY_FILTER_STATE) || prefs.contains(KEY_HIDE_PENDING)) return + val legacy = prefs.getInt(LEGACY_KEY_FILTER_STATE, LEGACY_FILTER_PAID) + val hidePending = legacy == LEGACY_FILTER_PAID + prefs.edit() + .putBoolean(KEY_HIDE_PENDING, hidePending) + .remove(LEGACY_KEY_FILTER_STATE) + .apply() + } - binding.filterHeader?.setOnClickListener { - toggleFilters() - } + private fun togglePending() { + val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE) + val current = prefs.getBoolean(KEY_HIDE_PENDING, true) + prefs.edit().putBoolean(KEY_HIDE_PENDING, !current).apply() + updateActiveFilterIndicator() + loadHistory() + } - binding.btnFilterStatus?.setOnClickListener { view -> - val popup = PopupMenu(this, view) - popup.menuInflater.inflate(R.menu.menu_filter_status, popup.menu) - - val filterState = prefs.getInt(KEY_FILTER_STATE, FILTER_PAID) - when (filterState) { - FILTER_PAID -> popup.menu.findItem(R.id.filter_status_paid)?.isChecked = true - FILTER_PENDING -> popup.menu.findItem(R.id.filter_status_pending)?.isChecked = true - FILTER_ALL -> popup.menu.findItem(R.id.filter_status_all)?.isChecked = true - } + private fun clearAllFilters() { + getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit() + .putBoolean(KEY_HIDE_PENDING, true) + .putLong(KEY_FILTER_DATE_START, 0L) + .putLong(KEY_FILTER_DATE_END, 0L) + .apply() + updateActiveFilterIndicator() + loadHistory() + } - popup.setOnMenuItemClickListener { item -> - val newState = when (item.itemId) { - R.id.filter_status_paid -> FILTER_PAID - R.id.filter_status_pending -> FILTER_PENDING - R.id.filter_status_all -> FILTER_ALL - else -> FILTER_PAID - } - prefs.edit().putInt(KEY_FILTER_STATE, newState).apply() - updateFilterButtonTexts() - loadHistory() - true - } - popup.show() - } - - binding.btnFilterDate?.setOnClickListener { view -> - val popup = PopupMenu(this, view) - popup.menuInflater.inflate(R.menu.menu_filter_date, popup.menu) - - popup.setOnMenuItemClickListener { item -> - when (item.itemId) { - R.id.filter_date_all -> { - prefs.edit() - .putLong(KEY_FILTER_DATE_START, 0L) - .putLong(KEY_FILTER_DATE_END, 0L) - .apply() - updateFilterButtonTexts() - loadHistory() - true - } - R.id.filter_date_custom -> { - showDateRangePicker() - true - } - else -> false - } + private fun showDateFilterSheet() { + val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE) + val currentStart = prefs.getLong(KEY_FILTER_DATE_START, 0L) + val currentEnd = prefs.getLong(KEY_FILTER_DATE_END, 0L) + DateFilterBottomSheet + .newInstance(currentStart, currentEnd) + .show(supportFragmentManager, DateFilterBottomSheet.TAG) + } + + private fun registerDateFilterResultListener() { + supportFragmentManager.setFragmentResultListener( + DateFilterBottomSheet.RESULT_KEY, + this + ) { _, bundle -> + val start = bundle.getLong(DateFilterBottomSheet.RESULT_START, 0L) + val end = bundle.getLong(DateFilterBottomSheet.RESULT_END, 0L) + if (start == DateFilterBottomSheet.SENTINEL_CUSTOM) { + showDateRangePicker() + return@setFragmentResultListener } - popup.show() + val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE) + prefs.edit() + .putLong(KEY_FILTER_DATE_START, start) + .putLong(KEY_FILTER_DATE_END, end) + .apply() + updateActiveFilterIndicator() + loadHistory() } } - private fun toggleFilters() { - isFiltersExpanded = !isFiltersExpanded - - if (isFiltersExpanded) { - binding.filtersContainer?.visibility = View.VISIBLE - binding.filterExpandIcon?.animate()?.rotation(180f)?.setDuration(200)?.start() + private fun updateActiveFilterIndicator() { + val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE) + val hidePending = prefs.getBoolean(KEY_HIDE_PENDING, true) + val start = prefs.getLong(KEY_FILTER_DATE_START, 0L) + val end = prefs.getLong(KEY_FILTER_DATE_END, 0L) + + val parts = mutableListOf() + if (start > 0L && end > 0L) { + val format = SimpleDateFormat("MMM d", Locale.getDefault()) + parts += getString( + R.string.history_filter_date_range_format, + format.format(Date(start)), + format.format(Date(end)) + ) + } + if (!hidePending) { + parts += getString(R.string.history_subtitle_pending_shown) + } + + val indicator = findViewById(R.id.active_filter_indicator) + if (parts.isEmpty()) { + indicator.visibility = View.GONE } else { - binding.filtersContainer?.visibility = View.GONE - binding.filterExpandIcon?.animate()?.rotation(0f)?.setDuration(200)?.start() + indicator.text = parts.joinToString(getString(R.string.history_subtitle_separator)) + indicator.visibility = View.VISIBLE } } @@ -434,6 +454,7 @@ class PaymentsHistoryActivity : AppCompatActivity() { .setValidator(DateValidatorPointBackward.now()) val builder = MaterialDatePicker.Builder.dateRangePicker() + .setTheme(R.style.ThemeOverlay_Numo_MaterialCalendar) .setTitleText(R.string.history_filter_date_picker_title) .setCalendarConstraints(constraintsBuilder.build()) @@ -457,64 +478,36 @@ class PaymentsHistoryActivity : AppCompatActivity() { .putLong(KEY_FILTER_DATE_START, selection.first) .putLong(KEY_FILTER_DATE_END, selection.second) .apply() - updateFilterButtonTexts() + updateActiveFilterIndicator() loadHistory() } picker.show(supportFragmentManager, "DATE_RANGE_PICKER") } - private fun updateFilterButtonTexts() { - val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE) - - val filterState = prefs.getInt(KEY_FILTER_STATE, FILTER_PAID) - val statusText = when (filterState) { - FILTER_PAID -> getString(R.string.history_menu_filter_paid) - FILTER_PENDING -> getString(R.string.history_menu_filter_pending) - FILTER_ALL -> getString(R.string.history_menu_filter_all) - else -> getString(R.string.history_menu_filter_paid) - } - binding.btnFilterStatus?.text = getString(R.string.history_filter_status_format, statusText) - - val start = prefs.getLong(KEY_FILTER_DATE_START, 0L) - val end = prefs.getLong(KEY_FILTER_DATE_END, 0L) - - var dateText = "" - if (start > 0 && end > 0) { - val format = SimpleDateFormat("MMM d", Locale.getDefault()) - val startStr = format.format(Date(start)) - val endStr = format.format(Date(end)) - dateText = getString(R.string.history_filter_date_range_format, startStr, endStr) - binding.btnFilterDate?.text = getString(R.string.history_filter_date_format, dateText) - } else { - dateText = getString(R.string.history_filter_date_all) - binding.btnFilterDate?.text = getString(R.string.history_filter_date_format, dateText) - } - - // Update the main header text to reflect active filters if any - if (filterState == FILTER_ALL && start == 0L && end == 0L) { - binding.filterHeaderText?.text = getString(R.string.history_menu_filter) - binding.filterHeaderText?.setTextColor(getColor(R.color.color_text_secondary)) - binding.filterExpandIcon?.setColorFilter(getColor(R.color.color_text_secondary)) - } else { - val activeFilters = mutableListOf() - if (filterState != FILTER_ALL) activeFilters.add(statusText) - if (start > 0 || end > 0) activeFilters.add(dateText) - - val summary = activeFilters.joinToString(", ") - binding.filterHeaderText?.text = summary - - // Highlight the text to indicate active filters - binding.filterHeaderText?.setTextColor(getColor(R.color.color_text_primary)) - binding.filterExpandIcon?.setColorFilter(getColor(R.color.color_text_primary)) - } - } - private fun showOverflowMenu(anchor: View) { + val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE) val popup = PopupMenu(this, anchor, android.view.Gravity.END) popup.menuInflater.inflate(R.menu.menu_activity_history, popup.menu) + val hidePending = prefs.getBoolean(KEY_HIDE_PENDING, true) + popup.menu.findItem(R.id.menu_toggle_pending)?.apply { + title = getString( + if (hidePending) R.string.history_overflow_show_pending + else R.string.history_overflow_hide_pending + ) + setIcon(if (hidePending) R.drawable.ic_visibility else R.drawable.ic_visibility_off) + } + popup.setOnMenuItemClickListener { menuItem -> when (menuItem.itemId) { + R.id.menu_toggle_pending -> { + togglePending() + true + } + R.id.menu_filter_date -> { + showDateFilterSheet() + true + } R.id.menu_export_activity -> { val dateStr = SimpleDateFormat("yyyy-MM-dd", Locale.US).format(Date()) csvExportLauncher.launch("numo_activity_export_$dateStr.csv") @@ -528,7 +521,7 @@ class PaymentsHistoryActivity : AppCompatActivity() { private fun loadHistory() { val prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE) - val filterState = prefs.getInt(KEY_FILTER_STATE, FILTER_PAID) // Hide pending by default + val hidePending = prefs.getBoolean(KEY_HIDE_PENDING, true) val filterStart = prefs.getLong(KEY_FILTER_DATE_START, 0L) val filterEnd = prefs.getLong(KEY_FILTER_DATE_END, 0L) @@ -541,11 +534,8 @@ class PaymentsHistoryActivity : AppCompatActivity() { var filteredList = (paymentHistory + withdrawHistory) .sortedByDescending { it.date.time } - // Apply Status Filter - if (filterState == FILTER_PAID) { + if (hidePending) { filteredList = filteredList.filterNot { it.isPending() } - } else if (filterState == FILTER_PENDING) { - filteredList = filteredList.filter { it.isPending() } } // Apply Date Filter @@ -554,7 +544,7 @@ class PaymentsHistoryActivity : AppCompatActivity() { val endOfDay = filterEnd + 86400000L - 1L filteredList = filteredList.filter { it.date.time in filterStart..endOfDay } } - + currentHistoryList = filteredList adapter.setEntries(currentHistoryList) @@ -589,12 +579,11 @@ class PaymentsHistoryActivity : AppCompatActivity() { companion object { private const val PREFS_NAME = "PaymentHistory" private const val KEY_HISTORY = "history" - private const val KEY_FILTER_STATE = "filter_state" + private const val KEY_HIDE_PENDING = "hide_pending" private const val KEY_FILTER_DATE_START = "filter_date_start" private const val KEY_FILTER_DATE_END = "filter_date_end" - private const val FILTER_ALL = 0 - private const val FILTER_PAID = 1 - private const val FILTER_PENDING = 2 + private const val LEGACY_KEY_FILTER_STATE = "filter_state" + private const val LEGACY_FILTER_PAID = 1 private const val REQUEST_TRANSACTION_DETAIL = 1001 private const val REQUEST_RESUME_PAYMENT = 1002 diff --git a/app/src/main/res/drawable/ic_calendar.xml b/app/src/main/res/drawable/ic_calendar.xml new file mode 100644 index 000000000..1253df687 --- /dev/null +++ b/app/src/main/res/drawable/ic_calendar.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml index fa1ec6832..5873e8c28 100644 --- a/app/src/main/res/layout/activity_history.xml +++ b/app/src/main/res/layout/activity_history.xml @@ -96,101 +96,29 @@ android:textSize="16sp" tools:text="₿21,305" /> - - - - - - + - - - - - - - - - - - + app:chipBackgroundColor="@color/color_bg_white" + app:chipStrokeColor="@color/color_divider" + app:chipStrokeWidth="1dp" + app:chipMinHeight="30dp" + app:chipStartPadding="10dp" + app:chipEndPadding="4dp" + app:closeIcon="@drawable/ic_close" + app:closeIconEnabled="true" + app:closeIconTint="@color/color_text_secondary" + app:closeIconSize="14dp" + app:rippleColor="@color/color_divider" + android:visibility="gone" + tools:text="Mar 15 - Apr 20 · Pending shown" + tools:visibility="visible" /> @@ -203,7 +131,7 @@ android:clipToPadding="false" android:paddingBottom="16dp" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintTop_toBottomOf="@id/filters_container" /> + app:layout_constraintTop_toBottomOf="@id/balance_section" /> + app:layout_constraintTop_toBottomOf="@id/balance_section" /> diff --git a/app/src/main/res/layout/bottom_sheet_date_filter.xml b/app/src/main/res/layout/bottom_sheet_date_filter.xml new file mode 100644 index 000000000..06d0c61fd --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_date_filter.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/menu_activity_history.xml b/app/src/main/res/menu/menu_activity_history.xml index 1e1e320e5..72038394f 100644 --- a/app/src/main/res/menu/menu_activity_history.xml +++ b/app/src/main/res/menu/menu_activity_history.xml @@ -1,6 +1,16 @@ + + + + diff --git a/app/src/main/res/menu/menu_filter_date.xml b/app/src/main/res/menu/menu_filter_date.xml deleted file mode 100644 index 4728bf903..000000000 --- a/app/src/main/res/menu/menu_filter_date.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - diff --git a/app/src/main/res/menu/menu_filter_status.xml b/app/src/main/res/menu/menu_filter_status.xml deleted file mode 100644 index 377e2dba5..000000000 --- a/app/src/main/res/menu/menu_filter_status.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/values-es/strings_history.xml b/app/src/main/res/values-es/strings_history.xml index 2d6b00310..f14ce2f6d 100644 --- a/app/src/main/res/values-es/strings_history.xml +++ b/app/src/main/res/values-es/strings_history.xml @@ -75,22 +75,12 @@ Saldo total Exportar actividad - Filtrar transacciones - Completado - Pendiente - Todas Todo - Hoy - Semana - Mes Actividad exportada a CSV Error al exportar actividad Recibo - Rango personalizado... - Estado: %1$s - Fecha: %1$s %1$s - %2$s Seleccionar rango diff --git a/app/src/main/res/values-ja/strings_history.xml b/app/src/main/res/values-ja/strings_history.xml index a3dbc2052..2d7e085ff 100644 --- a/app/src/main/res/values-ja/strings_history.xml +++ b/app/src/main/res/values-ja/strings_history.xml @@ -57,18 +57,8 @@ ラベルを保存 トークンがクリップボードにコピーされました アクティビティをエクスポート - トランザクションのフィルタリング - 完了のみ - 保留中のみ - すべて表示 全期間 - 今日 - - チップ追加 (%1$d%%) - カスタム範囲... - ステータス: %1$s - 日付: %1$s %1$s - %2$s 日付範囲を選択 \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings_history.xml b/app/src/main/res/values-ko/strings_history.xml index 46c1e344c..7532b936e 100644 --- a/app/src/main/res/values-ko/strings_history.xml +++ b/app/src/main/res/values-ko/strings_history.xml @@ -57,18 +57,8 @@ 라벨 저장 토큰이 클립보드에 복사되었습니다 활동 내보내기 - 거래 필터링 - 완료됨 - 대기 중 - 전체 전체 기간 - 오늘 - 이번 주 - 이번 달 팁 추가됨 (%1$d%%) - 사용자 지정 범위... - 상태: %1$s - 날짜: %1$s %1$s - %2$s 날짜 범위 선택 \ No newline at end of file diff --git a/app/src/main/res/values-pt/strings_history.xml b/app/src/main/res/values-pt/strings_history.xml index 49c157a0f..003346f08 100644 --- a/app/src/main/res/values-pt/strings_history.xml +++ b/app/src/main/res/values-pt/strings_history.xml @@ -75,22 +75,12 @@ Saldo total Exportar atividade - Filtrar transações - Concluído - Pendente - Todas Todo - Hoje - Semana - Mês Atividade exportada para CSV Erro ao exportar atividade Recibo - Intervalo personalizado... - Status: %1$s - Data: %1$s %1$s - %2$s Selecionar período diff --git a/app/src/main/res/values/strings_history.xml b/app/src/main/res/values/strings_history.xml index 8e51e2438..10079ba5c 100644 --- a/app/src/main/res/values/strings_history.xml +++ b/app/src/main/res/values/strings_history.xml @@ -74,20 +74,29 @@ Total Balance - Export Activity - Filter Transactions - Completed - Pending - All - All Time - Custom Range... - Status: %1$s - Date: %1$s - %1$s - %2$s - Select Date Range + Export to CSV + All time + %1$s – %2$s + Choose dates Activity exported to CSV Error exporting activity + + Show pending + Hide pending + Filter by date + + + Filter by date + Last 7 days + Last 30 days + This month + Custom range… + + + Including pending + " · " + Receipt diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index fe2b9a41b..b8be553e8 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -149,4 +149,15 @@ 0dp 0dp + + + diff --git a/app/src/test/java/com/electricdreams/numo/feature/history/PaymentsHistoryActivityTest.kt b/app/src/test/java/com/electricdreams/numo/feature/history/PaymentsHistoryActivityTest.kt index ccc9b70ad..8ac9ba3db 100644 --- a/app/src/test/java/com/electricdreams/numo/feature/history/PaymentsHistoryActivityTest.kt +++ b/app/src/test/java/com/electricdreams/numo/feature/history/PaymentsHistoryActivityTest.kt @@ -218,12 +218,12 @@ class PaymentsHistoryActivityTest { } @Test - fun `loadHistory shows only pending transactions when FILTER_PENDING is set`() { - // Change preference to show only pending transactions + fun `legacy FILTER_PENDING preference migrates to show-all behavior`() { + // Pre-refactor users on the now-removed "pending only" mode (filter_state=2) + // should see all transactions after upgrade, since pending-only is gone. val prefs = context.getSharedPreferences("PaymentHistory", Context.MODE_PRIVATE) - prefs.edit().putInt("filter_state", 2).apply() // 2 = FILTER_PENDING + prefs.edit().putInt("filter_state", 2).apply() - // Add one pending and one completed transaction val pendingId = PaymentsHistoryActivity.addPendingPayment( context = context, amount = 100L, entryUnit = "sat", enteredAmount = 100L, bitcoinPrice = null, paymentRequest = null, formattedAmount = null @@ -238,16 +238,19 @@ class PaymentsHistoryActivityTest { paymentType = PaymentHistoryEntry.TYPE_CASHU, mintUrl = null ) - // Launch the activity val controller = Robolectric.buildActivity(PaymentsHistoryActivity::class.java).setup() val activity = controller.get() val recyclerView = activity.findViewById(R.id.history_recycler_view) val adapter = recyclerView.adapter - // Expected size = 2 (1 Header + 1 Pending Transaction) + // 1 month header + 2 transactions (both pending and completed visible) assertNotNull("Adapter should not be null", adapter) - assertEquals(2, adapter!!.itemCount) + assertEquals(3, adapter!!.itemCount) + + // Migration should have removed the legacy key and written the new one. + assertFalse(prefs.contains("filter_state")) + assertFalse(prefs.getBoolean("hide_pending", true)) } @Test