fluffychat/lib/pages/voip/group_call_view.dart
2022-09-12 08:12:02 +05:30

214 lines
6.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:flutter_reorderable_grid_view/entities/order_update_entity.dart';
import 'package:flutter_reorderable_grid_view/widgets/widgets.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/voip/utils/group_call_session_state.dart';
import 'package:fluffychat/pages/voip/utils/stream_view.dart';
import 'dialer/dialer.dart';
class GroupCallView extends StatefulWidget {
final GroupCallSessionState call;
final Client client;
const GroupCallView({
Key? key,
required this.call,
required this.client,
}) : super(key: key);
@override
State<GroupCallView> createState() => _GroupCallViewState();
}
class _GroupCallViewState extends State<GroupCallView> {
WrappedMediaStream? get primaryStream => widget.call.primaryStream;
List<WrappedMediaStream> get screenSharingStreams =>
widget.call.screenSharingStreams;
List<WrappedMediaStream> get userMediaStreams => widget.call.userMediaStreams;
WrappedMediaStream? get primaryScreenShare =>
widget.call.screenSharingStreams.first;
void updateStreams() {
Logs().i('Group calls, updating streams');
widget.call.groupCall.onStreamAdd.stream.listen((event) {
if (event.purpose == SDPStreamMetadataPurpose.Usermedia) {
if (userMediaStreams.indexWhere((element) => element == event) == -1) {
if (mounted) {
setState(() {
userMediaStreams.add(event);
});
}
}
} else if (event.purpose == SDPStreamMetadataPurpose.Screenshare) {
if (screenSharingStreams.indexWhere((element) => element == event) ==
-1) {
if (mounted) {
setState(() {
screenSharingStreams.add(event);
});
}
}
}
});
widget.call.groupCall.onStreamRemoved.stream.listen((event) {
if (event.purpose == SDPStreamMetadataPurpose.Usermedia) {
userMediaStreams
.removeWhere((element) => element.stream!.id == event.stream!.id);
if (mounted) {
setState(() {
userMediaStreams.remove(event);
});
}
} else if (event.purpose == SDPStreamMetadataPurpose.Screenshare) {
screenSharingStreams
.removeWhere((element) => element.stream!.id == event.stream!.id);
if (mounted) {
setState(() {
screenSharingStreams.remove(event);
});
}
}
});
}
@override
void initState() {
updateStreams();
super.initState();
}
@override
Widget build(BuildContext context) {
if (screenSharingStreams.isNotEmpty) {
return Center(
child: Stack(
children: [
StreamView(
screenSharingStreams.first,
matrixClient: widget.client,
),
Positioned(
bottom: 150,
child: SizedBox(
// height: 400,
width: MediaQuery.of(context).size.width,
child: CallGrid(
call: widget.call,
screenSharing: true,
userMediaStreams: userMediaStreams,
client: widget.client,
)),
),
],
),
);
} else {
// No one is screen sharing, show avatars and user streams here
return Center(
child: CallGrid(
call: widget.call,
screenSharing: false,
userMediaStreams: userMediaStreams,
client: widget.client,
),
);
}
}
}
class CallGrid extends StatefulWidget {
final GroupCallSessionState call;
final Client client;
final bool screenSharing;
final List<WrappedMediaStream> userMediaStreams;
const CallGrid(
{Key? key,
required this.call,
required this.client,
required this.screenSharing,
required this.userMediaStreams})
: super(key: key);
@override
State<CallGrid> createState() => _CallGridState();
}
class _CallGridState extends State<CallGrid> {
int axisCount() {
var orientation = MediaQuery.of(context).orientation;
if (MediaQuery.of(context).size.width >= 600) {
orientation = Orientation.landscape;
}
if (widget.screenSharing) {
return orientation == Orientation.portrait ? 4 : 6;
}
if (widget.call.groupCall.participants.length > 2 ||
MediaQuery.of(context).size.width >= 600) {
return orientation == Orientation.portrait ? 2 : 4;
} else {
return 1;
}
}
final _scrollController = ScrollController();
final _gridViewKey = GlobalKey();
@override
Widget build(BuildContext context) {
final participants = widget.call.groupCall.participants;
Logs().w(participants
.map((e) => widget.userMediaStreams
.firstWhereOrNull((element) => element.userId == e.id))
.toString());
// adding a user to a call sometimes results in multiple userMediaStreams
// for the saem user, Just pick the latest one then.
final generatedChildren = participants
.map(
(participant) => widget.userMediaStreams
.lastWhereOrNull((stream) => stream.userId == participant.id),
)
.where((element) => element != null)
.map(
(userMediaStream) => StreamView(
userMediaStream!,
key: Key(userMediaStream.userId),
matrixClient: widget.client,
),
)
.toList();
if (widget.screenSharing &&
MediaQuery.of(context).orientation == Orientation.landscape) {
return Container();
}
return ReorderableBuilder(
scrollController: _scrollController,
onReorder: (List<OrderUpdateEntity> orderUpdateEntities) {
for (final orderUpdateEntity in orderUpdateEntities) {
final reorderParticipant =
participants.removeAt(orderUpdateEntity.oldIndex);
participants.insert(orderUpdateEntity.newIndex, reorderParticipant);
}
},
builder: (children) {
return GridView(
shrinkWrap: true,
key: _gridViewKey,
controller: _scrollController,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: axisCount(),
),
children: children,
);
},
children: generatedChildren,
);
}
}