💄 Grid view in call

This commit is contained in:
LittleSheep 2024-08-02 21:12:37 +08:00
parent 4238ea6fdc
commit 0ad4854443
4 changed files with 132 additions and 127 deletions

View File

@ -113,7 +113,7 @@ PODS:
- TOCropViewController (~> 2.7.4) - TOCropViewController (~> 2.7.4)
- image_picker_ios (0.0.1): - image_picker_ios (0.0.1):
- Flutter - Flutter
- livekit_client (2.2.2): - livekit_client (2.2.3):
- Flutter - Flutter
- WebRTC-SDK (= 125.6422.04) - WebRTC-SDK (= 125.6422.04)
- media_kit_libs_ios_video (1.0.4): - media_kit_libs_ios_video (1.0.4):
@ -295,7 +295,7 @@ SPEC CHECKSUMS:
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
livekit_client: c767049a635d5b6d43de3273dca3c439b8a6e970 livekit_client: bad83a7776a41abc42e1f26d903eeac9164c8a9f
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e

View File

@ -87,75 +87,77 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
Widget _buildListLayout() { Widget _buildListLayout() {
final ChatCallProvider call = Get.find(); final ChatCallProvider call = Get.find();
return Stack( return Obx(
children: [ () => Stack(
Container( children: [
color: Theme.of(context).colorScheme.surfaceContainer, Container(
child: call.focusTrack.value != null color: Theme.of(context).colorScheme.surfaceContainer,
? InteractiveParticipantWidget( child: call.focusTrack.value != null
isFixed: false, ? InteractiveParticipantWidget(
participant: call.focusTrack.value!, isFixedAvatar: false,
onTap: () {}, participant: call.focusTrack.value!,
) onTap: () {},
: const SizedBox(), )
), : const SizedBox(),
Positioned( ),
left: 0, Positioned(
right: 0, left: 0,
top: 0, right: 0,
child: SizedBox( top: 0,
height: 128, child: SizedBox(
child: ListView.builder( height: 128,
scrollDirection: Axis.horizontal, child: ListView.builder(
itemCount: math.max(0, call.participantTracks.length), scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) { itemCount: math.max(0, call.participantTracks.length),
final track = call.participantTracks[index]; itemBuilder: (BuildContext context, int index) {
if (track.participant.sid == final track = call.participantTracks[index];
call.focusTrack.value?.participant.sid) { if (track.participant.sid ==
return Container(); call.focusTrack.value?.participant.sid) {
} return Container();
}
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8, left: 8), padding: const EdgeInsets.only(top: 8, left: 8),
child: ClipRRect( child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)), borderRadius: const BorderRadius.all(Radius.circular(8)),
child: InteractiveParticipantWidget( child: InteractiveParticipantWidget(
isFixed: true, isFixedAvatar: true,
width: 120, width: 120,
height: 120, height: 120,
color: Theme.of(context).cardColor, color: Theme.of(context).cardColor,
participant: track, participant: track,
onTap: () { onTap: () {
if (track.participant.sid != if (track.participant.sid !=
call.focusTrack.value?.participant.sid) { call.focusTrack.value?.participant.sid) {
call.changeFocusTrack(track); call.changeFocusTrack(track);
} }
}, },
),
), ),
), );
); },
}, ),
), ),
), ),
), ],
], ),
); );
} }
Widget _buildGridLayout() { Widget _buildGridLayout() {
final ChatCallProvider call = Get.find(); final ChatCallProvider call = Get.find();
return LayoutBuilder( return LayoutBuilder(builder: (context, constraints) {
builder: (context, constraints) { double screenWidth = constraints.maxWidth;
double screenWidth = constraints.maxWidth; double screenHeight = constraints.maxHeight;
double screenHeight = constraints.maxHeight;
int columns = (math.sqrt(call.participantTracks.length)).ceil(); int columns = (math.sqrt(call.participantTracks.length)).ceil();
int rows = (call.participantTracks.length / columns).ceil(); int rows = (call.participantTracks.length / columns).ceil();
double tileWidth = screenWidth / columns; double tileWidth = screenWidth / columns;
double tileHeight = screenHeight / rows; double tileHeight = screenHeight / rows;
return GridView.builder( return Obx(
() => GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns, crossAxisCount: columns,
childAspectRatio: tileWidth / tileHeight, childAspectRatio: tileWidth / tileHeight,
@ -165,25 +167,26 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
final track = call.participantTracks[index]; final track = call.participantTracks[index];
return Padding( return Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: ClipRRect( child: Card(
borderRadius: const BorderRadius.all(Radius.circular(8)), child: ClipRRect(
child: InteractiveParticipantWidget( borderRadius: const BorderRadius.all(Radius.circular(8)),
isFixed: true, child: InteractiveParticipantWidget(
color: Theme.of(context).colorScheme.surfaceContainerLow, color: Theme.of(context).colorScheme.surfaceContainerHigh,
participant: track, participant: track,
onTap: () { onTap: () {
if (track.participant.sid != if (track.participant.sid !=
call.focusTrack.value?.participant.sid) { call.focusTrack.value?.participant.sid) {
call.changeFocusTrack(track); call.changeFocusTrack(track);
} }
}, },
),
), ),
), ),
); );
}, },
); ),
} );
); });
} }
@override @override
@ -234,31 +237,33 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
body: SafeArea( body: SafeArea(
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
child: Obx( child: Column(
() => Column( children: [
children: [ SizeTransition(
SizeTransition( sizeFactor: _controlsAnimation,
sizeFactor: _controlsAnimation, axis: Axis.vertical,
axis: Axis.vertical, child: SizedBox(
child: SizedBox( width: MediaQuery.of(context).size.width,
width: MediaQuery.of(context).size.width, height: 64,
height: 64, child: Row(
child: Row( children: [
children: [ const Expanded(child: SizedBox()),
const Expanded(child: SizedBox()), IconButton(
IconButton( icon: _layoutMode == 0
icon: _layoutMode == 0 ? const Icon(Icons.view_list)
? const Icon(Icons.view_list) : const Icon(Icons.grid_view),
: const Icon(Icons.grid_view), onPressed: () {
onPressed: () { _switchLayout();
_switchLayout(); },
}, ),
), ],
], ).paddingSymmetric(horizontal: 10),
).paddingSymmetric(horizontal: 10),
),
), ),
Expanded( ),
Expanded(
child: Material(
color: Theme.of(context).colorScheme.surfaceContainerLow,
elevation: 2,
child: Builder( child: Builder(
builder: (context) { builder: (context) {
switch (_layoutMode) { switch (_layoutMode) {
@ -270,20 +275,20 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
}, },
), ),
), ),
if (provider.room.localParticipant != null) ),
SizeTransition( if (provider.room.localParticipant != null)
sizeFactor: _controlsAnimation, SizeTransition(
axis: Axis.vertical, sizeFactor: _controlsAnimation,
child: SizedBox( axis: Axis.vertical,
width: MediaQuery.of(context).size.width, child: SizedBox(
child: ControlsWidget( width: MediaQuery.of(context).size.width,
provider.room, child: ControlsWidget(
provider.room.localParticipant!, provider.room,
), provider.room.localParticipant!,
), ),
), ),
], ),
), ],
), ),
onTap: () { onTap: () {
_toggleControls(); _toggleControls();

View File

@ -201,7 +201,7 @@ class InteractiveParticipantWidget extends StatelessWidget {
final double? width; final double? width;
final double? height; final double? height;
final Color? color; final Color? color;
final bool isFixed; final bool isFixedAvatar;
final ParticipantTrack participant; final ParticipantTrack participant;
final Function() onTap; final Function() onTap;
@ -210,7 +210,7 @@ class InteractiveParticipantWidget extends StatelessWidget {
this.width, this.width,
this.height, this.height,
this.color, this.color,
this.isFixed = false, this.isFixedAvatar = false,
required this.participant, required this.participant,
required this.onTap, required this.onTap,
}); });
@ -222,7 +222,7 @@ class InteractiveParticipantWidget extends StatelessWidget {
width: width, width: width,
height: height, height: height,
color: color, color: color,
child: ParticipantWidget.widgetFor(participant, isFixed: isFixed), child: ParticipantWidget.widgetFor(participant, isFixed: isFixedAvatar),
), ),
onTap: () => onTap(), onTap: () => onTap(),
onLongPress: () { onLongPress: () {

View File

@ -261,10 +261,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cross_file name: cross_file
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.4+1" version: "0.3.4+2"
crypto: crypto:
dependency: "direct main" dependency: "direct main"
description: description:
@ -684,10 +684,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_webrtc name: flutter_webrtc
sha256: d305793e6737c59a81c45b18484e1f985710827704eeb9092573387efcbae272 sha256: f46bd76cef6e8d787dc707d0c591f0e89c912a2970c7b5e68a55b9cca1bdde4c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.11.5" version: "0.11.6"
font_awesome_flutter: font_awesome_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
@ -732,10 +732,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: go_router name: go_router
sha256: "39dd52168d6c59984454183148dc3a5776960c61083adfc708cc79a7b3ce1ba8" sha256: d380de0355788c5c784fe9f81b43fc833b903991c25ecc4e2a416a67faefa722
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.1" version: "14.2.2"
graphs: graphs:
dependency: transitive dependency: transitive
description: description:
@ -820,10 +820,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: image_picker_for_web name: image_picker_for_web
sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3" sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.4" version: "3.0.5"
image_picker_ios: image_picker_ios:
dependency: transitive dependency: transitive
description: description:
@ -948,10 +948,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: livekit_client name: livekit_client
sha256: e6b1e8a3cdcae95f7e62c0371590648444bac245fce3a1bcfb4ec05889ad82f3 sha256: be2a3375851a6147d5de94a870edd6e831ab8d3d793e3563ba1ff1b05490b3de
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.2.3"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -1524,10 +1524,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: "3a293170d4d9403c3254ee05b84e62e8a9b3c5808ebd17de6a33fe9ea6457936" sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.0" version: "2.4.1"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
@ -1809,10 +1809,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" sha256: a36e2d7981122fa185006b216eb6b5b97ede3f9a54b7a511bc966971ab98d049
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.2"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description: