mirror of
https://github.com/Myzel394/quid_faciam_hodie.git
synced 2025-06-18 23:35:25 +02:00
added annotations; improvements & bugfixes
This commit is contained in:
parent
9f37648762
commit
5a8a0352c1
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:quid_faciam_hodie/constants/values.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
@ -9,12 +10,17 @@ extension ShowSnackBar on BuildContext {
|
||||
static ScaffoldFeatureController<SnackBar, SnackBarClosedReason>?
|
||||
pendingSnackBar;
|
||||
|
||||
ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showSnackBar({
|
||||
ScaffoldFeatureController<SnackBar, SnackBarClosedReason>? showSnackBar({
|
||||
required final String message,
|
||||
final Color backgroundColor = Colors.white,
|
||||
final Duration duration = const Duration(seconds: 4),
|
||||
final BuildContext? context,
|
||||
}) {
|
||||
if (!isMaterial(context ?? this)) {
|
||||
// Not implemented yet
|
||||
return null;
|
||||
}
|
||||
|
||||
pendingSnackBar?.close();
|
||||
pendingSnackBar = null;
|
||||
|
||||
|
@ -12,6 +12,7 @@ class Memory {
|
||||
final String filePath;
|
||||
final bool isPublic;
|
||||
final String userID;
|
||||
final String annotation;
|
||||
final MemoryLocation? location;
|
||||
|
||||
const Memory({
|
||||
@ -20,6 +21,7 @@ class Memory {
|
||||
required this.filePath,
|
||||
required this.isPublic,
|
||||
required this.userID,
|
||||
required this.annotation,
|
||||
this.location,
|
||||
});
|
||||
|
||||
@ -29,6 +31,7 @@ class Memory {
|
||||
filePath: jsonData['location'],
|
||||
isPublic: jsonData['is_public'],
|
||||
userID: jsonData['user_id'],
|
||||
annotation: jsonData['annotation'],
|
||||
location: MemoryLocation.parse(jsonData),
|
||||
);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
"generalError": "There was an error",
|
||||
"generalCancelButtonLabel": "Cancel",
|
||||
"generalContinueButtonLabel": "Continue",
|
||||
"generalSaveButtonLabel": "Save",
|
||||
"generalUnderstoodButtonLabel": "OK",
|
||||
"generalLoadingLabel": "Loading...",
|
||||
|
||||
@ -52,6 +53,10 @@
|
||||
"mainScreenHelpSheetTakePhotoExplanation": "Tap on the shutter button once to take a photo.",
|
||||
"mainScreenHelpSheetTakeVideoExplanation": "Hold down the shutter button to start recording a video. Leave the button to stop recording.",
|
||||
|
||||
"mainScreenAnnotationDialogTitle": "Add an annotation",
|
||||
"mainScreenAnnotationDialogExplanation": "You can add an annotation to your memory",
|
||||
"mainScreenAnnotationDialogAnnotationFieldLabel": "Annotation",
|
||||
|
||||
"recordingOverlayIsRecording": "Recording",
|
||||
|
||||
|
||||
@ -151,6 +156,7 @@
|
||||
"settingsScreenDeleteAccountConfirmLabel": "Delete Account now",
|
||||
"settingsScreenGeneralSectionTitle": "General",
|
||||
"settingsScreenGeneralSectionQualityLabel": "Quality",
|
||||
"settingsScreenGeneralSectionAskForMemoryAnnotationsLabel": "Ask for memory annotations",
|
||||
"settingsScreenResetHelpSheetsLabel": "Reset Help Sheets",
|
||||
"settingsScreenResetHelpSheetsResetSuccessfully": "Help Sheets reset successfully.",
|
||||
|
||||
|
@ -36,7 +36,8 @@ class FileManager {
|
||||
static uploadFile(
|
||||
final User user,
|
||||
final File file, {
|
||||
LocationData? locationData,
|
||||
final LocationData? locationData,
|
||||
final Future<String?>? annotationGetterFuture,
|
||||
}) async {
|
||||
await GlobalValuesManager.waitForInitialization();
|
||||
|
||||
@ -65,6 +66,15 @@ class FileManager {
|
||||
data['location_heading'] = locationData.heading!;
|
||||
}
|
||||
|
||||
if (annotationGetterFuture != null) {
|
||||
final annotation = await annotationGetterFuture;
|
||||
|
||||
if (annotation != null) {
|
||||
// User has specified annotation
|
||||
data['annotation'] = annotation;
|
||||
}
|
||||
}
|
||||
|
||||
final memoryResponse =
|
||||
await supabase.from('memories').insert(data).execute();
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
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';
|
||||
@ -9,14 +10,20 @@ const secure = FlutterSecureStorage();
|
||||
|
||||
class Settings extends ChangeNotifier {
|
||||
ResolutionPreset _resolution = ResolutionPreset.max;
|
||||
bool _askForMemoryAnnotations = false;
|
||||
|
||||
Settings({final ResolutionPreset resolution = ResolutionPreset.max})
|
||||
: _resolution = resolution;
|
||||
Settings({
|
||||
final ResolutionPreset? resolution,
|
||||
final bool? askForMemoryAnnotations,
|
||||
}) : _resolution = resolution ?? ResolutionPreset.max,
|
||||
_askForMemoryAnnotations = askForMemoryAnnotations ?? true;
|
||||
|
||||
ResolutionPreset get resolution => _resolution;
|
||||
bool get askForMemoryAnnotations => _askForMemoryAnnotations;
|
||||
|
||||
Map<String, dynamic> toJSONData() => {
|
||||
'resolution': _resolution.toString(),
|
||||
'askForMemoryAnnotations': _askForMemoryAnnotations ? 'true' : 'false',
|
||||
};
|
||||
|
||||
Future<void> save() async {
|
||||
@ -36,11 +43,23 @@ class Settings extends ChangeNotifier {
|
||||
}
|
||||
|
||||
final data = jsonDecode(rawData);
|
||||
final resolution = ResolutionPreset.values.firstWhere(
|
||||
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;
|
||||
}
|
||||
}();
|
||||
|
||||
return Settings(
|
||||
resolution: resolution,
|
||||
askForMemoryAnnotations: askForMemoryAnnotations,
|
||||
);
|
||||
}
|
||||
|
||||
@ -49,4 +68,10 @@ class Settings extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
save();
|
||||
}
|
||||
|
||||
void setAskForMemoryAnnotations(final bool askForMemoryAnnotations) {
|
||||
_askForMemoryAnnotations = askForMemoryAnnotations;
|
||||
notifyListeners();
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
@ -82,10 +82,9 @@ class _LoginScreenState extends AuthState<LoginScreen> with Loadable {
|
||||
await _signUp();
|
||||
} catch (error) {
|
||||
if (mounted) {
|
||||
if (isMaterial(context))
|
||||
context.showLongErrorSnackBar(
|
||||
message: localizations.loginScreenLoginFailed,
|
||||
);
|
||||
context.showLongErrorSnackBar(
|
||||
message: localizations.loginScreenLoginFailed,
|
||||
);
|
||||
|
||||
passwordController.clear();
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import 'package:quid_faciam_hodie/constants/values.dart';
|
||||
import 'package:quid_faciam_hodie/extensions/snackbar.dart';
|
||||
import 'package:quid_faciam_hodie/managers/file_manager.dart';
|
||||
import 'package:quid_faciam_hodie/managers/global_values_manager.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/settings_button_overlay.dart';
|
||||
import 'package:quid_faciam_hodie/utils/auth_required.dart';
|
||||
@ -188,6 +189,62 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
});
|
||||
}
|
||||
|
||||
Future<String?> _createAskAnnotationDialog() => showPlatformDialog(
|
||||
barrierDismissible: true,
|
||||
context: context,
|
||||
builder: (dialogContext) => const AnnotationDialog(),
|
||||
);
|
||||
|
||||
void _lockCamera() => setState(() {
|
||||
lockCamera = true;
|
||||
});
|
||||
|
||||
void _releaseCamera() => setState(() {
|
||||
lockCamera = false;
|
||||
});
|
||||
|
||||
void _showUploadingPhotoAnimation(final File file) => setState(() {
|
||||
uploadingPhotoAnimation = file.readAsBytesSync();
|
||||
});
|
||||
|
||||
void _releaseUploadingPhotoAnimation() => setState(() {
|
||||
uploadingPhotoAnimation = null;
|
||||
});
|
||||
|
||||
Future<String?> getAnnotation() async {
|
||||
final settings = GlobalValuesManager.settings!;
|
||||
|
||||
if (settings.askForMemoryAnnotations) {
|
||||
return _createAskAnnotationDialog();
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setFlashModeBeforeApplyingAction() async {
|
||||
if (isTorchEnabled) {
|
||||
await controller!.setFlashMode(FlashMode.torch);
|
||||
} else {
|
||||
await controller!.setFlashMode(FlashMode.off);
|
||||
}
|
||||
}
|
||||
|
||||
Future<LocationData?> getLocation([
|
||||
final File? fileToTag,
|
||||
]) async {
|
||||
if (!(await Permission.location.isGranted)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final locationData = await Location().getLocation();
|
||||
|
||||
if (fileToTag != null && Platform.isAndroid) {
|
||||
await tagLocationToImage(fileToTag, locationData);
|
||||
}
|
||||
|
||||
return locationData;
|
||||
}
|
||||
|
||||
Future<void> takePhoto() async {
|
||||
final localizations = AppLocalizations.of(context)!;
|
||||
|
||||
@ -195,109 +252,94 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
lockCamera = true;
|
||||
});
|
||||
_lockCamera();
|
||||
|
||||
try {
|
||||
if (isMaterial(context))
|
||||
context.showPendingSnackBar(
|
||||
message: localizations.mainScreenTakePhotoActionTakingPhoto,
|
||||
);
|
||||
context.showPendingSnackBar(
|
||||
message: localizations.mainScreenTakePhotoActionTakingPhoto,
|
||||
);
|
||||
|
||||
if (isTorchEnabled) {
|
||||
await controller!.setFlashMode(FlashMode.torch);
|
||||
} else {
|
||||
await controller!.setFlashMode(FlashMode.off);
|
||||
}
|
||||
await setFlashModeBeforeApplyingAction();
|
||||
|
||||
final file = File((await controller!.takePicture()).path);
|
||||
|
||||
setState(() {
|
||||
uploadingPhotoAnimation = file.readAsBytesSync();
|
||||
});
|
||||
final annotationGetterFuture = getAnnotation();
|
||||
final locationData = await getLocation(file);
|
||||
|
||||
if (isMaterial(context))
|
||||
context.showPendingSnackBar(
|
||||
message: localizations.mainScreenTakePhotoActionUploadingPhoto,
|
||||
);
|
||||
_showUploadingPhotoAnimation(file);
|
||||
|
||||
LocationData? locationData;
|
||||
|
||||
if (await Permission.location.isGranted) {
|
||||
locationData = await Location().getLocation();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
await tagLocationToImage(file, locationData);
|
||||
}
|
||||
}
|
||||
context.showPendingSnackBar(
|
||||
message: localizations.mainScreenTakePhotoActionUploadingPhoto,
|
||||
);
|
||||
|
||||
try {
|
||||
await FileManager.uploadFile(_user, file, locationData: locationData);
|
||||
await FileManager.uploadFile(
|
||||
_user,
|
||||
file,
|
||||
locationData: locationData,
|
||||
annotationGetterFuture: annotationGetterFuture,
|
||||
);
|
||||
} catch (error) {
|
||||
if (isMaterial(context))
|
||||
context.showErrorSnackBar(message: error.toString());
|
||||
context.showErrorSnackBar(message: error.toString());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMaterial(context))
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations.mainScreenUploadSuccess,
|
||||
);
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations.mainScreenUploadSuccess,
|
||||
);
|
||||
} finally {
|
||||
setState(() {
|
||||
lockCamera = false;
|
||||
uploadingPhotoAnimation = null;
|
||||
});
|
||||
_releaseCamera();
|
||||
_releaseUploadingPhotoAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> takeVideo() async {
|
||||
final localizations = AppLocalizations.of(context)!;
|
||||
|
||||
setState(() {
|
||||
isRecording = false;
|
||||
});
|
||||
|
||||
if (!controller!.value.isRecordingVideo) {
|
||||
// Recording has already been stopped
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
lockCamera = true;
|
||||
isRecording = false;
|
||||
});
|
||||
|
||||
_lockCamera();
|
||||
|
||||
try {
|
||||
if (isMaterial(context))
|
||||
context.showPendingSnackBar(
|
||||
message: localizations.mainScreenTakeVideoActionSaveVideo,
|
||||
);
|
||||
context.showPendingSnackBar(
|
||||
message: localizations.mainScreenTakeVideoActionSaveVideo,
|
||||
);
|
||||
|
||||
final file = File((await controller!.stopVideoRecording()).path);
|
||||
|
||||
if (isMaterial(context))
|
||||
context.showPendingSnackBar(
|
||||
message: localizations.mainScreenTakeVideoActionUploadingVideo,
|
||||
);
|
||||
final annotationGetterFuture = getAnnotation();
|
||||
final locationData = await getLocation();
|
||||
|
||||
context.showPendingSnackBar(
|
||||
message: localizations.mainScreenTakeVideoActionUploadingVideo,
|
||||
);
|
||||
|
||||
try {
|
||||
await FileManager.uploadFile(_user, file);
|
||||
await FileManager.uploadFile(
|
||||
_user,
|
||||
file,
|
||||
annotationGetterFuture: annotationGetterFuture,
|
||||
locationData: locationData,
|
||||
);
|
||||
} catch (error) {
|
||||
if (isMaterial(context)) {
|
||||
context.showErrorSnackBar(message: error.toString());
|
||||
}
|
||||
context.showErrorSnackBar(message: error.toString());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMaterial(context))
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations.mainScreenUploadSuccess,
|
||||
);
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations.mainScreenUploadSuccess,
|
||||
);
|
||||
} finally {
|
||||
setState(() {
|
||||
lockCamera = false;
|
||||
});
|
||||
_releaseCamera();
|
||||
}
|
||||
}
|
||||
|
||||
|
74
lib/screens/main_screen/annotation_dialog.dart
Normal file
74
lib/screens/main_screen/annotation_dialog.dart
Normal file
@ -0,0 +1,74 @@
|
||||
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';
|
||||
import 'package:quid_faciam_hodie/utils/theme.dart';
|
||||
|
||||
class AnnotationDialog extends StatefulWidget {
|
||||
const AnnotationDialog({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AnnotationDialog> createState() => _AnnotationDialogState();
|
||||
}
|
||||
|
||||
class _AnnotationDialogState extends State<AnnotationDialog> {
|
||||
final TextEditingController controller = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final localizations = AppLocalizations.of(context)!;
|
||||
|
||||
return PlatformAlertDialog(
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(MEDIUM_SPACE),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
localizations.mainScreenAnnotationDialogTitle,
|
||||
style: getTitleTextStyle(context),
|
||||
),
|
||||
const SizedBox(height: MEDIUM_SPACE),
|
||||
Text(
|
||||
localizations.mainScreenAnnotationDialogExplanation,
|
||||
style: getBodyTextTextStyle(context),
|
||||
),
|
||||
const SizedBox(height: MEDIUM_SPACE),
|
||||
TextField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(
|
||||
labelText: localizations
|
||||
.mainScreenAnnotationDialogAnnotationFieldLabel,
|
||||
),
|
||||
onSubmitted: (value) {
|
||||
Navigator.of(context).pop(value);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: <Widget>[
|
||||
PlatformDialogAction(
|
||||
child: Text(localizations.generalCancelButtonLabel),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
PlatformDialogAction(
|
||||
child: Text(localizations.generalSaveButtonLabel),
|
||||
onPressed: () => Navigator.pop(context, controller.text.trim()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -83,7 +83,7 @@ class _SettingsScreenState extends AuthRequiredState<SettingsScreen>
|
||||
);
|
||||
}
|
||||
|
||||
Widget getPicker() {
|
||||
Widget getQualityPicker() {
|
||||
final settings = GlobalValuesManager.settings!;
|
||||
final resolutionTextMapping = getResolutionTextMapping(context);
|
||||
final items = ResolutionPreset.values
|
||||
@ -125,6 +125,7 @@ class _SettingsScreenState extends AuthRequiredState<SettingsScreen>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = GlobalValuesManager.settings!;
|
||||
final localizations = AppLocalizations.of(context)!;
|
||||
|
||||
return PlatformScaffold(
|
||||
@ -203,7 +204,15 @@ class _SettingsScreenState extends AuthRequiredState<SettingsScreen>
|
||||
localizations
|
||||
.settingsScreenGeneralSectionQualityLabel,
|
||||
),
|
||||
title: getPicker(),
|
||||
title: getQualityPicker(),
|
||||
),
|
||||
SettingsTile.switchTile(
|
||||
initialValue: settings.askForMemoryAnnotations,
|
||||
onToggle: settings.setAskForMemoryAnnotations,
|
||||
title: Text(
|
||||
localizations
|
||||
.settingsScreenGeneralSectionAskForMemoryAnnotationsLabel,
|
||||
),
|
||||
),
|
||||
SettingsTile(
|
||||
leading: Icon(context.platformIcons.help),
|
||||
@ -213,12 +222,10 @@ class _SettingsScreenState extends AuthRequiredState<SettingsScreen>
|
||||
onPressed: (_) async {
|
||||
await UserHelpSheetsManager.deleteAll();
|
||||
|
||||
if (isMaterial(context)) {
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations
|
||||
.settingsScreenResetHelpSheetsResetSuccessfully,
|
||||
);
|
||||
}
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations
|
||||
.settingsScreenResetHelpSheetsResetSuccessfully,
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
|
@ -65,13 +65,11 @@ class _MemorySheetState extends State<MemorySheet> with Loadable {
|
||||
|
||||
Navigator.pop(context);
|
||||
|
||||
if (isMaterial(context))
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations.memorySheetSavedToGallery,
|
||||
);
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations.memorySheetSavedToGallery,
|
||||
);
|
||||
} catch (error) {
|
||||
if (isMaterial(context))
|
||||
context.showErrorSnackBar(message: localizations.generalError);
|
||||
context.showErrorSnackBar(message: localizations.generalError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,10 +92,9 @@ class _MemorySheetState extends State<MemorySheet> with Loadable {
|
||||
Navigator.pop(context);
|
||||
|
||||
if (isNowPublic) {
|
||||
if (isMaterial(context))
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations.memorySheetMemoryUpdatedToPublic,
|
||||
);
|
||||
context.showSuccessSnackBar(
|
||||
message: localizations.memorySheetMemoryUpdatedToPublic,
|
||||
);
|
||||
} else {
|
||||
if (isMaterial(context))
|
||||
context.showSuccessSnackBar(
|
||||
@ -105,8 +102,7 @@ class _MemorySheetState extends State<MemorySheet> with Loadable {
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (isMaterial(context))
|
||||
context.showErrorSnackBar(message: localizations.generalError);
|
||||
context.showErrorSnackBar(message: localizations.generalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
|
||||
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:provider/provider.dart';
|
||||
import 'package:quid_faciam_hodie/constants/spacing.dart';
|
||||
import 'package:quid_faciam_hodie/enums.dart';
|
||||
import 'package:quid_faciam_hodie/foreign_types/memory.dart';
|
||||
import 'package:quid_faciam_hodie/models/timeline.dart';
|
||||
import 'package:quid_faciam_hodie/widgets/raw_memory_display.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
@ -37,6 +40,7 @@ class MemoryView extends StatefulWidget {
|
||||
class _MemoryViewState extends State<MemoryView> {
|
||||
MemoryFetchStatus status = MemoryFetchStatus.downloading;
|
||||
Uint8List? data;
|
||||
Timer? _nextMemoryTimer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -45,7 +49,16 @@ class _MemoryViewState extends State<MemoryView> {
|
||||
loadMemoryFile();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nextMemoryTimer?.cancel();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> loadMemoryFile() async {
|
||||
final timeline = context.read<TimelineModel>();
|
||||
|
||||
setState(() {
|
||||
status = MemoryFetchStatus.downloading;
|
||||
});
|
||||
@ -75,6 +88,12 @@ class _MemoryViewState extends State<MemoryView> {
|
||||
setState(() {
|
||||
status = MemoryFetchStatus.error;
|
||||
});
|
||||
|
||||
_nextMemoryTimer = Timer(
|
||||
const Duration(seconds: 1),
|
||||
timeline.nextMemory,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -51,44 +51,70 @@ class TimelineOverlay extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: SMALL_SPACE,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: SMALL_SPACE * 2,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: SMALL_SPACE),
|
||||
padding: const EdgeInsets.symmetric(horizontal: MEDIUM_SPACE),
|
||||
child: AnimatedOpacity(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.linearToEaseOut,
|
||||
opacity: timeline.showOverlay ? 1.0 : 0.0,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
(timeline.currentMemory.annotation.isNotEmpty)
|
||||
? MainAxisAlignment.spaceBetween
|
||||
: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
AnimatedOpacity(
|
||||
opacity: timeline.currentMemory.isPublic ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.linearToEaseOut,
|
||||
child: Icon(
|
||||
Icons.public,
|
||||
size: platformThemeData(
|
||||
if (timeline.currentMemory.annotation.isNotEmpty)
|
||||
Text(
|
||||
timeline.currentMemory.annotation,
|
||||
style: platformThemeData(
|
||||
context,
|
||||
material: (data) => data.textTheme.bodyLarge!.fontSize,
|
||||
cupertino: (data) => data.textTheme.textStyle.fontSize,
|
||||
material: (data) => data.textTheme.titleSmall!.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
cupertino: (data) =>
|
||||
data.textTheme.navTitleTextStyle.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
color: Colors.white,
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
AnimatedOpacity(
|
||||
opacity: timeline.currentMemory.isPublic ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.linearToEaseOut,
|
||||
child: Icon(
|
||||
Icons.public,
|
||||
size: platformThemeData(
|
||||
context,
|
||||
material: (data) =>
|
||||
data.textTheme.bodyLarge!.fontSize,
|
||||
cupertino: (data) =>
|
||||
data.textTheme.textStyle.fontSize,
|
||||
),
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: SMALL_SPACE),
|
||||
Text(
|
||||
'$memoryIndex/$memoriesAmount',
|
||||
style: platformThemeData(
|
||||
context,
|
||||
material: (data) =>
|
||||
data.textTheme.titleSmall!.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
cupertino: (data) =>
|
||||
data.textTheme.navTitleTextStyle.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: SMALL_SPACE),
|
||||
Text(
|
||||
'$memoryIndex/$memoriesAmount',
|
||||
style: platformThemeData(
|
||||
context,
|
||||
material: (data) => data.textTheme.titleSmall!.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
cupertino: (data) =>
|
||||
data.textTheme.navTitleTextStyle.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -60,11 +60,9 @@ class KeyValueInfo extends StatelessWidget {
|
||||
HapticFeedback.lightImpact();
|
||||
Clipboard.setData(ClipboardData(text: value));
|
||||
|
||||
if (isMaterial(context)) {
|
||||
context.showSuccessSnackBar(
|
||||
message: 'Copied to clipboard!',
|
||||
);
|
||||
}
|
||||
context.showSuccessSnackBar(
|
||||
message: 'Copied to clipboard!',
|
||||
);
|
||||
},
|
||||
)
|
||||
: null,
|
||||
|
@ -43,12 +43,18 @@ class _RawMemoryDisplayState extends State<RawMemoryDisplay> {
|
||||
Future<File> createTempVideo() async {
|
||||
final tempDirectory = await getTemporaryDirectory();
|
||||
final path = '${tempDirectory.path}/${widget.filename ?? 'video.mp4'}';
|
||||
print("#" * 50);
|
||||
print(widget.filename);
|
||||
print(path);
|
||||
final file = File(path);
|
||||
print(await file.exists());
|
||||
print(widget.data);
|
||||
|
||||
/*
|
||||
if (await file.exists()) {
|
||||
// File already exists, so just return it
|
||||
return file;
|
||||
}
|
||||
}*/
|
||||
|
||||
// File needs to be created
|
||||
await file.create();
|
||||
|
@ -441,6 +441,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
morphing_text:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: morphing_text
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -63,6 +63,7 @@ dependencies:
|
||||
flutter_osm_plugin: ^0.39.0
|
||||
url_launcher: ^6.1.5
|
||||
apple_maps_flutter: ^1.2.0
|
||||
morphing_text: ^1.0.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
x
Reference in New Issue
Block a user