Repository navigation
Conversation
Code Review SummaryReports gain PDF, Excel, and CSV statement export for the selected period via 🚀 Key Improvements
💡 Minor Suggestions
|
Add a statement export (PDF, Excel, CSV) to the reports screen, covering the selected period, through the same guarded path as the transaction export. The save/share sheet moves into a shared ExportResultListener. Add a feedback screen under Settings for signed-in users that posts to /feedback and lists past submissions with their status.
Read the user's streaks from GET /streaks and show the daily tracking streak as a chip beside the Transactions heading, lit once it is running. Tapping it opens a sheet with the tracking and check-in streaks, daily and weekly, each beside its best run. Streaks are counted on the server, so the chip is for signed-in users only, stays hidden until the server answers, and keeps the last good numbers when a refresh fails. A transaction counts once it reaches the server, so the chip refreshes after each sync. Rows of a type or period this build does not know are skipped.
c6c7fd8 to
a70b64a
Compare
| StreakCubit(this._getStreaks) : super(StreakState.initial()); | ||
|
|
||
| Future<void> loadStreaks() async { | ||
| if (state.isLoading) return; |
There was a problem hiding this comment.
The early return silently drops the refresh that _StreakChipView fires when a sync completes, if the initial load is still in flight, so the chip keeps a stale count until the next sync. Record a pending reload and run it when the current load finishes instead of returning.
|
|
||
| cubit.exportStatement( | ||
| format: format, | ||
| start: today.subtract(Duration(days: _periodDays - 1)), |
There was a problem hiding this comment.
Subtracting a fixed Duration from a local midnight shifts the calendar date whenever a DST transition falls inside the window (e.g. a 30-day window spanning March), so the statement silently starts one day early and covers more days than the figures on screen. Use calendar arithmetic instead.
| start: today.subtract(Duration(days: _periodDays - 1)), | |
| start: DateTime(today.year, today.month, today.day - (_periodDays - 1)), |
| loadFailure: const Failure.none(), | ||
| )); | ||
|
|
||
| final result = await _getFeedback(NoParams()); |
There was a problem hiding this comment.
loadFeedback awaits the request and then emits, but the cubit can already be closed if the screen is left while the request is in flight; emit then throws StateError: Cannot emit new states after calling close. Bail out with if (isClosed) return; after the await, before folding.
| final result = await _getFeedback(NoParams()); | |
| final result = await _getFeedback(NoParams()); | |
| if (isClosed) return; | |
| result.fold( |
| )); | ||
|
|
||
| final trimmedSubject = subject?.trim(); | ||
| final result = await _submitFeedback(SubmitFeedbackUseCaseParams( |
There was a problem hiding this comment.
Submitting and immediately leaving the screen closes the cubit, so the emits below throw StateError after await and the result is lost as an unhandled error. Add the same closed-cubit guard before folding.
| final result = await _submitFeedback(SubmitFeedbackUseCaseParams( | |
| final result = await _submitFeedback(SubmitFeedbackUseCaseParams( | |
| type: type, | |
| subject: trimmedSubject == null || trimmedSubject.isEmpty | |
| ? null | |
| : trimmedSubject, | |
| message: message.trim(), | |
| )); | |
| if (isClosed) return; | |
| result.fold( |
| message: message.trim(), | ||
| )); | ||
|
|
||
| result.fold( |
There was a problem hiding this comment.
submitFeedback also emits only after awaiting the network call, so a send that finishes after the screen is disposed emits into a closed cubit and throws. Guard the fold with the same closed-cubit early return used for loading.
reports/export./feedback.ExportResultListener, reused by history and reports.Backend dependency:
GET /streaksis not available for