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

feat: 3783 - brought back the old visor #3785

Closed
Closed
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
219 changes: 93 additions & 126 deletions packages/smooth_app/lib/pages/scan/smooth_barcode_scanner_mlkit.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart' as zxing;
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/helpers/app_helper.dart';
import 'package:smooth_app/helpers/camera_helper.dart';
import 'package:smooth_app/helpers/haptic_feedback_helper.dart';
import 'package:smooth_app/pages/scan/scan_header.dart';
import 'package:smooth_app/pages/scan/smooth_barcode_scanner_visor.dart';
import 'package:smooth_app/widgets/screen_visibility.dart';
import 'package:visibility_detector/visibility_detector.dart';

Expand Down Expand Up @@ -103,137 +101,106 @@ class _SmoothBarcodeScannerMLKitState extends State<SmoothBarcodeScannerMLKit>
_visible = false;
await _stop();
},
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final Rect scanWindow = Rect.fromCenter(
center: Offset(
constraints.maxWidth / 2,
constraints.maxHeight / 2,
),
width: constraints.maxWidth - 2 * MINIMUM_TOUCH_SIZE,
height: constraints.maxHeight,
);
return Stack(
children: <Widget>[
MobileScanner(
controller: _controller,
fit: BoxFit.cover,
scanWindow: scanWindow,
errorBuilder: (
BuildContext context,
MobileScannerException error,
Widget? child,
) =>
EMPTY_WIDGET,
onDetect: (final BarcodeCapture capture) async {
for (final Barcode barcode in capture.barcodes) {
final String? string = barcode.displayValue;
if (string != null) {
await widget.onScan(string);
}
}
},
),
Container(
decoration: ShapeDecoration(
shape: zxing.QrScannerOverlayShape(
borderColor: Colors.white,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutWidth:
constraints.maxWidth - 2 * MINIMUM_TOUCH_SIZE,
cutOutHeight: constraints.maxHeight,
),
),
),
const Align(
alignment: Alignment.topCenter,
child: ScanHeader(),
),
Center(
child: SvgPicture.asset(
'assets/icons/visor_icon.svg',
package: AppHelper.APP_PACKAGE,
),
),
Align(
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: _showFlipCameraButton
? MainAxisAlignment.spaceBetween
: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
if (_showFlipCameraButton)
IconButton(
color: Colors.white,
icon: ValueListenableBuilder<CameraFacing>(
valueListenable: _controller.cameraFacingState,
builder: (
BuildContext context,
CameraFacing state,
Widget? child,
) {
switch (state) {
case CameraFacing.front:
return const Icon(Icons.camera_front);
case CameraFacing.back:
return const Icon(Icons.camera_rear);
}
},
),
onPressed: () async {
SmoothHapticFeedback.click();
await _controller.switchCamera();
},
),
ValueListenableBuilder<bool?>(
valueListenable: _controller.hasTorchState,
child: Stack(
children: <Widget>[
MobileScanner(
controller: _controller,
fit: BoxFit.cover,
errorBuilder: (
BuildContext context,
MobileScannerException error,
Widget? child,
) =>
EMPTY_WIDGET,
onDetect: (final BarcodeCapture capture) async {
for (final Barcode barcode in capture.barcodes) {
final String? string = barcode.displayValue;
if (string != null) {
await widget.onScan(string);
}
}
},
),
Center(child: SmoothBarcodeScannerVisor()),
const Align(
alignment: Alignment.topCenter,
child: ScanHeader(),
),
Align(
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: _showFlipCameraButton
? MainAxisAlignment.spaceBetween
: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
if (_showFlipCameraButton)
IconButton(
color: Colors.white,
icon: ValueListenableBuilder<CameraFacing>(
valueListenable: _controller.cameraFacingState,
builder: (
BuildContext context,
bool? state,
CameraFacing state,
Widget? child,
) {
if (state != true) {
return EMPTY_WIDGET;
switch (state) {
case CameraFacing.front:
return const Icon(Icons.camera_front);
case CameraFacing.back:
return const Icon(Icons.camera_rear);
}
return IconButton(
color: Colors.white,
icon: ValueListenableBuilder<TorchState>(
valueListenable: _controller.torchState,
builder: (
BuildContext context,
TorchState state,
Widget? child,
) {
switch (state) {
case TorchState.off:
return const Icon(
Icons.flash_off,
color: Colors.white,
);
case TorchState.on:
return const Icon(
Icons.flash_on,
color: Colors.white,
);
}
},
),
onPressed: () async {
SmoothHapticFeedback.click();
await _controller.toggleTorch();
},
);
},
),
],
onPressed: () async {
SmoothHapticFeedback.click();
await _controller.switchCamera();
},
),
ValueListenableBuilder<bool?>(
valueListenable: _controller.hasTorchState,
builder: (
BuildContext context,
bool? state,
Widget? child,
) {
if (state != true) {
return EMPTY_WIDGET;
}
return IconButton(
color: Colors.white,
icon: ValueListenableBuilder<TorchState>(
valueListenable: _controller.torchState,
builder: (
BuildContext context,
TorchState state,
Widget? child,
) {
switch (state) {
case TorchState.off:
return const Icon(
Icons.flash_off,
color: Colors.white,
);
case TorchState.on:
return const Icon(
Icons.flash_on,
color: Colors.white,
);
}
},
),
onPressed: () async {
SmoothHapticFeedback.click();
await _controller.toggleTorch();
},
);
},
),
),
],
);
},
],
),
),
],
),
);
}
122 changes: 122 additions & 0 deletions packages/smooth_app/lib/pages/scan/smooth_barcode_scanner_visor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:smooth_app/helpers/app_helper.dart';

/// Barcode Scanner Visor widget.
class SmoothBarcodeScannerVisor extends StatelessWidget {
/// Returns the Size of the visor
static Size _getSize(BuildContext context) => Size(
MediaQuery.of(context).size.width * 0.8,
150.0,
);

@override
Widget build(BuildContext context) => SizedBox.fromSize(
size: _getSize(context),
child: CustomPaint(
painter: _ScanVisorPainter(),
child: Center(
child: SvgPicture.asset(
'assets/icons/visor_icon.svg',
width: 35.0,
height: 32.0,
package: AppHelper.APP_PACKAGE,
),
),
),
);
}

class _ScanVisorPainter extends CustomPainter {
static const double strokeWidth = 3.0;
static const double _fullCornerSize = 31.0;
static const double _halfCornerSize = _fullCornerSize / 2;
static const Radius _borderRadius = Radius.circular(_halfCornerSize);

final Paint _paint = Paint()
..strokeWidth = strokeWidth
..color = Colors.white
..style = PaintingStyle.stroke;

@override
void paint(Canvas canvas, Size size) {
final Rect rect = Rect.fromLTRB(0.0, 0.0, size.width, size.height);
canvas.drawPath(getPath(rect, false), _paint);
}

@override
bool shouldRepaint(CustomPainter oldDelegate) => false;

/// Returns a path to draw the visor
/// [includeLineBetweenCorners] will draw lines between each corner, instead
/// of moving the cursor
static Path getPath(Rect rect, bool includeLineBetweenCorners) {
final double bottomPosition;
if (includeLineBetweenCorners) {
bottomPosition = rect.bottom - strokeWidth;
} else {
bottomPosition = rect.bottom;
}

final Path path = Path()
// Top left
..moveTo(rect.left, rect.top + _fullCornerSize)
..lineTo(rect.left, rect.top + _halfCornerSize)
..arcToPoint(
Offset(rect.left + _halfCornerSize, rect.top),
radius: _borderRadius,
)
..lineTo(rect.left + _fullCornerSize, rect.top);

// Top right
if (includeLineBetweenCorners) {
path.lineTo(rect.right - _fullCornerSize, rect.top);
} else {
path.moveTo(rect.right - _fullCornerSize, rect.top);
}

path
..lineTo(rect.right - _halfCornerSize, rect.top)
..arcToPoint(
Offset(rect.right, _halfCornerSize),
radius: _borderRadius,
)
..lineTo(rect.right, rect.top + _fullCornerSize);

// Bottom right
if (includeLineBetweenCorners) {
path.lineTo(rect.right, bottomPosition - _fullCornerSize);
} else {
path.moveTo(rect.right, bottomPosition - _fullCornerSize);
}

path
..lineTo(rect.right, bottomPosition - _halfCornerSize)
..arcToPoint(
Offset(rect.right - _halfCornerSize, bottomPosition),
radius: _borderRadius,
)
..lineTo(rect.right - _fullCornerSize, bottomPosition);

// Bottom left
if (includeLineBetweenCorners) {
path.lineTo(rect.left + _fullCornerSize, bottomPosition);
} else {
path.moveTo(rect.left + _fullCornerSize, bottomPosition);
}

path
..lineTo(rect.left + _halfCornerSize, bottomPosition)
..arcToPoint(
Offset(rect.left, bottomPosition - _halfCornerSize),
radius: _borderRadius,
)
..lineTo(rect.left, bottomPosition - _fullCornerSize);

if (includeLineBetweenCorners) {
path.lineTo(rect.left, rect.top + _halfCornerSize);
}

return path;
}
}
Loading