✨ Call grid layout
This commit is contained in:
		@@ -21,6 +21,8 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,6 +56,14 @@ 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);
 | 
				
			||||||
@@ -75,6 +85,107 @@ 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();
 | 
				
			||||||
@@ -124,78 +235,53 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
 | 
				
			|||||||
          child: GestureDetector(
 | 
					          child: GestureDetector(
 | 
				
			||||||
            behavior: HitTestBehavior.translucent,
 | 
					            behavior: HitTestBehavior.translucent,
 | 
				
			||||||
            child: Obx(
 | 
					            child: Obx(
 | 
				
			||||||
              () => Stack(
 | 
					              () => Column(
 | 
				
			||||||
                children: [
 | 
					                children: [
 | 
				
			||||||
                  Column(
 | 
					                  SizeTransition(
 | 
				
			||||||
                    children: [
 | 
					                    sizeFactor: _controlsAnimation,
 | 
				
			||||||
                      Expanded(
 | 
					                    axis: Axis.vertical,
 | 
				
			||||||
                        child: Container(
 | 
					 | 
				
			||||||
                          color: Theme.of(context).colorScheme.surfaceContainer,
 | 
					 | 
				
			||||||
                          child: provider.focusTrack.value != null
 | 
					 | 
				
			||||||
                              ? InteractiveParticipantWidget(
 | 
					 | 
				
			||||||
                                  isFixed: false,
 | 
					 | 
				
			||||||
                                  participant: provider.focusTrack.value!,
 | 
					 | 
				
			||||||
                                  onTap: () {},
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                              : const SizedBox(),
 | 
					 | 
				
			||||||
                        ),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                      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(
 | 
					                    child: SizedBox(
 | 
				
			||||||
                      height: 128,
 | 
					                      width: MediaQuery.of(context).size.width,
 | 
				
			||||||
                      child: ListView.builder(
 | 
					                      height: 64,
 | 
				
			||||||
                        scrollDirection: Axis.horizontal,
 | 
					                      child: Row(
 | 
				
			||||||
                        itemCount:
 | 
					                        children: [
 | 
				
			||||||
                            math.max(0, provider.participantTracks.length),
 | 
					                          const Expanded(child: SizedBox()),
 | 
				
			||||||
                        itemBuilder: (BuildContext context, int index) {
 | 
					                          IconButton(
 | 
				
			||||||
                          final track = provider.participantTracks[index];
 | 
					                            icon: _layoutMode == 0
 | 
				
			||||||
                          if (track.participant.sid ==
 | 
					                                ? const Icon(Icons.view_list)
 | 
				
			||||||
                              provider.focusTrack.value?.participant.sid) {
 | 
					                                : const Icon(Icons.grid_view),
 | 
				
			||||||
                            return Container();
 | 
					                            onPressed: () {
 | 
				
			||||||
                          }
 | 
					                              _switchLayout();
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
                          return Padding(
 | 
					                          ),
 | 
				
			||||||
                            padding: const EdgeInsets.only(top: 8, left: 8),
 | 
					                        ],
 | 
				
			||||||
                            child: ClipRRect(
 | 
					                      ).paddingSymmetric(horizontal: 10),
 | 
				
			||||||
                              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);
 | 
					 | 
				
			||||||
                                  }
 | 
					 | 
				
			||||||
                                },
 | 
					 | 
				
			||||||
                              ),
 | 
					 | 
				
			||||||
                            ),
 | 
					 | 
				
			||||||
                          );
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
 | 
					                  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!,
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user