WD: scanning screen along with the circular animation

dev_v3.13.6_CS_V2
taha.alam 12 months ago
parent a6c58372c2
commit 5a45247df2

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,6 @@
<svg fill="none" height="26" viewBox="0 0 26 26" width="26" xmlns="http://www.w3.org/2000/svg">
<circle cx="13" cy="13" fill="#EDF0EF" r="13" />
<path
d="M18.6947 8.71929L14.4018 13.0123L18.6947 17.3053C18.7902 17.3975 18.8664 17.5079 18.9188 17.6299C18.9712 17.7519 18.9988 17.8831 19 18.0159C19.0011 18.1487 18.9758 18.2803 18.9255 18.4032C18.8753 18.5261 18.801 18.6378 18.7071 18.7317C18.6132 18.8256 18.5016 18.8998 18.3787 18.9501C18.2558 19.0004 18.1241 19.0257 17.9913 19.0245C17.8585 19.0234 17.7273 18.9958 17.6053 18.9434C17.4833 18.891 17.373 18.8148 17.2807 18.7193L12.9877 14.4264L8.69471 18.7193C8.50611 18.9014 8.25351 19.0022 7.99131 19C7.72911 18.9977 7.4783 18.8925 7.29289 18.7071C7.10749 18.5217 7.00232 18.2709 7.00004 18.0087C6.99776 17.7465 7.09855 17.4939 7.28071 17.3053L11.5736 13.0123L7.28071 8.71929C7.09855 8.53069 6.99776 8.27808 7.00004 8.01589C7.00232 7.75369 7.10749 7.50288 7.29289 7.31747C7.4783 7.13206 7.72911 7.02689 7.99131 7.02461C8.25351 7.02234 8.50611 7.12313 8.69471 7.30529L12.9877 11.5982L17.2807 7.30529C17.373 7.20978 17.4833 7.1336 17.6053 7.08119C17.7273 7.02878 17.8585 7.00119 17.9913 7.00004C18.1241 6.99888 18.2558 7.02419 18.3787 7.07447C18.5016 7.12475 18.6132 7.199 18.7071 7.29289C18.801 7.38679 18.8753 7.49844 18.9255 7.62133C18.9758 7.74423 19.0011 7.87591 19 8.00869C18.9988 8.14147 18.9712 8.27269 18.9188 8.39469C18.8664 8.5167 18.7902 8.62704 18.6947 8.71929Z"
fill="black" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,5 @@
<svg fill="none" height="22" viewBox="0 0 22 22" width="22" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd" d="M0 10.75C0 16.687 4.813 21.5 10.75 21.5C16.687 21.5 21.5 16.687 21.5 10.75C21.5 4.813 16.687 0 10.75 0C4.813 0 0 4.813 0 10.75ZM15.426 7.01299C15.833 7.38599 15.86 8.01898 15.487 8.42598L9.98701 14.426C9.80301 14.627 9.544 14.744 9.272 14.75C8.999 14.756 8.73599 14.65 8.54299 14.457L6.04299 11.957C5.65199 11.567 5.65199 10.933 6.04299 10.543C6.43299 10.152 7.06701 10.152 7.45701 10.543L9.21899 12.304L14.013 7.07402C14.386 6.66702 15.019 6.63999 15.426 7.01299Z"
fill="#62BE96"
fill-rule="evenodd" />
</svg>

After

Width:  |  Height:  |  Size: 656 B

@ -472,8 +472,8 @@ class _CallScreenState extends State<CallScreen> {
],
),
);
if (errorType == Errors.SessionJoinFailed || errorType == Errors.SessionDisconncting) {
Timer(
// if (errorType == Errors.SessionJoinFailed || errorType == Errors.SessionDisconncting) {
Timer(
const Duration(milliseconds: 1000),
() => Navigator.pop(context),
// Navigator.popAndPushNamed(
@ -482,7 +482,7 @@ class _CallScreenState extends State<CallScreen> {
// arguments: JoinArguments(args.isJoin, sessionName.value, sessionPassword.value, args.displayName, args.sessionIdleTimeoutMins, args.role),
// ),
);
}
// }
},
);

@ -25,7 +25,7 @@ class ScanCondition extends StatelessWidget {
scanConditionName,
style: const TextStyle(
fontSize: 14,
color: Colors.black,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),

@ -1,4 +1,3 @@
import 'package:diplomaticquarterapp/theme/colors.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:flutter/material.dart';
import 'package:vital_sign_camera/vital_sign_camera.dart';
@ -18,78 +17,74 @@ class ScanConditionChecklist extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedBox(
height: deviceSize.width*0.4,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Material(
color: Colors.black.withOpacity(.4),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
TranslationBase.of(context).scanningConditions,
style: TextStyle(
fontSize: 15,
color: CustomColors.accentColor,
fontWeight: FontWeight.bold,
),
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Material(
color: Color(0xFF5d6b6c).withOpacity(.6),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
TranslationBase.of(context).scanningConditions,
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold,
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Row(
children: [
Expanded(
child: Column(
children: [
ScanCondition(
scanConditionName:
TranslationBase.of(context).lighting,
isConditionSatisfied: conditions.lighting,
),
ScanCondition(
scanConditionName:
TranslationBase.of(context).distance,
isConditionSatisfied: conditions.distance,
),
ScanCondition(
scanConditionName:
TranslationBase.of(context).centered,
isConditionSatisfied: conditions.centered,
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Row(
children: [
Expanded(
child: Column(
children: [
ScanCondition(
scanConditionName:
TranslationBase.of(context).lighting,
isConditionSatisfied: conditions.lighting,
),
ScanCondition(
scanConditionName:
TranslationBase.of(context).distance,
isConditionSatisfied: conditions.distance,
),
ScanCondition(
scanConditionName:
TranslationBase.of(context).centered,
isConditionSatisfied: conditions.centered,
),
],
),
Expanded(
child: Column(
children: [
ScanCondition(
scanConditionName:
TranslationBase.of(context).movement,
isConditionSatisfied: conditions.movement,
),
ScanCondition(
scanConditionName:
TranslationBase.of(context).frameRate,
isConditionSatisfied: conditions.frameRate,
),
ScanCondition(
scanConditionName:
TranslationBase.of(context).serverReady,
isConditionSatisfied: conditions.serverReady,
),
],
),
),
Expanded(
child: Column(
children: [
ScanCondition(
scanConditionName:
TranslationBase.of(context).movement,
isConditionSatisfied: conditions.movement,
),
ScanCondition(
scanConditionName:
TranslationBase.of(context).frameRate,
isConditionSatisfied: conditions.frameRate,
),
ScanCondition(
scanConditionName:
TranslationBase.of(context).serverReady,
isConditionSatisfied: conditions.serverReady,
),
],
),
],
),
),
],
),
],
),
),
],
),
),
),

@ -18,21 +18,32 @@ class ScanStatus extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
getRemainingTime(),
DefaultTextStyle(
style: const TextStyle(
fontSize: 16,
fontSize: 14,
color: Colors.white,
),
child: Text(
getRemainingTime(),
style: const TextStyle(
fontSize: 14,
color: Colors.white,
),
),
),
Text(
getScanStage(context),
DefaultTextStyle(
style: const TextStyle(
fontSize: 16,
fontSize: 14,
color: Colors.white,
),
child: Text(
getScanStage(context),
style: const TextStyle(
fontSize: 14,
color: Colors.white,
),
),
),
Container(height: 100),
],
),
);

@ -1,5 +1,6 @@
import 'package:diplomaticquarterapp/theme/colors.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart';
import 'package:flutter/material.dart';
class StartButton extends StatelessWidget {
@ -15,23 +16,16 @@ class StartButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(right: 16.0, bottom: 32),
child: Expanded(
child: ElevatedButton(
onPressed: (disabled) ? () {} : onPressed,
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
backgroundColor: (disabled) ? Colors.grey : CustomColors.accentColor,
elevation: 8,
),
child: Text(
TranslationBase.of(context).start,
style: TextStyle(
fontSize: 14,
),
),
),
),
);
padding: const EdgeInsets.only(right: 16.0, left: 16, bottom: 12),
child: DefaultButton(
TranslationBase.of(context).start,
(disabled)
? null
: () {
if (!disabled) onPressed();
},
color: Colors.black,
disabledColor: Colors.grey,
));
}
}

@ -1,3 +1,5 @@
import 'dart:math';
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -10,13 +12,17 @@ import 'components/scan_condition_checklist.dart';
import 'components/scan_status.dart';
import 'components/start_button.dart';
import 'result_screen.dart';
import 'package:lottie/lottie.dart';
final UserInfo userInfo = UserInfo(
age: 30,
gender: Gender.male,
weight: 75, // kg, Optional
height: 164, // cm, Optional
waistCircumference: 83, // cm Optional
weight: 75,
// kg, Optional
height: 164,
// cm, Optional
waistCircumference: 83,
// cm Optional
userId: 'dbd13e86-47f4-4a43-85f6-cf62fa750117');
final VitalSignCameraConfig config = VitalSignCameraConfig(
@ -24,7 +30,9 @@ final VitalSignCameraConfig config = VitalSignCameraConfig(
serverId: ServerId.awsEnterpriseProd);
class VitalSigns extends StatefulWidget {
const VitalSigns({super.key});
const VitalSigns({super.key, required this.userInfo});
final UserInfo userInfo;
@override
State<VitalSigns> createState() => _VitalSignsState();
@ -49,9 +57,9 @@ class _VitalSignsState extends State<VitalSigns> with RouteAware {
}
bool startedScanning =
false; // set true when start button is pressed, set false when health result is tapped or error occurs
false; // set true when start button is pressed, set false when health result is tapped or error occurs
bool isAllConditionsMet =
false; // check for the 6 scan conditions before enabling the start button
false; // check for the 6 scan conditions before enabling the start button
ScanConditions? _conditions;
GetHealthStage? _scanningStage;
@ -95,63 +103,71 @@ class _VitalSignsState extends State<VitalSigns> with RouteAware {
@override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return AppScaffold(
isShowAppBar: true,
appBarTitle: TranslationBase.of(context).scanning,
showNewAppBar: true,
showNewAppBarTitle: true,
overrideUserLogin: true,
backgroundColor: Color(0xffF8F8F8),
body: Column(
children: [
if (_conditions != null)
ScanConditionChecklist(
deviceSize: deviceSize, conditions: _conditions!),
Expanded(
child: Stack(
children: [
VitalSignCamera(
onCreated: _onVitalSignCameraCreated,
isActive: isCameraActive,
userInfo: userInfo,
config: config,
device: cameraDevice,
onVideoFrameProcessed: _onVideoFrameProcessed),
Positioned.fill(
// child: CustomPaint(
// painter: OvalOverlayPainter(),
// ),
child: SvgPicture.asset(
"assets/images/svg/overlay.svg",
),
),
if (_scanningStage !=
GetHealthStage
.idle) // show remaining time count down during scan
ScanStatus(
stage: _scanningStage, remainingTime: _remainingTime),
Column(children: [
ScanConditionChecklist(
deviceSize: deviceSize, conditions: _conditions!),
if (_scanningStage == GetHealthStage.idle &&
isCameraActive) // show start button only when it is not scanning
StartButton(
onPressed: () {
setState(() {
_vitalSignCameraController.startScanning();
startedScanning = true;
_healthResult = null;
_showedHealthResult = false;
});
},
disabled: !isAllConditionsMet,
),
])
],
return Stack(
children: [
VitalSignCamera(
onCreated: _onVitalSignCameraCreated,
isActive: isCameraActive,
userInfo: widget.userInfo,
config: config,
device: cameraDevice,
onVideoFrameProcessed: _onVideoFrameProcessed),
if (_scanningStage !=
GetHealthStage.idle) // show remaining time count down during scan
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: ScanStatus(
stage: _scanningStage, remainingTime: _remainingTime),
)),
if (mounted)
Column(children: [
Expanded(
child: CircularOverlay(
state: (_scanningStage == null ||
_scanningStage == GetHealthStage.idle)
? AnimationState.stop
: AnimationState.playing,
)),
if (_conditions != null)
ScanConditionChecklist(
deviceSize: deviceSize, conditions: _conditions!),
SizedBox(
height: 16,
),
if (_scanningStage == GetHealthStage.idle &&
isCameraActive) // show start button only when it is not scanning
...{
StartButton(
onPressed: () {
setState(() {
_vitalSignCameraController.startScanning();
startedScanning = true;
_healthResult = null;
_showedHealthResult = false;
});
},
disabled: !isAllConditionsMet,
),
),
],
),
} else
SizedBox(
height: 55,
)
]),
Padding(
padding: const EdgeInsetsDirectional.only(top: 32.0, start: 14),
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: SvgPicture.asset(
'assets/images/svg/cross.svg',
width: 32,
height: 32,
)),
)
],
);
// return Scaffold(
// body: Stack(
@ -283,11 +299,118 @@ class _VitalSignsState extends State<VitalSigns> with RouteAware {
}
}
enum AnimationState { playing, stop }
class CircularOverlay extends StatefulWidget {
final AnimationState state;
const CircularOverlay({Key? key, this.state = AnimationState.stop})
: super(key: key);
@override
State<CircularOverlay> createState() => _CircularOverlayState();
}
class _CircularOverlayState extends State<CircularOverlay>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void didChangeDependencies() {
if (widget.state == AnimationState.playing) {
_controller.forward(from: 0);
} else {
_controller.stop();
}
}
@override
void didUpdateWidget(CircularOverlay oldWidget) {
if (widget.state == AnimationState.playing) {
_controller.repeat();
} else {
_controller.stop();
}
}
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 8),
);
_controller.stop();
if (widget.state == AnimationState.playing) {
_controller.forward(from: 0);
} else {
_controller.stop();
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return CustomPaint(
painter: CircularBarsPainter(animationValue: _controller.value),
size: Size(MediaQuery.sizeOf(context).width * .9,
MediaQuery.sizeOf(context).height * .8),
);
},
);
}
}
class CircularBarsPainter extends CustomPainter {
final double animationValue;
CircularBarsPainter({required this.animationValue});
@override
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 1.8);
final radius = min(size.width / 2, size.height / 2);
final barPaint = Paint()
..color = Colors.white
..strokeWidth = 4
..style = PaintingStyle.stroke;
const numberOfBars = 64;
final angleIncrement = 2 * pi / numberOfBars;
for (int i = 0; i < numberOfBars; i++) {
final angle = i * angleIncrement + (animationValue * 2 * pi);
final start = Offset(
center.dx + radius * cos(angle),
center.dy + radius * sin(angle),
);
final end = Offset(
center.dx + (radius - 20) * cos(angle),
center.dy + (radius - 20) * sin(angle),
);
canvas.drawLine(start, end, barPaint);
}
}
@override
bool shouldRepaint(CircularBarsPainter oldDelegate) {
return oldDelegate.animationValue != animationValue;
}
}
class OvalOverlayPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Paint overlayPaint = Paint()
..color = Colors.white.withOpacity(0.7)
..color = Colors.white.withOpacity(0.1)
..style = PaintingStyle.fill;
canvas.drawRect(
@ -298,7 +421,7 @@ class OvalOverlayPainter extends CustomPainter {
final Rect ovalRect = Rect.fromCenter(
center: Offset(size.width / 2, size.height / 2),
width: size.width * 0.9,
height: size.height * 0.7,
height: size.height,
);
final Path ovalPath = Path()..addOval(ovalRect);

@ -187,6 +187,7 @@ dependencies:
firebase_crashlytics: ^3.0.0
cloudflare_turnstile: ^2.0.1
lottie: ^3.0.0
vital_sign_camera:
path: ./packages/vital_sign_camera

Loading…
Cancel
Save