Skip to content

Conversation

@epou
Copy link
Member

@epou epou commented Dec 22, 2025

No description provided.

@epou epou requested a review from Copilot December 22, 2025 15:20
@epou epou self-assigned this Dec 22, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements an "offline first" architecture for the Mosquito Alert mobile application, fundamentally changing how the app handles data synchronization and storage.

Key Changes:

  • Implements local-first data storage using Hive database with automatic background synchronization
  • Removes direct API dependencies from providers, introducing repository pattern with offline support
  • Adds outbox pattern for queuing operations when offline and syncing when connection is restored

Reviewed changes

Copilot reviewed 184 out of 205 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
lib/main.dart Initializes Hive database, outbox service, repositories, and auto-sync on connection changes
lib/services/api_service.dart Simplified to remove auth provider dependency, using static auth repository methods
lib/hive/hive_service.dart New service to initialize Hive database and register type adapters
lib/hive/hive_adapters.g.dart Generated Hive type adapters for offline storage models
lib/hive/hive_registrar.g.dart Generated Hive adapter registration code
lib/features/user/data/user_repository.dart New repository with Hive caching and stream-based user data
lib/utils/PushNotificationsManager.dart Deleted - push notification logic moved to features
lib/utils/BackgroundTracking.dart Deleted - tracking logic moved to features/fixes
lib/providers/* Deleted - replaced with feature-based repositories and providers
lib/screens/* New screen implementations replacing old page structure

Comment on lines 108 to 111
final apiConnection = InternetConnection.createInstance(
customCheckOptions: [
// TODO: use /ping endpoint.
InternetCheckOption(uri: Uri.parse(apiClient.dio.options.baseUrl)),
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TODO comment indicates the current approach of using the base URL for connectivity checks may not be ideal. The base URL may not be optimized for quick connectivity checks and could cause unnecessary load. Consider implementing a dedicated /ping endpoint on the backend and updating this code to use it for more efficient connectivity detection.

Suggested change
final apiConnection = InternetConnection.createInstance(
customCheckOptions: [
// TODO: use /ping endpoint.
InternetCheckOption(uri: Uri.parse(apiClient.dio.options.baseUrl)),
final String _normalizedBaseUrl =
apiClient.dio.options.baseUrl.replaceAll(RegExp(r'/+$'), '');
final Uri _pingUri = Uri.parse('$_normalizedBaseUrl/ping');
final apiConnection = InternetConnection.createInstance(
customCheckOptions: [
InternetCheckOption(uri: _pingUri),

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +27
getAccessToken: () async => await AuthRepository.getAccessToken() ?? '',
getRefreshToken: () async =>
await AuthRepository.getRefreshToken() ?? '',
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The await keyword is redundant when immediately returning a Future. The async arrow function already returns a Future, so you can remove await and just return the Future directly: getAccessToken: () => AuthRepository.getAccessToken() ?? ''

Copilot uses AI. Check for mistakes.
Text(
'ID: ',
style: TextStyle(
color: Colors.black.withValues(alpha: 0.7),
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the newer withValues API for color opacity is correct for recent Flutter versions. However, ensure the minimum Flutter SDK version in pubspec.yaml supports this API (Flutter 3.27+). If targeting older versions, use the deprecated withOpacity method for compatibility.

Suggested change
color: Colors.black.withValues(alpha: 0.7),
color: Colors.black.withOpacity(0.7),

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +114
unawaited(
Future(() async {
await notificationProvider.refresh();
}),
);
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapping an async call in Future(() async { ... }) is unnecessary. You can directly call notificationProvider.refresh() with unawaited. Simplify to: unawaited(notificationProvider.refresh());

Suggested change
unawaited(
Future(() async {
await notificationProvider.refresh();
}),
);
unawaited(notificationProvider.refresh());

Copilot uses AI. Check for mistakes.
return;
}
}
await syncManager.syncAll();
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stream listener for connection status changes lacks error handling for the syncAll() call. If synchronization fails, the error is not caught or logged. Consider wrapping syncManager.syncAll() in a try-catch block to handle synchronization failures gracefully and log appropriate errors.

Suggested change
await syncManager.syncAll();
try {
await syncManager.syncAll();
} catch (e, stackTrace) {
print('Error during automatic synchronization: $e');
print(stackTrace);
}

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Dec 22, 2025

Codecov Report

❌ Patch coverage is 36.92308% with 328 lines in your changes missing coverage. Please review.
✅ Project coverage is 39.17%. Comparing base (40891cf) to head (98a4418).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/features/bites/domain/models/bite_report.dart 0.00% 75 Missing ⚠️
lib/features/reports/domain/models/photo.dart 0.00% 55 Missing ⚠️
lib/core/providers/pagination_provider.dart 35.18% 35 Missing ⚠️
...ib/features/reports/domain/models/base_report.dart 0.00% 33 Missing ⚠️
...eatures/bites/data/models/bite_report_request.dart 0.00% 29 Missing ⚠️
...ions/presentation/state/notification_provider.dart 37.50% 15 Missing ⚠️
lib/core/utils/style.dart 33.33% 12 Missing ⚠️
...ons/presentation/pages/notification_list_page.dart 87.14% 9 Missing ⚠️
...ters/bite_request_event_environment_converter.dart 11.11% 8 Missing ⚠️
...onverters/bite_request_event_moment_converter.dart 11.11% 8 Missing ⚠️
... and 11 more
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main     #673       +/-   ##
===========================================
+ Coverage   24.50%   39.17%   +14.67%     
===========================================
  Files          27       26        -1     
  Lines        1751      850      -901     
===========================================
- Hits          429      333       -96     
+ Misses       1322      517      -805     
Flag Coverage Δ
unittests 39.17% <36.92%> (+14.67%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
lib/core/repositories/pagination_repository.dart 100.00% <100.00%> (ø)
lib/core/utils/html_parser.dart 88.00% <ø> (ø)
...settings/presentation/state/settings_provider.dart 100.00% <100.00%> (ø)
lib/screens/guide_page.dart 100.00% <100.00%> (ø)
lib/services/analytics_service.dart 12.50% <ø> (ø)
lib/core/data/models/requests.dart 0.00% <0.00%> (ø)
lib/core/localizations/MyLocalizations.dart 2.80% <50.00%> (ø)
lib/core/outbox/outbox_offline_model.dart 0.00% <0.00%> (ø)
lib/core/converters/uint8list_converter.dart 20.00% <20.00%> (ø)
...tures/reports/data/converters/photo_converter.dart 20.00% <20.00%> (ø)
... and 16 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@JohnPalmer
Copy link
Contributor

See the two pull requests I have made to fix minor issues I encountered on this branch when testing on iPhone. In addition:

  1. I am not sure I would use the red "offline mode" banner in the production version. I would rather users don't need to think about whether it is online or offline and that it simply work. That said, if you think it is important to show the they are offline, maybe just don't make it red, as they looks like an error more than normal functioning.

  2. All of the reports I have been trying to send over the past hours end up with an icon of a crossed out cloud when I look at them in My reports. This despite my phone being connect to wifi and to a data connection and despite waiting in the hope they will sync. Please check if they are in fact not syncing (as opposed to the issue being really just about the app displaying an icon art the wrong time or the wrong icon.

@epou
Copy link
Member Author

epou commented Jan 9, 2026

Hey John,

I’ve slightly adapted the PR you opened and have already merged those changes into this branch.

  1. Offline mode -> Good catch. I've changed the color from red to blue (blue aligns better with an informational state rather than a danger/error message)
  2. When the app is offline, reports are saved locally. That’s why we show the crossed-cloud icon (it indicates the data isn’t coming from the “cloud” -> our platform). Once the device is back online, the code automatically attempts to post those locally stored reports to the API. I've just tested this flow on the emulator and it worked as expected.

I can also see 3 adult mosquito reports on the dev server from an iOS device last night (I’m guessing that was you)

  • uKmI
  • hwdS
  • pmyk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants