Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FLUT-139: Auto-Hide Top & Bottom Bars after 5 seconds #1692

Merged
merged 4 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading