feat(equipment): currency presets, a default currency, and correct symbols - #805
Conversation
…mbols Equipment purchase price was hardcoded to a "$" prefix icon, the currency was free text with no presets, and the displayed price always used "$" regardless of the stored currency. - Add a shared currency util (core/utils/currency.dart): a curated list of common codes, code->symbol, and money formatting (via intl). - Add a diver-level default currency setting (Settings > Units > Default Currency), persisted in diver_settings via a v138 migration. - Equipment edit: the currency field is now an editable dropdown of common currencies (custom codes still allowed); new items default to the diver's currency; the price field's prefix shows the selected currency's symbol (EUR -> €, GBP -> £, ...) instead of a fixed "$". - Display: the detail page and the summary total now use the currency symbol, and the configurable-column price formatter uses the diver's default currency rather than a hardcoded "$". Adds tests: currency util, the v138 migration, and an equipment-edit test that the stored currency and its symbol show on the price field.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
📦 Build artifacts for this PR · commit
Artifacts expire in 7 days. Downloading requires being signed in to GitHub. macOS needs two extractions: unzip the downloaded artifact, then unzip the Updated automatically on each push. |
There was a problem hiding this comment.
Pull request overview
Adds currency-awareness to equipment pricing by introducing shared currency utilities, a persisted default currency setting, and updating equipment/settings UI and formatting to display the correct currency symbol/code.
Changes:
- Added
currencySymbol/formatMoneyutilities plus a curated common-currency preset list. - Introduced a default currency setting stored in
diver_settingswith a v138 DB migration and provider plumbing. - Updated equipment edit/detail/summary displays to use currency symbol formatting, plus added tests for currency utils, migration, and equipment edit UI.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/helpers/mock_providers.dart | Updates mock SettingsNotifier to support setDefaultCurrency. |
| test/features/statistics/presentation/pages/records_page_test.dart | Updates test mock to support setDefaultCurrency. |
| test/features/settings/presentation/pages/settings_page_test.dart | Updates test mock to support setDefaultCurrency. |
| test/features/equipment/presentation/equipment_edit_advanced_test.dart | Adds widget test asserting stored currency code/symbol appear on edit page. |
| test/core/utils/currency_test.dart | Adds unit tests for currency utilities. |
| test/core/database/migration_v138_default_currency_test.dart | Adds migration test for diver_settings.default_currency defaulting to USD. |
| lib/l10n/arb/app_localizations.dart | Adds generated localization getters for default currency setting labels. |
| lib/l10n/arb/app_localizations_zh.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_pt.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_nl.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_it.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_hu.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_he.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_fr.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_es.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_en.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_de.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_localizations_ar.dart | Adds generated strings for new localization keys. |
| lib/l10n/arb/app_en.arb | Adds new English localization strings for default currency setting. |
| lib/features/settings/presentation/providers/settings_providers.dart | Adds defaultCurrency to AppSettings, notifier setter, and provider. |
| lib/features/settings/presentation/pages/settings_page.dart | Adds default currency picker UI in Units settings section. |
| lib/features/settings/data/repositories/diver_settings_repository.dart | Persists/loads defaultCurrency to/from diver_settings. |
| lib/features/equipment/presentation/widgets/equipment_summary_widget.dart | Uses default currency symbol in summary “total value” display. |
| lib/features/equipment/presentation/pages/equipment_edit_page.dart | Defaults new items to diver default currency; adds editable currency dropdown and live prefix symbol. |
| lib/features/equipment/presentation/pages/equipment_detail_page.dart | Formats purchase price using formatMoney. |
| lib/features/equipment/domain/constants/equipment_field.dart | Uses diver default currency for configurable-column purchase price formatting. |
| lib/core/utils/currency.dart | New currency utilities and common-code preset list. |
| lib/core/database/database.dart | Adds defaultCurrency column, bumps schema to v138, and adds migration/backstop helper. |
…mock CI caught two gaps the local `analyze lib` run missed: - The default-currency ARB keys were only in the English template, failing the arb_parity guard. Add real translations for all ten locales. - A fourth SettingsNotifier test double (settings_page_shared_data_test) needed the new setDefaultCurrency override to compile. Also make an EquipmentItem literal const in a test (analyzer info).
Conflicts were the ten non-English ARB catalogs, all purely additive (this branch's default-currency keys vs main's new keys at the top of each file) - resolved as a union. Renumbered the default-currency migration v138 -> v139: v138 is claimed by the still-open divelogs.de branch, and main is at v137. The onUpgrade block stays after main's v137 weather-code step and the beforeOpen backstop heals any DB that upgraded past 139 without the column. Regenerated drift and l10n output from the merged sources.
Review comments: - currency_test pinned Intl.defaultLocale (and restores it). The symbol assertions were riding on intl's implicit fallback; under some locales USD renders as "US$". Number symbols are statically bundled, so no async initialization is needed here, unlike date formatting. - The equipment summary no longer adds items priced in different currencies into one figure under a single symbol. A new sumByCurrency() groups totals per currency (blank codes falling back to the diver's default) and the overview renders one card each. - Pickers keep a stored code that is outside the presets. Extracted the settings picker's inline logic as currencyCodesWith() and reused it on the equipment edit page, so an item priced in, say, ISK stays visible and re-selectable in the dropdown. - The Add Equipment bottom sheet no longer hardcodes USD: it opens in the diver's default currency, offers the same dropdown with live symbol prefix, and falls back to the default rather than USD on save. Its currency box is Expanded rather than a fixed width -- that row already carries a 250dp date button, so a fixed box would overflow on a narrow phone. The edit page's own blank-currency save path now resolves to the diver default too, and its controller starts empty so a stale USD cannot flash while an existing item loads. Tests: patch coverage 52% -> ~99%. New cases cover the settings currency picker end to end (list, select, cancel, non-preset code), SettingsNotifier.setDefaultCurrency normalisation, the detail page's formatted price, the configurable-column formatter under a non-USD default, the summary's per-currency totals, both equipment entry points' default-currency behaviour, and currency.dart's helpers including the unsupported-locale fallback (intl echoes unknown codes rather than throwing, so a bad code alone never reaches those branches).
|
Merged The migration is now v139, not v138
This branch is renumbered to v139, deliberately leaving 138 out of the ladder ( The PR description still says v138 — worth updating. Also of note: CoveragePatch coverage was 52.33%; it's now ~98.6% locally (138/140 changed lines). New tests cover the settings currency picker end to end, The two remaining uncovered lines are the Drift column declaration and the add sheet's save-time fallback. Full suite green locally (14975 passed, 15 skipped), |
PR submersion-app#868 (cylinder configurations, submersion-app#804) merged while CI was running and took v139, so the default-currency migration renumbers v139 -> v140 -- its third number, after v138 went to the divelogs.de branch. database.dart conflicted in the ladder and the onUpgrade tail; both resolved as a union with the currency block ordered after main's v139 cylinder-config step. Main's ladder already skips 138 to reserve it for divelogs, so this branch keeps that gap rather than filling it. Main's v139 migration test already asserts greaterThanOrEqualTo, so nothing needed relaxing; migration_v139_default_currency_test.dart is renamed to _v140_ and its fixture still stamps 137, now migrating 137 -> 140 through main's intervening cylinder-config block. Codegen and l10n regenerated against main's new tables.
Follow-up to the equipment currency work: ServiceRecord already carried a currency field, but nothing wrote or read it. Every service cost was stored as USD and displayed with a hardcoded '$', regardless of the diver's default currency or what the record actually said. - The service dialog gains a currency dropdown alongside the cost field, with the same live symbol prefix as the equipment forms. New records open in the diver's default; editing keeps the record's stored currency, so opening and saving an old EUR record cannot silently reprice it. A stored code outside the presets still leads the menu. - The per-record cost renders via formatMoney with the record's own currency. - The total was the equipment-summary bug one layer deeper, in raw SQL: SELECT SUM(cost) added rows priced in different currencies into a figure that is not a real amount in any of them. It now groups by currency, and the card shows one labelled row per currency. getTotalServiceCost -> getTotalServiceCostByCurrency, so the wrong helper does not survive for the next caller; the provider's type changes with it. New l10n key equipment_serviceDialog_currencyLabel in all 11 locales, reusing each one's existing wording for "Currency". Tests: seven widget tests for the display and dialog behaviour, plus five repository tests driving the new GROUP BY against a real database (summing, separation, cost-less records, equipment scoping) -- the widget tests only ever see a stubbed provider, so the SQL needed its own coverage.
Problem
On the equipment edit page, the Purchase Price field always showed a hardcoded
$prefix icon, the currency was a free-text field with no presets, and it never reflected the entered currency. The displayed price was also formatted with a hardcoded$regardless of the stored currency.Changes
Shared currency util (
lib/core/utils/currency.dart): a curatedkCommonCurrencyCodeslist,currencySymbol(code)(EUR → €, GBP → £, …, viaintl), andformatMoney(amount, code).Default currency setting — set your currency once (
Settings → Units → Default Currency), persisted indiver_settingsvia a new v138 migration (default_currency, defaults toUSD).Equipment edit page:
USD.$.Display:
equipment_field.dart) uses the diver's default currency (it has no per-item context there) rather than a hardcoded$.Tests
currency_test.dart: symbols, case/trim handling, fallback for unknown codes, formatting.migration_v138_default_currency_test.dart: the column is added and defaults toUSD.EUR) and its symbol (€) show on the price field.SettingsNotifiertest mocks for the newsetDefaultCurrency.Verified locally against Flutter 3.44.8 / Dart 3.12.2:
flutter analyze libclean;dart formatclean;flutter gen-l10n+ drift codegen run; currency/migration/settings/equipment suites pass. (One unrelated pre-existing date-dependent flake inservice_schedule_repository_test—2026vs2025— is untouched by this PR.)New
settings_units_defaultCurrency*localizations (untranslated locales fall back to English).