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.
174 lines
5.8 KiB
Dart
174 lines
5.8 KiB
Dart
4 years ago
|
import 'dart:async';
|
||
|
import 'dart:io';
|
||
|
|
||
|
import 'package:diplomaticquarterapp/pages/conference/clipped_video.dart';
|
||
|
import 'package:flutter/material.dart';
|
||
|
|
||
|
class DraggablePublisher extends StatefulWidget {
|
||
|
final Size availableScreenSize;
|
||
|
final Widget child;
|
||
|
final double scaleFactor;
|
||
|
final Stream<bool> onButtonBarVisible;
|
||
|
final Stream<double> onButtonBarHeight;
|
||
|
|
||
|
const DraggablePublisher({
|
||
|
Key key,
|
||
|
@required this.availableScreenSize,
|
||
|
this.child,
|
||
|
@required this.onButtonBarVisible,
|
||
|
@required this.onButtonBarHeight,
|
||
|
|
||
|
/// The portion of the screen the DraggableWidget should use.
|
||
|
this.scaleFactor = .25,
|
||
|
}) : assert(scaleFactor != null && scaleFactor > 0 && scaleFactor <= .4),
|
||
|
assert(availableScreenSize != null),
|
||
|
assert(onButtonBarVisible != null),
|
||
|
assert(onButtonBarHeight != null),
|
||
|
super(key: key);
|
||
|
|
||
|
@override
|
||
|
_DraggablePublisherState createState() => _DraggablePublisherState();
|
||
|
}
|
||
|
|
||
|
class _DraggablePublisherState extends State<DraggablePublisher> {
|
||
|
bool _isButtonBarVisible = true;
|
||
|
double _buttonBarHeight = 0;
|
||
|
double _width;
|
||
|
double _height;
|
||
|
double _top;
|
||
|
double _left;
|
||
|
double _viewPaddingTop;
|
||
|
double _viewPaddingBottom;
|
||
|
final double _padding = 8.0;
|
||
|
final Duration _duration300ms = const Duration(milliseconds: 300);
|
||
|
final Duration _duration0ms = const Duration(milliseconds: 0);
|
||
|
Duration _duration;
|
||
|
StreamSubscription _streamSubscription;
|
||
|
StreamSubscription _streamHeightSubscription;
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
|
_duration = _duration300ms;
|
||
|
_width = widget.availableScreenSize.width * widget.scaleFactor;
|
||
|
_height = _width * (widget.availableScreenSize.height / widget.availableScreenSize.width);
|
||
|
_top = widget.availableScreenSize.height - (_buttonBarHeight + _padding) - _height;
|
||
|
_left = widget.availableScreenSize.width - _padding - _width;
|
||
|
|
||
|
_streamSubscription = widget.onButtonBarVisible.listen(_buttonBarVisible);
|
||
|
_streamHeightSubscription = widget.onButtonBarHeight.listen(_getButtonBarHeight);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void didChangeDependencies() {
|
||
|
final mediaQuery = MediaQuery.of(context);
|
||
|
_viewPaddingTop = mediaQuery.viewPadding.top;
|
||
|
_viewPaddingBottom = mediaQuery.viewPadding.bottom;
|
||
|
super.didChangeDependencies();
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void dispose() {
|
||
|
_streamSubscription.cancel();
|
||
|
_streamHeightSubscription.cancel();
|
||
|
super.dispose();
|
||
|
}
|
||
|
|
||
|
void _getButtonBarHeight(double height) {
|
||
|
setState(() {
|
||
|
_buttonBarHeight = height;
|
||
|
_positionWidget();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void _buttonBarVisible(bool visible) {
|
||
|
if (!mounted) {
|
||
|
return;
|
||
|
}
|
||
|
setState(() {
|
||
|
_isButtonBarVisible = visible;
|
||
|
if (_duration == _duration300ms) {
|
||
|
// only position the widget when we are not currently dragging it around
|
||
|
_positionWidget();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return AnimatedPositioned(
|
||
|
top: _top,
|
||
|
left: _left,
|
||
|
width: _width,
|
||
|
height: _height,
|
||
|
duration: _duration,
|
||
|
child: Listener(
|
||
|
onPointerDown: (_) => _duration = _duration0ms,
|
||
|
onPointerMove: (PointerMoveEvent event) {
|
||
|
setState(() {
|
||
|
_left = (_left + event.delta.dx).roundToDouble();
|
||
|
_top = (_top + event.delta.dy).roundToDouble();
|
||
|
});
|
||
|
},
|
||
|
onPointerUp: (_) => _positionWidget(),
|
||
|
onPointerCancel: (_) => _positionWidget(),
|
||
|
child: ClippedVideo(
|
||
|
height: _height,
|
||
|
width: _width,
|
||
|
child: widget.child,
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
double _getCurrentStatusBarHeight() {
|
||
|
if (_isButtonBarVisible) {
|
||
|
return _viewPaddingTop;
|
||
|
}
|
||
|
final _defaultViewPaddingTop = Platform.isIOS ? 20.0 : Platform.isAndroid ? 24.0 : 0.0;
|
||
|
if (_viewPaddingTop > _defaultViewPaddingTop) {
|
||
|
// There must be a hardware notch in the display.
|
||
|
return _viewPaddingTop;
|
||
|
}
|
||
|
return 0.0;
|
||
|
}
|
||
|
|
||
|
double _getCurrentButtonBarHeight() {
|
||
|
if (_isButtonBarVisible) {
|
||
|
return _buttonBarHeight + _viewPaddingBottom;
|
||
|
}
|
||
|
return _viewPaddingBottom;
|
||
|
}
|
||
|
|
||
|
void _positionWidget() {
|
||
|
// Determine the center of the object being dragged so we can decide
|
||
|
// in which corner the object should be placed.
|
||
|
var dx = (_width / 2) + _left;
|
||
|
dx = dx < 0 ? 0 : dx >= widget.availableScreenSize.width ? widget.availableScreenSize.width - 1 : dx;
|
||
|
var dy = (_height / 2) + _top;
|
||
|
dy = dy < 0 ? 0 : dy >= widget.availableScreenSize.height ? widget.availableScreenSize.height - 1 : dy;
|
||
|
final draggableCenter = Offset(dx, dy);
|
||
|
|
||
|
setState(() {
|
||
|
_duration = _duration300ms;
|
||
|
if (Rect.fromLTRB(0, 0, widget.availableScreenSize.width / 2, widget.availableScreenSize.height / 2).contains(draggableCenter)) {
|
||
|
// Top-left
|
||
|
_top = _getCurrentStatusBarHeight() + _padding;
|
||
|
_left = _padding;
|
||
|
} else if (Rect.fromLTRB(widget.availableScreenSize.width / 2, 0, widget.availableScreenSize.width, widget.availableScreenSize.height / 2).contains(draggableCenter)) {
|
||
|
// Top-right
|
||
|
_top = _getCurrentStatusBarHeight() + _padding;
|
||
|
_left = widget.availableScreenSize.width - _padding - _width;
|
||
|
} else if (Rect.fromLTRB(0, widget.availableScreenSize.height / 2, widget.availableScreenSize.width / 2, widget.availableScreenSize.height).contains(draggableCenter)) {
|
||
|
// Bottom-left
|
||
|
_top = widget.availableScreenSize.height - (_getCurrentButtonBarHeight() + _padding) - _height;
|
||
|
_left = _padding;
|
||
|
} else if (Rect.fromLTRB(widget.availableScreenSize.width / 2, widget.availableScreenSize.height / 2, widget.availableScreenSize.width, widget.availableScreenSize.height).contains(draggableCenter)) {
|
||
|
// Bottom-right
|
||
|
_top = widget.availableScreenSize.height - (_getCurrentButtonBarHeight() + _padding) - _height;
|
||
|
_left = widget.availableScreenSize.width - _padding - _width;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|