Skip to content

Develop#487

Merged
tentamdin merged 42 commits into
mainfrom
develop
Jul 2, 2026
Merged

Develop#487
tentamdin merged 42 commits into
mainfrom
develop

Conversation

@tentamdin

@tentamdin tentamdin commented Jul 2, 2026

Copy link
Copy Markdown
Member
  • add offline mala round add
  • update localisation and UI inconsistent

dhakar66 and others added 30 commits July 1, 2026 17:32
…ly Streak, enhancing user engagement through shareable links
…te others to join groups via shareable links
…g duplicate dispatches and enhancing user experience when navigating back to the home screen. tryng to solve the cold start loading issue when clicked back button.
…ounts, update documentation and provider logic
…ocal taps and updating related documentation
@tentamdin tentamdin merged commit 423f456 into main Jul 2, 2026
2 of 5 checks passed
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 3/5

Safe to merge for the core offline-round and group-reset flows, but the sync-callback design has a real edge case where a second mala screen invalidates the wrong preset's provider.

The single-slot onGroupCountSynced field on the app-scoped MalaSyncManager is overwritten each time a GroupAccumulationCountsNotifier is created; if two preset screens are simultaneously watched, the earlier preset's handler is lost and its joinedAccumulatorGroupsProvider won't refresh after a group sync. The N+1 parallel GET pattern in joinedGroupUserCountsProvider re-fires on every round-complete boundary. The dead groups parameter in countFor/increment/addRounds is a maintenance hazard left behind by the refactor.

mala_sync_manager.dart (single-slot callback), accumulator_groups_provider.dart (N+1 fetches), group_accumulation_counts_provider.dart (dead parameter)

Reviews (1): Last reviewed commit: "Merge pull request #485 from OpenPecha/f..." | Re-trigger Greptile


/// Called after a group session count POST succeeds. Used to refresh lifetime
/// totals from `GET /accumulators/{id}/groups`.
void Function(String groupAccumulatorId)? onGroupCountSynced;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Single-slot callback overwritten by concurrent preset notifiers

onGroupCountSynced is a single mutable field on the app-scoped MalaSyncManager. Every GroupAccumulationCountsNotifier constructor writes _sync.onGroupCountSynced = handleGroupCountSynced, so the last notifier to initialise silently overwrites any earlier one. If two mala screens for different preset IDs are simultaneously in the widget tree (e.g. push navigation stacking screens while the previous one is still mounted and watching its providers), the earlier preset's handler is lost. When a group POST completes, _pushGroupTotal calls onGroupCountSynced?.call(groupAccumulatorId), which invokes the surviving handler — invalidating joinedAccumulatorGroupsProvider for the wrong preset. The active preset's group counts would then not refresh after a sync.

The autoDispose + onDispose guard reduces exposure, but the guard only prevents the disposee from clearing the callback when it has already been overwritten — it does not prevent the overwrite itself from causing the wrong handler to fire.

Comment on lines +22 to +44
/// `GroupAccumulatorDetail.user.totalCount`.
final joinedGroupUserCountsProvider = FutureProvider.autoDispose
.family<Map<String, int>, String>((ref, presetId) async {
final groups = await ref.watch(
joinedAccumulatorGroupsProvider(presetId).future,
);
if (groups.isEmpty) return const {};

final repository = ref.watch(groupAccumulatorRepositoryProvider);
final entries = await Future.wait(
groups.map((group) async {
final result = await repository.getGroupAccumulator(
group.groupAccumulatorId,
);
final count = result.fold(
(_) => 0,
(detail) => detail.user?.totalCount ?? 0,
);
return MapEntry(group.groupAccumulatorId, count);
}),
);
return Map.fromEntries(entries);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 N+1 parallel requests re-triggered after every round-complete sync

joinedGroupUserCountsProvider issues one getGroupAccumulator call per joined group via Future.wait. This provider is re-fetched whenever joinedAccumulatorGroupsProvider is invalidated. The invalidation chain is: round complete → POST group count succeeds → onGroupCountSynced fires → joinedAccumulatorGroupsProvider invalidated (via handleGroupCountSynced) → joinedGroupUserCountsProvider re-watches it → N group-detail GETs fire in parallel.

For a user who completes rounds frequently and belongs to several groups, this generates a burst of N+1 requests on every 108-bead boundary. Consider batching on the server or caching the results with a TTL rather than re-fetching the full set after each sync.

Comment on lines 122 to 130
if (hasDirtyTail) unawaited(_sync.flush(SyncReason.launch));
}

int countFor(String groupAccumulatorId, List<AccumulatorGroup> groups) {
int countFor(String groupAccumulatorId, [List<AccumulatorGroup>? groups]) {
final fromState = state[groupAccumulatorId];
if (fromState != null) return fromState;

final userId = _userId;
if (userId != null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 groups parameter is accepted but never used in countFor, increment, and addRounds

countFor was updated to read exclusively from in-memory state and Hive, dropping the old fallback to group.userTotalCount. The groups parameter is now optional and silently ignored. All three callers — increment, addRounds, and any external call sites — still pass a groups list that is dead code. This creates maintenance risk: future readers may assume the list is actually consulted and pass stale data thinking it matters. The parameter should be removed from countFor, increment, and addRounds to make the new ownership model explicit.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants