Conversation
Joined button opens a sheet with per-group chat and content push toggles and a confirmed Leave group action. Master switch off now unregisters the push device and greys out the toggles. Route EVENT_REMINDER pushes to the event, and skip the foreground banner for the open chat room.
Claiming the active room from initState and dispose tripped Riverpod's lifecycle guard and red-screened the chat screen. Use a plain holder object instead; push suppression reads it the same way.
Master switch flips during an in-flight register or unregister could leave the device registered after opt-out, or lose the id of a fresh registration. Route both through one reconcile loop that re-reads state after each pass. Track open chat rooms as a stack so popping one chat re-mutes the one under it.
A master-switch opt-out whose DELETE failed offline left the device registered until some unrelated event reconciled again. Retry failed passes with linear backoff up to five times; an explicit request cancels a pending retry.
- Added support for selecting multiple messages in the group chat thread. - Introduced a pill UI for reactions that appears above selected messages. - Implemented functionality to copy selected messages and handle message deletion. - Updated the GroupChatThread widget to manage selection state and provide callbacks for selection changes. - Enhanced the ChatMessageParentDTO to handle deleted messages and ensure proper serialization. - Added tests for new selection and copy functionalities, ensuring correct behavior for various message states. - Removed the deprecated group_chat_message_menu_test as its functionality is now integrated into the main thread.
…into feat/chatUIupdate
…languages and adjust sharing functionality in the poem sharing utility. Update Podfile.lock with new dependency checksums.
- Introduced _deletedOriginals to track deleted messages for accurate quoting. - Updated _applyPendingDeletions to handle deleted originals. - Added deleteInFlight state to prevent duplicate delete requests. - Implemented chatSelectionStaleIds to manage stale selections. - Enhanced tests for deletion scenarios and selection state.
…_providers.dart Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
The curve animation was never disposed, leaking on every reader and live plan-details screen that mounts the header.
Chore: Tara Additional Requirement
chore(l10n): sync translations from Tolgee
The bell was silent with the screen off on iOS: the app is suspended a moment after locking, so the Dart timer never reached the bell. Hold the audio session open for the length of a session — the app already declares the `audio` background mode — by looping a silent track, which keeps the isolate ticking so the real bell plays at the start and at the end. Category playback (heard with the ringer switch on silent) with mixWithOthers, so music the user already has playing is left alone. Android is a no-op there; its timers keep firing with the screen off. Scheduled notifications stay as a backstop for a suspended app, but now disarm themselves two seconds before the bell when a tick proves the app is still alive — which also removes the double ring on Android, where both used to fire at the deadline. Locking during the pre-roll arms both bells up front, and a session that starts while locked counts from when the pre-roll was due rather than from when the screen came back. Wait for playback to finish before releasing the keep-alive: the release tears down the session the bell is playing through, which silenced the completion bell on a locked screen. Verify a scheduled bell is actually pending afterwards — iOS keeps only the 64 soonest — and fall back to the in-app bell when the OS dropped it. Also: retry a bell schedule that failed on the next lifecycle event, move both bells onto one timer_bell channel and delete the silent channels it replaces, queue the end-of-session cancel behind in-flight schedules so a late one cannot leave a bell armed, and restore the lockfiles and the formatting the previous commits churned.
Pausing and immediately resuming fired stop() and start() without either awaiting or re-reading the wanted flag, so a release could restore the app's audio configuration on top of the hold that replaced it and leave the session unheld — a suspended app and a missed bell on a locked iOS screen. Queue the two, re-check after every platform call, and let a failed hold be retried by a later start.
Update notification channels and timer handling
…how load errors Serialize PATCHes per toggle so the backend ends on the value shown. Release the active chat room while another page covers it. Show a retry row instead of defaults when preferences fail to load.
Adopt develop's ForegroundPushFilter for banner suppression and drop the branch's own active-room mechanism; keep the master switch, reminder routing and preference work.
…target A preference write that succeeded while a newer value was queued was skipped entirely, so a later failure reverted the switch to a stale value the backend no longer held. Record every confirmed value before checking for a queued write.
…controls feat(group_profile): add group notification toggles and leave sheet
A connect rejection usually carries only `detail`, with no code, so it read as non-fatal and the reader reconnected into the same refusal for as long as it stayed open. It is now fatal on its shape alone. jumpToSegment matched the operator's segment id literally, ignoring the segments' mappings, so following across languages worked only while the live line happened to sit in the loaded window. Both checks now resolve through the mappings. The frame the server sends on connect is where the room already was, not the operator moving on, but the two were indistinguishable — and since that frame usually lands just after the reader's first build, it pushed the user off the text they had opened (and marked it complete for plan texts). The state now carries positionIsSnapshot, and the reader pauses following instead of navigating.
Nothing marks a frame as the snapshot the server sends on connect, so it is inferred from arriving before the grace window closes. In a session with no stored position, an operator's first move inside that window looks exactly the same — and pausing there stranded the user off the recitation until they re-armed Sync by hand, since both the switch and the scroll early-return once following is off. A snapshot on another text of the sequence now falls through instead: the user stays on the text they opened and keeps following, so the next move carries them along. Pausing is left to the unambiguous case, a position already live before the screen had rendered.
Feat: Live sync for Tara
Feat: Multiple subtask support
|
| if (seriesId != null) { | ||
| await _enterSeries(event, seriesId); | ||
| await _enterSeries( | ||
| event, | ||
| seriesId, | ||
| showLiveStream: participation == GroupEventParticipationType.online, | ||
| ); | ||
| } else { | ||
| await _openPlanPreview(planId!); | ||
| await _openPlanPreview(planId!, eventId: event.id); |
There was a problem hiding this comment.
Online attendance enables live sync
For a hybrid event backed directly by a plan, this branch passes eventId to the preview regardless of the selected attendance mode. Online attendees therefore enable reader live-sync, while the series path intentionally enables it only for in-person attendees because online users receive the text through the video stream.
Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/features/group_profile/presentation/screens/group_event_detail_screen.dart
Line: 399-406
Comment:
**Online attendance enables live sync**
For a hybrid event backed directly by a plan, this branch passes `eventId` to the preview regardless of the selected attendance mode. Online attendees therefore enable reader live-sync, while the series path intentionally enables it only for in-person attendees because online users receive the text through the video stream.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.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!
| void markClosed() { | ||
| state = state.copyWith(roomStatus: PrayerRoomStatus.closed); | ||
| } |
There was a problem hiding this comment.
markClosed changes only the status and leaves state.roomId intact. After the sheet clears its local room ID, the resulting rebuild reads this stale ID and calls _syncRoom, reconnecting to the room the server just closed and potentially refreshing it again.
Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/features/group_chat/presentation/providers/prayer_requests_providers.dart
Line: 282-284
Comment:
**Closed prayer room reconnects**
`markClosed` changes only the status and leaves `state.roomId` intact. After the sheet clears its local room ID, the resulting rebuild reads this stale ID and calls `_syncRoom`, reconnecting to the room the server just closed and potentially refreshing it again.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| final wasExact = _completionBell.isExactFor(_endsAt!); | ||
| _reclaimBellIfDue(_completionBell, remainingMs, _cancelCompletionBell); | ||
| if (remainingMs <= 0) { | ||
| _completeSession(playBell: true); | ||
| _completeSession(playBell: !wasExact); |
There was a problem hiding this comment.
If cancellation wins the race with OS alarm delivery when a tick reaches the deadline, _reclaimBellIfDue cancels the pending exact alarm while the earlier wasExact snapshot suppresses the in-app bell. Neither bell then fires, so the timer starts or completes silently. The start-bell path has the same ordering at lines 281–287.
Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/features/timer/presentation/screens/active_timer_screen.dart
Line: 334-337
Comment:
**Timer boundary can be silent**
If cancellation wins the race with OS alarm delivery when a tick reaches the deadline, `_reclaimBellIfDue` cancels the pending exact alarm while the earlier `wasExact` snapshot suppresses the in-app bell. Neither bell then fires, so the timer starts or completes silently. The start-bell path has the same ordering at lines 281–287.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
🆕 New Features
🛠 Improvements & Fixes
🌐 Localization