-
Notifications
You must be signed in to change notification settings - Fork 33
Ticket : 3066 Bug in intendance #697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Kirundi localization fix added
…isNotEligible check
…ock_changes_after_clf
…for delivery team
…'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
…date-skb custom qr scanner bloc added
…h-campaign-field-worker-app into uat-bug-fixes-skb
Burundi development
fix: update version to 1.6.34
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes. 💤 Files selected but had no reviewable changes (4)
You can disable this status message by setting the WalkthroughThis 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
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
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
Possibly related PRs
Suggested reviewers
Poem
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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 inconsistencyThe 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
searchCLFFiltersis nullable, yet the back‑end will usually send an array (possibly empty). Treating “no key” and “empty list” the same avoids extranullchecks 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:RefugeeCampOptionslacks anactiveflagAll other option models (e.g.
SearchCLFFilters,CommonMasterModel) include anactiveboolean 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.activeshould be@JsonKey(defaultValue: true)Without a default, missing
activein 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 beFuture<void>for clarity
loadLocalizationperforms side effects and doesn’t return a result, but the current signatureFuturehides that intent and defeats type checking. Make it explicit:-Future loadLocalization({ +Future<void> loadLocalization({
45-53: Unnecessary use ofjoin([])adds complexitySince no join tables are provided,
selectalone is sufficient and yields a strongly‑typed result, eliminating the need forreadTableOrNull:-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 thespeedArraylist for safer calculations
List speedArray = [];defaults toList<dynamic>, losing type safety. UseList<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 configurableHard‑coding
150may 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 styleReplaced 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 codeThe 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 handlingThe 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 batteryUsing
PRIORITY_HIGH_ACCURACYfor 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_ACCURACYOr 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
ServiceBlocis added to the tree, yetServiceBloc.close()is not called whenAuthenticatedPageWrapperis disposed (it’s aStatelessWidget). Normally Flutter takes care of disposing blocs added byBlocProvider, but because_drawerVisibilityControlleris manually created here and not disposed, please double‑check that no additional unmanaged resources were introduced inServiceBloc(e.g. timers, streams).Consider converting
AuthenticatedPageWrappertoStatefulWidgetand disposing_drawerVisibilityControllerthere.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 limitsFive‑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 (barCodevsbarCodes)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: ExposemanualCode& manage duplicates in stateConsider 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
statuscondition appears twice in the samewhereclause. 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
progressBarSearchfetches all matching tasks and aggregates in memory. For large datasets this may exhaust RAM. Consider adding limit/offset parameters or using Drift’sStreamPaginationutilities.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, andgetClosedHouseholdProjectBeneficiaryiterate through each list and performSet.containsper element, which is fine, but you first build aSet<String?>calledfilteredBeneficiariesClientRefIdwith nullable entries.
You can:
- Build the set as non‑nullable
Set<String>and skip nulls during insert.- Replace manual
forloops withwhereplus 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:shouldReloadsignature mismatch
shouldReloadshould receive acovariant LocalizationsDelegate<MaterialLocalizations>parameter, notdynamic. 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 EnglishMost 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().millisecondsSinceEpochis invoked dozens of times; the resulting few‑millisecond drift can break optimistic‑locking schemes that rely on identicalcreatedTimeacross related entities.Capture a single timestamp at the start of
_handleSubmitand 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
attendeesare 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:getMissedDaysreturns localised string but ignores locale change
getMissedDaysbuilds and stores the result in themissedDaysfield only once. If the user changes locale while the page is alive, the description stays in the old language.
Consider computing the string on eachbuild()instead of caching in a field, or rebuild it whenAppLocalizationsupdates.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
dateVsProjectBeneficiariesanddateVsProjectBeneficiaryClientRefIdare created but never populated / consumed.
Either remove them or complete the missing aggregation; keeping dead code harms readability and may mislead maintainers.
271-296:resourceDistributedsilently swallows invalid dataThe 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:listenToChangesemits deleted rowsThe 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: 1000is hard‑coded three times. If the tenant ever exceeds this count the remainder is silently dropped. Consider:
- Replacing the magic number with a
const _pageLimit = 1000;.- Implementing paginated fetching (loop until
results.length < _pageLimit).This applies equally to the Facilities query below.
394-440: Heavy synchronous processing on UI threadThe nested attendance / individual / log fetch happens inside
_handleProjectSelectionand 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‑causeThe outer
try‑catchconverts every error todebugPrint, 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 & VCSThis 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 timeRecommend adding
*.freezed.dart&*.g.dartto.gitignoreor usingexport-ignorein.gitattributesand 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 – considerUnmodifiableListViewonly when needed
EqualUnmodifiableListViewwrappers 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 injectedctxinstead of outercontextfor repository look‑ups
Inside thecreate:callback you ignore the suppliedBuildContext(_) and capture the outercontext.
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 registrationThe 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 stopThe 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
⛔ Files ignored due to path filters (40)
.github/workflows/dart.ymlis excluded by!**/*.ymlapps/health_campaign_field_worker_app/android/app/google-services.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/android/app/src/debug/AndroidManifest.xmlis excluded by!**/*.xmlapps/health_campaign_field_worker_app/android/app/src/main/AndroidManifest.xmlis excluded by!**/*.xmlapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-hdpi/burundi_logo_tsinda_malaria.jpgis excluded by!**/*.jpg,!**/*.jpgapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.pngis excluded by!**/*.png,!**/*.pngapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-mdpi/burundi_logo_tsinda_malaria.jpgis excluded by!**/*.jpg,!**/*.jpgapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.pngis excluded by!**/*.png,!**/*.pngapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xhdpi/burundi_logo_tsinda_malaria.jpgis excluded by!**/*.jpg,!**/*.jpgapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.pngis excluded by!**/*.png,!**/*.pngapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xxhdpi/burundi_logo_tsinda_malaria.jpgis excluded by!**/*.jpg,!**/*.jpgapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.pngis excluded by!**/*.png,!**/*.pngapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xxxhdpi/burundi_logo_tsinda_malaria.jpgis excluded by!**/*.jpg,!**/*.jpgapps/health_campaign_field_worker_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngis excluded by!**/*.png,!**/*.pngapps/health_campaign_field_worker_app/android/app/src/profile/AndroidManifest.xmlis excluded by!**/*.xmlapps/health_campaign_field_worker_app/assets/animated_json/alert.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/assets/animated_json/error.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/assets/animated_json/inline_loader.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/assets/animated_json/overlay_loader.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/assets/animated_json/page_loader.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/assets/animated_json/success.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/assets/icons/svg/closed_household.svgis excluded by!**/*.svg,!**/*.svgapps/health_campaign_field_worker_app/lib/models/model_configs/enum_community_types.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/lib/models/model_configs/enum_roles.jsonis excluded by!**/*.jsonapps/health_campaign_field_worker_app/pubspec.lockis excluded by!**/*.lock,!**/*.lockapps/health_campaign_field_worker_app/pubspec.yamlis excluded by!**/*.yamlmason_templates/digit_entity/hooks/pubspec.lockis excluded by!**/*.lock,!**/*.lockmason_templates/digit_entity/hooks/pubspec.yamlis excluded by!**/*.yamlmason_templates/freezed_bloc/hooks/pubspec.lockis excluded by!**/*.lock,!**/*.lockmason_templates/freezed_bloc/hooks/pubspec.yamlis excluded by!**/*.yamlmelos.yamlis excluded by!**/*.yamlpackages/attendance_management/analysis_options.yamlis excluded by!**/*.yamlpackages/attendance_management/assets/icons/app_icon.pngis excluded by!**/*.png,!**/*.pngpackages/attendance_management/assets/icons/svg/mychecklist.svgis excluded by!**/*.svg,!**/*.svgpackages/attendance_management/assets/icons/svg/no_result.svgis excluded by!**/*.svg,!**/*.svgpackages/attendance_management/assets/images/powered_by_digit.pngis excluded by!**/*.png,!**/*.pngpackages/attendance_management/build.yamlis excluded by!**/*.yamlpackages/attendance_management/pubspec.lockis excluded by!**/*.lock,!**/*.lockpackages/attendance_management/pubspec.yamlis excluded by!**/*.yamlpackages/auto_route/analysis_options.yamlis 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.
Usinggradle-7.4-bin.zipreduces 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.fvmrcprevents checking in Flutter version manager artifacts. This aligns with the root and app-level.gitignoreupdates.apps/health_campaign_field_worker_app/.gitignore (2)
36-36: Added environment-specific ignore rule.
Ignoring.env-qaensures CI/CD or local QA environment files are not committed. This aligns with best practices.
48-51: Ignored FVM cache directories.
Adding.fvm/and.fvmrcprevents 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
DioExceptioninstead of the deprecatedDioError. 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
DioErrorclass in the Dio package was officially renamed toDioExceptionin the Dio 5.x series. The source code explicitly marksDioErroras 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 useDioException, andDioErrorserves 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 deprecatingDioErrorin favor ofDioException[9].So, the renaming from
DioErrortoDioExceptionoccurred with the release of Dio 5.0.0, and developers should now useDioExceptionto handle errors when working with newer versions of the package[8][9].Citations:
- 1: https://pub.dev/packages/dio
- 2: cfug/dio#1703
- 3: cfug/dio#1647
- 4: https://docs.sentry.io/platforms/dart/integrations/dio/
- 5: https://www.zipy.ai/blog/debug-flutter-web-dioerror-or-networkexception
- 6: https://clouds.hashnode.dev/efficient-crud-operations-in-flutter-a-guide-to-implementing-http-requests-with-clean-architecture-and-dio
- 7: https://www.scaler.com/topics/dio-flutter/
- 8: https://github.com/cfug/dio/blob/main/dio/lib/src/dio_exception.dart
- 9: https://pub.dev/packages/dio/changelog
Confirmed:
DioExceptionIs the Correct Error TypeThe
DioErrorclass was officially renamed toDioExceptionstarting in Dio 5.0.0 (withDioErrormarked deprecated and slated for removal in 6.0.0). Your update to catchDioExceptionis 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 attendanceStaffThe authentication logic has been expanded to provide special privileges to users with the
attendanceStaffrole, similar todistrictSupervisor. 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 moduleThe addition of
searchCLFFiltersandrefugeeCampsto 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 mastersThe addition of the
privacyPolicyenum 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 rolesThe mapper has been properly extended to decode string values for the new
attendanceStaffandcommunityDistributorroles. This ensures correct deserialization when these roles are received from the backend.
68-71: Added encode support for new rolesThe 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 managementThe addition of
closeHouseholdandregisteredstatus 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 readabilityThe 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 valuesThe decoder now correctly handles the new
closeHouseholdandregisteredstatus values, which will help support the new features for household closure tracking and registration status.
80-83: Implemented bidirectional mapping for new statusesThe 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 enumsThe 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 enumsThe 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 annotationsThe 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 readabilityThe 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 systemThe implementation adds two new roles:
attendanceStaffandcommunityDistributor. 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-structuredThe
CommunityTypesenum 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 logicThis change enhances the precision of finding the specific OpLogEntry by matching on
clientReferenceIdinstead 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 storeThe localization delegate has been properly updated to use
LocalSqlDataStoreinstead 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 initializationThe 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 localizationThe 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 configurationThe 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 configurationThe 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 optionsThe mapping for refugee camp options follows the established pattern and is well-implemented.
336-344: LGTM: Well-structured implementation for search filtersThe 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 ofLocalizationParams
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 matchesUsing
sql.localization.module.contains(moduleToExclude)will match any module whose name merely contains the supplied substring (e.g. searching forhrwill also matchehr).
If the intent is an exact match, preferequals(); if multiple exact modules are required, useisIn([...]).[ request_verification ]
33-37:Constant(false)eliminates rows when no code filter is suppliedWhen no
codefilter is given,codeConditionbecomesConstant(false)which is OR‑ed withmoduleCondition.
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 VCSStatic 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:
- Regenerate and restrict the key(s) in Google Cloud → API & Services.
- Move secrets to a secure storage mechanism (e.g. environment variables +
flutter_dotenv, CI secret manager, etc.).- 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 betweenDefaultFirebaseOptionsandProdFirebaseOptionsBoth 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_versionmay be undefined after the plugin‑block migration
plugins { id 'kotlin-android' }automatically supplies a Kotlin version, but the$kotlin_versionGradle property you reference here is not declared in this file any more.
If it isn’t set in the rootgradle.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‑pathIf
USE_GOOGLE_SERVICESis 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: Missingbreak;causes illegal fall‑throughThe
case DataModelType.sideEffect:block does not end withbreak,return, orcontinue, so the compiler will throw “Switch case must end with break” for Dart >= 2.17.Add an explicit
break;(orreturn) 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‑unwrapsclientReferenceId, yet a few lines later you treat the same field as nullable (toString()call).
If any entry has a nullclientReferenceId, 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 constantsInline literals
'taskResourceId'and'householdAddressId'have replaced the earliertaskResourceIdKey/householdAddressIdKeyconstants.
This increases the risk of typos and makes refactoring harder. Consider reinstating the constants at the top of the file (or in a sharedconstants.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 betweendisk_space_updateand previous package
DiskSpace.getFreeDiskSpaceis still invoked, but the imported package changed todisk_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 breakwriteToEntityDB
individualLocalRepositoryis now passed first. IfwriteToEntityDBrelies 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 libraryThe imports have been properly updated from
digit_componentsto the newdigit_ui_componentspackage, which is good for consistency.
14-20: Correctly imported necessary modules with consistent patternThe imports include necessary modules from attendance management and router configurations.
22-31: Class renamed consistently from ManageAttendancePage to CustomManageAttendancePageThe class and state names have been renamed consistently, maintaining inheritance from LocalizedStatefulWidget.
66-67: Theme retrieval approach updated to standard patternChanged from using DigitTheme singleton to the standard Theme.of(context) approach, which is the recommended pattern in Flutter.
97-104: Date formatting utilities consistently updatedChanged date formatting logic to use the AttendanceDateTimeManagement utility consistently.
180-185: Improved layout with theme-based spacingPadding 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 themingThe DigitCard widget is used with theme-based spacing, ensuring consistent UI.
280-286: Replaced DigitTableCard with LabelValueSummaryUI components were switched from DigitTableCard to LabelValueSummary with LabelValueItem for displaying key-value pairs.
288-294: Updated button implementation with explicit propertiesChanged from DigitElevatedButton to DigitButton with explicit size, type, and layout properties.
296-301: Updated toast notification APIToast notifications changed from DigitToast.show to Toast.showToast with the new API signature.
307-310: Toast implementation consistent with earlier changeThe second toast usage matches the first one, maintaining consistency in the codebase.
312-317: Updated routing to use custom implementationRoute 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 optionsNew field for refugee camp options with proper JSON serialization/deserialization.
142-144: Added support for searchCLFFiltersNew field for search CLF filters with proper nullable handling in JSON deserialization.
164-164: Added proper serialization for refugee camp optionsThe serialization entry correctly maps the refugeeCampOptions field to its JSON key.
169-169: Added proper serialization for search CLF filtersThe serialization entry correctly maps the searchCLFFilters field to its JSON key.
196-198: Added support for privacy policy configurationNew field for privacy policy configuration with proper JSON deserialization.
206-206: Added proper serialization for privacy policy configurationThe serialization entry correctly maps the privacyPolicyConfig field to its JSON key.
320-332: Added new RefugeeCampOptions implementationImplemented JSON serialization/deserialization for the RefugeeCampOptions class with name and code fields.
468-482: Added new SearchCLFFilters implementationImplemented 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-stopThe 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
LocationServicestill 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_LOCATIONandroid.permission.ACCESS_BACKGROUND_LOCATIONandroid.permission.FOREGROUND_SERVICEI couldn’t locate an
AndroidManifest.xmlunderapps/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 goodSwitching from
colorScheme.backgroundtocolorScheme.surfacehelps 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
BeneficiaryDownSyncBlocwere 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.dartLength of output: 8069
🏁 Script executed:
#!/bin/bash sed -n '150,240p' apps/health_campaign_field_worker_app/lib/pages/authenticated.dartLength 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 filtersField and embedded class are modelled correctly and annotated, so Isar will persist them without additional migration steps.
174-179: Embedded list insideSearchCLFFiltersis fineNo 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 reviewThis file is produced by
freezedand 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.closedtasks are stored indateVsClosedHouseholdAbsentTask, which is semantically wrong and will mis‑report metrics.- if (reason == ClosedHouseholdReasonsEnum.closed.name.toUpperCase()) { - dateVsClosedHouseholdAbsentTask + if (reason == ClosedHouseholdReasonsEnum.closed.name.toUpperCase()) { + dateVsClosedHouseholdTask // or …ClosedHouseholdClosedTaskVerify 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 issueDelegate returns EN localisation class instead of Kirundi
load()constructsMaterialLocalizationKiBIwhich is explicitly documented as “English, as used in India”.
For Kirundi you likely want aMaterialLocalizationKiinstance withlocaleName = 'rn_BI'.- return MaterialLocalizationKiBI( + return MaterialLocalizationKi( localeName: 'rn_BI',(or create
MaterialLocalizationKiBIwith 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 configurationsThis 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 additionThe addition of
privacyPolicyConfigto theCommonMastersWrapperModelis 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: Unusedlocalityvariable until deep copy
localityis declared but only applied inside latercopyWithcalls, while newLocalityModelinstances 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.dartis 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: UsingcontextinsideinitStatecan throw if provider is not yet mounted
context.repository…andcontext.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 alwaysfalse
checkConnectivity()returns a singleConnectivityResultenum, hencefirstOrNullis undefined and currently alwaysnull.- 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 SDKThe generated unions rely on Dart 3’s record syntax (
(BarcodeScanType, GS1Barcode)).
Ensuresdk: ">=3.0.0 <4.0.0"is declared inpubspec.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 kotlinLength 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
TheLocationServiceclass 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
ServicewithonStartCommand,onDestroy, andonBindimplementations- 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 inMainActivityNo further changes needed here.
| "@executable_path/Frameworks", | ||
| ); | ||
| PRODUCT_BUNDLE_IDENTIFIER = org.egov.salama; | ||
| PRODUCT_BUNDLE_IDENTIFIER = org.egov.qa.bi; |
There was a problem hiding this comment.
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_IDENTIFIERkey) 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.
| class LocalizationLocalRepository { | ||
| FutureOr<List<Localization>> returnLocalizationFromSQL( | ||
| LocalSqlDataStore sql) async { | ||
| final selectQuery = sql.select(sql.localization).join([]); |
There was a problem hiding this comment.
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.
| 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 []; | |
| } | |
| } | |
| } |
| 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(); | ||
| } |
There was a problem hiding this comment.
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.
| 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(); |
| 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(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:
- Implement the methods with proper functionality
- Add detailed TODO comments with JIRA/ticket references
- Document why these are intentionally unimplemented if this is transitional code
- 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| @JsonKey(name: 'REFUGEE_CAMPS') | ||
| required List<RefugeeCampOptions> refugeeCampOptions, | ||
| @JsonKey(name: 'BACKEND_INTERFACE') |
There was a problem hiding this comment.
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 || trueLength 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.
| 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 |
There was a problem hiding this comment.
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| flutterEngine!!.dartExecutor.binaryMessenger, | ||
| CHANNEL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| flutterEngine!!.dartExecutor.binaryMessenger, | |
| CHANNEL | |
| flutterEngine?.dartExecutor?.binaryMessenger | |
| ?: return@setMethodCallHandler result.error( | |
| "UNAVAILABLE", | |
| "Flutter engine not available", | |
| null | |
| ), | |
| CHANNEL |
| 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 | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
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.
| 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 | |
| ) | |
| ) | |
| } | |
| } | |
| } |
| 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() | ||
| } | ||
| } |
There was a problem hiding this comment.
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.
| 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) | |
| ) | |
| } | |
| } | |
| } |
| 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 | ||
| } |
There was a problem hiding this comment.
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
}…-field-fix HDDF-3069:: Fixed comment field issue for Single Value List in checklist
…-group-distribution-logic hddf-3071::add bedcount method and update special group distribution …
…atory Driver field mandatory
…/health-campaign-field-worker-app into Satvik_flutter_burundi
Was able to view the records on scroll itself.