feature:implemented the profile screen - #12
Conversation
WalkthroughThe PR adds shared transport and tracking models, synchronizes user and trip provider state with persistence, introduces a profile editing screen, adds monthly trip reset logic, and revises map permission and trip interaction flows. ChangesApplication state and user flows
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ProfileScreen
participant UserNotifier
participant DatabaseHelper
ProfileScreen->>UserNotifier: save updated profile
UserNotifier->>DatabaseHelper: persist user
DatabaseHelper-->>UserNotifier: persisted user
UserNotifier-->>ProfileScreen: updated provider state
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/features/map/services/location_service.dart (1)
15-53: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReturn the same failure shape for permanently denied permission.
deniedForeverstill throws, soMapScreenfalls back to a generic exception message instead of handling the documented{status, message}response. Return{'status': false, 'message': ...}here as well.Proposed fix
if (permission == LocationPermission.deniedForever) { - return Future.error( - 'Location permissions are permanently denied, we cannot request permissions.', - ); + return { + 'status': false, + 'message': + 'Location permissions are permanently denied. Enable them in device settings.', + }; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/features/map/services/location_service.dart` around lines 15 - 53, Update isPermissionGranted() so the LocationPermission.deniedForever branch returns the same {'status': false, 'message': ...} map shape as other permission failures instead of returning Future.error. Preserve the existing permanent-denial message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/core/providers/trips_provider.dart`:
- Around line 30-38: Update deleteTrips to log clearTrips failures with
deletion-specific context and rethrow the caught error so callers can handle
failed deletions. Await loadTrips only after a successful clear, and prevent the
reload from running when deletion fails.
In `@lib/core/providers/user_provider.dart`:
- Around line 22-31: Make saveUser() concurrency-safe by replacing the separate
query-then-insert/update sequence with an atomic database upsert or a
provider-level serialized write queue. Ensure concurrent updates cannot both
insert or overwrite newer profile data with stale User snapshots, while
preserving the final state assignment.
In `@lib/database/models/user.dart`:
- Around line 61-80: Update User.copyWith so callers can explicitly clear the
nullable sustainabilityThoughts field while preserving the existing value when
the argument is omitted. Use an explicit sentinel or equivalent
presence-tracking mechanism for sustainabilityThoughts, and ensure
copyWith(sustainabilityThoughts: null) produces a User with a null value rather
than retaining this.sustainabilityThoughts.
In `@lib/features/map/screens/map_screen.dart`:
- Around line 62-67: In the permission-check flow after awaiting
MapService.isPermissionGranted(), add an immediate mounted guard that returns
before the !res['status'] branch can call setState. Keep the existing
error-message handling unchanged.
In `@lib/features/onboarding/screens/user_info.dart`:
- Around line 393-394: Update the tracking help content used by the modal around
trackingModesInfo so its title/description or selectable option labels
consistently name the modes actually offered: Refresh, High, and Eco. Ensure no
conflicting Balanced or Eco-Friendly terminology remains in this tracking
guidance.
In `@lib/features/profile/screens/profile.dart`:
- Around line 375-384: Update the “Clear Stored Trips” ListTile onTap handler to
show a destructive-action confirmation dialog before clearing history; only
after the user confirms should it await
ref.read(tripProvider.notifier).deleteTrips(), and it must surface any deletion
failure using the screen’s existing error-handling mechanism.
- Around line 365-374: Update the Export Data ListTile in the profile screen to
prevent users from invoking the unimplemented action: either remove or hide the
tile, or disable it and display an explicit “Coming soon” state. Do not leave
the current enabled onTap handler that performs no action.
---
Outside diff comments:
In `@lib/features/map/services/location_service.dart`:
- Around line 15-53: Update isPermissionGranted() so the
LocationPermission.deniedForever branch returns the same {'status': false,
'message': ...} map shape as other permission failures instead of returning
Future.error. Preserve the existing permanent-denial message.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: fe4e825e-157e-4c83-a432-8b915d2442ae
📒 Files selected for processing (28)
lib/core/config/app_constants.dartlib/core/data/trackingOptions.dartlib/core/data/transportPreferences.dartlib/core/extensions/string_extensions.dartlib/core/providers/trips_provider.dartlib/core/providers/user_provider.dartlib/core/widgets/loader.dartlib/core/widgets/modal.dartlib/database/database_helper.dartlib/database/models/user.dartlib/features/carbon/providers/summary_provider.dartlib/features/fitness/screens/fitness_metrics_screen.dartlib/features/fitness/screens/main_screen.dartlib/features/fitness/services/health_service.dartlib/features/map/screens/map_screen.dartlib/features/map/services/location_service.dartlib/features/map/widgets/location_button.dartlib/features/map/widgets/map_modal.dartlib/features/onboarding/data/onboarding_options.dartlib/features/onboarding/screens/splash_screen.dartlib/features/onboarding/screens/user_info.dartlib/features/profile/.gitkeeplib/features/profile/screens/profile.dartlib/features/profile/widgets/section_header.dartlib/features/profile/widgets/tracking_option_tile.dartlib/features/profile/widgets/transport_chip.dartlib/main.dartlib/shared/widgets/.gitkeep
💤 Files with no reviewable changes (2)
- lib/features/onboarding/data/onboarding_options.dart
- lib/features/carbon/providers/summary_provider.dart
| Future<void> deleteTrips() async { | ||
| try { | ||
| await _databaseHelper.clearTrips(); | ||
| state = []; | ||
| } catch (e) { | ||
| debugPrint("Error loading trips: $e"); | ||
| } | ||
| loadTrips(); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Propagate trip-deletion failures to the caller.
clearTrips() failures are logged and swallowed, so the UI cannot tell the user that their trips were not deleted. Log the deletion error, rethrow it (or return a failure result), and avoid the unawaited reload.
Proposed fix
Future<void> deleteTrips() async {
try {
await _databaseHelper.clearTrips();
state = [];
- } catch (e) {
- debugPrint("Error loading trips: $e");
+ } catch (e, st) {
+ debugPrint("Error deleting trips: $e\n$st");
+ rethrow;
}
- loadTrips();
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Future<void> deleteTrips() async { | |
| try { | |
| await _databaseHelper.clearTrips(); | |
| state = []; | |
| } catch (e) { | |
| debugPrint("Error loading trips: $e"); | |
| } | |
| loadTrips(); | |
| } | |
| Future<void> deleteTrips() async { | |
| try { | |
| await _databaseHelper.clearTrips(); | |
| state = []; | |
| } catch (e, st) { | |
| debugPrint("Error deleting trips: $e\n$st"); | |
| rethrow; | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/core/providers/trips_provider.dart` around lines 30 - 38, Update
deleteTrips to log clearTrips failures with deletion-specific context and
rethrow the caught error so callers can handle failed deletions. Await loadTrips
only after a successful clear, and prevent the reload from running when deletion
fails.
| Future<void> saveUser(User user) async { | ||
| await _databaseHelper.insert('user', user); | ||
| final existingUser = await _databaseHelper.queryUser(); | ||
|
|
||
| if (existingUser == null) { | ||
| await _databaseHelper.insert('user', user); | ||
| } else { | ||
| await _databaseHelper.updateData('user', user); | ||
| } | ||
|
|
||
| state = user; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Serialize saveUser() or make the upsert atomic.
Concurrent profile updates can both observe the same existingUser, then write stale User snapshots in completion order. When no user exists, concurrent calls can also both attempt insertion. Use a database transaction/upsert or a provider-level write queue that merges from the latest state before persisting.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/core/providers/user_provider.dart` around lines 22 - 31, Make saveUser()
concurrency-safe by replacing the separate query-then-insert/update sequence
with an atomic database upsert or a provider-level serialized write queue.
Ensure concurrent updates cannot both insert or overwrite newer profile data
with stale User snapshots, while preserving the final state assignment.
| trackingModesInfo["title"] ?? "Tracking modes", | ||
| trackingModesInfo["description"] ?? "", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Align the tracking help text with the selectable modes.
The UI offers Refresh, High, and Eco, but trackingModesInfo describes Balanced and Eco-Friendly instead. Update the shared description or option labels so the modal accurately documents the modes users can select.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/features/onboarding/screens/user_info.dart` around lines 393 - 394,
Update the tracking help content used by the modal around trackingModesInfo so
its title/description or selectable option labels consistently name the modes
actually offered: Refresh, High, and Eco. Ensure no conflicting Balanced or
Eco-Friendly terminology remains in this tracking guidance.
| ListTile( | ||
| leading: const Icon(Icons.download_outlined), | ||
| title: const Text( | ||
| 'Export Data', | ||
| style: TextStyle(fontSize: 14), | ||
| ), | ||
| onTap: () { | ||
| // To be implemented | ||
| }, | ||
| ), |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Remove or disable the unimplemented export action.
Export Data is enabled but does nothing when tapped. Hide it until implemented, or render it disabled with an explicit “Coming soon” state.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/features/profile/screens/profile.dart` around lines 365 - 374, Update the
Export Data ListTile in the profile screen to prevent users from invoking the
unimplemented action: either remove or hide the tile, or disable it and display
an explicit “Coming soon” state. Do not leave the current enabled onTap handler
that performs no action.
There was a problem hiding this comment.
This will be implemented this week
There was a problem hiding this comment.
@aneesafatima Understood. Since the enabled control currently has no effect, could you disable/hide it in this PR until the implementation lands? If it is intentionally deferred to a follow-up, would you like me to open an issue for it?
| ListTile( | ||
| leading: const Icon(Icons.delete_outline, color: _redColor), | ||
| title: const Text( | ||
| 'Clear Stored Trips', | ||
| style: TextStyle(fontSize: 14, color: _redColor), | ||
| ), | ||
| onTap: () { | ||
| ref.read(tripProvider.notifier).deleteTrips(); | ||
| }, | ||
| ), |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Require confirmation before permanently clearing trip history.
This immediately deletes all stored trips with no confirmation or recovery path. Show a destructive-action confirmation dialog, then await deleteTrips() and surface any failure.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/features/profile/screens/profile.dart` around lines 375 - 384, Update the
“Clear Stored Trips” ListTile onTap handler to show a destructive-action
confirmation dialog before clearing history; only after the user confirms should
it await ref.read(tripProvider.notifier).deleteTrips(), and it must surface any
deletion failure using the screen’s existing error-handling mechanism.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/features/profile/screens/profile.dart (2)
424-427: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winAwait user deletion before navigating away.
deleteUser()is started and ignored before routing to onboarding. A new onboarding save can race the deletion, and failures can leave the user believing sign-out succeeded while the database still contains the record.Proposed fix
- onPressed: () { - ref.read(userProvider.notifier).deleteUser(); - context.goNamed('onboarding'); - }, + onPressed: () async { + await ref.read(userProvider.notifier).deleteUser(); + if (!mounted) return; + context.goNamed('onboarding'); + },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/features/profile/screens/profile.dart` around lines 424 - 427, Update the onPressed handler to await the Future returned by userProvider’s deleteUser() before calling context.goNamed('onboarding'). Preserve the existing onboarding navigation, ensuring it occurs only after deletion completes and deletion failures are not silently ignored.
305-317: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winMake sustainability thoughts a multiline field.
The
TextFieldfor “Sustainability Thoughts” has nomaxLinesorinputFormatters/TextInputType.multilineconfiguration, so it renders as a single-line input. Add multiline support so longer thoughts are easier to enter and read.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/features/profile/screens/profile.dart` around lines 305 - 317, Update the Sustainability Thoughts TextField by configuring TextInputType.multiline and allowing multiple lines with maxLines. Keep the existing controller, styling, alignment, and decoration unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@lib/features/profile/screens/profile.dart`:
- Around line 424-427: Update the onPressed handler to await the Future returned
by userProvider’s deleteUser() before calling context.goNamed('onboarding').
Preserve the existing onboarding navigation, ensuring it occurs only after
deletion completes and deletion failures are not silently ignored.
- Around line 305-317: Update the Sustainability Thoughts TextField by
configuring TextInputType.multiline and allowing multiple lines with maxLines.
Keep the existing controller, styling, alignment, and decoration unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 46778f52-ae12-4025-a516-ef9d686bb27e
📒 Files selected for processing (6)
lib/core/providers/trips_provider.dartlib/core/providers/user_provider.dartlib/features/map/screens/map_screen.dartlib/features/onboarding/data/tracking_modes_info.dartlib/features/profile/screens/profile.dartlib/features/profile/trips_delete_modal_data.dart
💤 Files with no reviewable changes (2)
- lib/core/providers/trips_provider.dart
- lib/features/onboarding/data/tracking_modes_info.dart
Week 9
What this PR does:
SectionHeader,TrackingOptionTile, andTransportChipwidgets for the profile screenuser_provider.dartfrom onboarding folder tocore/providersso other features can use itcopyWithmethod toUsermodelupdateUseranddeleteUsermethods toUserNotifierdeleteTripsmethod toTripsNotifiertrackingOptionsandtransportPreferencesdata files with icons, replacing the old onboarding options filecapitalize()string extension for tracking option labelstrackingOption) instead of plain stringsMapService.isPermissionGranted()to return a map with status and message instead of throwing errors, so the map screen can show a proper error messageonCloseandonCompletedcallbacks were swappedmain.dartso trips get cleared and reset dates get saved when a new month startsflutter/cupertinoimports withflutter/foundationwhere onlydebugPrintwas neededloader.dartfrom shared widgets to core widgetsScreenshots/Recordings:
WhatsApp.Video.2026-07-26.at.21.51.03.mp4
(Android)
Screen_recording_20260726_214507.webm
Additional Notes:
Checklist
We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact.
Summary by CodeRabbit