Conversation
Implements U1 of docs/plans/2026-09-10-001-feat-insights-analytics-plan.md: - InsightsTimeframe (thisMonth / lastQuarter / ytd) resolves to a current analysis window plus the previous comparable window for period-over-period deltas, all inclusive ranges. - InsightsSummary/PillarInsight/EnvelopeInsight/InsightsDelta entities: inflow (income + investment) vs outflow (expense) totals, Level-1 pillar rollups via the cycle-safe getRootPillar, per-envelope buckets with activity shares, and delta math with a "new" contract when the previous window is zero. - GetInsightsSummaryUseCase fetches both windows plus categories in one call; missing categories land in one stable "Uncategorized" bucket per aggregation run. Amounts bucket by TransactionType (never CategoryType) so the investment-type/category-type mismatch stays inert. Nine usecase tests cover the three timeframe boundaries, rollup shares, the investment inflow rule, the uncategorized bucket, empty windows, and both failure paths.
Implements U2 of docs/plans/2026-09-10-001-feat-insights-analytics-plan.md: - InsightsState mirrors DashboardState: InsightsStatus (initial/loading/loaded/failure), selectedTimeframe (default thisMonth), summary?, and dartz failureOption with copyWith(clearSummary). - InsightsCubit fetches on demand (load, selectTimeframe, refresh) and never subscribes to live streams. A request token discards stale responses so rapid timeframe switches can't overwrite the newest result. nowProvider is injected for deterministic test resolution. - Registered via @Injectable (DI config regenerated). Six cubit tests: initial state, loading->loaded transition order, failure status with populated failureOption, timeframe switch fetching new params only, refresh, and the stale-response guard (Completer- driven). Note: mocktail's constructor param for the now-provider needed a typedef (injectable can't resolve bare function types).
Implements U3 of docs/plans/2026-09-10-001-feat-insights-analytics-plan.md: - TimeframeFilterRow: capsule segmented control (This Month / Last Quarter / YTD), gradient-filled active segment, Manrope/Inter. - InsightsHeroCard: primary-gradient hero with total outflow/inflow and direction-aware delta chips (outflow up = red, inflow up = green; "NEW" when the previous window was silent, dash when fully silent). - PillarDistributionChart: multi-segment outflow bar split by shareOfTotalOutflow with rotating segment colours (Portfolio- DistributionCard precedent), legend with share/amount, muted track when no spending. Income pillars take no bar segment. - EnvelopeDrillDownList: per-pillar sections with envelope rows (icon, name, breadcrumb, share bar, amount); zero-activity pillars omitted. Small plan-faithful amendment: EnvelopeInsight gained a breadcrumb field computed in the usecase via getBreadcrumbPath so widgets stay data-dumb. Eight widget tests cover the filter callback, delta chip variants (positive/NEW/dash), proportional bar segments via ValueKeys, legend shares, breadcrumbs, and silent-pillar omission.
…time (U4) Implements U4 of docs/plans/2026-09-10-001-feat-insights-analytics-plan.md plus two review-driven additions (Custom range and All Time timeframes): - InsightsPage: timeframe filter, gradient hero, distribution chart, and drill-down inside a pull-to-refresh view; flash-on-failure keeps previously loaded content; dedicated empty state for silent periods; insightsCubit test seam. The easter-egg "visit the Stats tab" trigger moves here from the deleted placeholder page. - Router: /stats now builds InsightsPage (BlocProvider + getIt<InsightsCubit>()..load()); MainLayout renames the nav slot to "Insights" (donut icon), keeping the same index. Placeholder page deleted. - All Time timeframe: single unfiltered fetch, delta chips render a dash (no comparable previous window). - Custom range: 4th pill opens a hand-built fullscreen picker page (Flutter's built-in M3 picker is a centered dialog with no year dropdown) — month/year dropdown opens a 2000-2035 year grid, month chevrons, two-tap range selection with normalized boundaries, Save gated on a complete range. Previous window = equal-length span immediately before the range, so deltas stay meaningful. - Period label rendered under the filter row; cubit computes it per timeframe. Selecting a preset clears a picked custom range. 17 new tests: page render/refetch/failure/empty state, custom normalization and fetch, preset-clears-custom, allTime single fetch, custom passthrough with equal-length previous, five-pill rendering, custom callback. 163 tests pass; analyze/format/merged-runner clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
What:
GetInsightsSummaryUseCasefetches the current window, the previous comparable window (prior month / prior quarter / same span last year / equal-length span before a custom range), and the category list; rolls transactions from Level-3 envelopes up to Level-1 pillars via the cycle-safegetRootPillar; bucket inflow = income + investment, outflow = expense; missing categories land in one stable "Uncategorized" bucket.InsightsCubitfetches on demand (open, timeframe switch, pull-to-refresh) with a stale-response guard for rapid switches;periodLabelis computed per timeframe and rendered under the filter row.TimeframeFilterRow(capsule segmented control, 5 scrollable pills),InsightsHeroCard(primary gradient#00113A → #002366, direction-aware delta chips: outflow up = red, inflow up = green, "NEW" after a silent window),PillarDistributionChart(multi-segment bar, PortfolioDistributionCard color precedent),EnvelopeDrillDownList(breadcrumbs, share bars, amounts).How:
insightsfeature folder (domain entities/usecase, presentation blocs/pages/widgets) registered via injectable;/statsroute builds the page withBlocProvider(create: getIt<InsightsCubit>()..load()).Why:
Type of Change
Code Checklist
fvm flutter test),fvm flutter analyze --no-pubclean,dart formatclean, and the CI-equivalent merged runner (very_good test --optimization) exits 0