Compare commits
No commits in common. "4238ea6fdc1d009d0a64578cfd42522e5eaa5bce" and "7e8993fbd2b388626bbedcdfb9151aae80cc6301" have entirely different histories.
4238ea6fdc
...
7e8993fbd2
@ -21,8 +21,6 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
|
|||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
String _currentDuration = '00:00:00';
|
String _currentDuration = '00:00:00';
|
||||||
|
|
||||||
int _layoutMode = 0;
|
|
||||||
|
|
||||||
bool _showControls = true;
|
bool _showControls = true;
|
||||||
CancelableOperation? _hideControlsOperation;
|
CancelableOperation? _hideControlsOperation;
|
||||||
|
|
||||||
@ -56,14 +54,6 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _switchLayout() {
|
|
||||||
if (_layoutMode < 1) {
|
|
||||||
setState(() => _layoutMode++);
|
|
||||||
} else {
|
|
||||||
setState(() => _layoutMode = 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _toggleControls() {
|
void _toggleControls() {
|
||||||
if (_showControls) {
|
if (_showControls) {
|
||||||
setState(() => _showControls = false);
|
setState(() => _showControls = false);
|
||||||
@ -85,107 +75,6 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildListLayout() {
|
|
||||||
final ChatCallProvider call = Get.find();
|
|
||||||
return Stack(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
|
||||||
child: call.focusTrack.value != null
|
|
||||||
? InteractiveParticipantWidget(
|
|
||||||
isFixed: false,
|
|
||||||
participant: call.focusTrack.value!,
|
|
||||||
onTap: () {},
|
|
||||||
)
|
|
||||||
: const SizedBox(),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
top: 0,
|
|
||||||
child: SizedBox(
|
|
||||||
height: 128,
|
|
||||||
child: ListView.builder(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
itemCount: math.max(0, call.participantTracks.length),
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
|
||||||
final track = call.participantTracks[index];
|
|
||||||
if (track.participant.sid ==
|
|
||||||
call.focusTrack.value?.participant.sid) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8, left: 8),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
child: InteractiveParticipantWidget(
|
|
||||||
isFixed: true,
|
|
||||||
width: 120,
|
|
||||||
height: 120,
|
|
||||||
color: Theme.of(context).cardColor,
|
|
||||||
participant: track,
|
|
||||||
onTap: () {
|
|
||||||
if (track.participant.sid !=
|
|
||||||
call.focusTrack.value?.participant.sid) {
|
|
||||||
call.changeFocusTrack(track);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildGridLayout() {
|
|
||||||
final ChatCallProvider call = Get.find();
|
|
||||||
return LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
double screenWidth = constraints.maxWidth;
|
|
||||||
double screenHeight = constraints.maxHeight;
|
|
||||||
|
|
||||||
int columns = (math.sqrt(call.participantTracks.length)).ceil();
|
|
||||||
int rows = (call.participantTracks.length / columns).ceil();
|
|
||||||
|
|
||||||
double tileWidth = screenWidth / columns;
|
|
||||||
double tileHeight = screenHeight / rows;
|
|
||||||
|
|
||||||
return GridView.builder(
|
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: columns,
|
|
||||||
childAspectRatio: tileWidth / tileHeight,
|
|
||||||
),
|
|
||||||
itemCount: math.max(0, call.participantTracks.length),
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
|
||||||
final track = call.participantTracks[index];
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
child: InteractiveParticipantWidget(
|
|
||||||
isFixed: true,
|
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerLow,
|
|
||||||
participant: track,
|
|
||||||
onTap: () {
|
|
||||||
if (track.participant.sid !=
|
|
||||||
call.focusTrack.value?.participant.sid) {
|
|
||||||
call.changeFocusTrack(track);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
Get.find<ChatCallProvider>().setupRoom();
|
Get.find<ChatCallProvider>().setupRoom();
|
||||||
@ -235,53 +124,78 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.translucent,
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => Column(
|
() => Stack(
|
||||||
children: [
|
children: [
|
||||||
SizeTransition(
|
Column(
|
||||||
sizeFactor: _controlsAnimation,
|
children: [
|
||||||
axis: Axis.vertical,
|
Expanded(
|
||||||
child: SizedBox(
|
child: Container(
|
||||||
width: MediaQuery.of(context).size.width,
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
height: 64,
|
child: provider.focusTrack.value != null
|
||||||
child: Row(
|
? InteractiveParticipantWidget(
|
||||||
children: [
|
isFixed: false,
|
||||||
const Expanded(child: SizedBox()),
|
participant: provider.focusTrack.value!,
|
||||||
IconButton(
|
onTap: () {},
|
||||||
icon: _layoutMode == 0
|
)
|
||||||
? const Icon(Icons.view_list)
|
: const SizedBox(),
|
||||||
: const Icon(Icons.grid_view),
|
|
||||||
onPressed: () {
|
|
||||||
_switchLayout();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).paddingSymmetric(horizontal: 10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
switch (_layoutMode) {
|
|
||||||
case 1:
|
|
||||||
return _buildGridLayout();
|
|
||||||
default:
|
|
||||||
return _buildListLayout();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (provider.room.localParticipant != null)
|
|
||||||
SizeTransition(
|
|
||||||
sizeFactor: _controlsAnimation,
|
|
||||||
axis: Axis.vertical,
|
|
||||||
child: SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
child: ControlsWidget(
|
|
||||||
provider.room,
|
|
||||||
provider.room.localParticipant!,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (provider.room.localParticipant != null)
|
||||||
|
SizeTransition(
|
||||||
|
sizeFactor: _controlsAnimation,
|
||||||
|
axis: Axis.vertical,
|
||||||
|
child: SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
child: ControlsWidget(
|
||||||
|
provider.room,
|
||||||
|
provider.room.localParticipant!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 128,
|
||||||
|
child: ListView.builder(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemCount:
|
||||||
|
math.max(0, provider.participantTracks.length),
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
final track = provider.participantTracks[index];
|
||||||
|
if (track.participant.sid ==
|
||||||
|
provider.focusTrack.value?.participant.sid) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8, left: 8),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius:
|
||||||
|
const BorderRadius.all(Radius.circular(8)),
|
||||||
|
child: InteractiveParticipantWidget(
|
||||||
|
isFixed: true,
|
||||||
|
width: 120,
|
||||||
|
height: 120,
|
||||||
|
color: Theme.of(context).cardColor,
|
||||||
|
participant: track,
|
||||||
|
onTap: () {
|
||||||
|
if (track.participant.sid !=
|
||||||
|
provider
|
||||||
|
.focusTrack.value?.participant.sid) {
|
||||||
|
provider.changeFocusTrack(track);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -217,25 +217,28 @@ class InteractiveParticipantWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return Material(
|
||||||
child: Container(
|
color: Colors.transparent,
|
||||||
width: width,
|
child: GestureDetector(
|
||||||
height: height,
|
child: Container(
|
||||||
color: color,
|
width: width,
|
||||||
child: ParticipantWidget.widgetFor(participant, isFixed: isFixed),
|
height: height,
|
||||||
|
color: color,
|
||||||
|
child: ParticipantWidget.widgetFor(participant, isFixed: isFixed),
|
||||||
|
),
|
||||||
|
onTap: () => onTap(),
|
||||||
|
onLongPress: () {
|
||||||
|
if (participant.participant is LocalParticipant) return;
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => ParticipantMenu(
|
||||||
|
participant: participant.participant as RemoteParticipant,
|
||||||
|
videoTrack: participant.videoTrack,
|
||||||
|
isScreenShare: participant.isScreenShare,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
onTap: () => onTap(),
|
|
||||||
onLongPress: () {
|
|
||||||
if (participant.participant is LocalParticipant) return;
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => ParticipantMenu(
|
|
||||||
participant: participant.participant as RemoteParticipant,
|
|
||||||
videoTrack: participant.videoTrack,
|
|
||||||
isScreenShare: participant.isScreenShare,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:livekit_client/livekit_client.dart';
|
import 'package:livekit_client/livekit_client.dart';
|
||||||
|
|
||||||
class ParticipantInfoWidget extends StatelessWidget {
|
class ParticipantInfoWidget extends StatelessWidget {
|
||||||
@ -35,42 +34,38 @@ class ParticipantInfoWidget extends StatelessWidget {
|
|||||||
style: const TextStyle(color: Colors.white),
|
style: const TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 5),
|
|
||||||
isScreenShare
|
isScreenShare
|
||||||
? const Icon(
|
? const Padding(
|
||||||
Icons.monitor,
|
padding: EdgeInsets.only(left: 5),
|
||||||
color: Colors.white,
|
child: Icon(
|
||||||
size: 16,
|
Icons.monitor,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: Icon(
|
: Padding(
|
||||||
audioAvailable ? Icons.mic : Icons.mic_off,
|
padding: const EdgeInsets.only(left: 5),
|
||||||
color: audioAvailable ? Colors.white : Colors.red,
|
child: Icon(
|
||||||
size: 16,
|
audioAvailable ? Icons.mic : Icons.mic_off,
|
||||||
|
color: audioAvailable ? Colors.white : Colors.red,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 3),
|
|
||||||
if (connectionQuality != ConnectionQuality.unknown)
|
if (connectionQuality != ConnectionQuality.unknown)
|
||||||
Icon(
|
Padding(
|
||||||
{
|
padding: const EdgeInsets.only(left: 5),
|
||||||
ConnectionQuality.excellent: Icons.signal_cellular_alt,
|
child: Icon(
|
||||||
ConnectionQuality.good: Icons.signal_cellular_alt_2_bar,
|
connectionQuality == ConnectionQuality.poor
|
||||||
ConnectionQuality.poor: Icons.signal_cellular_alt_1_bar,
|
? Icons.wifi_off_outlined
|
||||||
}[connectionQuality],
|
: Icons.wifi,
|
||||||
color: {
|
color: {
|
||||||
ConnectionQuality.excellent: Colors.green,
|
ConnectionQuality.excellent: Colors.green,
|
||||||
ConnectionQuality.good: Colors.orange,
|
ConnectionQuality.good: Colors.orange,
|
||||||
ConnectionQuality.poor: Colors.red,
|
ConnectionQuality.poor: Colors.red,
|
||||||
}[connectionQuality],
|
}[connectionQuality],
|
||||||
size: 16,
|
size: 16,
|
||||||
)
|
|
||||||
else
|
|
||||||
const SizedBox(
|
|
||||||
width: 12,
|
|
||||||
height: 12,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
color: Colors.white,
|
|
||||||
strokeWidth: 2,
|
|
||||||
),
|
),
|
||||||
).paddingAll(3),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user