Implement mirror check#482
Conversation
…e original branch had incorrect parent.
…e original branch had incorrect parent.
|
Visit the preview URL for this PR (updated for commit 2afeff8): https://gen-hls-bkc-7627--pr482-jr-feat-mirror-check-hfijea56.web.app (expires Fri, 26 Jun 2026 16:06:51 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: eed668cca81618d491d024574a8f8a6003deaa8d |
…ck using media_device_svc.
There was a problem hiding this comment.
Pull request overview
Implements a per-event “mirror check” flow that forces users to review/select camera & microphone devices before they can stream A/V or see other participants in a meeting. This is integrated into meeting connection, UI controls, participant rendering, and persisted locally so the mirror check is only shown once per event.
Changes:
- Added mirror-check completion persistence via
SharedPreferencesServiceand used it to gate A/V streaming and participant visibility. - Updated meeting UI to distinguish “device enabled” vs “actually streaming” and updated toggles/participant rendering accordingly.
- Refreshed the media settings dialog UI/copy and device-save logic, including new l10n keys.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| client/lib/l10n/app_en.arb | Adds mirror-check related strings; currently introduces a duplicate key issue (and). |
| client/lib/l10n/app_es.arb | Adds mirror-check related strings; currently introduces a duplicate key issue (and). |
| client/lib/l10n/app_zh.arb | Adds mirror-check related strings; currently introduces a duplicate key issue (and). |
| client/lib/l10n/app_zh_Hant_TW.arb | Adds mirror-check related strings (Traditional Chinese). |
| client/lib/core/widgets/media_settings_widget.dart | Updates A/V settings dialog UI and save behavior for mirror-check mode; contains a critical rollback bug and dead state. |
| client/lib/core/utils/media_device_service.dart | Minor formatting-only change. |
| client/lib/core/data/services/shared_preferences_service.dart | Adds per-event mirror-check completion tracking APIs. |
| client/lib/features/events/features/live_meeting/features/video/data/providers/agora_room.dart | Introduces separate “is streaming” flags for local participant A/V state. |
| client/lib/features/events/features/live_meeting/features/video/data/providers/conference_room.dart | Gates A/V streaming on mirror-check completion; shows mirror-check dialog on connect; introduces unused imports and state-semantic mismatch. |
| client/lib/features/events/features/live_meeting/features/video/presentation/widgets/control_bar.dart | Updates controls to use streaming flags and (partially) gate toggles based on mirror-check completion; video toggle gating and messaging need fixes. |
| client/lib/features/events/features/live_meeting/features/video/presentation/widgets/participant_widget.dart | Uses streaming flags for local audio state and hides video view until mirror check is complete. |
| client/lib/features/events/features/live_meeting/features/video/presentation/views/video_flutter_meeting.dart | Hides participant grid until mirror check is complete (but only for one layout branch). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| child: Container( | ||
| padding: const EdgeInsets.all(8), | ||
| alignment: Alignment.center, | ||
| child: ParticipantGridLayout(), | ||
| // Only show the grid if mirror check is complete for this event | ||
| child: sharedPreferencesService.hasMirrorCheckCompletedForEvent(widget.liveMeetingProvider.eventProvider.eventId) | ||
| ? ParticipantGridLayout() | ||
| : const SizedBox.shrink(), |
There was a problem hiding this comment.
defaultStageView is currently not exposed as an option to be changed, so the grid view is always Brady Bunch.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 12 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (1)
client/lib/features/events/features/live_meeting/features/video/data/providers/conference_room.dart:382
- On camera permission denial, the code sets
videoTrackEnabled = falsebut leavesvideoIsStreamingunchanged and does not updateshouldStartLocalVideoOn. Since the UI now usesvideoIsStreaming(and the provider usesshouldStartLocalVideoOn) for state, this can leave the UI/provider out of sync after a failed enable attempt.
if (updatedEnabledValue) {
final permissionStatus = await Permission.camera.request();
if (permissionStatus.isDenied || permissionStatus.isPermanentlyDenied) {
if (!context.mounted) return;
await showAlert(
context,
'Error enabling camera. Please ensure you have granted permission.',
);
_room?.localParticipant?.videoTrackEnabled = false;
return;
| try { | ||
| if (sharedPreferencesService.hasMirrorCheckCompletedForEvent(liveMeetingProvider.eventProvider.eventId)) { | ||
| await _room!.localParticipant!.enableVideo( | ||
| setEnabled: updatedEnabledValue, | ||
| ); | ||
| } | ||
| if (updateProvider) { | ||
| liveMeetingProvider.shouldStartLocalVideoOn = updatedEnabledValue; | ||
| } | ||
| } catch (e) { | ||
| loggingService.log('Error toggling video: $e'); | ||
| } |
| try { | ||
| final audioEnableFutures = [ | ||
| if (sharedPreferencesService.hasMirrorCheckCompletedForEvent(liveMeetingProvider.eventProvider.eventId)) | ||
| _room!.localParticipant!.enableAudio( | ||
| setEnabled: updatedEnabledValue, | ||
| ), | ||
| if ((liveMeetingProvider | ||
| .eventProvider.selfParticipant?.muteOverride ?? | ||
| false) && | ||
| updatedEnabledValue) | ||
| firestoreLiveMeetingService.updateParticipantMuteOverride( | ||
| event: liveMeetingProvider.eventProvider.event, | ||
| participantId: userService.currentUserId!, | ||
| muteOverride: false, | ||
| ), | ||
| ]; | ||
|
|
||
| await Future.wait(audioEnableFutures); | ||
|
|
||
| if (updateProvider) { | ||
| liveMeetingProvider.shouldStartLocalAudioOn = updatedEnabledValue; | ||
| } | ||
| } catch (e) { | ||
| loggingService.log('Error toggling audio: $e'); | ||
| } |
| _room?.localParticipant?.audioIsStreaming = false; | ||
| return; |
| setState(() { | ||
| isLoadingCameraChange = false; | ||
| }); |
| return MediaSettingsWidget( | ||
| conferenceRoom: this, | ||
| shouldShowVideoPreview: liveMeetingProvider.videoDefaultOn, | ||
| isMirrorCheck: true, | ||
| ); |
| return videoEnabled | ||
| ? AgoraVideoView( | ||
| controller: videoViewController!, | ||
| ) | ||
| : SizedBox.shrink(); |
What is in this PR?
Introduces a basic "mirror check" feature to ensure users verify their camera and microphone settings before joining a meeting. The changes also enhance error handling and user feedback during device setup.
Changes in the codebase
MediaDeviceServicefor runtime access. (media_device_service.dart)MediaSettingsWidgetto support a mirror check mode, including a new introductory message, modified save button behavior, and logic to mark the mirror check as complete. (media_settings_widget.dart)media_settings_widget.dart)audioIsStreaming,videoIsStreaming) to track whether audio/video is actually being sent, separate from device enablement. Updated all relevant logic and toggles to use these flags. (agora_room.dart,conference_room.dart).conference_room.dart)SharedPreferencesServiceto track if the user has completed the mirror check per event.media_settings_widget.dart,conference_room.dart)video_flutter_meeting.dart)Testing this PR
PR Checklist
function-mapping.json.AI tools used (if applicable):
Copilot assisted in drafting this PR.