Skip to content
Open
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
12 changes: 6 additions & 6 deletions lib/models/pad_button_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ import 'gestures.dart';
/// Model of one padd button.
class PadButtonItem {
/// [index] required parameter, the key to recognize button instance.
final int index;
final int? index;

/// [buttonText] optional parameter, the text to be displayed inside the
/// button. Omitted if [buttonImage] is set. Default value is empty string.
final String buttonText;
final String? buttonText;

/// [buttonImage] optional parameter, image which will be displayed inside
/// the button.
final Image buttonImage;
final Image? buttonImage;

/// [buttonIcon] optional parameter, image which will be displayed inside
/// the button.
final Icon buttonIcon;
final Icon? buttonIcon;

/// [backgroundColor] color of button in default state.
final Color backgroundColor;
final Color? backgroundColor;

/// [pressedColor] color of button when it is pressed.
final Color pressedColor;
final Color? pressedColor;

/// [supportedGestures] optional parameter, list of gestures for button which
/// will call the callback [PadButtonsView.padButtonPressedCallback].
Expand Down
41 changes: 22 additions & 19 deletions lib/views/circle_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class CircleView extends StatelessWidget {
final double size;
final double? size;

final Color color;
final Color? color;

final List<BoxShadow> boxShadow;
final List<BoxShadow>? boxShadow;

final Border border;
final Border? border;

final double opacity;
final double? opacity;

final Image buttonImage;
final Image? buttonImage;

final Icon buttonIcon;
final Icon? buttonIcon;

final String buttonText;
final String? buttonText;

CircleView({
this.size,
Expand All @@ -34,19 +34,22 @@ class CircleView extends StatelessWidget {
return Container(
width: size,
height: size,
child: Center(
child: buttonIcon != null
? buttonIcon
: (buttonImage != null)
? buttonImage
: (buttonText != null) ? Text(buttonText) : null,
),
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
border: border,
boxShadow: boxShadow,
),
child: Center(
// ignore: prefer_if_null_operators
child: buttonIcon != null
? buttonIcon
: (buttonImage != null)
? buttonImage
: (buttonText != null)
? Text(buttonText!)
: null,
),
);
}

Expand Down Expand Up @@ -85,9 +88,9 @@ class CircleView extends StatelessWidget {
],
);

factory CircleView.padBackgroundCircle(
double size, Color backgroundColour, borderColor, Color shadowColor,
{double opacity}) =>
factory CircleView.padBackgroundCircle(double? size, Color? backgroundColour,
borderColor, Color? shadowColor,
{double? opacity}) =>
CircleView(
size: size,
color: backgroundColour,
Expand All @@ -99,7 +102,7 @@ class CircleView extends StatelessWidget {
),
boxShadow: <BoxShadow>[
BoxShadow(
color: shadowColor,
color: shadowColor!,
spreadRadius: 8.0,
blurRadius: 8.0,
)
Expand Down
121 changes: 62 additions & 59 deletions lib/views/joystick_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,34 @@ class JoystickView extends StatelessWidget {
///
/// Defaults to half of the width in the portrait
/// or half of the height in the landscape mode
final double size;
final double? size;

/// Color of the icons
///
/// Defaults to [Colors.white54]
final Color iconsColor;
final Color? iconsColor;

/// Color of the joystick background
///
/// Defaults to [Colors.blueGrey]
final Color backgroundColor;
final Color? backgroundColor;

/// Color of the inner (smaller) circle background
///
/// Defaults to [Colors.blueGrey]
final Color innerCircleColor;
final Color? innerCircleColor;

/// Opacity of the joystick
///
/// The opacity applies to the whole joystick including icons
///
/// Defaults to [null] which means there will be no [Opacity] widget used
final double opacity;
final double? opacity;

/// Callback to be called when user pans the joystick
///
/// Defaults to [null]
final JoystickDirectionCallback onDirectionChanged;
final JoystickDirectionCallback? onDirectionChanged;

/// Indicates how often the [onDirectionChanged] should be called.
///
Expand All @@ -50,7 +50,7 @@ class JoystickView extends StatelessWidget {
///
/// The exception is the [onDirectionChanged] callback being called
/// on the [onPanStart] and [onPanEnd] callbacks. It will be called immediately.
final Duration interval;
final Duration? interval;

/// Shows top/right/bottom/left arrows on top of Joystick
///
Expand All @@ -69,71 +69,74 @@ class JoystickView extends StatelessWidget {

@override
Widget build(BuildContext context) {
double actualSize = size != null
? size
: _math.min(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height) *
0.5;
double innerCircleSize = actualSize / 2;
Offset lastPosition = Offset(innerCircleSize, innerCircleSize);
Offset joystickInnerPosition = _calculatePositionOfInnerCircle(
double? actualSize;
if (size != null) {
actualSize = size;
} else {
actualSize = _math.min(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height) *
0.5;
}
double? innerCircleSize = actualSize! / 2;
Offset? lastPosition = Offset(innerCircleSize, innerCircleSize);
Offset? joystickInnerPosition = _calculatePositionOfInnerCircle(
lastPosition, innerCircleSize, actualSize, Offset(0, 0));

DateTime _callbackTimestamp;
DateTime? _callbackTimestamp;

return Center(
child: StatefulBuilder(
builder: (context, setState) {
Widget joystick = Stack(
children: <Widget>[
CircleView.joystickCircle(
actualSize,
backgroundColor,
actualSize!,
backgroundColor!,
),
Positioned(
top: joystickInnerPosition!.dy,
left: joystickInnerPosition!.dx,
child: CircleView.joystickInnerCircle(
actualSize / 2,
innerCircleColor,
innerCircleColor!,
),
top: joystickInnerPosition.dy,
left: joystickInnerPosition.dx,
),
if (showArrows) ...createArrows(),
],
);

return GestureDetector(
onPanStart: (details) {
_callbackTimestamp = _processGesture(actualSize, actualSize / 2,
details.localPosition, _callbackTimestamp);
_callbackTimestamp = _processGesture(actualSize!, actualSize / 2,
details.localPosition, _callbackTimestamp!);
setState(() => lastPosition = details.localPosition);
},
onPanEnd: (details) {
_callbackTimestamp = null;
if (onDirectionChanged != null) {
onDirectionChanged(0, 0);
onDirectionChanged!(0, 0);
}
joystickInnerPosition = _calculatePositionOfInnerCircle(
Offset(innerCircleSize, innerCircleSize),
innerCircleSize,
actualSize,
actualSize!,
Offset(0, 0));
setState(() =>
lastPosition = Offset(innerCircleSize, innerCircleSize));
},
onPanUpdate: (details) {
_callbackTimestamp = _processGesture(actualSize, actualSize / 2,
details.localPosition, _callbackTimestamp);
_callbackTimestamp = _processGesture(actualSize!, actualSize / 2,
details.localPosition, _callbackTimestamp!);
joystickInnerPosition = _calculatePositionOfInnerCircle(
lastPosition,
lastPosition!,
innerCircleSize,
actualSize,
details.localPosition);

setState(() => lastPosition = details.localPosition);
},
child: (opacity != null)
? Opacity(opacity: opacity, child: joystick)
? Opacity(opacity: opacity!, child: joystick)
: joystick,
);
},
Expand All @@ -144,67 +147,67 @@ class JoystickView extends StatelessWidget {
List<Widget> createArrows() {
return [
Positioned(
top: 16.0,
left: 0.0,
right: 0.0,
child: Icon(
Icons.arrow_upward,
color: iconsColor,
),
top: 16.0,
left: 0.0,
right: 0.0,
),
Positioned(
top: 0.0,
bottom: 0.0,
left: 16.0,
child: Icon(
Icons.arrow_back,
color: iconsColor,
),
top: 0.0,
bottom: 0.0,
left: 16.0,
),
Positioned(
top: 0.0,
bottom: 0.0,
right: 16.0,
child: Icon(
Icons.arrow_forward,
color: iconsColor,
),
top: 0.0,
bottom: 0.0,
right: 16.0,
),
Positioned(
bottom: 16.0,
left: 0.0,
right: 0.0,
child: Icon(
Icons.arrow_downward,
color: iconsColor,
),
bottom: 16.0,
left: 0.0,
right: 0.0,
),
];
}

DateTime _processGesture(double size, double ignoreSize, Offset offset,
DateTime callbackTimestamp) {
double middle = size / 2.0;
double? middle = size / 2.0;

double angle = _math.atan2(offset.dy - middle, offset.dx - middle);
double degrees = angle * 180 / _math.pi + 90;
double? angle = _math.atan2(offset.dy - middle, offset.dx - middle);
double? degrees = angle * 180 / _math.pi + 90;
if (offset.dx < middle && offset.dy < middle) {
degrees = 360 + degrees;
}

double dx = _math.max(0, _math.min(offset.dx, size));
double dy = _math.max(0, _math.min(offset.dy, size));
double? dx = _math.max(0, _math.min(offset.dx, size));
double? dy = _math.max(0, _math.min(offset.dy, size));

double distance =
double? distance =
_math.sqrt(_math.pow(middle - dx, 2) + _math.pow(middle - dy, 2));

double normalizedDistance = _math.min(distance / (size / 2), 1.0);
double? normalizedDistance = _math.min(distance / (size / 2), 1.0);

DateTime _callbackTimestamp = callbackTimestamp;
DateTime? _callbackTimestamp = callbackTimestamp;
if (onDirectionChanged != null &&
_canCallOnDirectionChanged(callbackTimestamp)) {
_callbackTimestamp = DateTime.now();
onDirectionChanged(degrees, normalizedDistance);
onDirectionChanged!(degrees, normalizedDistance);
}

return _callbackTimestamp;
Expand All @@ -215,10 +218,10 @@ class JoystickView extends StatelessWidget {
/// Returns true if enough time has passed since last time it was called
/// or when there is no [interval] set.
bool _canCallOnDirectionChanged(DateTime callbackTimestamp) {
if (interval != null && callbackTimestamp != null) {
int intervalMilliseconds = interval.inMilliseconds;
int timestampMilliseconds = callbackTimestamp.millisecondsSinceEpoch;
int currentTimeMilliseconds = DateTime.now().millisecondsSinceEpoch;
if (interval != null) {
int? intervalMilliseconds = interval!.inMilliseconds;
int? timestampMilliseconds = callbackTimestamp.millisecondsSinceEpoch;
int? currentTimeMilliseconds = DateTime.now().millisecondsSinceEpoch;

if (currentTimeMilliseconds - timestampMilliseconds <=
intervalMilliseconds) {
Expand All @@ -231,16 +234,16 @@ class JoystickView extends StatelessWidget {

Offset _calculatePositionOfInnerCircle(
Offset lastPosition, double innerCircleSize, double size, Offset offset) {
double middle = size / 2.0;
double? middle = size / 2.0;

double angle = _math.atan2(offset.dy - middle, offset.dx - middle);
double degrees = angle * 180 / _math.pi;
double? angle = _math.atan2(offset.dy - middle, offset.dx - middle);
double? degrees = angle * 180 / _math.pi;
if (offset.dx < middle && offset.dy < middle) {
degrees = 360 + degrees;
}
bool isStartPosition = lastPosition.dx == innerCircleSize &&
bool? isStartPosition = lastPosition.dx == innerCircleSize &&
lastPosition.dy == innerCircleSize;
double lastAngleRadians =
double? lastAngleRadians =
(isStartPosition) ? 0 : (degrees) * (_math.pi / 180.0);

var rBig = size / 2;
Expand Down
Loading