Skip to content

Commit

Permalink
FLUT-139: Auto-Hide Top & Bottom Bars after 5 seconds (#1692)
Browse files Browse the repository at this point in the history
* Added auto hide functionality for header and footer

* 🤖 Automated Format and Fix

* Fixed conflicts

---------

Co-authored-by: Decoder07 <[email protected]>
Co-authored-by: ygit <[email protected]>
  • Loading branch information
3 people authored Jan 17, 2024
1 parent 787091f commit fd53744
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 131 deletions.
124 changes: 124 additions & 0 deletions packages/hms_room_kit/lib/src/meeting/meeting_grid_component.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
///Dart imports
import 'dart:io';

///Package imports
import 'package:flutter/material.dart';
import 'package:hmssdk_flutter/hmssdk_flutter.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';

///Project imports
import 'package:hms_room_kit/hms_room_kit.dart';
import 'package:hms_room_kit/src/enums/meeting_mode.dart';
import 'package:hms_room_kit/src/meeting/meeting_navigation_visibility_controller.dart';
import 'package:hms_room_kit/src/meeting/meeting_store.dart';
import 'package:hms_room_kit/src/model/peer_track_node.dart';
import 'package:hms_room_kit/src/widgets/meeting_modes/custom_one_to_one_grid.dart';
import 'package:hms_room_kit/src/widgets/meeting_modes/one_to_one_mode.dart';

///[MeetingGridComponent] is a component that is used to show the video grid
class MeetingGridComponent extends StatelessWidget {
final MeetingNavigationVisibilityController? visibilityController;

const MeetingGridComponent({super.key, required this.visibilityController});

@override
Widget build(BuildContext context) {
return Selector<
MeetingStore,
Tuple6<List<PeerTrackNode>, bool, int, int, MeetingMode,
PeerTrackNode?>>(
selector: (_, meetingStore) => Tuple6(
meetingStore.peerTracks,
meetingStore.isHLSLink,
meetingStore.peerTracks.length,
meetingStore.screenShareCount,
meetingStore.meetingMode,
meetingStore.peerTracks.isNotEmpty
? meetingStore.peerTracks[meetingStore.screenShareCount]
: null),
builder: (_, data, __) {
if (data.item3 == 0) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(
strokeWidth: 2,
color: HMSThemeColors.primaryDefault,
),
const SizedBox(
height: 10,
),
if (context.read<MeetingStore>().peers.isNotEmpty)
HMSTitleText(
text: "Please wait for broadcaster to join",
textColor: HMSThemeColors.onSurfaceHighEmphasis)
],
));
}
return Selector<MeetingStore, Tuple2<MeetingMode, HMSPeer?>>(
selector: (_, meetingStore) =>
Tuple2(meetingStore.meetingMode, meetingStore.localPeer),
builder: (_, modeData, __) {
///This renders the video grid based on whether the controls are visible or not
return Selector<MeetingNavigationVisibilityController, bool>(
selector: (_, meetingNavigationVisibilityController) =>
meetingNavigationVisibilityController.showControls,
builder: (_, showControls, __) {
return Center(
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),

///If the controls are visible we reduce the
///height of video grid by 140 else it covers the whole screen
///
///Here we also check for the platform and reduce the height accordingly
height: showControls
? MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
MediaQuery.of(context).padding.bottom -
(Platform.isAndroid
? 160
: Platform.isIOS
? 230
: 160)
: MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
MediaQuery.of(context).padding.bottom -
20,
child: GestureDetector(
onTap: () => visibilityController
?.toggleControlsVisibility(),
child: (modeData.item1 ==
MeetingMode.activeSpeakerWithInset &&
(context
.read<MeetingStore>()
.localPeer
?.audioTrack !=
null ||
context
.read<MeetingStore>()
.localPeer
?.videoTrack !=
null))
? OneToOneMode(
///This is done to keep the inset tile
///at correct position when controls are hidden
bottomMargin: showControls ? 250 : 130,
peerTracks: data.item1,
screenShareCount: data.item4,
context: context,
)
: CustomOneToOneGrid(
isLocalInsetPresent: false,
peerTracks: data.item1,
),
),
),
);
});
});
});
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
///Dart imports
import 'dart:async';

///Package imports
import 'package:flutter/widgets.dart';

class MeetingNavigationVisibilityController extends ChangeNotifier {
bool showControls = true;

///This variable stores whether the timer is active or not
///
///This is done to avoid multiple timers running at the same time
bool _isTimerActive = false;

///This method toggles the visibility of the buttons
void toggleControlsVisibility() {
showControls = !showControls;

///If the controls are now visible and
///If the timer is not active, we start the timer
if (showControls && !_isTimerActive) {
startTimerToHideButtons();
}
notifyListeners();
}

///This method starts a timer for 5 seconds and then hides the buttons
void startTimerToHideButtons() {
_isTimerActive = true;
Timer(const Duration(seconds: 5), () {
showControls = false;
_isTimerActive = false;
notifyListeners();
});
}
}
137 changes: 8 additions & 129 deletions packages/hms_room_kit/lib/src/meeting/meeting_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ import 'package:hmssdk_flutter/hmssdk_flutter.dart';

///Project imports
import 'package:hms_room_kit/hms_room_kit.dart';
import 'package:hms_room_kit/src/enums/meeting_mode.dart';
import 'package:hms_room_kit/src/model/peer_track_node.dart';
import 'package:hms_room_kit/src/widgets/meeting_modes/custom_one_to_one_grid.dart';
import 'package:hms_room_kit/src/widgets/meeting_modes/one_to_one_mode.dart';
import 'package:hms_room_kit/src/meeting/meeting_grid_component.dart';
import 'package:hms_room_kit/src/meeting/meeting_navigation_visibility_controller.dart';
import 'package:hms_room_kit/src/meeting/meeting_bottom_navigation_bar.dart';
import 'package:hms_room_kit/src/meeting/meeting_header.dart';
Expand Down Expand Up @@ -63,6 +60,7 @@ class _MeetingPageState extends State<MeetingPage> {
checkAudioState();
_enableForegroundService();
_visibilityController = MeetingNavigationVisibilityController();
_visibilityController!.startTimerToHideButtons();
}

void checkAudioState() async {
Expand Down Expand Up @@ -185,130 +183,11 @@ class _MeetingPageState extends State<MeetingPage> {
MediaQuery.of(context).padding.bottom,
child: Stack(
children: [
Selector<
MeetingStore,
Tuple6<
List<PeerTrackNode>,
bool,
int,
int,
MeetingMode,
PeerTrackNode?>>(
selector: (_, meetingStore) => Tuple6(
meetingStore.peerTracks,
meetingStore.isHLSLink,
meetingStore
.peerTracks.length,
meetingStore.screenShareCount,
meetingStore.meetingMode,
meetingStore
.peerTracks.isNotEmpty
? meetingStore.peerTracks[
meetingStore
.screenShareCount]
: null),
builder: (_, data, __) {
if (data.item3 == 0) {
return Center(
child: Column(
mainAxisSize:
MainAxisSize.min,
children: [
CircularProgressIndicator(
strokeWidth: 2,
color: HMSThemeColors
.primaryDefault,
),
const SizedBox(
height: 10,
),
if (context
.read<MeetingStore>()
.peers
.isNotEmpty)
HMSTitleText(
text:
"Please wait for broadcaster to join",
textColor:
HMSThemeColors
.onSurfaceHighEmphasis)
],
));
}
return Selector<
MeetingStore,
Tuple2<MeetingMode,
HMSPeer?>>(
selector: (_,
meetingStore) =>
Tuple2(
meetingStore
.meetingMode,
meetingStore
.localPeer),
builder: (_, modeData, __) {
Size size = Size(
MediaQuery.of(context)
.size
.width,
MediaQuery.of(context)
.size
.height -
122 -
MediaQuery.of(
context)
.padding
.bottom -
MediaQuery.of(
context)
.padding
.top);
return Positioned(
top: 55,
left: 0,
right: 0,
bottom: 68,
/***
* The logic for gridview is as follows:
* - Default mode is Active Speaker mode which displays only 4 tiles on screen without scroll and updates the tile according to who is currently speaking
* - If there are only 2 peers in the room in which one is local peer then automatically the mode is switched to oneToOne mode
* - As the peer count increases the mode is switched back to active speaker view in case of default mode
* - Remaining as the mode from bottom sheet is selected corresponding grid layout is rendered
*/
child:
GestureDetector(
onTap: () =>
_visibilityController
?.toggleControlsVisibility(),
child: (modeData
.item1 ==
MeetingMode
.activeSpeakerWithInset &&
(context.read<MeetingStore>().localPeer?.audioTrack !=
null ||
context.read<MeetingStore>().localPeer?.videoTrack !=
null))
? OneToOneMode(
bottomMargin:
225,
peerTracks:
data
.item1,
screenShareCount:
data
.item4,
context:
context,
size: size)
: CustomOneToOneGrid(
isLocalInsetPresent:
false,
peerTracks:
data.item1,
),
));
});
}),
ChangeNotifierProvider.value(
value: _visibilityController,
child: MeetingGridComponent(
visibilityController:
_visibilityController)),
Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
Expand Down Expand Up @@ -396,7 +275,7 @@ class _MeetingPageState extends State<MeetingPage> {
child: Stack(
children: [
///This renders the video component
///[HMSVideoView] is only rendered if video is ON
///[HMSTextureView] is only rendered if video is ON
///
///else we render the [HMSCircularAvatar]
Selector<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ import 'package:hms_room_kit/src/widgets/peer_widgets/inset_collapsed_view.dart'
class OneToOneMode extends StatefulWidget {
final List<PeerTrackNode> peerTracks;
final BuildContext context;
final Size size;
final int screenShareCount;
final double bottomMargin;
const OneToOneMode(
{Key? key,
required this.peerTracks,
required this.context,
required this.size,
required this.screenShareCount,
this.bottomMargin = 272})
: super(key: key);
Expand Down

0 comments on commit fd53744

Please sign in to comment.