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...",
|
||||
"mainScreenTakeVideoActionUploadingVideo": "Video wird hochgeladen...",
|
||||
|
||||
"recordingOverlayIsRecording": "Aufnahme",
|
||||
|
||||
|
||||
"loginScreenTitle": "Anmelden",
|
||||
"loginScreenLoginError": "E-Mail oder Passwort inkorrekt",
|
||||
|
@ -21,6 +21,8 @@
|
||||
"mainScreenTakeVideoActionSaveVideo": "Taking video, please hold still...",
|
||||
"mainScreenTakeVideoActionUploadingVideo": "Uploading video...",
|
||||
|
||||
"recordingOverlayIsRecording": "Recording",
|
||||
|
||||
|
||||
"loginScreenTitle": "Login",
|
||||
"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/widgets/animate_in_builder.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:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
import 'main_screen/change_camera_button.dart';
|
||||
import 'main_screen/record_button.dart';
|
||||
import 'main_screen/recording_overlay.dart';
|
||||
import 'main_screen/today_photo_button.dart';
|
||||
import 'main_screen/uploading_photo.dart';
|
||||
|
||||
@ -178,6 +180,12 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
message: localizations.mainScreenTakePhotoActionTakingPhoto,
|
||||
);
|
||||
|
||||
if (isTorchEnabled) {
|
||||
await controller!.setFlashMode(FlashMode.torch);
|
||||
} else {
|
||||
await controller!.setFlashMode(FlashMode.off);
|
||||
}
|
||||
|
||||
final file = File((await controller!.takePicture()).path);
|
||||
|
||||
setState(() {
|
||||
@ -302,8 +310,11 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1 / controller!.value.aspectRatio,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: <Widget>[
|
||||
controller!.buildPreview(),
|
||||
if (isRecording)
|
||||
RecordingOverlay(controller: controller!),
|
||||
if (uploadingPhotoAnimation != null)
|
||||
UploadingPhoto(
|
||||
data: uploadingPhotoAnimation!,
|
||||
@ -347,7 +358,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
opacityDuration: DEFAULT_OPACITY_DURATION *
|
||||
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
|
||||
child: ChangeCameraButton(
|
||||
disabled: lockCamera,
|
||||
disabled: lockCamera || isRecording,
|
||||
onChangeCamera: () {
|
||||
final currentCameraIndex = GlobalValuesManager
|
||||
.cameras
|
||||
@ -421,10 +432,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
ElevatedButton.icon(
|
||||
icon: const Icon(Icons.flashlight_on_rounded),
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.mainScreenActionsTorchButton),
|
||||
ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
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(
|
||||
style: ButtonStyle(
|
||||
|
@ -29,7 +29,7 @@ class _RecordButtonState extends State<RecordButton> {
|
||||
bool videoInAnimationActive = false;
|
||||
|
||||
void cancelAnimation() {
|
||||
if (videoInAnimationActive || animateToVideoIcon) {
|
||||
if (videoInAnimationActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ class _RecordButtonState extends State<RecordButton> {
|
||||
decoration: BoxDecoration(
|
||||
color: videoInAnimationActive ? Colors.red : Colors.white,
|
||||
borderRadius: videoInAnimationActive
|
||||
? BorderRadius.circular(4)
|
||||
? BorderRadius.circular(8)
|
||||
: 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