Skip to content

Conversation

@satviktm7
Copy link

Was able to view the records on scroll itself.

amitverma-egov and others added 30 commits January 21, 2025 15:01
…'t have any validations for userloggedinuuid when team code entered manaully
…/health-campaign-field-worker-app into stock_changes_after_clf
…ed if manualcount is diff from calculated and set default value in product variant field
…th-campaign-field-worker-app into stock_changes_after_clf
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 21, 2025

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

💤 Files selected but had no reviewable changes (4)
  • apps/health_campaign_field_worker_app/lib/pages/beneficiary/custom_deliver_intervention.dart
  • apps/health_campaign_field_worker_app/lib/pages/checklist/custom_survey_form_view.dart
  • apps/health_campaign_field_worker_app/lib/pages/custom_qr_scanner.dart
  • apps/health_campaign_field_worker_app/lib/pages/inventory/custom_stock_details.dart

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update introduces significant new features, refactoring, and removals across the health campaign field worker app. Major highlights include the addition of custom summary report Blocs, closed household and custom scanner Blocs, and new localization delegates for Kirundi. The Android app's native code is overhauled to support location tracking via a foreground service, with corresponding Kotlin classes added and updated. Several new data models and enum values are introduced, especially for configuration and MDMS integration. The complaints registration and inbox features are removed, including their models and Blocs. The localization system transitions from Isar to a SQL-based store. Gradle and project configuration files are modernized, and new ignore rules are added for Flutter Version Management files.

Changes

Files/Paths Change Summary
.gitignore, apps/health_campaign_field_worker_app/.gitignore, .../gradle-wrapper.properties Added ignore rules for FVM files; minor formatting; switched Gradle wrapper to binary distribution.
apps/health_campaign_field_worker_app/README.md Added a note on changing the package name in location_service.kt.
apps/health_campaign_field_worker_app/android/app/build.gradle, .../settings.gradle Modernized Gradle configuration, switched to plugins block, updated SDK/language versions, changed applicationId, added conditional Google Services task disabling.
apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/... Deleted old MainActivity; added new MainActivity with MethodChannel for location tracking and a new LocationService for background location updates.
apps/health_campaign_field_worker_app/ios/Runner.xcodeproj/project.pbxproj Changed iOS bundle identifier from org.egov.salama to org.egov.qa.bi.
apps/health_campaign_field_worker_app/lib/app.dart Added multiple new repository and Bloc providers (custom scanner, summary reports, closed household, etc.), improved locale handling, updated localization and project Bloc dependencies, and reorganized dependency injection.
apps/health_campaign_field_worker_app/lib/blocs/app_initialization/app_initialization.dart Added new master enums to MDMS fetch: searchCLFFilters, refugeeCamps, privacyPolicy.
apps/health_campaign_field_worker_app/lib/blocs/auth/auth.dart Extended login logic to check for new roles: attendanceStaff in addition to districtSupervisor.
apps/health_campaign_field_worker_app/lib/blocs/complaints_inbox/, .../complaints_registration/ Deleted: All complaints registration and inbox Blocs, events, states, and related generated code.
apps/health_campaign_field_worker_app/lib/blocs/custom_blocs/closed_household.dart, ...freezed.dart New: Added ClosedHouseholdBloc, events, and state for handling closed household submissions and summaries.
apps/health_campaign_field_worker_app/lib/blocs/localization/* Replaced Isar with SQL for localization data; updated constructors and methods accordingly.
apps/health_campaign_field_worker_app/lib/blocs/project/project.dart Added service definition and dashboard repositories, bandwidth check; refactored project initialization and selection logic; updated dependencies.
apps/health_campaign_field_worker_app/lib/blocs/projects_beneficiary_downsync/project_beneficiaries_downsync.dart Reordered and updated repository and parameter handling; updated imports.
apps/health_campaign_field_worker_app/lib/blocs/scanner/custom_digit_scanner_bloc.dart, ...freezed.dart New: Added CustomDigitScannerBloc and related event/state classes for barcode/QR code scanning with scan type support.
apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_distribution_summary_report.dart, ...freezed.dart New: Added Bloc and generated code for custom distribution summary reports, aggregating data by date and entity type.
apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_enumeration_summary_report.dart, ...freezed.dart New: Added Bloc and generated code for custom enumeration summary reports, aggregating registration and closed household data.
apps/health_campaign_field_worker_app/lib/data/local/localization.dart, .../repositories/local/localization.dart New: Added LocalizationLocalRepository for SQL-based localization queries and filtering.
apps/health_campaign_field_worker_app/lib/data/local_store/no_sql/schema/app_configuration.dart Added new fields and embedded classes for searchCLFFilters, privacyPolicyConfig, and refugeeCampOptions.
apps/health_campaign_field_worker_app/lib/data/local_store/no_sql/schema/entity_mapper.dart Updated entity mappers: added complaints, removed hFReferral, adjusted mapping order.
apps/health_campaign_field_worker_app/lib/data/repositories/local/custom_project_beneficiary.dart New: Added CustomProjectBeneficiaryLocalRepository with advanced query, bulk insert, and progressBarSearch.
apps/health_campaign_field_worker_app/lib/data/repositories/local/custom_task.dart New: Added CustomTaskLocalRepository with advanced query, listenToChanges, and progressBarSearch.
apps/health_campaign_field_worker_app/lib/data/repositories/oplog.dart New: Added DownsyncOpLogManager stub for downsync model operation logs.
apps/health_campaign_field_worker_app/lib/data/repositories/remote/bandwidth_check.dart Updated exception handling to use DioException instead of DioError.
apps/health_campaign_field_worker_app/lib/data/repositories/remote/localization.dart Switched localization persistence from Isar to Drift SQL; updated loadLocalization logic.
apps/health_campaign_field_worker_app/lib/data/repositories/remote/mdms.dart Added parsing and mapping for privacyPolicyConfig, refugeeCampOptions, and searchCLFFilters in app configuration.
apps/health_campaign_field_worker_app/lib/data/repositories/sync/sync_down.dart, .../sync_up.dart Removed complaints and hFReferral sync-down logic; cleaned up imports and constants; adjusted sync-up logic for complaints.
apps/health_campaign_field_worker_app/lib/firebase_options.dart Updated Android appId, split Firebase options into Default and Prod classes, removed iOS support.
apps/health_campaign_field_worker_app/lib/localization_delegates/cupertino_localization_delegate_ki.dart New: Added CupertinoLocalizationDelegateKi and CupertinoLocalizationKi for Kirundi (rn-BI), with all members unimplemented.
apps/health_campaign_field_worker_app/lib/localization_delegates/material_localization_delegate_ki.dart New: Added MaterialLocalizationDelegateKi, MaterialLocalizationKi, and MaterialLocalizationKiBI for Kirundi (rn_BI) with full localization overrides.
apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.dart, ...freezed.dart, ...g.dart Added new data models: RefugeeCampOptions, SearchCLFFilters; extended wrapper models with new fields and updated serialization.
apps/health_campaign_field_worker_app/lib/models/complaints/complaints.dart, ...freezed.dart, ...g.dart Deleted: All complaints models and their generated code.
apps/health_campaign_field_worker_app/lib/models/data_model.init.dart Added initialization for new downsync and community types mappers.
apps/health_campaign_field_worker_app/lib/models/entities/community_types.dart, ...mapper.dart New: Added CommunityTypes enum and generated mapper.
apps/health_campaign_field_worker_app/lib/models/entities/mdms_master_enums.dart, ...mapper.dart Added new enum values and mapping for searchCLFFilters, privacyPolicy, and refugeeCamps in MasterEnums.
apps/health_campaign_field_worker_app/lib/models/entities/roles_type.dart, ...mapper.dart Added new enum values and mapping for attendanceStaff and communityDistributor in RolesType.
apps/health_campaign_field_worker_app/lib/models/entities/status.dart, ...mapper.dart Added new enum values and mapping for closeHousehold and registered in Status.
apps/health_campaign_field_worker_app/lib/pages/attendance/custom_manage_attendance.dart Renamed ManageAttendancePage to CustomManageAttendancePage; updated UI components and navigation, replaced Digit components with Digit UI equivalents.
apps/health_campaign_field_worker_app/lib/pages/attendance/custom_mark_attendance.dart New: Added CustomMarkAttendancePage for marking attendance with search, validation, and location capture.
apps/health_campaign_field_worker_app/lib/pages/attendance/custom_session_select.dart New: Added CustomAttendanceDateSessionSelectionPage for selecting attendance dates and sessions with validation and info cards.
apps/health_campaign_field_worker_app/lib/pages/authenticated.dart Updated imports, changed background color, altered boundary name display logic, reordered Bloc providers, removed HouseholdDetailsBloc, updated BeneficiaryDownSyncBloc parameters.

Sequence Diagram(s)

sequenceDiagram
    participant FlutterApp
    participant MainActivity (Android)
    participant LocationService
    participant NotificationManager

    FlutterApp->>MainActivity: Invoke "startLocationUpdates" via MethodChannel
    MainActivity->>LocationService: Start foreground service with interval/stop timestamp
    LocationService->>LocationService: Request location updates
    LocationService->>NotificationManager: Show persistent notification
    loop Every interval
        LocationService->>LocationService: Receive location update
        LocationService->>NotificationManager: Update notification with new location
        LocationService->>File: Write location data to file
        LocationService->>MainActivity: Broadcast location update
        MainActivity->>FlutterApp: Forward location update via MethodChannel
    end
    FlutterApp->>MainActivity: Invoke "stopLocationUpdates"
    MainActivity->>LocationService: Stop service
Loading
sequenceDiagram
    participant User
    participant FlutterApp
    participant CustomEnumerationSummaryReportBloc
    participant LocalRepositories

    User->>FlutterApp: Request enumeration summary report
    FlutterApp->>CustomEnumerationSummaryReportBloc: Dispatch loadData(userId)
    CustomEnumerationSummaryReportBloc->>LocalRepositories: Fetch households, beneficiaries, closed household tasks
    CustomEnumerationSummaryReportBloc->>CustomEnumerationSummaryReportBloc: Aggregate counts by date/type
    CustomEnumerationSummaryReportBloc->>FlutterApp: Emit summaryData state
    FlutterApp->>User: Display summary report
Loading

Possibly related PRs

  • #404: Updates lib/app.dart and related Bloc/repository setup, similar to the new Bloc/repository providers and localization changes here.
  • #582: Adds location tracking integration in Android native code, directly related to the new MainActivity and LocationService changes.
  • #433: Removes complaints sync-down logic, matching the removal of complaints-related code and sync logic in this PR.

Suggested reviewers

  • naveenr-egov

Poem

🐇

In fields of code, the carrots grow,
New Blocs and models in tidy rows.
Complaints have hopped away with haste,
While custom summaries take their place.
The bunny tracks your location true,
In Kirundi, “hello” and “how do you do?”
With every merge, the garden’s bright—
Hop on, dear devs, the future’s light!

🥕


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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 42

🧹 Nitpick comments (40)
apps/health_campaign_field_worker_app/README.md (1)

17-18: Enhance the package name change instructions to be more specific.

While this note provides essential information for developers, it could be more helpful with specific steps or examples of how to change the package name in location_service.kt. Consider adding a brief example or link to more detailed documentation about package naming conventions.

-## change the package name of location_service.kt when building as per the desired package name
+## Package Name Configuration
+When building the app, you must update the package name in `location_service.kt` to match your desired package name.
+
+Example: If your package name is `org.egov.fieldworker`, update the first line of `android/app/src/main/kotlin/org/egov/health_campaign_field_worker_app/location_service.kt` to:
+```kotlin
+package org.egov.fieldworker
+```
apps/health_campaign_field_worker_app/lib/blocs/localization/localization.dart (1)

62-65: Consider adding error handling to _loadLocale method.

The _loadLocale method now correctly sets the locale and uses the SQL store, but lacks error handling for potential SQL operation failures.

FutureOr<void> _loadLocale(List codes) async {
  LocalizationParams().setLocale(Locale(codes.first, codes.last));
-  await AppLocalizations(Locale(codes.first, codes.last),sql).load();
+  try {
+    await AppLocalizations(Locale(codes.first, codes.last), sql).load();
+  } catch (error) {
+    debugPrint('Failed to load localizations: $error');
+    // Consider notifying the user if appropriate
+  }
}
apps/health_campaign_field_worker_app/lib/data/repositories/local/localization.dart (1)

29-40: Complex condition building could be more readable.

The complex conditional logic for module exclusion and code inclusion could benefit from clearer variable naming and possibly refactoring into smaller helper methods for better readability.

Consider extracting the module and code condition logic into a separate method like Expression<bool> buildModuleCodeCondition(bool exclude) to make the main method more concise and easier to understand.

apps/health_campaign_field_worker_app/lib/data/repositories/remote/mdms.dart (1)

251-257: Variable naming inconsistency

The variable was renamed from "checklist" to "surveyForm" but the type is still ChecklistTypes. This creates confusion about the nature of the data.

  final List<ChecklistTypes>? checklistTypes =
      element?.checklistTypes.map((e) {
-    final surveyForm = ChecklistTypes()
+    final checklist = ChecklistTypes()
      ..name = e.name
      ..code = e.code;

-    return surveyForm;
+    return checklist;
  }).toList();

Alternatively, if this represents a conceptual change, consider updating the model class name to match the new concept.

apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.dart (3)

93-95: Inconsistent nullability between declaration and semantics

searchCLFFilters is nullable, yet the back‑end will usually send an array (possibly empty). Treating “no key” and “empty list” the same avoids extra null checks at call‑sites:

-@JsonKey(name: 'SEARCH_CLF_FILTERS')
-List<SearchCLFFilters>? searchCLFFilters,
+@JsonKey(name: 'SEARCH_CLF_FILTERS', defaultValue: [])
+List<SearchCLFFilters>? searchCLFFilters,

This preserves backward compatibility and simplifies usage.


220-229: RefugeeCampOptions lacks an active flag

All other option models (e.g. SearchCLFFilters, CommonMasterModel) include an active boolean to allow soft‑deactivation. Was this omitted intentionally? If not, extend the model to maintain consistency:

   factory RefugeeCampOptions({
     required String name,
     required String code,
+    @Default(true) bool active,
   }) = _RefugeeCampOptions;

340-350: SearchCLFFilters.active should be @JsonKey(defaultValue: true)

Without a default, missing active in the payload will throw. Follow existing patterns to default the flag:

-  factory SearchCLFFilters({
+  factory SearchCLFFilters({
     required String name,
     required String code,
-    required bool active,
+    @JsonKey(defaultValue: true) required bool active,
   }) = _SearchCLFFilters;
apps/health_campaign_field_worker_app/lib/data/repositories/remote/localization.dart (2)

37-42: Return type should be Future<void> for clarity

loadLocalization performs side effects and doesn’t return a result, but the current signature Future hides that intent and defeats type checking. Make it explicit:

-Future loadLocalization({
+Future<void> loadLocalization({

45-53: Unnecessary use of join([]) adds complexity

Since no join tables are provided, select alone is sufficient and yields a strongly‑typed result, eliminating the need for readTableOrNull:

-final query = _sql.select(_sql.localization).join([])
-  ..where(...)
+final query = _sql.select(_sql.localization)
+  ..where(...)

This reduces boilerplate and improves readability.

apps/health_campaign_field_worker_app/lib/blocs/projects_beneficiary_downsync/project_beneficiaries_downsync.dart (2)

85-91: Type the speedArray list for safer calculations

List speedArray = []; defaults to List<dynamic>, losing type safety. Use List<double>:

-List speedArray = [];
+final List<double> speedArray = [];

Also, storing a single measurement in a list just to compute an average is overkill—consider using the value directly.


160-166: Disk‑space check assumes 150 KB per entity—make it configurable

Hard‑coding 150 may quickly become outdated as payload size evolves. Extract it into a constant or read from remote config so future changes don’t require a code push.

apps/health_campaign_field_worker_app/lib/pages/attendance/custom_manage_attendance.dart (1)

189-192: Simplified color application in text style

Replaced complex text styling with direct Colors.black application, which is cleaner but loses theme consistency.

While the change simplifies the code, it hardcodes the color rather than using theme values. Consider using theme colors:

- ?.apply(color: Colors.black)
+ ?.apply(color: theme.colorScheme.onSurface)
apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/health_campaign_field_worker_app/location_service.kt (3)

47-58: Notification implementation has redundant code

The same code is executed regardless of the Android version check, making the conditional block unnecessary.

- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-     startForeground(1, notification)
- } else {
-     startForeground(1, notification)
- }
+ startForeground(1, notification)

149-167: File operations lack proper error handling

The file writing operation catches exceptions but only prints stack traces, potentially missing critical errors.

Improve error handling and consider using a more robust approach:

private fun writeToFile(data: String) {
    try {
        val fileName = "location_data.txt"
        val file: File

        // Access Downloads folder
        val downloadsFolder = File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "")
+       if (!downloadsFolder.exists() && !downloadsFolder.mkdirs()) {
+           Log.e("LocationService", "Failed to create downloads directory")
+           return
+       }
        file = File(downloadsFolder, fileName)

-       val fileOutputStream = FileOutputStream(file, true) // Append mode
-       fileOutputStream.write((data + "\n").toByteArray())
-       fileOutputStream.close()
+       FileOutputStream(file, true).use { output ->
+           output.write((data + "\n").toByteArray())
+       }

        // Print the file path
        println("File saved at: ${file.absolutePath}")
    } catch (e: Exception) {
-       e.printStackTrace()
+       Log.e("LocationService", "Error writing location data to file", e)
    }
}

65-66: High-accuracy location request may drain battery

Using PRIORITY_HIGH_ACCURACY for all location requests may consume excessive battery, especially for a background service.

Consider using a more battery-efficient approach:

- priority = LocationRequest.PRIORITY_HIGH_ACCURACY
+ priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY

Or make it configurable based on the use case:

private var locationPriority: Int = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    locationUpdateInterval = intent?.getLongExtra("interval", 60000L) ?: 60000L
    stopAfterTimestamp = intent?.getLongExtra("stopAfterTimestamp", System.currentTimeMillis() + 60000L) ?: System.currentTimeMillis() + 60000L
+   locationPriority = intent?.getIntExtra("priority", LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) 
+      ?: LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
    startLocationUpdates()
    return START_STICKY
}

private fun startLocationUpdates() {
    val locationRequest = LocationRequest.create().apply {
        interval = locationUpdateInterval
        fastestInterval = locationUpdateInterval
-       priority = LocationRequest.PRIORITY_HIGH_ACCURACY
+       priority = locationPriority
    }
}
apps/health_campaign_field_worker_app/lib/pages/authenticated.dart (1)

116-124: ServiceBloc created but never disposed

ServiceBloc is added to the tree, yet ServiceBloc.close() is not called when AuthenticatedPageWrapper is disposed (it’s a StatelessWidget). Normally Flutter takes care of disposing blocs added by BlocProvider, but because _drawerVisibilityController is manually created here and not disposed, please double‑check that no additional unmanaged resources were introduced in ServiceBloc (e.g. timers, streams).

Consider converting AuthenticatedPageWrapper to StatefulWidget and disposing _drawerVisibilityController there.

apps/health_campaign_field_worker_app/lib/data/local_store/no_sql/schema/app_configuration.dart (1)

219-247: Deeply nested embedded objects – watch Isar size limits

Five‑level nesting (PrivacyPolicy → Content → Description → SubDescription) can bloat each collection row. If policies grow, consider normalising into a separate collection and storing only an ID here.

apps/health_campaign_field_worker_app/lib/blocs/scanner/custom_digit_scanner_bloc.dart (3)

1-1: Remove stale comment

// part 'auth.freezed.dart' is unrelated and confuses readers.

-// part 'auth.freezed.dart' need to be added to auto generate the files for freezed model

37-44: Event naming inconsistency (barCode vs barCodes)

Pluralise both the event and state fields to stay consistent.

-@Default([]) List<(BarcodeScanType, GS1Barcode)> barCode,
+@Default([]) List<(BarcodeScanType, GS1Barcode)> barCodes,

This also avoids confusion when calling copyWith(barCodes: event.barCodes).


48-52: Expose manualCode & manage duplicates in state

Consider extending state:

 @Default([]) List<String> qrCodes,
+@Default('') String manualCode,
 @Default(false) bool loading,
 @Default(false) bool duplicate,

and update the Freezed copyWith/constructor accordingly so UI can react to manual entry and duplicate scans.

apps/health_campaign_field_worker_app/lib/data/repositories/local/custom_task.dart (2)

123-126: Redundant status filter

status condition appears twice in the same where clause. Drop the duplicate to keep generated SQL lean.

-  if (query.status != null)
-    sql.task.status.equals(query.status!),

71-78: Heavy query could benefit from paging

progressBarSearch fetches all matching tasks and aggregates in memory. For large datasets this may exhaust RAM. Consider adding limit/offset parameters or using Drift’s StreamPagination utilities.

apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_enumeration_summary_report.dart (1)

291-314: Quadratic scans over large collections – consider set look‑ups

filteredHouseholds, filterProjectBeneficiaryList, and getClosedHouseholdProjectBeneficiary iterate through each list and perform Set.contains per element, which is fine, but you first build a Set<String?> called filteredBeneficiariesClientRefId with nullable entries.
You can:

  1. Build the set as non‑nullable Set<String> and skip nulls during insert.
  2. Replace manual for loops with where plus spread for readability.

Not critical, yet improves maintainability and slightly reduces branching.

apps/health_campaign_field_worker_app/lib/localization_delegates/material_localization_delegate_ki.dart (2)

48-51: shouldReload signature mismatch

shouldReload should receive a covariant LocalizationsDelegate<MaterialLocalizations> parameter, not dynamic. Declare the correct type to avoid implicit‑dynamic warnings:

-  bool shouldReload(old) {
+  @override
+  bool shouldReload(covariant MaterialLocalizationDelegateKi old) {

54-569: Many untranslated strings – fallback to English

Most getters still return English text (e.g., alertDialogLabel, backButtonTooltip).
If Kirundi support is a project requirement, consider completing translations or delegate to Flutter’s fallback mechanism instead of hard‑coding English.

This is not blocking for code correctness but affects UX quality.

apps/health_campaign_field_worker_app/lib/blocs/custom_blocs/closed_household.dart (1)

59-84: Timestamp drift – capture once and reuse

DateTime.now().millisecondsSinceEpoch is invoked dozens of times; the resulting few‑millisecond drift can break optimistic‑locking schemes that rely on identical createdTime across related entities.

Capture a single timestamp at the start of _handleSubmit and reuse it:

-    emit(state.copyWith(loading: true));
-    var locality = LocalityModel(...);
+    emit(state.copyWith(loading: true));
+
+    final now = DateTime.now().millisecondsSinceEpoch;
+    final locality = LocalityModel(...);

-    createdTime: DateTime.now().millisecondsSinceEpoch,
+    createdTime: now,

This also improves readability and performance.

Also applies to: 94-106, 118-134, 140-154

apps/health_campaign_field_worker_app/lib/pages/attendance/custom_session_select.dart (2)

205-236: Heavy filtering and list allocation inside on‑press handler

attendees are filtered every tap, allocating a new list. For large registers this may cause jank.

Extract the filter into a helper and memoise on date/session change instead of every button press.


421-423: getMissedDays returns localised string but ignores locale change

getMissedDays builds and stores the result in the missedDays field only once. If the user changes locale while the page is alive, the description stays in the old language.
Consider computing the string on each build() instead of caching in a field, or rebuild it when AppLocalizations updates.

apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_distribution_summary_report.dart (2)

104-114: Unused variables hint at incomplete aggregation logic

dateVsProjectBeneficiaries and dateVsProjectBeneficiaryClientRefId are created but never populated / consumed.
Either remove them or complete the missing aggregation; keeping dead code harms readability and may mislead maintainers.


271-296: resourceDistributed silently swallows invalid data

The regex/try‑catch logic suppresses all parsing errors and negative / NaN values without telemetry.
At minimum, add logging so data issues surface during QA; otherwise distribution counts can silently drift.

apps/health_campaign_field_worker_app/lib/data/repositories/local/custom_project_beneficiary.dart (1)

36-53: listenToChanges emits deleted rows

The reactive query lacks isDeleted.isNotIn([1, true]). Consumers will receive soft‑deleted records.

apps/health_campaign_field_worker_app/lib/blocs/project/project.dart (3)

337-355: Magic number & un‑bounded fetch in _loadProjectFacilities()

limit: 1000 is hard‑coded three times. If the tenant ever exceeds this count the remainder is silently dropped. Consider:

  1. Replacing the magic number with a const _pageLimit = 1000;.
  2. Implementing paginated fetching (loop until results.length < _pageLimit).

This applies equally to the Facilities query below.


394-440: Heavy synchronous processing on UI thread

The nested attendance / individual / log fetch happens inside _handleProjectSelection and blocks the same isolate that emits BLoC states. With slow networks this noticeably freezes the UI.

Move the whole block to a separate await compute() or isolate / background service, then emit intermediate loading states. This will keep the app responsive.


500-504: Swallowing exceptions hides failure root‑cause

The outer try‑catch converts every error to debugPrint, losing both stack trace and user‑visible error state. Prefer:

} catch (e, st) {
  AppLogger.instance.error('Failed to pre‑fetch attendance data', error: e, stackTrace: st);
  emit(state.copyWith(loading: false, syncError: ProjectSyncErrorType.project));
  return;
}

This preserves diagnostics and ensures the UI shows a consistent error.

apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_enumeration_summary_report.freezed.dart (1)

1-5: Generated code should be excluded from code‑review & VCS

This file is 800+ LOC of machine‑generated Freezed boilerplate. Keeping it in the repository:

• Inflates PRs & slows reviews
• Risks accidental manual edits (header even warns)
• Requires extra CI lint time

Recommend adding *.freezed.dart & *.g.dart to .gitignore or using export-ignore in .gitattributes and generating inside CI/CD instead.

apps/health_campaign_field_worker_app/lib/blocs/scanner/custom_digit_scanner_bloc.freezed.dart (1)

308-315: Large immutable lists – consider UnmodifiableListView only when needed

EqualUnmodifiableListView wrappers are great for immutability but allocate a new list when the source is already immutable (e.g., const []). For high‑frequency scanner events this may cause GC churn. Profiling may show negligible impact, but consider shallow copies (List.unmodifiable) or raw lists if perf issues arise.

apps/health_campaign_field_worker_app/lib/app.dart (2)

105-106: Remove leftover “INFO” placeholder comment
The comment was useful during the migration but now introduces noise and suggests unfinished work.

-              // INFO : Need to add bloc of package Here

348-367: Use the injected ctx instead of outer context for repository look‑ups
Inside the create: callback you ignore the supplied BuildContext (_) and capture the outer context.
Although it works, it is error‑prone and breaks the convention followed elsewhere in this file.

-                      create: (_) {
+                      create: (ctx) {
 ...
-                              householdMemberRepository: context.repository<
+                              householdMemberRepository: ctx.repository<
 ...
-                              taskRepository: context
-                                  .repository<TaskModel, TaskSearchModel>(),
+                              taskRepository:
+                                  ctx.repository<TaskModel, TaskSearchModel>(),

This prevents accidental misuse and reads consistently.

apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/qa/bi/MainActivity.kt (2)

74-78: Add comment explaining Android 13+ specific receiver registration

The code correctly handles the RECEIVER_EXPORTED flag for Android 13+, but it would be helpful to add a comment explaining why this is necessary.

// Register the receiver for location updates, with proper export settings for Android 13+
val filter = IntentFilter("LocationUpdate")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+   // Android 13+ requires explicit receiver export settings for security
    registerReceiver(locationReceiver, filter, Context.RECEIVER_EXPORTED)
} else {
    registerReceiver(locationReceiver, filter)
}

99-107: Move Toast message after successful service stop

The Toast message is shown before actually stopping the service, which might be misleading if the stopService call fails.

private fun stopService() {
    try {
        val serviceIntent = Intent(this, LocationService::class.java)
-       Toast.makeText(this, "Stopping location service", Toast.LENGTH_SHORT).show()
        stopService(serviceIntent)
+       Toast.makeText(this, "Location service stopped", Toast.LENGTH_SHORT).show()
    } catch (e: Exception) {
        e.printStackTrace()
+       Toast.makeText(this, "Failed to stop location service: ${e.message}", Toast.LENGTH_SHORT).show()
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9eb8916 and 5009d88.

⛔ Files ignored due to path filters (40)
  • .github/workflows/dart.yml is excluded by !**/*.yml
  • apps/health_campaign_field_worker_app/android/app/google-services.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/android/app/src/debug/AndroidManifest.xml is excluded by !**/*.xml
  • apps/health_campaign_field_worker_app/android/app/src/main/AndroidManifest.xml is excluded by !**/*.xml
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-hdpi/burundi_logo_tsinda_malaria.jpg is excluded by !**/*.jpg, !**/*.jpg
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png is excluded by !**/*.png, !**/*.png
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-mdpi/burundi_logo_tsinda_malaria.jpg is excluded by !**/*.jpg, !**/*.jpg
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png is excluded by !**/*.png, !**/*.png
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xhdpi/burundi_logo_tsinda_malaria.jpg is excluded by !**/*.jpg, !**/*.jpg
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png is excluded by !**/*.png, !**/*.png
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xxhdpi/burundi_logo_tsinda_malaria.jpg is excluded by !**/*.jpg, !**/*.jpg
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png is excluded by !**/*.png, !**/*.png
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xxxhdpi/burundi_logo_tsinda_malaria.jpg is excluded by !**/*.jpg, !**/*.jpg
  • apps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png is excluded by !**/*.png, !**/*.png
  • apps/health_campaign_field_worker_app/android/app/src/profile/AndroidManifest.xml is excluded by !**/*.xml
  • apps/health_campaign_field_worker_app/assets/animated_json/alert.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/assets/animated_json/error.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/assets/animated_json/inline_loader.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/assets/animated_json/overlay_loader.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/assets/animated_json/page_loader.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/assets/animated_json/success.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/assets/icons/svg/closed_household.svg is excluded by !**/*.svg, !**/*.svg
  • apps/health_campaign_field_worker_app/lib/models/model_configs/enum_community_types.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/lib/models/model_configs/enum_roles.json is excluded by !**/*.json
  • apps/health_campaign_field_worker_app/pubspec.lock is excluded by !**/*.lock, !**/*.lock
  • apps/health_campaign_field_worker_app/pubspec.yaml is excluded by !**/*.yaml
  • mason_templates/digit_entity/hooks/pubspec.lock is excluded by !**/*.lock, !**/*.lock
  • mason_templates/digit_entity/hooks/pubspec.yaml is excluded by !**/*.yaml
  • mason_templates/freezed_bloc/hooks/pubspec.lock is excluded by !**/*.lock, !**/*.lock
  • mason_templates/freezed_bloc/hooks/pubspec.yaml is excluded by !**/*.yaml
  • melos.yaml is excluded by !**/*.yaml
  • packages/attendance_management/analysis_options.yaml is excluded by !**/*.yaml
  • packages/attendance_management/assets/icons/app_icon.png is excluded by !**/*.png, !**/*.png
  • packages/attendance_management/assets/icons/svg/mychecklist.svg is excluded by !**/*.svg, !**/*.svg
  • packages/attendance_management/assets/icons/svg/no_result.svg is excluded by !**/*.svg, !**/*.svg
  • packages/attendance_management/assets/images/powered_by_digit.png is excluded by !**/*.png, !**/*.png
  • packages/attendance_management/build.yaml is excluded by !**/*.yaml
  • packages/attendance_management/pubspec.lock is excluded by !**/*.lock, !**/*.lock
  • packages/attendance_management/pubspec.yaml is excluded by !**/*.yaml
  • packages/auto_route/analysis_options.yaml is excluded by !**/*.yaml
📒 Files selected for processing (68)
  • .gitignore (1 hunks)
  • apps/health_campaign_field_worker_app/.gitignore (2 hunks)
  • apps/health_campaign_field_worker_app/README.md (1 hunks)
  • apps/health_campaign_field_worker_app/android/app/build.gradle (4 hunks)
  • apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/health_campaign_field_worker_app/MainActivity.kt (0 hunks)
  • apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/health_campaign_field_worker_app/location_service.kt (1 hunks)
  • apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/qa/bi/MainActivity.kt (1 hunks)
  • apps/health_campaign_field_worker_app/android/build.gradle (1 hunks)
  • apps/health_campaign_field_worker_app/android/gradle/wrapper/gradle-wrapper.properties (1 hunks)
  • apps/health_campaign_field_worker_app/android/settings.gradle (1 hunks)
  • apps/health_campaign_field_worker_app/ios/Runner.xcodeproj/project.pbxproj (3 hunks)
  • apps/health_campaign_field_worker_app/lib/app.dart (9 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/app_initialization/app_initialization.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/auth/auth.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/complaints_inbox/complaints_inbox.dart (0 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/complaints_inbox/complaints_inbox.freezed.dart (0 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/complaints_registration/complaints_registration.dart (0 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/complaints_registration/complaints_registration.freezed.dart (0 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/custom_blocs/closed_household.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/custom_blocs/closed_household.freezed.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/localization/app_localization.dart (2 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/localization/app_localizations_delegate.dart (2 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/localization/localization.dart (3 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/project/project.dart (9 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/projects_beneficiary_downsync/project_beneficiaries_downsync.dart (4 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/scanner/custom_digit_scanner_bloc.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/scanner/custom_digit_scanner_bloc.freezed.dart (19 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_distribution_summary_report.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_distribution_summary_report.freezed.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_enumeration_summary_report.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_enumeration_summary_report.freezed.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/local/localization.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/local_store/downsync/downsync.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/local_store/no_sql/schema/app_configuration.dart (4 hunks)
  • apps/health_campaign_field_worker_app/lib/data/local_store/no_sql/schema/entity_mapper.dart (2 hunks)
  • apps/health_campaign_field_worker_app/lib/data/network_manager.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/local/custom_project_beneficiary.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/local/custom_task.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/local/localization.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/oplog.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/remote/bandwidth_check.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/remote/downsync.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/remote/localization.dart (3 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/remote/mdms.dart (5 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/sync/sync_down.dart (4 hunks)
  • apps/health_campaign_field_worker_app/lib/data/repositories/sync/sync_up.dart (3 hunks)
  • apps/health_campaign_field_worker_app/lib/firebase_options.dart (2 hunks)
  • apps/health_campaign_field_worker_app/lib/localization_delegates/cupertino_localization_delegate_ki.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/localization_delegates/material_localization_delegate_ki.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.dart (5 hunks)
  • apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.freezed.dart (37 hunks)
  • apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.g.dart (6 hunks)
  • apps/health_campaign_field_worker_app/lib/models/complaints/complaints.dart (0 hunks)
  • apps/health_campaign_field_worker_app/lib/models/complaints/complaints.freezed.dart (0 hunks)
  • apps/health_campaign_field_worker_app/lib/models/complaints/complaints.g.dart (0 hunks)
  • apps/health_campaign_field_worker_app/lib/models/data_model.init.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/models/entities/community_types.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/models/entities/community_types.mapper.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/models/entities/mdms_master_enums.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/models/entities/mdms_master_enums.mapper.dart (2 hunks)
  • apps/health_campaign_field_worker_app/lib/models/entities/roles_type.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/models/entities/roles_type.mapper.dart (2 hunks)
  • apps/health_campaign_field_worker_app/lib/models/entities/status.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/models/entities/status.mapper.dart (2 hunks)
  • apps/health_campaign_field_worker_app/lib/pages/attendance/custom_manage_attendance.dart (7 hunks)
  • apps/health_campaign_field_worker_app/lib/pages/attendance/custom_mark_attendance.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/pages/attendance/custom_session_select.dart (1 hunks)
  • apps/health_campaign_field_worker_app/lib/pages/authenticated.dart (6 hunks)
💤 Files with no reviewable changes (8)
  • apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/health_campaign_field_worker_app/MainActivity.kt
  • apps/health_campaign_field_worker_app/lib/models/complaints/complaints.g.dart
  • apps/health_campaign_field_worker_app/lib/models/complaints/complaints.dart
  • apps/health_campaign_field_worker_app/lib/blocs/complaints_registration/complaints_registration.dart
  • apps/health_campaign_field_worker_app/lib/blocs/complaints_inbox/complaints_inbox.dart
  • apps/health_campaign_field_worker_app/lib/models/complaints/complaints.freezed.dart
  • apps/health_campaign_field_worker_app/lib/blocs/complaints_registration/complaints_registration.freezed.dart
  • apps/health_campaign_field_worker_app/lib/blocs/complaints_inbox/complaints_inbox.freezed.dart
🧰 Additional context used
🪛 Gitleaks (8.21.2)
apps/health_campaign_field_worker_app/lib/firebase_options.dart

103-103: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

🔇 Additional comments (87)
apps/health_campaign_field_worker_app/android/build.gradle (1)

34-34: No-op whitespace change.
Removed the trailing newline at the end of the file. This is a non-functional formatting adjustment.

apps/health_campaign_field_worker_app/android/gradle/wrapper/gradle-wrapper.properties (1)

5-5: Switched to binary-only Gradle distribution.
Using gradle-7.4-bin.zip reduces download size and is sufficient for build purposes. Ensure no need for source distributions in local troubleshooting scenarios.

.gitignore (1)

59-62: Added Flutter Version Management ignore rules.
Ignoring .fvm/ and .fvmrc prevents checking in Flutter version manager artifacts. This aligns with the root and app-level .gitignore updates.

apps/health_campaign_field_worker_app/.gitignore (2)

36-36: Added environment-specific ignore rule.
Ignoring .env-qa ensures CI/CD or local QA environment files are not committed. This aligns with best practices.


48-51: Ignored FVM cache directories.
Adding .fvm/ and .fvmrc prevents Flutter Version Management artifacts from being checked in.

apps/health_campaign_field_worker_app/lib/data/local_store/downsync/downsync.dart (1)

5-5: Import path change looks good.

The change from the previous import to a relative path for the downsync model aligns with the broader import restructuring across the app. This improves modularity and makes the source of the model clearer.

apps/health_campaign_field_worker_app/lib/data/network_manager.dart (1)

7-12: Improved import specificity.

Replacing the broad package import with explicit imports for each entity model improves code clarity and modularity. This makes dependencies more transparent and follows best practices for import management.

apps/health_campaign_field_worker_app/lib/data/repositories/remote/downsync.dart (1)

4-4: Import path change looks good.

The change to a relative path for the downsync model is consistent with the import restructuring seen across the app. This ensures proper model resolution after the apparent restructuring of model locations.

apps/health_campaign_field_worker_app/lib/data/repositories/remote/bandwidth_check.dart (1)

30-30:

✅ Verification successful

Updated to use DioException instead of DioError.

Good update to use DioException instead of the deprecated DioError. This change aligns with newer versions of the Dio package where this rename occurred.


🌐 Web query:

When was DioError renamed to DioException in the Dio package?

💡 Result:

The DioError class in the Dio package was officially renamed to DioException in the Dio 5.x series. The source code explicitly marks DioError as deprecated with the note: “Use DioException instead. This will be removed in 6.0.0”[8]. This means that starting with Dio 5.0.0, developers are encouraged to use DioException, and DioError serves as an alias for backward compatibility until version 6.0.0, where it will be completely removed[8]. The changelog for the Dio package also indicates that this transition occurred in the 5.x releases, with continued references to deprecating DioError in favor of DioException[9].

So, the renaming from DioError to DioException occurred with the release of Dio 5.0.0, and developers should now use DioException to handle errors when working with newer versions of the package[8][9].

Citations:


Confirmed: DioException Is the Correct Error Type

The DioError class was officially renamed to DioException starting in Dio 5.0.0 (with DioError marked deprecated and slated for removal in 6.0.0). Your update to catch DioException is accurate and aligns with the latest Dio package API.

apps/health_campaign_field_worker_app/lib/blocs/auth/auth.dart (1)

102-104: Added role check for attendanceStaff

The authentication logic has been expanded to provide special privileges to users with the attendanceStaff role, similar to districtSupervisor. This ensures attendanceStaff users properly get their logged-in individual details fetched from the remote repository and have their ID stored in local storage.

apps/health_campaign_field_worker_app/lib/blocs/app_initialization/app_initialization.dart (2)

99-100: Added new master enums for HCM module

The addition of searchCLFFilters and refugeeCamps to the HCM module master details is appropriate for expanding the application's functionality. These new configuration options will help with filtering and displaying records related to the intendance feature.


107-108: Added privacyPolicy master enum to common masters

The addition of the privacyPolicy enum to the common masters module is appropriate for ensuring privacy policy configuration is properly loaded during app initialization.

apps/health_campaign_field_worker_app/lib/models/entities/roles_type.mapper.dart (2)

42-45: Added decode support for new roles

The mapper has been properly extended to decode string values for the new attendanceStaff and communityDistributor roles. This ensures correct deserialization when these roles are received from the backend.


68-71: Added encode support for new roles

The mapper now correctly encodes the new role enum values to their string representations for API communication. This completes the bidirectional mapping required for the new roles.

apps/health_campaign_field_worker_app/lib/models/entities/status.dart (2)

28-31: Added new status values for household management

The addition of closeHousehold and registered status values enhances the application's ability to track household states. These new statuses align with the PR objective of improving the intendance feature to show records immediately upon scrolling.


6-33: Improved enum formatting for better readability

The Status enum has been reformatted with consistent indentation and line breaks, making it more readable while preserving its functionality. This is a good practice for maintaining clean code as the enum grows.

apps/health_campaign_field_worker_app/lib/models/entities/status.mapper.dart (2)

48-51: Added support for new status values

The decoder now correctly handles the new closeHousehold and registered status values, which will help support the new features for household closure tracking and registration status.


80-83: Implemented bidirectional mapping for new statuses

The encoder implementation aligns with the decoder, ensuring proper serialization of the new status values when sending data to the backend.

apps/health_campaign_field_worker_app/lib/models/entities/mdms_master_enums.mapper.dart (2)

64-69: Added decoder support for new MDMS master enums

The implementation properly handles the three new enum values for search filters, privacy policy, and refugee camps configurations. This allows the app to correctly parse these values from backend responses.


114-119: Added encoder support for new MDMS master enums

The encoder implementation correctly matches the decoder, ensuring consistent bidirectional serialization for the new configuration options.

apps/health_campaign_field_worker_app/lib/models/entities/mdms_master_enums.dart (1)

44-49: Added new master enum values with appropriate annotations

The implementation adds three new configuration-related enums with their corresponding mappable values. Note that there's a slight inconsistency in the casing style - "PrivacyPolicy" uses PascalCase while the others use "UPPER_SNAKE_CASE". This appears intentional but might be worth verifying with the backend API contract.

Verify that the casing of the string values matches what the backend expects, especially for "PrivacyPolicy" which uses a different casing pattern than the other values.

apps/health_campaign_field_worker_app/lib/models/entities/roles_type.dart (2)

8-21: Improved code formatting for better readability

The enum values have been reformatted with annotations and enum members on separate lines, which improves readability while maintaining the same functionality.


22-25: Added new role types for expanded user role system

The implementation adds two new roles: attendanceStaff and communityDistributor. These roles will enable more granular permission control and role-specific features in the application.

Ensure that these new roles have been properly integrated into the authentication and authorization flows throughout the application. For example, verify that any role-based UI elements or permissions checks have been updated to handle these new roles appropriately.

apps/health_campaign_field_worker_app/lib/models/entities/community_types.dart (1)

1-12: New enum definition looks well-structured

The CommunityTypes enum is properly defined with appropriate mappable annotations for serialization. The naming convention follows Dart standards with camelCase for enum values and snake_case for serialized values.

This enum will help standardize community type references throughout the app and provides proper serialization support via the dart_mappable library.

apps/health_campaign_field_worker_app/lib/data/repositories/sync/sync_up.dart (1)

223-225: Improved entity matching logic

This change enhances the precision of finding the specific OpLogEntry by matching on clientReferenceId instead of assuming the entry's position. This makes the sync process more reliable, especially when dealing with multiple entries.

apps/health_campaign_field_worker_app/lib/blocs/localization/app_localizations_delegate.dart (1)

2-2: Successful migration from Isar to SQL data store

The localization delegate has been properly updated to use LocalSqlDataStore instead of Isar. This change aligns with the broader migration of localization data handling from NoSQL to SQL across the app.

The constructor, field type, and load method have all been consistently updated to reflect this change in data storage strategy.

Also applies to: 10-10, 12-12, 31-31

apps/health_campaign_field_worker_app/lib/models/data_model.init.dart (1)

6-14: Properly extended mapper initialization

The imports have been reorganized with appropriate aliases, and the initializeMappers() function has been extended to initialize additional mappers for new models including:

  • Downsync related mappers (DownsyncSearchModelMapper, DownsyncModelMapper, DownsyncAdditionalFieldsMapper)
  • CommunityTypesMapper

This change supports the new models introduced elsewhere in the PR, ensuring proper serialization/deserialization capabilities.

Also applies to: 17-27

apps/health_campaign_field_worker_app/lib/data/local_store/no_sql/schema/entity_mapper.dart (2)

1-5: The imports have been consolidated well.

The import statements have been consolidated from individual entity imports to broader package imports, making the code cleaner and more maintainable.


66-73: New complaints case and service case repositioning look good.

The addition of the "complaints" case and repositioning of the "service" case align with the broader project changes where complaints-related models are being restructured. The implementation follows the established pattern consistently.

apps/health_campaign_field_worker_app/lib/blocs/localization/localization.dart (2)

2-9: Imports correctly updated for SQL-based localization.

The import statements have been properly updated to support the transition from Isar NoSQL to SQL-based data store for localization.


18-24: Successfully transitioned from Isar to LocalSqlDataStore.

The LocalizationBloc constructor and properties now use LocalSqlDataStore instead of Isar, which aligns with the broader refactoring of the localization subsystem.

apps/health_campaign_field_worker_app/lib/data/repositories/local/localization.dart (1)

1-9: Imports are correctly structured for the new repository.

The import statements provide the necessary dependencies for SQL operations and localization utilities.

apps/health_campaign_field_worker_app/lib/models/entities/community_types.mapper.dart (1)

1-53: Generated mapper code looks correct.

This is auto-generated code for mapping between CommunityTypes enum values and their string representations. The generation follows standard patterns and implements the mapping correctly.

apps/health_campaign_field_worker_app/lib/blocs/localization/app_localization.dart (1)

1-1: Clean transition from Isar to SQL storage for localization

The code effectively migrates localization data storage from Isar (NoSQL) to SqlStore, maintaining the same functionality with a different backend. The repository pattern usage is well-implemented.

One suggestion: Consider cleaning up possibly unused NoSQL schema imports (like on line 3-4) if they're no longer needed for localization functionality.

Also applies to: 5-5, 10-12, 22-24, 29-31

apps/health_campaign_field_worker_app/android/settings.gradle (1)

1-27: Well-executed modernization of Gradle configuration

The changes follow modern Gradle best practices by:

  • Using pluginManagement and plugins DSL
  • Programmatically handling Flutter SDK path with proper error checking
  • Explicit version management for dependencies
  • Clear repository declarations

This makes the build configuration more maintainable and readable.

apps/health_campaign_field_worker_app/lib/data/repositories/remote/mdms.dart (3)

214-240: Well-structured mapping for privacy policy configuration

The implementation correctly maps the nested privacy policy structure with proper null handling. The structure with Content, Description, and SubDescription is well-organized.

Consider adding comments to explain the complex nested structure of the privacy policy configuration to help future developers understand the data model.


277-284: LGTM: Clean implementation of refugee camp options

The mapping for refugee camp options follows the established pattern and is well-implemented.


336-344: LGTM: Well-structured implementation for search filters

The implementation for searchCLFFilters follows the established pattern and is correctly integrated into the configuration.

apps/health_campaign_field_worker_app/lib/data/local/localization.dart (3)

18-27: Avoid repeated instantiation of LocalizationParams

LocalizationParams() is invoked multiple times inside this method. Because it almost certainly behaves like a value‑object / singleton, you can cache it in a local variable to (a) avoid unnecessary allocations and (b) make the code easier to read.

-    // Add condition for locale if provided
-    if (LocalizationParams().locale != null) {
-      final localeString = '${LocalizationParams().locale!}';
+    final params = LocalizationParams();
+
+    // Add condition for locale if provided
+    if (params.locale != null) {
+      final localeString = params.locale!;

[ suggest_optional_refactor ]


31-50: contains() may lead to unintended partial matches

Using sql.localization.module.contains(moduleToExclude) will match any module whose name merely contains the supplied substring (e.g. searching for hr will also match ehr).
If the intent is an exact match, prefer equals(); if multiple exact modules are required, use isIn([...]).

[ request_verification ]


33-37: Constant(false) eliminates rows when no code filter is supplied

When no code filter is given, codeCondition becomes Constant(false) which is OR‑ed with moduleCondition.
This still works, but generates "moduleCondition OR FALSE" in SQL, which prevents SQLite from using indexes and slightly complicates the query plan.
You can eliminate the extra expression by skipping the OR when the list is empty.

[ suggest_optional_refactor ]

apps/health_campaign_field_worker_app/lib/firebase_options.dart (2)

55-61: Hard‑coded GCP API key committed to VCS

Static analysis (gitleaks) flags the API key on lines 56 and 103 as a potential secret.
Even if your Firebase project is currently locked down, publishing keys in a public repo increases the attack surface.

Recommended actions:

  1. Regenerate and restrict the key(s) in Google Cloud → API & Services.
  2. Move secrets to a secure storage mechanism (e.g. environment variables + flutter_dotenv, CI secret manager, etc.).
  3. Add the regenerated key to .gitignore/secret‑scanning allow‑list if absolutely necessary in code.

[ flag_critical_issue ]

Also applies to: 102-108

🧰 Tools
🪛 Gitleaks (8.21.2)

56-56: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)


64-100: Large duplication between DefaultFirebaseOptions and ProdFirebaseOptions

Both classes are identical except for appId. You can remove ~80 duplicated LOC by extracting the common logic and only parameterising the differing values, e.g.:

class _FirebaseOptsBuilder {
  const _FirebaseOptsBuilder(this.appId);
  final String appId;

  FirebaseOptions build() => const FirebaseOptions(
        apiKey: _kApiKey,
        appId: appId,
        messagingSenderId: '397617237644',
        projectId: 'digit-health-75ed0',
        storageBucket: 'digit-health-75ed0.appspot.com',
      );
}

class FirebaseOptionsSet {
  static const _kApiKey = '***'; // move to secret storage

  static final dev = _FirebaseOptsBuilder('1:...:android:2efde986bec30f99f6b5a9').build();
  static final prod = _FirebaseOptsBuilder('1:...:android:68fc441605038da0f6b5a9').build();
}

[ suggest_optional_refactor ]

apps/health_campaign_field_worker_app/android/app/build.gradle (2)

76-78: $kotlin_version may be undefined after the plugin‑block migration

plugins { id 'kotlin-android' } automatically supplies a Kotlin version, but the $kotlin_version Gradle property you reference here is not declared in this file any more.
If it isn’t set in the root gradle.properties, this line will break the build with “Could not find method kotlin_version”.

-implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+implementation("org.jetbrains.kotlin:kotlin-stdlib")

or simply rely on the BOM:

implementation(platform("org.jetbrains.kotlin:kotlin-bom"))

[ flag_critical_issue ]


63-69: Conditionally disabling Google‑Services tasks still keeps the plugin on the class‑path

If USE_GOOGLE_SERVICES is absent you disable the tasks, but the plugin class is still initialised (and thus Gradle downloads it).
Consider applying the plugin only when desired:

plugins {
  ...
  id 'com.google.gms.google-services' apply false
}

if (project.hasProperty('USE_GOOGLE_SERVICES')) {
  apply plugin: 'com.google.gms.google-services'
}

[ suggest_optional_refactor ]

apps/health_campaign_field_worker_app/lib/data/repositories/sync/sync_down.dart (3)

261-306: Missing break; causes illegal fall‑through

The case DataModelType.sideEffect: block does not end with break, return, or continue, so the compiler will throw “Switch case must end with break” for Dart >= 2.17.

Add an explicit break; (or return) after line 304.

   }
 }
 
 break; // ← add this
-
 case DataModelType.referral:

[ flag_critical_issue ]


552-560: Potential null‑assertion crash in attendance search

map((e) => e.clientReferenceId!) force‑unwraps clientReferenceId, yet a few lines later you treat the same field as nullable (toString() call).
If any entry has a null clientReferenceId, the ! will throw before you even reach the null‑safe handling below.

Recommend filtering out nulls explicitly:

-  .map((e) => e.clientReferenceId!)
+  .where((e) => e.clientReferenceId != null)
+  .map((e) => e.clientReferenceId!)

[ flag_critical_issue ]


428-433: Magic strings replace previously centralised constants

Inline literals 'taskResourceId' and 'householdAddressId' have replaced the earlier taskResourceIdKey / householdAddressIdKey constants.
This increases the risk of typos and makes refactoring harder. Consider reinstating the constants at the top of the file (or in a shared constants.dart).

[ suggest_essential_refactor ]

Also applies to: 181-186

apps/health_campaign_field_worker_app/lib/blocs/projects_beneficiary_downsync/project_beneficiaries_downsync.dart (2)

5-6: Confirm API parity between disk_space_update and previous package

DiskSpace.getFreeDiskSpace is still invoked, but the imported package changed to disk_space_update.
If the class or method signature differs, this will be a compile‑time error. Please verify that the new package exposes the same static API or update the call accordingly.


211-218: Changing repository order may break writeToEntityDB

individualLocalRepository is now passed first. If writeToEntityDB relies on positional correspondence with the server payload (e.g., same index → same entity type), this silent change could mis‑route data.
Verify the implementation and update its internal mapping/tests if necessary.

apps/health_campaign_field_worker_app/lib/pages/attendance/custom_manage_attendance.dart (12)

6-10: Updated imports to use the new UI component library

The imports have been properly updated from digit_components to the new digit_ui_components package, which is good for consistency.


14-20: Correctly imported necessary modules with consistent pattern

The imports include necessary modules from attendance management and router configurations.


22-31: Class renamed consistently from ManageAttendancePage to CustomManageAttendancePage

The class and state names have been renamed consistently, maintaining inheritance from LocalizedStatefulWidget.


66-67: Theme retrieval approach updated to standard pattern

Changed from using DigitTheme singleton to the standard Theme.of(context) approach, which is the recommended pattern in Flutter.


97-104: Date formatting utilities consistently updated

Changed date formatting logic to use the AttendanceDateTimeManagement utility consistently.


180-185: Improved layout with theme-based spacing

Padding values now use theme-based spacers instead of fixed constants, which is better for consistency and theming support.


277-279: Updated card component with consistent theming

The DigitCard widget is used with theme-based spacing, ensuring consistent UI.


280-286: Replaced DigitTableCard with LabelValueSummary

UI components were switched from DigitTableCard to LabelValueSummary with LabelValueItem for displaying key-value pairs.


288-294: Updated button implementation with explicit properties

Changed from DigitElevatedButton to DigitButton with explicit size, type, and layout properties.


296-301: Updated toast notification API

Toast notifications changed from DigitToast.show to Toast.showToast with the new API signature.


307-310: Toast implementation consistent with earlier change

The second toast usage matches the first one, maintaining consistency in the codebase.


312-317: Updated routing to use custom implementation

Route pushed on button press was changed from AttendanceDateSessionSelectionRoute to CustomAttendanceDateSessionSelectionRoute.

apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.g.dart (8)

127-129: Added support for refugee camp options

New field for refugee camp options with proper JSON serialization/deserialization.


142-144: Added support for searchCLFFilters

New field for search CLF filters with proper nullable handling in JSON deserialization.


164-164: Added proper serialization for refugee camp options

The serialization entry correctly maps the refugeeCampOptions field to its JSON key.


169-169: Added proper serialization for search CLF filters

The serialization entry correctly maps the searchCLFFilters field to its JSON key.


196-198: Added support for privacy policy configuration

New field for privacy policy configuration with proper JSON deserialization.


206-206: Added proper serialization for privacy policy configuration

The serialization entry correctly maps the privacyPolicyConfig field to its JSON key.


320-332: Added new RefugeeCampOptions implementation

Implemented JSON serialization/deserialization for the RefugeeCampOptions class with name and code fields.


468-482: Added new SearchCLFFilters implementation

Implemented JSON serialization/deserialization for the SearchCLFFilters class with name, code, and active fields.

apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/health_campaign_field_worker_app/location_service.kt (2)

74-79: Improved service lifecycle management with auto-stop

The service properly checks if it should stop based on the specified timestamp, which helps prevent unnecessary battery drain.


21-27:

❓ Verification inconclusive

Location service implementation with insufficient configuration validation

The location service lacks validation for configuration parameters and doesn't handle potential permission issues.

The service should validate location permissions and handle configuration more robustly. Add permission checks and error handling:

private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback
private var locationUpdateInterval: Long = 60000L
private var stopAfterTimestamp: Long = 0L
+ private var isServiceRunning = false

+ private fun hasLocationPermission(): Boolean {
+     // Check for ACCESS_FINE_LOCATION and ACCESS_BACKGROUND_LOCATION
+     return ContextCompat.checkSelfPermission(this, 
+         Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
+ }

Can you search the Android manifest to see if the required permissions are declared?


🏁 Script executed:

#!/bin/bash
grep -r "android.permission.ACCESS_FINE_LOCATION\|android.permission.ACCESS_BACKGROUND_LOCATION\|android.permission.FOREGROUND_SERVICE" apps/health_campaign_field_worker_app/android/

Length of output: 184


🏁 Script executed:

#!/bin/bash
# Locate the AndroidManifest.xml and check for required permissions
manifest=$(find apps/health_campaign_field_worker_app/android -type f -iname "AndroidManifest.xml")
if [ -z "$manifest" ]; then
  echo "No AndroidManifest.xml found"
  exit 0
fi

echo "Found manifest at: $manifest"
echo "--- Checking for ACCESS_FINE_LOCATION ---"
grep -n "android.permission.ACCESS_FINE_LOCATION" "$manifest" || echo "not declared"
echo "--- Checking for ACCESS_BACKGROUND_LOCATION ---"
grep -n "android.permission.ACCESS_BACKGROUND_LOCATION" "$manifest" || echo "not declared"
echo "--- Checking for FOREGROUND_SERVICE ---"
grep -n "android.permission.FOREGROUND_SERVICE" "$manifest" || echo "not declared"

Length of output: 192


🏁 Script executed:

#!/bin/bash
# Search for AndroidManifest.xml in the entire health campaign field worker app
find apps/health_campaign_field_worker_app -type f -iname "AndroidManifest.xml"

Length of output: 79


Ensure runtime permission checks and manifest declarations

The LocationService still needs runtime permission validation and manifest entries for location and foreground service permissions.

• In LocationService, add a flag and permission check:

 private lateinit var fusedLocationClient: FusedLocationProviderClient
 private lateinit var locationCallback: LocationCallback
 private var locationUpdateInterval: Long = 60000L
 private var stopAfterTimestamp: Long = 0L
+ private var isServiceRunning = false

+ private fun hasLocationPermission(): Boolean {
+     // Check for ACCESS_FINE_LOCATION and ACCESS_BACKGROUND_LOCATION
+     return ContextCompat.checkSelfPermission(
+         this, Manifest.permission.ACCESS_FINE_LOCATION
+     ) == PackageManager.PERMISSION_GRANTED
+ }

• Confirm that your Android manifest (or merged manifests) includes:

  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_BACKGROUND_LOCATION
  • android.permission.FOREGROUND_SERVICE

I couldn’t locate an AndroidManifest.xml under apps/health_campaign_field_worker_app/android. Please verify the manifest location and ensure these permissions are declared.

apps/health_campaign_field_worker_app/lib/pages/authenticated.dart (2)

52-52: Background colour change aligns with Material 3 defaults – looks good

Switching from colorScheme.background to colorScheme.surface helps widgets blend better with elevation overlays in Material 3. No functional impact spotted.


192-200:

❌ Incorrect review comment

Parameter order changed – verify all call sites

Constructor arguments of BeneficiaryDownSyncBloc were re‑ordered; existing instantiations outside this file will now break at compile‑time if not updated. A quick grep can confirm:


🏁 Script executed:

rg --pretty 'BeneficiaryDownSyncBloc\('

Length of output: 324


🏁 Script executed:

#!/bin/bash
sed -n '1,200p' apps/health_campaign_field_worker_app/lib/blocs/projects_beneficiary_downsync/project_beneficiaries_downsync.dart

Length of output: 8069


🏁 Script executed:

#!/bin/bash
sed -n '150,240p' apps/health_campaign_field_worker_app/lib/pages/authenticated.dart

Length of output: 4449


Dismiss: Named parameter reordering is non‑breaking

Reordering named parameters in Dart does not affect call sites—arguments are matched by name, not position. A search reveals only one instantiation:

  • apps/health_campaign_field_worker_app/lib/pages/authenticated.dart – uses named arguments that exactly match the constructor’s parameter names.

No other call sites exist. No changes required.

Likely an incorrect or invalid review comment.

apps/health_campaign_field_worker_app/lib/data/local_store/no_sql/schema/app_configuration.dart (2)

73-75: 👍 Added CLF search filters

Field and embedded class are modelled correctly and annotated, so Isar will persist them without additional migration steps.


174-179: Embedded list inside SearchCLFFilters is fine

No issues found; all attributes are primitive types so Isar supports the object graph.

apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_distribution_summary_report.freezed.dart (1)

1-6: Generated file detected – skipping manual review

This file is produced by freezed and should not be edited directly. No manual review required unless you committed it by mistake.

apps/health_campaign_field_worker_app/lib/blocs/summary_reports/custom_enumeration_summary_report.dart (1)

150-158: Incorrect task‑reason bucket assignment

ClosedHouseholdReasonsEnum.closed tasks are stored in dateVsClosedHouseholdAbsentTask, which is semantically wrong and will mis‑report metrics.

-        if (reason == ClosedHouseholdReasonsEnum.closed.name.toUpperCase()) {
-          dateVsClosedHouseholdAbsentTask
+        if (reason == ClosedHouseholdReasonsEnum.closed.name.toUpperCase()) {
+          dateVsClosedHouseholdTask      // or …ClosedHouseholdClosedTask

Verify the three categories (closed / absent / refusal) and ensure each feeds the right map.

apps/health_campaign_field_worker_app/lib/localization_delegates/material_localization_delegate_ki.dart (1)

36-46: ⚠️ Potential issue

Delegate returns EN localisation class instead of Kirundi

load() constructs MaterialLocalizationKiBI which is explicitly documented as “English, as used in India”.
For Kirundi you likely want a MaterialLocalizationKi instance with localeName = 'rn_BI'.

-    return MaterialLocalizationKiBI(
+    return MaterialLocalizationKi(
         localeName: 'rn_BI',

(or create MaterialLocalizationKiBI with Kirundi strings).

Current behaviour will surface English labels despite selecting Kirundi.

Likely an incorrect or invalid review comment.

apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.freezed.dart (2)

944-946: LGTM: Generated model changes for new app configurations

This auto-generated code correctly implements new app configuration models for refugee camps and search filters. The integration follows the same patterns as existing models with proper serialization, equality checks, and immutability.

Also applies to: 958-960, 994-995, 1029-1030, 1034-1035, 1075-1078, 1165-1166, 1170-1171, 1211-1214, 1232-1234, 1289-1290, 1294-1295, 1389-1397, 1442-1452, 1466-1469, 1497-1498, 1507-1508, 1527-1528, 1532-1533, 1617-1619, 1632-1634, 3381-3534, 5149-5320


1819-1821: LGTM: Privacy policy configuration addition

The addition of privacyPolicyConfig to the CommonMastersWrapperModel is properly implemented with the required JSON annotations and integration into the model's properties, equality, and serialization logic.

Also applies to: 1837-1839, 1961-1969, 1973-1974, 1984-1986, 1994-1995, 2014-2019, 2031-2033

apps/health_campaign_field_worker_app/lib/blocs/custom_blocs/closed_household.dart (1)

54-57: Unused locality variable until deep copy

locality is declared but only applied inside later copyWith calls, while new LocalityModel instances are created repeatedly in the meantime.
Either reuse the same instance everywhere or construct it only when needed; this will avoid accidental divergence.

apps/health_campaign_field_worker_app/lib/blocs/custom_blocs/closed_household.freezed.dart (1)

1-890: Generated file – no manual review required

closed_household.freezed.dart is auto‑generated by Freezed; manual modifications would be overwritten.
Skipping detailed review unless generation errors are reported.

apps/health_campaign_field_worker_app/lib/pages/attendance/custom_mark_attendance.dart (1)

76-83: Using context inside initState can throw if provider is not yet mounted

context.repository… and context.read… rely on ancestor providers already being in the tree.
If this page is the provider boundary, a runtime exception will be thrown.

Consider deferring repository look‑ups to didChangeDependencies() or retrieving them from constructor parameters.

apps/health_campaign_field_worker_app/lib/blocs/project/project.dart (1)

189-192: ⚠️ Potential issue

Connectivity().checkConnectivity() misuse – logic always false

checkConnectivity() returns a single ConnectivityResult enum, hence firstOrNull is undefined and currently always null.

-    final isOnline =
-        connectivityResult.firstOrNull == ConnectivityResult.wifi ||
-            connectivityResult.firstOrNull == ConnectivityResult.mobile;
+    final isOnline = connectivityResult == ConnectivityResult.wifi ||
+        connectivityResult == ConnectivityResult.mobile;

Without this fix every launch is treated as offline even when a network is available.

⛔ Skipped due to learnings
Learnt from: naveenr-egov
PR: egovernments/health-campaign-field-worker-app#684
File: apps/health_campaign_field_worker_app/lib/utils/utils.dart:0-0
Timestamp: 2025-02-14T10:03:34.143Z
Learning: The connectivity_plus package's checkConnectivity() method returns List<ConnectivityResult>, so firstOrNull should be used to get the first connectivity state.
apps/health_campaign_field_worker_app/lib/blocs/scanner/custom_digit_scanner_bloc.freezed.dart (1)

6-20: Record‑type ((T1,T2)) requires Dart 3 – check minimum SDK

The generated unions rely on Dart 3’s record syntax ((BarcodeScanType, GS1Barcode)).
Ensure sdk: ">=3.0.0 <4.0.0" is declared in pubspec.yaml; otherwise builds on older toolchains will fail.

apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/qa/bi/MainActivity.kt (1)

1-122:

✅ Verification successful

Verify LocationService class implementation

The code references a LocationService class that isn't defined in this file. Ensure that this class exists in the project and is properly implemented.


🏁 Script executed:

#!/bin/bash
# Search for LocationService class definition
rg "class LocationService" --type kotlin

Length of output: 206


🏁 Script executed:

#!/bin/bash
FILE="apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/health_campaign_field_worker_app/location_service.kt"

echo "---------- File content (first 200 lines) ----------"
sed -n '1,200p' "$FILE"

echo -e "\n---------- sendBroadcast occurrences -----------"
rg -n "sendBroadcast" "$FILE"

echo -e "\n---------- Intent action usage ------------"
rg -n "Intent" "$FILE"

Length of output: 8120


LocationService implementation confirmed
The LocationService class is present at
apps/health_campaign_field_worker_app/android/app/src/main/kotlin/org/egov/health_campaign_field_worker_app/location_service.kt
and correctly:

  • Extends Service with onStartCommand, onDestroy, and onBind implementations
  • Creates a notification channel and runs as a foreground service
  • Requests high‑accuracy location updates via FusedLocationProviderClient
  • Broadcasts an intent with action "LocationUpdate" containing the "latitude", "longitude", and "accuracy" extras that match the receiver in MainActivity

No further changes needed here.

"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.egov.salama;
PRODUCT_BUNDLE_IDENTIFIER = org.egov.qa.bi;
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Updated iOS bundle identifiers to match Android.
The PRODUCT_BUNDLE_IDENTIFIER has been changed from org.egov.salama to org.egov.qa.bi across Profile, Debug, and Release configurations. Confirm that:

  • The Info.plist (PRODUCT_BUNDLE_IDENTIFIER key) and any entitlements files are updated accordingly.
  • Provisioning profiles and App Store Connect settings reflect the new bundle ID.

To verify no legacy bundle IDs remain:

Also applies to: 520-520, 542-542


🏁 Script executed:

#!/usr/bin/env bash
# Search for occurrences of the old bundle identifier
rg -n "org\.egov\.salama"

Length of output: 138


ACTION REQUIRED: Update legacy bundle ID in GoogleService-Info.plist

A search revealed one remaining reference to the old bundle identifier:

• apps/health_campaign_field_worker_app/ios/Runner/GoogleService-Info.plist:16

<string>org.egov.salama</string>

Please update this to the new bundle ID (org.egov.qa.bi) or replace the file with the version generated for the updated iOS bundle identifier. After updating, verify that:

  • Info.plist (PRODUCT_BUNDLE_IDENTIFIER) and any entitlements files match org.egov.qa.bi.
  • Your provisioning profiles and App Store Connect settings are configured for org.egov.qa.bi.

Comment on lines +10 to +13
class LocalizationLocalRepository {
FutureOr<List<Localization>> returnLocalizationFromSQL(
LocalSqlDataStore sql) async {
final selectQuery = sql.select(sql.localization).join([]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Missing error handling in repository method.

The repository method should include error handling to gracefully manage SQL errors.

class LocalizationLocalRepository {
  FutureOr<List<Localization>> returnLocalizationFromSQL(
      LocalSqlDataStore sql) async {
+    try {
      final selectQuery = sql.select(sql.localization).join([]);
      
      // Rest of the method...
      
+    } catch (e) {
+      debugPrint('Error retrieving localizations from SQL: $e');
+      return [];
+    }
  }
}
📝 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.

Suggested change
class LocalizationLocalRepository {
FutureOr<List<Localization>> returnLocalizationFromSQL(
LocalSqlDataStore sql) async {
final selectQuery = sql.select(sql.localization).join([]);
class LocalizationLocalRepository {
FutureOr<List<Localization>> returnLocalizationFromSQL(
LocalSqlDataStore sql) async {
try {
final selectQuery = sql.select(sql.localization).join([]);
// Rest of the method...
} catch (e) {
debugPrint('Error retrieving localizations from SQL: $e');
return [];
}
}
}

Comment on lines +64 to +75
final result = await selectQuery.get();

return result.map((row) {
final data = row.readTableOrNull(sql.localization);

return Localization()
..code = data!.code
..locale = data.locale
..module = data.module
..message = data.message;
}).toList();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Data mapping looks correct but lacks null checks.

The code properly maps database rows to Localization objects, but should include null checks on the data retrieved from the database.

return result.map((row) {
  final data = row.readTableOrNull(sql.localization);
+  
+  if (data == null) {
+    return Localization(); // Return empty object or skip
+  }

  return Localization()
-    ..code = data!.code
+    ..code = data.code
    ..locale = data.locale
    ..module = data.module
    ..message = data.message;
}).toList();
📝 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.

Suggested change
final result = await selectQuery.get();
return result.map((row) {
final data = row.readTableOrNull(sql.localization);
return Localization()
..code = data!.code
..locale = data.locale
..module = data.module
..message = data.message;
}).toList();
}
final result = await selectQuery.get();
return result.map((row) {
final data = row.readTableOrNull(sql.localization);
if (data == null) {
return Localization();
}
return Localization()
..code = data.code
..locale = data.locale
..module = data.module
..message = data.message;
}).toList();

Comment on lines +5 to +30
class DownsyncOpLogManager extends OpLogManager<DownsyncModel> {
DownsyncOpLogManager(super.isar);

@override
DownsyncModel applyServerGeneratedIdToEntity(
DownsyncModel entity,
String serverGeneratedId,
int rowVersion,
) =>
throw UnimplementedError();

@override
String getClientReferenceId(DownsyncModel entity) =>
throw UnimplementedError();

@override
String? getServerGeneratedId(DownsyncModel entity) =>
throw UnimplementedError();

@override
int? getRowVersion(DownsyncModel entity) => throw UnimplementedError();

@override
bool? getNonRecoverableError(DownsyncModel entity) =>
throw UnimplementedError();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical issue: Unimplemented operation log methods

All methods in this class throw UnimplementedError, which will crash the application if called. This appears to be placeholder code that isn't ready for production.

Consider one of these approaches:

  1. Implement the methods with proper functionality
  2. Add detailed TODO comments with JIRA/ticket references
  3. Document why these are intentionally unimplemented if this is transitional code
  4. Remove the file from this PR if the implementation isn't ready
  @override
  DownsyncModel applyServerGeneratedIdToEntity(
    DownsyncModel entity,
    String serverGeneratedId,
    int rowVersion,
  ) =>
-      throw UnimplementedError();
+      // TODO: TICKET-1234 - Implement entity ID application for downsync models
+      entity; // Return unmodified entity as temporary implementation

Comment on lines +84 to 86
@JsonKey(name: 'REFUGEE_CAMPS')
required List<RefugeeCampOptions> refugeeCampOptions,
@JsonKey(name: 'BACKEND_INTERFACE')
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Avoid introducing required fields that may not be present in older MDMS payloads

refugeeCampOptions is marked as required. If even a single tenant’s MDMS payload misses the new REFUGEE_CAMPS master, the entire app will crash at deserialisation time (Bad state: Tried to read required key).
Unless every environment has already been back‑filled, make the field nullable and provide a sensible default (const []) in fromJson:

-@JsonKey(name: 'REFUGEE_CAMPS')
-required List<RefugeeCampOptions> refugeeCampOptions,
+@JsonKey(
+  name: 'REFUGEE_CAMPS',
+  defaultValue: [],
+)
+required List<RefugeeCampOptions> refugeeCampOptions,

If the data is truly optional, also drop required.


🏁 Script executed:

#!/bin/bash
# Locate occurrences of refugeeCampOptions to inspect JsonKey usage
rg "refugeeCampOptions" -n apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.dart || true

# Show the surrounding lines for context
sed -n '70,100p' apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.dart || true

Length of output: 1782


Provide a safe default or drop required for refugeeCampOptions

The new REFUGEE_CAMPS master may be missing in some MDMS payloads—if the key is absent, json_serializable will throw “Bad state: Tried to read required key” and crash. You need to supply a compile‐time default or make the field truly optional:

• File: apps/health_campaign_field_worker_app/lib/models/app_config/app_config_model.dart
Location: around line 85

Suggested diff:

-  @JsonKey(name: 'REFUGEE_CAMPS')
-  required List<RefugeeCampOptions> refugeeCampOptions,
+  @JsonKey(
+    name: 'REFUGEE_CAMPS',
+    defaultValue: const <RefugeeCampOptions>[],
+  )
+  required List<RefugeeCampOptions> refugeeCampOptions,

Alternatively, if this master is optional at runtime, drop required entirely and let it default to []:

@JsonKey(
  name: 'REFUGEE_CAMPS',
  defaultValue: const <RefugeeCampOptions>[],
)
List<RefugeeCampOptions> refugeeCampOptions,

Either approach ensures missing or null payloads won’t break deserialization.

Comment on lines +1 to +122
package org.egov.qa.bi
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import io.flutter.embedding.android.FlutterActivity
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
private val CHANNEL = "com.digit.location_tracker"
private val locationReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val latitude = intent?.getDoubleExtra("latitude", 0.0)
val longitude = intent?.getDoubleExtra("longitude", 0.0)
val accuracy = intent?.getFloatExtra("accuracy", 0.0f) // Retrieve accuracy here

// Handle the location data here
Toast.makeText(
context,
"Latitude: $latitude, Longitude: $longitude, Accuracy: $accuracy",
Toast.LENGTH_LONG
).show()
// Optionally, you can send this data to Flutter via MethodChannel
flutterEngine?.dartExecutor?.binaryMessenger?.let {
MethodChannel(it, CHANNEL).invokeMethod(
"locationUpdate", mapOf(
"latitude" to latitude,
"longitude" to longitude,
"accuracy" to accuracy
)
)
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

MethodChannel(
flutterEngine!!.dartExecutor.binaryMessenger,
CHANNEL
).setMethodCallHandler { call, result ->
when (call.method) {
"startLocationUpdates" -> {
val interval = (call.argument<Number>("interval")?.toLong()) ?: 60000L
val stopAfterTimestamp = (call.argument<Number>("stopAfterTimestamp")?.toLong())
?: (System.currentTimeMillis() + 60000L)
if (!isMyServiceRunning(LocationService::class.java)) {
startService(interval, stopAfterTimestamp)
} else {
Toast.makeText(
this,
"Location service is already running",
Toast.LENGTH_SHORT
).show()
}
result.success(null)
}

"stopLocationUpdates" -> {
stopService()
result.success(null)
}

else -> result.notImplemented()
}
}

// Register the receiver for location updates, with proper export settings for Android 13+
val filter = IntentFilter("LocationUpdate")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(locationReceiver, filter, Context.RECEIVER_EXPORTED)
} else {
registerReceiver(locationReceiver, filter)
}
}

override fun onDestroy() {
super.onDestroy()
// Unregister the receiver
unregisterReceiver(locationReceiver)
}

private fun startService(locationUpdateInterval: Long, stopAfterTimestamp: Long) {
try {
val serviceIntent = Intent(this, LocationService::class.java).apply {
putExtra("interval", locationUpdateInterval) // Pass the interval to the service
putExtra("stopAfterTimestamp", stopAfterTimestamp)
}
startService(serviceIntent)
} catch (e: Exception) {
e.printStackTrace()
}
}

private fun stopService() {
try {
val serviceIntent = Intent(this, LocationService::class.java)
Toast.makeText(this, "Stopping location service", Toast.LENGTH_SHORT).show()
stopService(serviceIntent)
} catch (e: Exception) {
e.printStackTrace()
}
}

// Check if service is running
private fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
for (service in manager.getRunningServices(Int.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
Toast.makeText(this, "Location service is already running", Toast.LENGTH_SHORT)
.show()
return true
}
}
Toast.makeText(this, "Location service starting", Toast.LENGTH_SHORT).show()
return false
}
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add handling for disabled location services

The code doesn't check if location services are enabled on the device before starting the location tracking. This could lead to the service running without actually getting any location updates.

Add a method to check if location services are enabled:

private fun isLocationEnabled(): Boolean {
    val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || 
           locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
}

And use it before starting the service:

"startLocationUpdates" -> {
    val interval = (call.argument<Number>("interval")?.toLong()) ?: 60000L
    val stopAfterTimestamp = (call.argument<Number>("stopAfterTimestamp")?.toLong())
        ?: (System.currentTimeMillis() + 60000L)
+   if (!isLocationEnabled()) {
+       result.error("LOCATION_DISABLED", "Location services are disabled", null)
+       return@setMethodCallHandler
+   }
    if (!isMyServiceRunning(LocationService::class.java)) {
        startService(interval, stopAfterTimestamp)
    } else {
        // ...
    }
    // ...
}

Don't forget to add the import:

import android.location.LocationManager

Comment on lines +43 to +44
flutterEngine!!.dartExecutor.binaryMessenger,
CHANNEL
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid using not-null assertion operator (!!) with flutterEngine

Using flutterEngine!! can cause a NullPointerException if flutterEngine is null. Consider using a safe call operator or handling the null case properly.

- flutterEngine!!.dartExecutor.binaryMessenger,
+ flutterEngine?.dartExecutor?.binaryMessenger ?: return@setMethodCallHandler result.error("UNAVAILABLE", "Flutter engine not available", null),
📝 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.

Suggested change
flutterEngine!!.dartExecutor.binaryMessenger,
CHANNEL
flutterEngine?.dartExecutor?.binaryMessenger
?: return@setMethodCallHandler result.error(
"UNAVAILABLE",
"Flutter engine not available",
null
),
CHANNEL

Comment on lines +14 to +37
private val locationReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val latitude = intent?.getDoubleExtra("latitude", 0.0)
val longitude = intent?.getDoubleExtra("longitude", 0.0)
val accuracy = intent?.getFloatExtra("accuracy", 0.0f) // Retrieve accuracy here

// Handle the location data here
Toast.makeText(
context,
"Latitude: $latitude, Longitude: $longitude, Accuracy: $accuracy",
Toast.LENGTH_LONG
).show()
// Optionally, you can send this data to Flutter via MethodChannel
flutterEngine?.dartExecutor?.binaryMessenger?.let {
MethodChannel(it, CHANNEL).invokeMethod(
"locationUpdate", mapOf(
"latitude" to latitude,
"longitude" to longitude,
"accuracy" to accuracy
)
)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider removing debug Toast messages

The Toast message displaying latitude, longitude, and accuracy in the BroadcastReceiver is showing sensitive location information on screen. This could be a privacy concern if left in production code, especially with frequent location updates.

- Toast.makeText(
-     context,
-     "Latitude: $latitude, Longitude: $longitude, Accuracy: $accuracy",
-     Toast.LENGTH_LONG
- ).show()

Also, clean up development comments that are no longer needed:

- // Handle the location data here
- // Optionally, you can send this data to Flutter via MethodChannel
📝 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.

Suggested change
private val locationReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val latitude = intent?.getDoubleExtra("latitude", 0.0)
val longitude = intent?.getDoubleExtra("longitude", 0.0)
val accuracy = intent?.getFloatExtra("accuracy", 0.0f) // Retrieve accuracy here
// Handle the location data here
Toast.makeText(
context,
"Latitude: $latitude, Longitude: $longitude, Accuracy: $accuracy",
Toast.LENGTH_LONG
).show()
// Optionally, you can send this data to Flutter via MethodChannel
flutterEngine?.dartExecutor?.binaryMessenger?.let {
MethodChannel(it, CHANNEL).invokeMethod(
"locationUpdate", mapOf(
"latitude" to latitude,
"longitude" to longitude,
"accuracy" to accuracy
)
)
}
}
}
private val locationReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val latitude = intent?.getDoubleExtra("latitude", 0.0)
val longitude = intent?.getDoubleExtra("longitude", 0.0)
val accuracy = intent?.getFloatExtra("accuracy", 0.0f) // Retrieve accuracy here
flutterEngine?.dartExecutor?.binaryMessenger?.let {
MethodChannel(it, CHANNEL).invokeMethod(
"locationUpdate", mapOf(
"latitude" to latitude,
"longitude" to longitude,
"accuracy" to accuracy
)
)
}
}
}

Comment on lines +87 to +97
private fun startService(locationUpdateInterval: Long, stopAfterTimestamp: Long) {
try {
val serviceIntent = Intent(this, LocationService::class.java).apply {
putExtra("interval", locationUpdateInterval) // Pass the interval to the service
putExtra("stopAfterTimestamp", stopAfterTimestamp)
}
startService(serviceIntent)
} catch (e: Exception) {
e.printStackTrace()
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling in startService method

The current error handling only prints the stack trace without properly notifying the user or Flutter about the failure.

private fun startService(locationUpdateInterval: Long, stopAfterTimestamp: Long) {
    try {
        val serviceIntent = Intent(this, LocationService::class.java).apply {
            putExtra("interval", locationUpdateInterval) // Pass the interval to the service
            putExtra("stopAfterTimestamp", stopAfterTimestamp)
        }
        startService(serviceIntent)
+       Toast.makeText(this, "Location service started", Toast.LENGTH_SHORT).show()
    } catch (e: Exception) {
        e.printStackTrace()
+       Toast.makeText(this, "Failed to start location service: ${e.message}", Toast.LENGTH_SHORT).show()
+       // Notify Flutter about the failure
+       flutterEngine?.dartExecutor?.binaryMessenger?.let {
+           MethodChannel(it, CHANNEL).invokeMethod(
+               "serviceError", mapOf("error" to e.message)
+           )
+       }
    }
}
📝 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.

Suggested change
private fun startService(locationUpdateInterval: Long, stopAfterTimestamp: Long) {
try {
val serviceIntent = Intent(this, LocationService::class.java).apply {
putExtra("interval", locationUpdateInterval) // Pass the interval to the service
putExtra("stopAfterTimestamp", stopAfterTimestamp)
}
startService(serviceIntent)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun startService(locationUpdateInterval: Long, stopAfterTimestamp: Long) {
try {
val serviceIntent = Intent(this, LocationService::class.java).apply {
putExtra("interval", locationUpdateInterval) // Pass the interval to the service
putExtra("stopAfterTimestamp", stopAfterTimestamp)
}
startService(serviceIntent)
Toast.makeText(this, "Location service started", Toast.LENGTH_SHORT).show()
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(this, "Failed to start location service: ${e.message}", Toast.LENGTH_SHORT).show()
// Notify Flutter about the failure
flutterEngine?.dartExecutor?.binaryMessenger?.let {
MethodChannel(it, CHANNEL).invokeMethod(
"serviceError", mapOf("error" to e.message)
)
}
}
}

Comment on lines +110 to +121
private fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
for (service in manager.getRunningServices(Int.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
Toast.makeText(this, "Location service is already running", Toast.LENGTH_SHORT)
.show()
return true
}
}
Toast.makeText(this, "Location service starting", Toast.LENGTH_SHORT).show()
return false
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove Toast messages from isMyServiceRunning method

The isMyServiceRunning method should only check and return a boolean without side effects like showing Toast messages. This is mixing concerns of checking state and updating UI.

// Check if service is running
private fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
    val manager = getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
-   for (service in manager.getRunningServices(Int.MAX_VALUE)) {
+   // Use a reasonable limit instead of Int.MAX_VALUE
+   for (service in manager.getRunningServices(100)) {
        if (serviceClass.name == service.service.className) {
-           Toast.makeText(this, "Location service is already running", Toast.LENGTH_SHORT)
-               .show()
            return true
        }
    }
-   Toast.makeText(this, "Location service starting", Toast.LENGTH_SHORT).show()
    return false
}

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.

7 participants