forked from eatvio/eatvio_app
feat(vide_calls): gms calls handling
This commit is contained in:
@@ -140,26 +140,34 @@ class VideoCallConnectingEntranceScreen extends StatelessWidget {
|
||||
const SizedBox(height: _topContentSpacing),
|
||||
_avatar(context, counterpartDisplayName, counterpartAvatarUrl),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.greenA700,
|
||||
shape: BoxShape.circle,
|
||||
if (canEnterCall)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.greenA700,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
s.video_call_status_online,
|
||||
style: CustomTextStyles.bodySmallMulishBlack900
|
||||
.copyWith(height: 14 / 12),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
s.video_call_status_online,
|
||||
style: CustomTextStyles.bodySmallMulishBlack900
|
||||
.copyWith(height: 14 / 12),
|
||||
),
|
||||
],
|
||||
)
|
||||
else
|
||||
Text(
|
||||
s.video_call_screen_connecting_subtitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: CustomTextStyles.bodySmallMulishBlack900
|
||||
.copyWith(height: 14 / 12),
|
||||
),
|
||||
SizedBox(height: canEnterCall ? 20 : 16),
|
||||
Text(
|
||||
s.video_call_screen_connecting_title,
|
||||
textAlign: TextAlign.center,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:eatvio_app/core/app_router.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/features/video_calls/presentation/bloc/video_call_session/video_call_session_cubit.dart';
|
||||
import 'package:eatvio_app/features/video_calls/presentation/bloc/video_call_session/video_call_session_state.dart';
|
||||
import 'package:eatvio_app/features/video_calls/presentation/pages/video_call_screen.dart';
|
||||
@@ -41,6 +43,7 @@ class _VideoCallGlobalPipLayerState extends State<VideoCallGlobalPipLayer> {
|
||||
void _openFullscreenRoute(VideoCallSessionState s) {
|
||||
final ctx = AppRouter.navigatorKey.currentContext;
|
||||
if (ctx == null) return;
|
||||
unawaited(sl<VideoCallSessionCubit>().restoreFullscreenFromPip());
|
||||
GoRouter.of(ctx).pushNamed(
|
||||
VideoCallScreen.name,
|
||||
extra: <String, dynamic>{
|
||||
@@ -71,6 +74,7 @@ class _VideoCallGlobalPipLayerState extends State<VideoCallGlobalPipLayer> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<VideoCallSessionCubit, VideoCallSessionState>(
|
||||
bloc: sl<VideoCallSessionCubit>(),
|
||||
buildWhen: (a, b) =>
|
||||
a.uiMode != b.uiMode ||
|
||||
a.connectPhase != b.connectPhase ||
|
||||
|
||||
@@ -8,6 +8,11 @@ abstract final class VideoCallLiveKitTrackUtils {
|
||||
|
||||
static lk.VideoTrack? visibleVideoFromPublication(lk.TrackPublication? pub) {
|
||||
if (pub == null || pub.muted) return null;
|
||||
if (pub is lk.RemoteTrackPublication) {
|
||||
if (!pub.subscribed || pub.streamState != lk.StreamState.active) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
final v = asVideoTrack(pub.track);
|
||||
if (v == null || v.muted) return null;
|
||||
return v;
|
||||
|
||||
@@ -24,11 +24,14 @@ class VideoCallRemoteVideoStage extends StatelessWidget {
|
||||
if (remote != null) {
|
||||
return lk.VideoTrackRenderer(remote, fit: lk.VideoViewFit.cover);
|
||||
}
|
||||
final showConnectError =
|
||||
connectError != null &&
|
||||
room.connectionState != lk.ConnectionState.connected;
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
const VideoCallNoVideoBackground(),
|
||||
if (connectError != null)
|
||||
if (showConnectError)
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/video_calls/presentation/widgets/video_call_controls.dart';
|
||||
import 'package:eatvio_app/features/video_calls/presentation/widgets/video_call_top_overlay.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:eatvio_app/features/video_calls/presentation/widgets/video_call_livekit_track_utils.dart';
|
||||
import 'package:eatvio_app/features/video_calls/presentation/widgets/video_call_name_chips.dart';
|
||||
import 'package:eatvio_app/features/video_calls/presentation/widgets/video_call_no_video_background.dart';
|
||||
@@ -25,6 +28,7 @@ class VideoCallStageLayout extends StatefulWidget {
|
||||
required this.localDisplayName,
|
||||
required this.remoteDisplayName,
|
||||
required this.micEnabled,
|
||||
this.systemAudioInterrupted = false,
|
||||
required this.videoEnabled,
|
||||
required this.splitParticipantView,
|
||||
required this.mainStageShowsLocalVideo,
|
||||
@@ -49,6 +53,7 @@ class VideoCallStageLayout extends StatefulWidget {
|
||||
final String localDisplayName;
|
||||
final String remoteDisplayName;
|
||||
final bool micEnabled;
|
||||
final bool systemAudioInterrupted;
|
||||
final bool videoEnabled;
|
||||
final bool splitParticipantView;
|
||||
final bool mainStageShowsLocalVideo;
|
||||
@@ -161,10 +166,23 @@ class _VideoCallStageLayoutState extends State<VideoCallStageLayout> {
|
||||
),
|
||||
..._bottomBarGradient(),
|
||||
..._bottomControlsRow(),
|
||||
..._systemInterruptionBanner(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _systemInterruptionBanner() {
|
||||
if (!widget.systemAudioInterrupted) return const [];
|
||||
return [
|
||||
Positioned(
|
||||
left: 16,
|
||||
right: 16,
|
||||
top: widget.topInset + 8,
|
||||
child: const _VideoCallSystemInterruptionBanner(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Widget _buildFullscreenLayout(BoxConstraints constraints) {
|
||||
final maxW = constraints.maxWidth;
|
||||
final maxH = constraints.maxHeight;
|
||||
@@ -203,6 +221,7 @@ class _VideoCallStageLayoutState extends State<VideoCallStageLayout> {
|
||||
),
|
||||
..._bottomBarGradient(),
|
||||
..._bottomControlsRow(),
|
||||
..._systemInterruptionBanner(),
|
||||
Positioned(
|
||||
top: widget.topInset + _edgeInset + _shrinkExpandExtraTop,
|
||||
left: _controlsHorizontalInset,
|
||||
@@ -487,3 +506,57 @@ class _VideoCallPipLocalContent extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _VideoCallSystemInterruptionBanner extends StatelessWidget {
|
||||
const _VideoCallSystemInterruptionBanner();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Material(
|
||||
color: appTheme.videoCallNoticeBannerBackground,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
elevation: 6,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
VideoCallTopOverlay.warningSvg,
|
||||
width: 22,
|
||||
height: 22,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
s.video_call_mic_muted_phone_call,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
height: 1.25,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
s.video_call_system_interruption,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
height: 1.25,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user