💄 Grid view in call
This commit is contained in:
		| @@ -113,7 +113,7 @@ PODS: | ||||
|     - TOCropViewController (~> 2.7.4) | ||||
|   - image_picker_ios (0.0.1): | ||||
|     - Flutter | ||||
|   - livekit_client (2.2.2): | ||||
|   - livekit_client (2.2.3): | ||||
|     - Flutter | ||||
|     - WebRTC-SDK (= 125.6422.04) | ||||
|   - media_kit_libs_ios_video (1.0.4): | ||||
| @@ -295,7 +295,7 @@ SPEC CHECKSUMS: | ||||
|   GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 | ||||
|   image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf | ||||
|   image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 | ||||
|   livekit_client: c767049a635d5b6d43de3273dca3c439b8a6e970 | ||||
|   livekit_client: bad83a7776a41abc42e1f26d903eeac9164c8a9f | ||||
|   media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 | ||||
|   media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a | ||||
|   media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e | ||||
|   | ||||
| @@ -87,75 +87,77 @@ 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 Obx( | ||||
|       () => Stack( | ||||
|         children: [ | ||||
|           Container( | ||||
|             color: Theme.of(context).colorScheme.surfaceContainer, | ||||
|             child: call.focusTrack.value != null | ||||
|                 ? InteractiveParticipantWidget( | ||||
|                     isFixedAvatar: 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); | ||||
|                         } | ||||
|                       }, | ||||
|                   return Padding( | ||||
|                     padding: const EdgeInsets.only(top: 8, left: 8), | ||||
|                     child: ClipRRect( | ||||
|                       borderRadius: const BorderRadius.all(Radius.circular(8)), | ||||
|                       child: InteractiveParticipantWidget( | ||||
|                         isFixedAvatar: 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; | ||||
|     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(); | ||||
|       int columns = (math.sqrt(call.participantTracks.length)).ceil(); | ||||
|       int rows = (call.participantTracks.length / columns).ceil(); | ||||
|  | ||||
|         double tileWidth = screenWidth / columns; | ||||
|         double tileHeight = screenHeight / rows; | ||||
|       double tileWidth = screenWidth / columns; | ||||
|       double tileHeight = screenHeight / rows; | ||||
|  | ||||
|         return GridView.builder( | ||||
|       return Obx( | ||||
|         () => GridView.builder( | ||||
|           gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( | ||||
|             crossAxisCount: columns, | ||||
|             childAspectRatio: tileWidth / tileHeight, | ||||
| @@ -165,25 +167,26 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin { | ||||
|             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); | ||||
|                     } | ||||
|                   }, | ||||
|               child: Card( | ||||
|                 child: ClipRRect( | ||||
|                   borderRadius: const BorderRadius.all(Radius.circular(8)), | ||||
|                   child: InteractiveParticipantWidget( | ||||
|                     color: Theme.of(context).colorScheme.surfaceContainerHigh, | ||||
|                     participant: track, | ||||
|                     onTap: () { | ||||
|                       if (track.participant.sid != | ||||
|                           call.focusTrack.value?.participant.sid) { | ||||
|                         call.changeFocusTrack(track); | ||||
|                       } | ||||
|                     }, | ||||
|                   ), | ||||
|                 ), | ||||
|               ), | ||||
|             ); | ||||
|           }, | ||||
|         ); | ||||
|       } | ||||
|     ); | ||||
|         ), | ||||
|       ); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
| @@ -234,31 +237,33 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin { | ||||
|         body: SafeArea( | ||||
|           child: GestureDetector( | ||||
|             behavior: HitTestBehavior.translucent, | ||||
|             child: Obx( | ||||
|               () => Column( | ||||
|                 children: [ | ||||
|                   SizeTransition( | ||||
|                     sizeFactor: _controlsAnimation, | ||||
|                     axis: Axis.vertical, | ||||
|                     child: SizedBox( | ||||
|                       width: MediaQuery.of(context).size.width, | ||||
|                       height: 64, | ||||
|                       child: Row( | ||||
|                         children: [ | ||||
|                           const Expanded(child: SizedBox()), | ||||
|                           IconButton( | ||||
|                             icon: _layoutMode == 0 | ||||
|                                 ? const Icon(Icons.view_list) | ||||
|                                 : const Icon(Icons.grid_view), | ||||
|                             onPressed: () { | ||||
|                               _switchLayout(); | ||||
|                             }, | ||||
|                           ), | ||||
|                         ], | ||||
|                       ).paddingSymmetric(horizontal: 10), | ||||
|                     ), | ||||
|             child: Column( | ||||
|               children: [ | ||||
|                 SizeTransition( | ||||
|                   sizeFactor: _controlsAnimation, | ||||
|                   axis: Axis.vertical, | ||||
|                   child: SizedBox( | ||||
|                     width: MediaQuery.of(context).size.width, | ||||
|                     height: 64, | ||||
|                     child: Row( | ||||
|                       children: [ | ||||
|                         const Expanded(child: SizedBox()), | ||||
|                         IconButton( | ||||
|                           icon: _layoutMode == 0 | ||||
|                               ? const Icon(Icons.view_list) | ||||
|                               : const Icon(Icons.grid_view), | ||||
|                           onPressed: () { | ||||
|                             _switchLayout(); | ||||
|                           }, | ||||
|                         ), | ||||
|                       ], | ||||
|                     ).paddingSymmetric(horizontal: 10), | ||||
|                   ), | ||||
|                   Expanded( | ||||
|                 ), | ||||
|                 Expanded( | ||||
|                   child: Material( | ||||
|                     color: Theme.of(context).colorScheme.surfaceContainerLow, | ||||
|                     elevation: 2, | ||||
|                     child: Builder( | ||||
|                       builder: (context) { | ||||
|                         switch (_layoutMode) { | ||||
| @@ -270,20 +275,20 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin { | ||||
|                       }, | ||||
|                     ), | ||||
|                   ), | ||||
|                   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!, | ||||
|                       ), | ||||
|                     ), | ||||
|                 ], | ||||
|               ), | ||||
|                   ), | ||||
|               ], | ||||
|             ), | ||||
|             onTap: () { | ||||
|               _toggleControls(); | ||||
|   | ||||
| @@ -201,7 +201,7 @@ class InteractiveParticipantWidget extends StatelessWidget { | ||||
|   final double? width; | ||||
|   final double? height; | ||||
|   final Color? color; | ||||
|   final bool isFixed; | ||||
|   final bool isFixedAvatar; | ||||
|   final ParticipantTrack participant; | ||||
|   final Function() onTap; | ||||
|  | ||||
| @@ -210,7 +210,7 @@ class InteractiveParticipantWidget extends StatelessWidget { | ||||
|     this.width, | ||||
|     this.height, | ||||
|     this.color, | ||||
|     this.isFixed = false, | ||||
|     this.isFixedAvatar = false, | ||||
|     required this.participant, | ||||
|     required this.onTap, | ||||
|   }); | ||||
| @@ -222,7 +222,7 @@ class InteractiveParticipantWidget extends StatelessWidget { | ||||
|         width: width, | ||||
|         height: height, | ||||
|         color: color, | ||||
|         child: ParticipantWidget.widgetFor(participant, isFixed: isFixed), | ||||
|         child: ParticipantWidget.widgetFor(participant, isFixed: isFixedAvatar), | ||||
|       ), | ||||
|       onTap: () => onTap(), | ||||
|       onLongPress: () { | ||||
|   | ||||
							
								
								
									
										28
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -261,10 +261,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: cross_file | ||||
|       sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" | ||||
|       sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.3.4+1" | ||||
|     version: "0.3.4+2" | ||||
|   crypto: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -684,10 +684,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: flutter_webrtc | ||||
|       sha256: d305793e6737c59a81c45b18484e1f985710827704eeb9092573387efcbae272 | ||||
|       sha256: f46bd76cef6e8d787dc707d0c591f0e89c912a2970c7b5e68a55b9cca1bdde4c | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.11.5" | ||||
|     version: "0.11.6" | ||||
|   font_awesome_flutter: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -732,10 +732,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: go_router | ||||
|       sha256: "39dd52168d6c59984454183148dc3a5776960c61083adfc708cc79a7b3ce1ba8" | ||||
|       sha256: d380de0355788c5c784fe9f81b43fc833b903991c25ecc4e2a416a67faefa722 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "14.2.1" | ||||
|     version: "14.2.2" | ||||
|   graphs: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -820,10 +820,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: image_picker_for_web | ||||
|       sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3" | ||||
|       sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.0.4" | ||||
|     version: "3.0.5" | ||||
|   image_picker_ios: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -948,10 +948,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: livekit_client | ||||
|       sha256: e6b1e8a3cdcae95f7e62c0371590648444bac245fce3a1bcfb4ec05889ad82f3 | ||||
|       sha256: be2a3375851a6147d5de94a870edd6e831ab8d3d793e3563ba1ff1b05490b3de | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.2.2" | ||||
|     version: "2.2.3" | ||||
|   logging: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1524,10 +1524,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: shared_preferences_web | ||||
|       sha256: "3a293170d4d9403c3254ee05b84e62e8a9b3c5808ebd17de6a33fe9ea6457936" | ||||
|       sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.4.0" | ||||
|     version: "2.4.1" | ||||
|   shared_preferences_windows: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1809,10 +1809,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_web | ||||
|       sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" | ||||
|       sha256: a36e2d7981122fa185006b216eb6b5b97ede3f9a54b7a511bc966971ab98d049 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.1" | ||||
|     version: "2.3.2" | ||||
|   url_launcher_windows: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user