285 lines
8.7 KiB
Dart
285 lines
8.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:get/get.dart';
|
|
import '../../core/services/screen_recording_service.dart';
|
|
|
|
class RecordingOverlay extends StatelessWidget {
|
|
final Widget child;
|
|
final bool showRecordingIndicator;
|
|
|
|
const RecordingOverlay({
|
|
Key? key,
|
|
required this.child,
|
|
this.showRecordingIndicator = true,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Stack(
|
|
children: [
|
|
child,
|
|
if (showRecordingIndicator)
|
|
Positioned(
|
|
top: 20.h,
|
|
right: 20.w,
|
|
child: GetBuilder<ScreenRecordingService>(
|
|
builder: (recordingService) {
|
|
if (!recordingService.isRecording) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
return Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
|
|
decoration: BoxDecoration(
|
|
color: Colors.red.shade600,
|
|
borderRadius: BorderRadius.circular(20.r),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.3),
|
|
blurRadius: 8.r,
|
|
offset: Offset(0, 2.h),
|
|
),
|
|
],
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// Recording dot
|
|
Container(
|
|
width: 8.w,
|
|
height: 8.h,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
shape: BoxShape.circle,
|
|
),
|
|
),
|
|
SizedBox(width: 8.w),
|
|
// Recording text
|
|
Flexible(
|
|
child: Text(
|
|
'REC ${recordingService.formatDuration(recordingService.recordingDuration)}',
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12.sp,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class RecordingControls extends StatelessWidget {
|
|
final VoidCallback? onStartRecording;
|
|
final VoidCallback? onStopRecording;
|
|
final bool isRecording;
|
|
final double recordingDuration;
|
|
|
|
const RecordingControls({
|
|
Key? key,
|
|
this.onStartRecording,
|
|
this.onStopRecording,
|
|
this.isRecording = false,
|
|
this.recordingDuration = 0.0,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
padding: EdgeInsets.all(16.w),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade100,
|
|
borderRadius: BorderRadius.circular(12.r),
|
|
border: Border.all(color: Colors.grey.shade300),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Icon(
|
|
Icons.videocam,
|
|
color: Colors.red.shade600,
|
|
size: 20.w,
|
|
),
|
|
SizedBox(width: 8.w),
|
|
Expanded(
|
|
child: Text(
|
|
'Draw Recording',
|
|
style: TextStyle(
|
|
fontSize: 16.sp,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.grey.shade800,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 12.h),
|
|
|
|
if (isRecording) ...[
|
|
// Recording in progress
|
|
Row(
|
|
children: [
|
|
Container(
|
|
width: 12.w,
|
|
height: 12.h,
|
|
decoration: BoxDecoration(
|
|
color: Colors.red.shade600,
|
|
shape: BoxShape.circle,
|
|
),
|
|
),
|
|
SizedBox(width: 8.w),
|
|
Expanded(
|
|
child: Text(
|
|
'Recording: ${_formatDuration(recordingDuration)}',
|
|
style: TextStyle(
|
|
fontSize: 14.sp,
|
|
color: Colors.red.shade600,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 12.h),
|
|
SizedBox(
|
|
width: double.infinity,
|
|
child: ElevatedButton.icon(
|
|
onPressed: onStopRecording,
|
|
icon: Icon(Icons.stop, size: 18.w),
|
|
label: Text('Stop Recording'),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.red.shade600,
|
|
foregroundColor: Colors.white,
|
|
padding: EdgeInsets.symmetric(vertical: 12.h),
|
|
),
|
|
),
|
|
),
|
|
] else ...[
|
|
// Not recording
|
|
Text(
|
|
'Record the draw process for transparency and verification',
|
|
style: TextStyle(
|
|
fontSize: 12.sp,
|
|
color: Colors.grey.shade600,
|
|
),
|
|
textAlign: TextAlign.center,
|
|
overflow: TextOverflow.ellipsis,
|
|
maxLines: 2,
|
|
),
|
|
SizedBox(height: 12.h),
|
|
SizedBox(
|
|
width: double.infinity,
|
|
child: ElevatedButton.icon(
|
|
onPressed: onStartRecording,
|
|
icon: Icon(Icons.videocam, size: 18.w),
|
|
label: Text('Start Recording'),
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.green.shade600,
|
|
foregroundColor: Colors.white,
|
|
padding: EdgeInsets.symmetric(vertical: 12.h),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
String _formatDuration(double seconds) {
|
|
final minutes = (seconds / 60).floor();
|
|
final remainingSeconds = (seconds % 60).floor();
|
|
return '${minutes.toString().padLeft(2, '0')}:${remainingSeconds.toString().padLeft(2, '0')}';
|
|
}
|
|
}
|
|
|
|
class RecordingStatusBanner extends StatelessWidget {
|
|
final bool isRecording;
|
|
final double duration;
|
|
final VoidCallback? onStop;
|
|
|
|
const RecordingStatusBanner({
|
|
Key? key,
|
|
required this.isRecording,
|
|
this.duration = 0.0,
|
|
this.onStop,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (!isRecording) return const SizedBox.shrink();
|
|
|
|
return Container(
|
|
width: double.infinity,
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
|
|
decoration: BoxDecoration(
|
|
color: Colors.red.shade600,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.1),
|
|
blurRadius: 4.r,
|
|
offset: Offset(0, 2.h),
|
|
),
|
|
],
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
width: 8.w,
|
|
height: 8.h,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
shape: BoxShape.circle,
|
|
),
|
|
),
|
|
SizedBox(width: 12.w),
|
|
Expanded(
|
|
child: Text(
|
|
'Recording Draw Process - ${_formatDuration(duration)}',
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 14.sp,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
if (onStop != null)
|
|
GestureDetector(
|
|
onTap: onStop,
|
|
child: Container(
|
|
padding: EdgeInsets.all(4.w),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withOpacity(0.2),
|
|
borderRadius: BorderRadius.circular(4.r),
|
|
),
|
|
child: Icon(
|
|
Icons.stop,
|
|
color: Colors.white,
|
|
size: 16.w,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
String _formatDuration(double seconds) {
|
|
final minutes = (seconds / 60).floor();
|
|
final remainingSeconds = (seconds % 60).floor();
|
|
return '${minutes.toString().padLeft(2, '0')}:${remainingSeconds.toString().padLeft(2, '0')}';
|
|
}
|
|
}
|