mirror of
https://github.com/Myzel394/quid_faciam_hodie.git
synced 2025-06-19 15:45:26 +02:00
added recording overlay
This commit is contained in:
parent
0b0c2ce15f
commit
c10cdb254f
@ -21,6 +21,8 @@
|
|||||||
"mainScreenTakeVideoActionSaveVideo": "Video wird aufgenommen, halte still...",
|
"mainScreenTakeVideoActionSaveVideo": "Video wird aufgenommen, halte still...",
|
||||||
"mainScreenTakeVideoActionUploadingVideo": "Video wird hochgeladen...",
|
"mainScreenTakeVideoActionUploadingVideo": "Video wird hochgeladen...",
|
||||||
|
|
||||||
|
"recordingOverlayIsRecording": "Aufnahme",
|
||||||
|
|
||||||
|
|
||||||
"loginScreenTitle": "Anmelden",
|
"loginScreenTitle": "Anmelden",
|
||||||
"loginScreenLoginError": "E-Mail oder Passwort inkorrekt",
|
"loginScreenLoginError": "E-Mail oder Passwort inkorrekt",
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
"mainScreenTakeVideoActionSaveVideo": "Taking video, please hold still...",
|
"mainScreenTakeVideoActionSaveVideo": "Taking video, please hold still...",
|
||||||
"mainScreenTakeVideoActionUploadingVideo": "Uploading video...",
|
"mainScreenTakeVideoActionUploadingVideo": "Uploading video...",
|
||||||
|
|
||||||
|
"recordingOverlayIsRecording": "Recording",
|
||||||
|
|
||||||
|
|
||||||
"loginScreenTitle": "Login",
|
"loginScreenTitle": "Login",
|
||||||
"loginScreenLoginError": "Invalid password or email",
|
"loginScreenLoginError": "Invalid password or email",
|
||||||
|
@ -15,11 +15,13 @@ import 'package:quid_faciam_hodie/utils/auth_required.dart';
|
|||||||
import 'package:quid_faciam_hodie/utils/loadable.dart';
|
import 'package:quid_faciam_hodie/utils/loadable.dart';
|
||||||
import 'package:quid_faciam_hodie/widgets/animate_in_builder.dart';
|
import 'package:quid_faciam_hodie/widgets/animate_in_builder.dart';
|
||||||
import 'package:quid_faciam_hodie/widgets/fade_and_move_in_animation.dart';
|
import 'package:quid_faciam_hodie/widgets/fade_and_move_in_animation.dart';
|
||||||
|
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
|
||||||
import 'package:quid_faciam_hodie/widgets/sheet_indicator.dart';
|
import 'package:quid_faciam_hodie/widgets/sheet_indicator.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
|
|
||||||
import 'main_screen/change_camera_button.dart';
|
import 'main_screen/change_camera_button.dart';
|
||||||
import 'main_screen/record_button.dart';
|
import 'main_screen/record_button.dart';
|
||||||
|
import 'main_screen/recording_overlay.dart';
|
||||||
import 'main_screen/today_photo_button.dart';
|
import 'main_screen/today_photo_button.dart';
|
||||||
import 'main_screen/uploading_photo.dart';
|
import 'main_screen/uploading_photo.dart';
|
||||||
|
|
||||||
@ -178,6 +180,12 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
message: localizations.mainScreenTakePhotoActionTakingPhoto,
|
message: localizations.mainScreenTakePhotoActionTakingPhoto,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isTorchEnabled) {
|
||||||
|
await controller!.setFlashMode(FlashMode.torch);
|
||||||
|
} else {
|
||||||
|
await controller!.setFlashMode(FlashMode.off);
|
||||||
|
}
|
||||||
|
|
||||||
final file = File((await controller!.takePicture()).path);
|
final file = File((await controller!.takePicture()).path);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -302,8 +310,11 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 1 / controller!.value.aspectRatio,
|
aspectRatio: 1 / controller!.value.aspectRatio,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
|
fit: StackFit.expand,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
controller!.buildPreview(),
|
controller!.buildPreview(),
|
||||||
|
if (isRecording)
|
||||||
|
RecordingOverlay(controller: controller!),
|
||||||
if (uploadingPhotoAnimation != null)
|
if (uploadingPhotoAnimation != null)
|
||||||
UploadingPhoto(
|
UploadingPhoto(
|
||||||
data: uploadingPhotoAnimation!,
|
data: uploadingPhotoAnimation!,
|
||||||
@ -347,7 +358,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
opacityDuration: DEFAULT_OPACITY_DURATION *
|
opacityDuration: DEFAULT_OPACITY_DURATION *
|
||||||
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
|
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
|
||||||
child: ChangeCameraButton(
|
child: ChangeCameraButton(
|
||||||
disabled: lockCamera,
|
disabled: lockCamera || isRecording,
|
||||||
onChangeCamera: () {
|
onChangeCamera: () {
|
||||||
final currentCameraIndex = GlobalValuesManager
|
final currentCameraIndex = GlobalValuesManager
|
||||||
.cameras
|
.cameras
|
||||||
@ -421,10 +432,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ElevatedButton.icon(
|
ElevatedButton(
|
||||||
icon: const Icon(Icons.flashlight_on_rounded),
|
|
||||||
label: Text(AppLocalizations.of(context)!
|
|
||||||
.mainScreenActionsTorchButton),
|
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
MaterialStateProperty.resolveWith<Color>(
|
MaterialStateProperty.resolveWith<Color>(
|
||||||
@ -446,6 +454,10 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
child: IconButtonChild(
|
||||||
|
icon: const Icon(Icons.flashlight_on_rounded),
|
||||||
|
label: Text(localizations.mainScreenActionsTorchButton),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
|
@ -29,7 +29,7 @@ class _RecordButtonState extends State<RecordButton> {
|
|||||||
bool videoInAnimationActive = false;
|
bool videoInAnimationActive = false;
|
||||||
|
|
||||||
void cancelAnimation() {
|
void cancelAnimation() {
|
||||||
if (videoInAnimationActive || animateToVideoIcon) {
|
if (videoInAnimationActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ class _RecordButtonState extends State<RecordButton> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: videoInAnimationActive ? Colors.red : Colors.white,
|
color: videoInAnimationActive ? Colors.red : Colors.white,
|
||||||
borderRadius: videoInAnimationActive
|
borderRadius: videoInAnimationActive
|
||||||
? BorderRadius.circular(4)
|
? BorderRadius.circular(8)
|
||||||
: BorderRadius.circular(50),
|
: BorderRadius.circular(50),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
115
lib/screens/main_screen/recording_overlay.dart
Normal file
115
lib/screens/main_screen/recording_overlay.dart
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:camera/camera.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
|
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||||
|
|
||||||
|
class RecordingOverlay extends StatefulWidget {
|
||||||
|
final CameraController controller;
|
||||||
|
|
||||||
|
const RecordingOverlay({
|
||||||
|
Key? key,
|
||||||
|
required this.controller,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RecordingOverlay> createState() => _RecordingOverlayState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RecordingOverlayState extends State<RecordingOverlay> {
|
||||||
|
late final Timer _timer;
|
||||||
|
bool animateIn = false;
|
||||||
|
bool initialAnimateIn = false;
|
||||||
|
int recordingTime = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_timer = Timer.periodic(const Duration(seconds: 1), (_) {
|
||||||
|
setState(() {
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordingTime++;
|
||||||
|
|
||||||
|
animateIn = !animateIn;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
initialAnimateIn = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_timer.cancel();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFormattedTime() {
|
||||||
|
final minutes = recordingTime ~/ 60;
|
||||||
|
final seconds = recordingTime % 60;
|
||||||
|
|
||||||
|
return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final localizations = AppLocalizations.of(context)!;
|
||||||
|
|
||||||
|
return Positioned(
|
||||||
|
left: 0,
|
||||||
|
top: SMALL_SPACE,
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
opacity: initialAnimateIn ? 1.0 : 0.0,
|
||||||
|
child: SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
AnimatedOpacity(
|
||||||
|
curve: Curves.linear,
|
||||||
|
opacity: animateIn ? 1.0 : 0.0,
|
||||||
|
duration: const Duration(seconds: 1),
|
||||||
|
child: Icon(
|
||||||
|
Icons.circle,
|
||||||
|
size: platformThemeData(
|
||||||
|
context,
|
||||||
|
material: (data) => data.textTheme.subtitle1!.fontSize,
|
||||||
|
cupertino: (data) => data.textTheme.textStyle.fontSize,
|
||||||
|
),
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: SMALL_SPACE),
|
||||||
|
Text(
|
||||||
|
localizations.recordingOverlayIsRecording,
|
||||||
|
style: platformThemeData(
|
||||||
|
context,
|
||||||
|
material: (data) => data.textTheme.bodyLarge,
|
||||||
|
cupertino: (data) => data.textTheme.textStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: SMALL_SPACE),
|
||||||
|
Text(
|
||||||
|
getFormattedTime(),
|
||||||
|
style: platformThemeData(
|
||||||
|
context,
|
||||||
|
material: (data) => data.textTheme.bodyLarge,
|
||||||
|
cupertino: (data) => data.textTheme.textStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user