You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PatientApp-KKUMC/lib/pages/conference/conference_button_bar.dart

239 lines
6.6 KiB
Dart

import 'dart:async';
import 'package:after_layout/after_layout.dart';
import 'package:diplomaticquarterapp/pages/conference/widgets/circle_button.dart';
import 'package:flutter/material.dart';
class ConferenceButtonBar extends StatefulWidget {
final VoidCallback onVideoEnabled;
final VoidCallback onAudioEnabled;
final VoidCallback onHangup;
final VoidCallback onSwitchCamera;
final VoidCallback onPersonAdd;
final VoidCallback onPersonRemove;
final void Function(double) onHeight;
final VoidCallback onHide;
final VoidCallback onShow;
final Stream<bool> videoEnabled;
final Stream<bool> audioEnabled;
const ConferenceButtonBar({
Key key,
this.onVideoEnabled,
this.onAudioEnabled,
this.onHangup,
this.onSwitchCamera,
this.onPersonAdd,
this.onPersonRemove,
@required this.videoEnabled,
@required this.audioEnabled,
this.onHeight,
this.onHide,
this.onShow,
}) : assert(videoEnabled != null),
assert(audioEnabled != null),
super(key: key);
@override
_ConferenceButtonBarState createState() => _ConferenceButtonBarState();
}
class _ConferenceButtonBarState extends State<ConferenceButtonBar> with AfterLayoutMixin<ConferenceButtonBar> {
var _bottom = -100.0;
Timer _timer;
int _remaining;
var _videoEnabled = true;
var _audioEnabled = true;
double _hidden;
double _visible;
final _keyButtonBarHeight = GlobalKey();
final Duration timeout = const Duration(seconds: 5);
final Duration ms = const Duration(milliseconds: 1);
final Duration periodicDuration = const Duration(milliseconds: 100);
Timer startTimeout([int milliseconds]) {
final duration = milliseconds == null ? timeout : ms * milliseconds;
_remaining = duration.inMilliseconds;
return Timer.periodic(periodicDuration, (Timer timer) {
_remaining -= periodicDuration.inMilliseconds;
if (_remaining <= 0) {
timer.cancel();
_toggleBar();
}
});
}
void _pauseTimer() {
if (_timer == null) {
return;
}
_timer.cancel();
_timer = null;
}
void _resumeTimer() {
// resume the timer only when there is no timer active or when
// the bar is not already hidden.
if ((_timer != null && _timer.isActive) || _bottom == _hidden) {
return;
}
_timer = startTimeout(_remaining);
}
void _toggleBar() {
setState(() {
_bottom = _bottom == _visible ? _hidden : _visible;
if (_bottom == _visible && widget.onShow != null) {
widget.onShow();
}
if (_bottom == _hidden && widget.onHide != null) {
widget.onHide();
}
});
}
void _toggleBarOnEnd() {
if (_timer != null) {
if (_timer.isActive) {
_timer.cancel();
}
_timer = null;
}
if (_bottom == 0) {
_timer = startTimeout();
}
}
@override
void initState() {
super.initState();
_timer = startTimeout();
}
@override
void didChangeDependencies() {
_visible = MediaQuery.of(context).viewPadding.bottom;
super.didChangeDependencies();
}
@override
void afterFirstLayout(BuildContext context) {
final RenderBox renderBoxButtonBar = _keyButtonBarHeight.currentContext.findRenderObject();
final heightButtonBar = renderBoxButtonBar.size.height;
// Because the `didChangeDependencies` fires before the `afterFirstLayout`, we can use the `_visible` property here.
_hidden = -(heightButtonBar + _visible);
widget.onHeight(heightButtonBar);
_toggleBar();
}
@override
void dispose() {
super.dispose();
if (_timer != null && _timer.isActive) {
_timer.cancel();
_timer = null;
}
}
@override
Widget build(BuildContext context) {
return Positioned(
top: 0,
left: 0,
right: 0,
bottom: 0,
child: GestureDetector(
key: Key('show-hide-button-bar-gesture'),
behavior: HitTestBehavior.translucent,
onTapDown: (_) => _pauseTimer(),
onTapUp: (_) => _toggleBar(),
onTapCancel: () => _resumeTimer(),
child: Stack(
children: <Widget>[
AnimatedPositioned(
key: Key('button-bar'),
bottom: _bottom,
left: 0,
right: 0,
duration: const Duration(milliseconds: 300),
curve: Curves.linear,
child: _buildRow(context),
onEnd: _toggleBarOnEnd,
),
],
),
),
);
}
void _onPressed(VoidCallback callback) {
if (callback != null) {
callback();
}
if (_timer != null && _timer.isActive) {
_timer.cancel();
}
_timer = startTimeout();
}
Widget _buildRow(BuildContext context) {
return Padding(
key: _keyButtonBarHeight,
padding: const EdgeInsets.only(bottom: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
CircleButton(
child: StreamBuilder<bool>(
stream: widget.videoEnabled,
initialData: _videoEnabled,
builder: (context, snapshot) {
_videoEnabled = snapshot.data;
return Icon(
_videoEnabled ? Icons.videocam : Icons.videocam_off,
color: Colors.white,
);
}),
key: Key('camera-button'),
onPressed: () => _onPressed(widget.onVideoEnabled),
),
CircleButton(
child: StreamBuilder<bool>(
stream: widget.audioEnabled,
initialData: _audioEnabled,
builder: (context, snapshot) {
_audioEnabled = snapshot.data;
return Icon(
_audioEnabled ? Icons.mic : Icons.mic_off,
color: Colors.white,
);
}),
key: Key('microphone-button'),
onPressed: () => _onPressed(widget.onAudioEnabled),
),
CircleButton(
child: const Icon(Icons.switch_camera, color: Colors.white),
key: Key('switch-camera-button'),
onPressed: () => _onPressed(widget.onSwitchCamera),
),
CircleButton(
radius: 35,
child: const RotationTransition(
turns: AlwaysStoppedAnimation<double>(135 / 360),
child: Icon(
Icons.phone,
color: Colors.white,
size: 40,
),
),
color: Colors.red.withAlpha(200),
key: Key('hangup-button'),
onPressed: () => _onPressed(widget.onHangup),
),
],
),
);
}
}