added startup recording settings

This commit is contained in:
Myzel394 2022-08-22 21:10:12 +02:00
parent 684de568b3
commit 696d43d67f
8 changed files with 135 additions and 59 deletions

View File

@ -111,6 +111,7 @@
"settingsScreenGeneralSectionTitle": "General",
"settingsScreenGeneralSectionQualityLabel": "Qualität",
"settingsScreenGeneralSectionAskForMemoryAnnotationsLabel": "Nach Anmerkungen für Erinnerungen fragen",
"settingsScreenGeneralSectionStartRecordingOnStartupLabel": "Aufnahme automatisch beim Öffnen der App starten",
"settingsScreenResetHelpSheetsLabel": "Hilf-Sheets zurücksetzen",
"settingsScreenResetHelpSheetsResetSuccessfully": "Hilf-Sheets wurden zurückgesetzt.",

View File

@ -161,6 +161,7 @@
"settingsScreenGeneralSectionTitle": "General",
"settingsScreenGeneralSectionQualityLabel": "Quality",
"settingsScreenGeneralSectionAskForMemoryAnnotationsLabel": "Ask for memory annotations",
"settingsScreenGeneralSectionStartRecordingOnStartupLabel": "Automatically start recording on startup",
"settingsScreenResetHelpSheetsLabel": "Reset Help Sheets",
"settingsScreenResetHelpSheetsResetSuccessfully": "Help Sheets reset successfully.",

View File

@ -5,25 +5,31 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:quid_faciam_hodie/constants/storage_keys.dart';
import 'package:quid_faciam_hodie/utils/string_to_bool.dart';
const secure = FlutterSecureStorage();
class Settings extends ChangeNotifier {
ResolutionPreset _resolution = ResolutionPreset.max;
bool _askForMemoryAnnotations = false;
bool _recordOnStartup = false;
Settings({
final ResolutionPreset? resolution,
final bool? askForMemoryAnnotations,
}) : _resolution = resolution ?? ResolutionPreset.max,
_askForMemoryAnnotations = askForMemoryAnnotations ?? true;
Settings(
{final ResolutionPreset? resolution,
final bool? askForMemoryAnnotations,
final bool? recordOnStartup})
: _resolution = resolution ?? ResolutionPreset.max,
_askForMemoryAnnotations = askForMemoryAnnotations ?? true,
_recordOnStartup = recordOnStartup ?? false;
ResolutionPreset get resolution => _resolution;
bool get askForMemoryAnnotations => _askForMemoryAnnotations;
bool get recordOnStartup => _recordOnStartup;
Map<String, dynamic> toJSONData() => {
'resolution': _resolution.toString(),
'askForMemoryAnnotations': _askForMemoryAnnotations ? 'true' : 'false',
'recordOnStartup': _recordOnStartup ? 'true' : 'false',
};
Future<void> save() async {
@ -46,20 +52,14 @@ class Settings extends ChangeNotifier {
final resolution = ResolutionPreset.values.firstWhereOrNull(
(preset) => preset.toString() == data['resolution'],
);
final askForMemoryAnnotations = () {
switch (data['askForMemoryAnnotations']) {
case 'true':
return true;
case 'false':
return false;
default:
return null;
}
}();
final askForMemoryAnnotations =
stringToBool(data['askForMemoryAnnotations']);
final recordOnStartup = stringToBool(data['recordOnStartup']);
return Settings(
resolution: resolution,
askForMemoryAnnotations: askForMemoryAnnotations,
recordOnStartup: recordOnStartup,
);
}
@ -74,4 +74,10 @@ class Settings extends ChangeNotifier {
notifyListeners();
save();
}
void setRecordOnStartup(final bool recordOnStartup) {
_recordOnStartup = recordOnStartup;
notifyListeners();
save();
}
}

View File

@ -20,6 +20,7 @@ import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
import 'package:quid_faciam_hodie/models/memories.dart';
import 'package:quid_faciam_hodie/screens/main_screen/annotation_dialog.dart';
import 'package:quid_faciam_hodie/screens/main_screen/camera_help_content.dart';
import 'package:quid_faciam_hodie/screens/main_screen/cancel_recording_button.dart';
import 'package:quid_faciam_hodie/screens/main_screen/settings_button_overlay.dart';
import 'package:quid_faciam_hodie/utils/auth_required.dart';
import 'package:quid_faciam_hodie/utils/loadable.dart';
@ -49,6 +50,7 @@ class MainScreen extends StatefulWidget {
class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
int currentZoomLevelIndex = 0;
bool hasRecordedOnStartup = false;
bool isRecording = false;
bool lockCamera = false;
bool isTorchEnabled = false;
@ -148,6 +150,19 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
}
}
Future<void> startRecording() async {
setState(() {
isRecording = true;
});
if (controller!.value.isRecordingVideo) {
// A recording has already started, do nothing.
return;
}
await controller!.startVideoRecording();
}
void onNewCameraSelected(final CameraDescription cameraDescription) async {
final settings = GlobalValuesManager.settings!;
final previousCameraController = controller;
@ -179,6 +194,12 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
await controller!.initialize();
await controller!.prepareForVideoRecording();
if (settings.recordOnStartup && !hasRecordedOnStartup) {
startRecording();
hasRecordedOnStartup = true;
}
await determineZoomLevels();
if (!mounted) {
@ -420,7 +441,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
controller!.buildPreview(),
if (isRecording)
RecordingOverlay(controller: controller!),
if (!isRecording) SettingsButtonOverlay(),
if (!isRecording) const SettingsButtonOverlay(),
if (uploadingPhotoAnimation != null)
UploadingPhoto(
data: uploadingPhotoAnimation!,
@ -465,22 +486,34 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
opacityDuration: DEFAULT_OPACITY_DURATION *
SECONDARY_BUTTONS_DURATION_MULTIPLIER,
child: ChangeCameraButton(
disabled: lockCamera || isRecording,
onChangeCamera: () {
final currentCameraIndex =
GlobalValuesManager.cameras
.indexOf(controller!.description);
final availableCameras =
GlobalValuesManager.cameras.length;
child: isRecording
? CancelRecordingButton(
onCancel: () {
setState(() {
isRecording = false;
});
onNewCameraSelected(
GlobalValuesManager.cameras[
(currentCameraIndex + 1) %
availableCameras],
);
},
),
controller!.stopVideoRecording();
},
)
: ChangeCameraButton(
disabled: lockCamera || isRecording,
onChangeCamera: () {
final currentCameraIndex =
GlobalValuesManager.cameras
.indexOf(
controller!.description);
final availableCameras =
GlobalValuesManager
.cameras.length;
onNewCameraSelected(
GlobalValuesManager.cameras[
(currentCameraIndex + 1) %
availableCameras],
);
},
),
),
),
Expanded(
@ -488,18 +521,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
child: RecordButton(
disabled: lockCamera,
active: isRecording,
onVideoBegin: () async {
setState(() {
isRecording = true;
});
if (controller!.value.isRecordingVideo) {
// A recording has already started, do nothing.
return;
}
await controller!.startVideoRecording();
},
onVideoBegin: startRecording,
onVideoEnd: takeVideo,
onPhotoShot: takePhoto,
),

View File

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
class CancelRecordingButton extends StatelessWidget {
final VoidCallback onCancel;
const CancelRecordingButton({
Key? key,
required this.onCancel,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
HapticFeedback.heavyImpact();
onCancel();
},
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Icon(
Icons.circle,
size: 60,
color: Colors.white.withOpacity(.2),
),
Icon(
context.platformIcons.clear,
size: 25,
color: Colors.white,
),
],
),
);
}
}

View File

@ -26,15 +26,12 @@ const OUT_DURATION = Duration(milliseconds: 300);
class _RecordButtonState extends State<RecordButton> {
bool animateToVideoIcon = false;
bool videoInAnimationActive = false;
void cancelAnimation() {
if (videoInAnimationActive) {
if (widget.active) {
return;
}
setState(() {
videoInAnimationActive = false;
animateToVideoIcon = false;
});
}
@ -49,7 +46,6 @@ class _RecordButtonState extends State<RecordButton> {
}
setState(() {
videoInAnimationActive = false;
animateToVideoIcon = false;
});
@ -69,7 +65,6 @@ class _RecordButtonState extends State<RecordButton> {
setState(() {
animateToVideoIcon = false;
videoInAnimationActive = true;
});
HapticFeedback.heavyImpact();
@ -87,7 +82,6 @@ class _RecordButtonState extends State<RecordButton> {
}
setState(() {
videoInAnimationActive = false;
animateToVideoIcon = false;
});
@ -117,19 +111,18 @@ class _RecordButtonState extends State<RecordButton> {
alignment: Alignment.center,
children: <Widget>[
AnimatedContainer(
duration: videoInAnimationActive ? Duration.zero : OUT_DURATION,
duration: widget.active ? Duration.zero : OUT_DURATION,
width: 60,
height: 60,
decoration: BoxDecoration(
color: videoInAnimationActive
? Colors.white
: Colors.white.withOpacity(.2),
color:
widget.active ? Colors.white : Colors.white.withOpacity(.2),
borderRadius: BorderRadius.circular(30),
),
),
AnimatedScale(
duration: () {
if (videoInAnimationActive) {
if (widget.active) {
return Duration(milliseconds: 400);
}
@ -141,7 +134,7 @@ class _RecordButtonState extends State<RecordButton> {
}(),
curve: Curves.easeInOut,
scale: () {
if (videoInAnimationActive) {
if (widget.active) {
return .6;
}
@ -153,7 +146,7 @@ class _RecordButtonState extends State<RecordButton> {
}(),
child: AnimatedContainer(
duration: () {
if (videoInAnimationActive) {
if (widget.active) {
return Duration(milliseconds: 400);
}
@ -166,8 +159,8 @@ class _RecordButtonState extends State<RecordButton> {
width: 40,
height: 40,
decoration: BoxDecoration(
color: videoInAnimationActive ? Colors.red : Colors.white,
borderRadius: videoInAnimationActive
color: widget.active ? Colors.red : Colors.white,
borderRadius: widget.active
? BorderRadius.circular(8)
: BorderRadius.circular(50),
),

View File

@ -218,6 +218,12 @@ class _SettingsScreenState extends AuthRequiredState<SettingsScreen>
.settingsScreenGeneralSectionAskForMemoryAnnotationsLabel,
),
),
SettingsTile.switchTile(
initialValue: settings.recordOnStartup,
onToggle: settings.setRecordOnStartup,
title: Text(localizations
.settingsScreenGeneralSectionStartRecordingOnStartupLabel),
),
SettingsTile(
leading: Icon(context.platformIcons.help),
title: Text(

View File

@ -0,0 +1,10 @@
bool? stringToBool(final String value) {
switch (value) {
case 'true':
return true;
case 'false':
return false;
default:
return null;
}
}