Compare commits

...

3 commits

Author SHA1 Message Date
Prateek Sunal fae54faffc fix(icons): update dev flavor icon 2024-05-26 17:29:04 +05:30
Prateek Sunal d4f781bf35 fix(auth): update video editor 2024-05-20 20:57:44 +05:30
Prateek Sunal 9c4e72aa0f feat(mobile): init video editor 2024-05-17 01:32:13 +05:30
41 changed files with 1087 additions and 132 deletions

View file

@ -43,7 +43,7 @@ android {
defaultConfig {
applicationId "io.ente.photos"
minSdkVersion 21
minSdkVersion 24
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

View file

@ -0,0 +1,4 @@
flutter_launcher_icons:
android: "launcher_icon"
ios: true
image_path: "assets/launcher_icon/ente-icon-dev.png"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View file

@ -0,0 +1 @@
{"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-dev-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-dev-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-dev-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-dev-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-dev-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-dev-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-dev-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-dev-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-dev-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-dev-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-dev-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-dev-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-dev-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-dev-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-dev-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-dev-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-dev-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-dev-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-dev-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-dev-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-dev-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-dev-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-dev-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-dev-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-dev-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}

View file

@ -123,9 +123,8 @@ Future<void> _runBackgroundTask(String taskId, {String mode = 'normal'}) async {
if (_isProcessRunning) {
_logger.info("Background task triggered when process was already running");
await _sync('bgTaskActiveProcess');
BackgroundFetch.finish(taskId);
BackgroundFetch.finish(taskId).ignore();
} else {
// ignore: unawaited_futures
_runWithLogs(
() async {
_logger.info("Starting background task in $mode mode");
@ -133,7 +132,7 @@ Future<void> _runBackgroundTask(String taskId, {String mode = 'normal'}) async {
_runInBackground(taskId);
},
prefix: "[bg]",
);
).ignore();
}
}
@ -141,7 +140,7 @@ Future<void> _runInBackground(String taskId) async {
await Future.delayed(const Duration(seconds: 3));
if (await _isRunningInForeground()) {
_logger.info("FG task running, skipping BG taskID: $taskId");
BackgroundFetch.finish(taskId);
BackgroundFetch.finish(taskId).ignore();
return;
} else {
_logger.info("FG task is not running");
@ -161,7 +160,7 @@ Future<void> _runInBackground(String taskId) async {
}(),
],
);
BackgroundFetch.finish(taskId);
BackgroundFetch.finish(taskId).ignore();
}
// https://stackoverflow.com/a/73796478/546896
@ -334,7 +333,7 @@ Future<void> _killBGTask([String? taskId]) async {
await prefs.remove(kLastBGTaskHeartBeatTime);
if (taskId != null) {
BackgroundFetch.finish(taskId);
BackgroundFetch.finish(taskId).ignore();
}
///Band aid for background process not getting killed. Should migrate to using

View file

@ -0,0 +1,177 @@
import 'package:flutter/material.dart';
import 'package:fraction/fraction.dart';
import 'package:video_editor/video_editor.dart';
class CropPage extends StatelessWidget {
const CropPage({super.key, required this.controller});
final VideoEditorController controller;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 30),
child: Column(
children: [
Row(
children: [
Expanded(
child: IconButton(
onPressed: () =>
controller.rotate90Degrees(RotateDirection.left),
icon: const Icon(Icons.rotate_left),
),
),
Expanded(
child: IconButton(
onPressed: () =>
controller.rotate90Degrees(RotateDirection.right),
icon: const Icon(Icons.rotate_right),
),
),
],
),
const SizedBox(height: 15),
Expanded(
child: CropGridViewer.edit(
controller: controller,
rotateCropArea: false,
margin: const EdgeInsets.symmetric(horizontal: 20),
),
),
const SizedBox(height: 15),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
flex: 2,
child: IconButton(
onPressed: () => Navigator.pop(context),
icon: const Center(
child: Text(
"cancel",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
),
Expanded(
flex: 4,
child: AnimatedBuilder(
animation: controller,
builder: (_, __) => Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () =>
controller.preferredCropAspectRatio =
controller.preferredCropAspectRatio
?.toFraction()
.inverse()
.toDouble(),
icon: controller.preferredCropAspectRatio !=
null &&
controller.preferredCropAspectRatio! < 1
? const Icon(
Icons.panorama_vertical_select_rounded,
)
: const Icon(
Icons.panorama_vertical_rounded,
),
),
IconButton(
onPressed: () =>
controller.preferredCropAspectRatio =
controller.preferredCropAspectRatio
?.toFraction()
.inverse()
.toDouble(),
icon: controller.preferredCropAspectRatio !=
null &&
controller.preferredCropAspectRatio! > 1
? const Icon(
Icons
.panorama_horizontal_select_rounded,
)
: const Icon(
Icons.panorama_horizontal_rounded,
),
),
],
),
Row(
children: [
_buildCropButton(context, null),
_buildCropButton(context, 1.toFraction()),
_buildCropButton(
context,
Fraction.fromString("9/16"),
),
_buildCropButton(
context,
Fraction.fromString("3/4"),
),
],
),
],
),
),
),
Expanded(
flex: 2,
child: IconButton(
onPressed: () {
// WAY 1: validate crop parameters set in the crop view
controller.applyCacheCrop();
// WAY 2: update manually with Offset values
// controller.updateCrop(const Offset(0.2, 0.2), const Offset(0.8, 0.8));
Navigator.pop(context);
},
icon: Center(
child: Text(
"done",
style: TextStyle(
color:
const CropGridStyle().selectedBoundariesColor,
fontWeight: FontWeight.bold,
),
),
),
),
),
],
),
],
),
),
),
);
}
Widget _buildCropButton(BuildContext context, Fraction? f) {
if (controller.preferredCropAspectRatio != null &&
controller.preferredCropAspectRatio! > 1) f = f?.inverse();
return Flexible(
child: TextButton(
style: ElevatedButton.styleFrom(
elevation: 0,
backgroundColor: controller.preferredCropAspectRatio == f?.toDouble()
? Colors.grey.shade800
: null,
foregroundColor: controller.preferredCropAspectRatio == f?.toDouble()
? Colors.white
: null,
textStyle: Theme.of(context).textTheme.bodySmall,
),
onPressed: () => controller.preferredCropAspectRatio = f?.toDouble(),
child: Text(f == null ? 'free' : '${f.numerator}:${f.denominator}'),
),
);
}
}

View file

@ -0,0 +1,199 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:fraction/fraction.dart';
import 'package:path/path.dart' as path;
import 'package:video_player/video_player.dart';
Future<void> _getImageDimension(
File file, {
required Function(Size) onResult,
}) async {
final decodedImage = await decodeImageFromList(file.readAsBytesSync());
onResult(Size(decodedImage.width.toDouble(), decodedImage.height.toDouble()));
}
String _fileMBSize(File file) =>
' ${(file.lengthSync() / (1024 * 1024)).toStringAsFixed(1)} MB';
class VideoResultPopup extends StatefulWidget {
const VideoResultPopup({super.key, required this.video});
final File video;
@override
State<VideoResultPopup> createState() => _VideoResultPopupState();
}
class _VideoResultPopupState extends State<VideoResultPopup> {
VideoPlayerController? _controller;
FileImage? _fileImage;
Size _fileDimension = Size.zero;
late final bool _isGif =
path.extension(widget.video.path).toLowerCase() == ".gif";
late String _fileMbSize;
@override
void initState() {
super.initState();
if (_isGif) {
_getImageDimension(
widget.video,
onResult: (d) => setState(() => _fileDimension = d),
);
} else {
_controller = VideoPlayerController.file(widget.video);
_controller?.initialize().then((_) {
_fileDimension = _controller?.value.size ?? Size.zero;
setState(() {});
_controller?.play();
_controller?.setLooping(true);
});
}
_fileMbSize = _fileMBSize(widget.video);
}
@override
void dispose() {
if (_isGif) {
_fileImage?.evict();
} else {
_controller?.pause();
_controller?.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(30),
child: Center(
child: Stack(
alignment: Alignment.bottomLeft,
children: [
AspectRatio(
aspectRatio: _fileDimension.aspectRatio == 0
? 1
: _fileDimension.aspectRatio,
child:
_isGif ? Image.file(widget.video) : VideoPlayer(_controller!),
),
Positioned(
bottom: 0,
child: FileDescription(
description: {
'Video path': widget.video.path,
if (!_isGif)
'Video duration':
'${((_controller?.value.duration.inMilliseconds ?? 0) / 1000).toStringAsFixed(2)}s',
'Video ratio': Fraction.fromDouble(_fileDimension.aspectRatio)
.reduce()
.toString(),
'Video dimension': _fileDimension.toString(),
'Video size': _fileMbSize,
},
),
),
],
),
),
);
}
}
class CoverResultPopup extends StatefulWidget {
const CoverResultPopup({super.key, required this.cover});
final File cover;
@override
State<CoverResultPopup> createState() => _CoverResultPopupState();
}
class _CoverResultPopupState extends State<CoverResultPopup> {
late final Uint8List _imagebytes = widget.cover.readAsBytesSync();
Size? _fileDimension;
late String _fileMbSize;
@override
void initState() {
super.initState();
_getImageDimension(
widget.cover,
onResult: (d) => setState(() => _fileDimension = d),
);
_fileMbSize = _fileMBSize(widget.cover);
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(30),
child: Center(
child: Stack(
children: [
Image.memory(_imagebytes),
Positioned(
bottom: 0,
child: FileDescription(
description: {
'Cover path': widget.cover.path,
'Cover ratio':
Fraction.fromDouble(_fileDimension?.aspectRatio ?? 0)
.reduce()
.toString(),
'Cover dimension': _fileDimension.toString(),
'Cover size': _fileMbSize,
},
),
),
],
),
),
);
}
}
class FileDescription extends StatelessWidget {
const FileDescription({super.key, required this.description});
final Map<String, String> description;
@override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: const TextStyle(fontSize: 11),
child: Container(
width: MediaQuery.of(context).size.width - 60,
padding: const EdgeInsets.all(10),
color: Colors.black.withOpacity(0.5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: description.entries
.map(
(entry) => Text.rich(
TextSpan(
children: [
TextSpan(
text: '${entry.key}: ',
style: const TextStyle(fontSize: 11),
),
TextSpan(
text: entry.value,
style: TextStyle(
fontSize: 10,
color: Colors.white.withOpacity(0.8),
),
),
],
),
),
)
.toList(),
),
),
);
}
}

View file

@ -0,0 +1,49 @@
import 'dart:developer';
import 'dart:io';
import 'package:ffmpeg_kit_flutter_min/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter_min/ffmpeg_kit_config.dart';
import 'package:ffmpeg_kit_flutter_min/ffmpeg_session.dart';
import 'package:ffmpeg_kit_flutter_min/return_code.dart';
import 'package:ffmpeg_kit_flutter_min/statistics.dart';
import 'package:video_editor/video_editor.dart';
class ExportService {
static Future<void> dispose() async {
final executions = await FFmpegKit.listSessions();
if (executions.isNotEmpty) await FFmpegKit.cancel();
}
static Future<FFmpegSession> runFFmpegCommand(
FFmpegVideoEditorExecute execute, {
required void Function(File file) onCompleted,
void Function(Object, StackTrace)? onError,
void Function(Statistics)? onProgress,
}) {
log('FFmpeg start process with command = ${execute.command}');
return FFmpegKit.executeAsync(
execute.command,
(session) async {
final state =
FFmpegKitConfig.sessionStateToString(await session.getState());
final code = await session.getReturnCode();
if (ReturnCode.isSuccess(code)) {
onCompleted(File(execute.outputPath));
} else {
if (onError != null) {
onError(
Exception(
'FFmpeg process exited with state $state and return code $code.\n${await session.getOutput()}',
),
StackTrace.current,
);
}
return;
}
},
null,
onProgress,
);
}
}

View file

@ -0,0 +1,367 @@
import 'dart:io';
import 'package:flutter/material.dart';
import "package:photos/models/file/file.dart";
import 'package:photos/ui/tools/editor/crop_video_page.dart';
import 'package:photos/ui/tools/editor/export_video_result.dart';
import 'package:photos/ui/tools/editor/export_video_service.dart';
import "package:photos/ui/viewer/file/detail_page.dart";
import "package:video_editor/video_editor.dart";
class VideoEditorPage extends StatefulWidget {
const VideoEditorPage({
super.key,
required this.file,
required this.ioFile,
required this.detailPageConfig,
});
final EnteFile file;
final File ioFile;
final DetailPageConfiguration detailPageConfig;
@override
State<VideoEditorPage> createState() => _VideoEditorPageState();
}
class _VideoEditorPageState extends State<VideoEditorPage> {
final _exportingProgress = ValueNotifier<double>(0.0);
final _isExporting = ValueNotifier<bool>(false);
final double height = 60;
late final VideoEditorController _controller;
@override
void initState() {
super.initState();
_controller = VideoEditorController.file(
widget.ioFile,
minDuration: const Duration(seconds: 1),
);
_controller.initialize().then((_) => setState(() {})).catchError(
(error) {
// handle minumum duration bigger than video duration error
Navigator.pop(context);
},
test: (e) => e is VideoMinDurationError,
);
}
@override
void dispose() async {
_exportingProgress.dispose();
_isExporting.dispose();
_controller.dispose().ignore();
ExportService.dispose().ignore();
super.dispose();
}
void _showErrorSnackBar(String message) =>
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: const Duration(seconds: 1),
),
);
void _exportVideo() async {
_exportingProgress.value = 0;
_isExporting.value = true;
final config = VideoFFmpegVideoEditorConfig(
_controller,
// format: VideoExportFormat.gif,
// commandBuilder: (config, videoPath, outputPath) {
// final List<String> filters = config.getExportFilters();
// filters.add('hflip'); // add horizontal flip
// return '-i $videoPath ${config.filtersCmd(filters)} -preset ultrafast $outputPath';
// },
);
await ExportService.runFFmpegCommand(
await config.getExecuteConfig(),
onProgress: (stats) {
_exportingProgress.value =
config.getFFmpegProgress(stats.getTime().toInt());
},
onError: (e, s) => _showErrorSnackBar("Error on export video :("),
onCompleted: (file) {
_isExporting.value = false;
if (!mounted) return;
showDialog(
context: context,
builder: (_) => VideoResultPopup(video: file),
);
},
);
}
void _exportCover() async {
final config = CoverFFmpegVideoEditorConfig(_controller);
final execute = await config.getExecuteConfig();
if (execute == null) {
_showErrorSnackBar("Error on cover exportation initialization.");
return;
}
await ExportService.runFFmpegCommand(
execute,
onError: (e, s) => _showErrorSnackBar("Error on cover exportation :("),
onCompleted: (cover) {
if (!mounted) return;
showDialog(
context: context,
builder: (_) => CoverResultPopup(cover: cover),
);
},
);
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: Scaffold(
backgroundColor: Colors.black,
body: _controller.initialized
? SafeArea(
child: Stack(
children: [
Column(
children: [
_topNavBar(),
Expanded(
child: DefaultTabController(
length: 2,
child: Column(
children: [
Expanded(
child: TabBarView(
physics:
const NeverScrollableScrollPhysics(),
children: [
Stack(
alignment: Alignment.center,
children: [
CropGridViewer.preview(
controller: _controller,
),
AnimatedBuilder(
animation: _controller.video,
builder: (_, __) => AnimatedOpacity(
opacity:
_controller.isPlaying ? 0 : 1,
duration: kThemeAnimationDuration,
child: GestureDetector(
onTap: _controller.video.play,
child: Container(
width: 40,
height: 40,
decoration:
const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: const Icon(
Icons.play_arrow,
color: Colors.black,
),
),
),
),
),
],
),
CoverViewer(controller: _controller),
],
),
),
Container(
height: 200,
margin: const EdgeInsets.only(top: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: _trimSlider(),
),
),
ValueListenableBuilder(
valueListenable: _isExporting,
builder: (_, bool export, Widget? child) =>
AnimatedSize(
duration: kThemeAnimationDuration,
child: export ? child : null,
),
child: AlertDialog(
title: ValueListenableBuilder(
valueListenable: _exportingProgress,
builder: (_, double value, __) => Text(
"Exporting video ${(value * 100).ceil()}%",
style: const TextStyle(fontSize: 12),
),
),
),
),
],
),
),
),
],
),
],
),
)
: const Center(child: CircularProgressIndicator()),
),
);
}
Widget _topNavBar() {
return SafeArea(
child: SizedBox(
height: height,
child: Row(
children: [
Expanded(
child: IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(Icons.exit_to_app),
tooltip: 'Leave editor',
),
),
const VerticalDivider(endIndent: 22, indent: 22),
Expanded(
child: IconButton(
onPressed: () =>
_controller.rotate90Degrees(RotateDirection.left),
icon: const Icon(Icons.rotate_left),
tooltip: 'Rotate unclockwise',
),
),
Expanded(
child: IconButton(
onPressed: () =>
_controller.rotate90Degrees(RotateDirection.right),
icon: const Icon(Icons.rotate_right),
tooltip: 'Rotate clockwise',
),
),
Expanded(
child: IconButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute<void>(
builder: (context) => CropPage(controller: _controller),
),
),
icon: const Icon(Icons.crop),
tooltip: 'Open crop screen',
),
),
const VerticalDivider(endIndent: 22, indent: 22),
Expanded(
child: PopupMenuButton(
tooltip: 'Open export menu',
icon: const Icon(Icons.save),
itemBuilder: (context) => [
PopupMenuItem(
onTap: _exportCover,
child: const Text('Export cover'),
),
PopupMenuItem(
onTap: _exportVideo,
child: const Text('Export video'),
),
],
),
),
],
),
),
);
}
String formatter(Duration duration) => [
duration.inMinutes.remainder(60).toString().padLeft(2, '0'),
duration.inSeconds.remainder(60).toString().padLeft(2, '0'),
].join(":");
List<Widget> _trimSlider() {
return [
AnimatedBuilder(
animation: Listenable.merge([
_controller,
_controller.video,
]),
builder: (_, __) {
final int duration = _controller.videoDuration.inSeconds;
final double pos = _controller.trimPosition * duration;
return Padding(
padding: EdgeInsets.symmetric(horizontal: height / 4),
child: Row(
children: [
Text(formatter(Duration(seconds: pos.toInt()))),
const Expanded(child: SizedBox()),
AnimatedOpacity(
opacity: _controller.isTrimming ? 1 : 0,
duration: kThemeAnimationDuration,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(formatter(_controller.startTrim)),
const SizedBox(width: 10),
Text(formatter(_controller.endTrim)),
],
),
),
],
),
);
},
),
Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(vertical: height / 4),
child: TrimSlider(
controller: _controller,
height: height,
horizontalMargin: height / 4,
child: TrimTimeline(
controller: _controller,
padding: const EdgeInsets.only(top: 10),
),
),
),
];
}
Widget _coverSelection() {
return SingleChildScrollView(
child: Center(
child: Container(
margin: const EdgeInsets.all(15),
child: CoverSelection(
controller: _controller,
size: height + 10,
quantity: 8,
selectedCoverBuilder: (cover, size) {
return Stack(
alignment: Alignment.center,
children: [
cover,
Icon(
Icons.check_circle,
color: const CoverSelectionStyle().selectedBorderColor,
),
],
);
},
),
),
),
);
}
}

View file

@ -13,6 +13,7 @@ import 'package:photos/models/file/file.dart';
import "package:photos/models/file/file_type.dart";
import "package:photos/ui/common/fast_scroll_physics.dart";
import 'package:photos/ui/tools/editor/image_editor_page.dart';
import "package:photos/ui/tools/editor/video_editor_page.dart";
import "package:photos/ui/viewer/file/file_app_bar.dart";
import "package:photos/ui/viewer/file/file_bottom_bar.dart";
import 'package:photos/ui/viewer/file/file_widget.dart';
@ -370,6 +371,21 @@ class _DetailPageState extends State<DetailPage> {
await dialog.hide();
return;
}
if (file.fileType == FileType.video) {
await dialog.hide();
replacePage(
context,
VideoEditorPage(
file: file,
ioFile: ioFile,
detailPageConfig: widget.config.copyWith(
files: _files,
selectedIndex: _selectedIndexNotifier.value,
),
),
);
return;
}
final imageProvider =
ExtendedFileImageProvider(ioFile, cacheRawData: true);
await precacheImage(imageProvider, context);

View file

@ -85,7 +85,8 @@ class FileBottomBarState extends State<FileBottomBar> {
if (!widget.showOnlyInfoButton && widget.file is! TrashFile) {
if (widget.file.fileType == FileType.image ||
widget.file.fileType == FileType.livePhoto) {
widget.file.fileType == FileType.livePhoto ||
widget.file.fileType == FileType.video) {
children.add(
Tooltip(
message: "Edit",

View file

@ -1,7 +1,6 @@
import 'dart:io';
import 'package:archive/archive_io.dart';
import "package:cross_file/cross_file.dart";
import 'package:email_validator/email_validator.dart';
import "package:file_saver/file_saver.dart";
import 'package:flutter/cupertino.dart';
@ -133,7 +132,7 @@ Future<String> getZippedLogsFile(BuildContext context) async {
final encoder = ZipFileEncoder();
encoder.create(zipFilePath);
await encoder.addDirectory(logsDirectory);
encoder.close();
encoder.close().ignore();
await dialog.hide();
return zipFilePath;
}

View file

@ -179,7 +179,7 @@ Future<void> _computeZip(Map<String, dynamic> args) async {
encoder.create(zipPath);
await encoder.addFile(File(imagePath), "image" + extension(imagePath));
await encoder.addFile(File(videoPath), "video" + extension(videoPath));
encoder.close();
encoder.close().ignore();
}
Future<void> zip({

View file

@ -5,18 +5,18 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
url: "https://pub.dev"
source: hosted
version: "61.0.0"
version: "67.0.0"
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "0cb43f83f36ba8cb20502dee0c205e3f3aafb751732d724aeac3f2e044212cc2"
sha256: "2350805d7afefb0efe7acd325cb19d3ae8ba4039b906eade3807ffb69938a01f"
url: "https://pub.dev"
source: hosted
version: "1.3.29"
version: "1.3.33"
adaptive_theme:
dependency: "direct main"
description:
@ -29,10 +29,10 @@ packages:
dependency: transitive
description:
name: analyzer
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
url: "https://pub.dev"
source: hosted
version: "5.13.0"
version: "6.4.1"
animate_do:
dependency: "direct main"
description:
@ -69,10 +69,10 @@ packages:
dependency: "direct main"
description:
name: archive
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265
url: "https://pub.dev"
source: hosted
version: "3.4.10"
version: "3.5.1"
args:
dependency: transitive
description:
@ -93,10 +93,10 @@ packages:
dependency: "direct main"
description:
name: background_fetch
sha256: dbffec0317ccdef6e2014cb543e147f52441e29c4fcb53dfd23558c4d92ddece
sha256: "2fe367c9be0e256dadb75b8b637b0b58a2a2d2317b7c8420bb1ae8b41e23fde3"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.3.4"
battery_info:
dependency: "direct main"
description:
@ -205,10 +205,10 @@ packages:
dependency: transitive
description:
name: cached_network_image_web
sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316"
sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.2.0"
cast:
dependency: transitive
description:
@ -295,10 +295,10 @@ packages:
dependency: "direct main"
description:
name: connectivity_plus
sha256: ebe15d94de9dd7c31dc2ac54e42780acdf3384b1497c69290c9f3c5b0279fc57
sha256: db7a4e143dc72cc3cb2044ef9b052a7ebfe729513e6a82943bc3526f784365b8
url: "https://pub.dev"
source: hosted
version: "6.0.2"
version: "6.0.3"
connectivity_plus_platform_interface:
dependency: transitive
description:
@ -319,10 +319,10 @@ packages:
dependency: transitive
description:
name: coverage
sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76"
sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e"
url: "https://pub.dev"
source: hosted
version: "1.7.2"
version: "1.8.0"
cross_file:
dependency: "direct main"
description:
@ -359,10 +359,10 @@ packages:
dependency: transitive
description:
name: dart_style
sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.3.6"
dbus:
dependency: transitive
description:
@ -544,6 +544,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
ffmpeg_kit_flutter_min:
dependency: "direct main"
description:
name: ffmpeg_kit_flutter_min
sha256: "123bfbc0e0b9e7cf6d32d8ba8e08b666d66af0f52c07683dd2305fbfc13f494a"
url: "https://pub.dev"
source: hosted
version: "6.0.3"
ffmpeg_kit_flutter_platform_interface:
dependency: transitive
description:
name: ffmpeg_kit_flutter_platform_interface
sha256: addf046ae44e190ad0101b2fde2ad909a3cd08a2a109f6106d2f7048b7abedee
url: "https://pub.dev"
source: hosted
version: "0.2.1"
figma_squircle:
dependency: "direct main"
description:
@ -569,14 +585,46 @@ packages:
url: "https://github.com/jesims/file_saver.git"
source: git
version: "0.2.9"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492"
url: "https://pub.dev"
source: hosted
version: "0.9.2+1"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385
url: "https://pub.dev"
source: hosted
version: "0.9.4"
file_selector_platform_interface:
dependency: transitive
description:
name: file_selector_platform_interface
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
url: "https://pub.dev"
source: hosted
version: "2.6.2"
file_selector_windows:
dependency: transitive
description:
name: file_selector_windows
sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0
url: "https://pub.dev"
source: hosted
version: "0.9.3+1"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "6b1152a5af3b1cfe7e45309e96fc1aa14873f410f7aadb3878aa7812acfa7531"
sha256: "372d94ced114b9c40cb85e18c50ac94a7e998c8eec630c50d7aec047847d27bf"
url: "https://pub.dev"
source: hosted
version: "2.30.0"
version: "2.31.0"
firebase_core_platform_interface:
dependency: transitive
description:
@ -589,34 +637,34 @@ packages:
dependency: transitive
description:
name: firebase_core_web
sha256: c8b02226e548f35aace298e2bb2e6c24e34e8a203d614e742bb1146e5a4ad3c8
sha256: "43d9e951ac52b87ae9cc38ecdcca1e8fa7b52a1dd26a96085ba41ce5108db8e9"
url: "https://pub.dev"
source: hosted
version: "2.15.0"
version: "2.17.0"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: "87e3eda0ecdfeadb5fd1cf0dc5153aea5307a0cfca751c4b1ac97bfdd805660e"
sha256: e0882a7426821f7caccaabfc15a535155cd15b4daa73a5a7b3af701a552d73ab
url: "https://pub.dev"
source: hosted
version: "14.8.1"
version: "14.9.2"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: "80b4ccf20066b0579ebc88d4678230a5f53ab282fe040e31671af745db1588f9"
sha256: "52e12cc50e1395ad7ea3552dcbe9958fb1994b5afcf58ee4c0db053932a6fce5"
url: "https://pub.dev"
source: hosted
version: "4.5.31"
version: "4.5.35"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "9224aa4db1ce6f08d96a82978453d37e9980204a20e410a11d9b774b24c6841c"
sha256: "8812cc5929380b783f92290d934bf32e2fea06701583f47cdccd5f13f4f24522"
url: "https://pub.dev"
source: hosted
version: "3.8.1"
version: "3.8.5"
fixnum:
dependency: transitive
description:
@ -727,10 +775,10 @@ packages:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: f9a05409385b77b06c18f200a41c7c2711ebf7415669350bb0f8474c07bd40d1
sha256: "40e6fbd2da7dcc7ed78432c5cdab1559674b4af035fddbfb2f9a8f9c2112fcef"
url: "https://pub.dev"
source: hosted
version: "17.0.0"
version: "17.1.2"
flutter_local_notifications_linux:
dependency: transitive
description:
@ -743,10 +791,10 @@ packages:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef"
sha256: "340abf67df238f7f0ef58f4a26d2a83e1ab74c77ab03cd2b2d5018ac64db30b7"
url: "https://pub.dev"
source: hosted
version: "7.0.0+1"
version: "7.1.0"
flutter_localizations:
dependency: "direct main"
description: flutter
@ -780,10 +828,10 @@ packages:
dependency: "direct main"
description:
name: flutter_native_splash
sha256: "558f10070f03ee71f850a78f7136ab239a67636a294a44a06b6b7345178edb1e"
sha256: edf39bcf4d74aca1eb2c1e43c3e445fd9f494013df7f0da752fefe72020eedc0
url: "https://pub.dev"
source: hosted
version: "2.3.10"
version: "2.4.0"
flutter_password_strength:
dependency: "direct main"
description:
@ -812,34 +860,34 @@ packages:
dependency: transitive
description:
name: flutter_secure_storage_linux
sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e"
sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.2.1"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c
sha256: b768a7dab26d6186b68e2831b3104f8968154f0f4fdbf66e7c2dd7bdf299daaf
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.1.1"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e"
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.2"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20"
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.2.1"
flutter_secure_storage_windows:
dependency: transitive
description:
@ -894,10 +942,18 @@ packages:
dependency: "direct main"
description:
name: fluttertoast
sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1
sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66"
url: "https://pub.dev"
source: hosted
version: "8.2.4"
version: "8.2.5"
fraction:
dependency: "direct main"
description:
name: fraction
sha256: "09e9504c9177bbd77df56e5d147abfbb3b43360e64bf61510059c14d6a82d524"
url: "https://pub.dev"
source: hosted
version: "5.0.2"
freezed:
dependency: "direct dev"
description:
@ -1027,66 +1083,130 @@ packages:
dependency: "direct main"
description:
name: image_editor
sha256: "6401a431ef1e988e35a8b19ff02cb7d31bd881fd7db0d39261ac8236683ef1c1"
sha256: "0fe70befea0dbaf24a7cacc32c28311a65118f66637997ad072e9063f59efdd8"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.5.1"
image_editor_common:
dependency: transitive
description:
name: image_editor_common
sha256: "07fc9bcc16918a8230e132b9d9a9f66bb1cef3ac99f5e2939cf2ad7a6775b511"
sha256: d141c0847148a7da573a5be5ca02e70d381e61cb6484ebef52a230ca1d6c56ab
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.1.2"
image_editor_ohos:
dependency: transitive
description:
name: image_editor_ohos
sha256: aee8fa1490fedbb98583dfaebb4162c295abeb0044e94f2eb2ad52ae419e6f6e
sha256: "06756859586d5acefec6e3b4f356f9b1ce05ef09213bcb9a0ce1680ecea2d054"
url: "https://pub.dev"
source: hosted
version: "0.0.7"
version: "0.0.9"
image_editor_platform_interface:
dependency: transitive
description:
name: image_editor_platform_interface
sha256: ee01ec5e228e10c40f96d7f822c176d4140c15b6706e4a701866ee0cdd1c2b72
sha256: "474517efc770464f7d99942472d8cfb369a3c378e95466ec17f74d2b80bd40de"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.1.0"
image_picker:
dependency: "direct main"
description:
name: image_picker
sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
sha256: "0f57fee1e8bfadf8cc41818bbcd7f72e53bb768a54d9496355d5e8a5681a19f1"
url: "https://pub.dev"
source: hosted
version: "0.8.12+1"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3"
url: "https://pub.dev"
source: hosted
version: "3.0.4"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: "4824d8c7f6f89121ef0122ff79bb00b009607faecc8545b86bca9ab5ce1e95bf"
url: "https://pub.dev"
source: hosted
version: "0.8.11+2"
image_picker_linux:
dependency: transitive
description:
name: image_picker_linux
sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa"
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
image_picker_macos:
dependency: transitive
description:
name: image_picker_macos
sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62"
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80"
url: "https://pub.dev"
source: hosted
version: "2.10.0"
image_picker_windows:
dependency: transitive
description:
name: image_picker_windows
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
in_app_purchase:
dependency: "direct main"
description:
name: in_app_purchase
sha256: def70fbaa2a274f4d835677459f6f7afc5469de912438f86076e51cbd4cbd5b4
sha256: "960f26a08d9351fb8f89f08901f8a829d41b04d45a694b8f776121d9e41dcad6"
url: "https://pub.dev"
source: hosted
version: "3.1.13"
version: "3.2.0"
in_app_purchase_android:
dependency: transitive
description:
name: in_app_purchase_android
sha256: b9d4ecf70c51ab46222502c050b1535f6249caf9d768c4abd856ea16a18a882d
sha256: bc4e58e8bd9f1027ca869f419737773bdf80ad36074037fa8ed81e5ca15dc655
url: "https://pub.dev"
source: hosted
version: "0.3.3+1"
version: "0.3.5+1"
in_app_purchase_platform_interface:
dependency: transitive
description:
name: in_app_purchase_platform_interface
sha256: "412efce2b9238c5ace4f057acad43f793ed06880e366d26ae322e796cadb051a"
sha256: "1d353d38251da5b9fea6635c0ebfc6bb17a2d28d0e86ea5e083bf64244f1fb4c"
url: "https://pub.dev"
source: hosted
version: "1.3.7"
version: "1.4.0"
in_app_purchase_storekit:
dependency: transitive
description:
name: in_app_purchase_storekit
sha256: e0f860e760488dbd666e0f27e239d128cba744607fc62434dc76c19d1c292439
sha256: "3eea5e173fca0a59ab2fcec5201bea14bb808dfad01004d2b1d7bfdb9244c5e6"
url: "https://pub.dev"
source: hosted
version: "0.3.13+1"
version: "0.3.16"
integration_test:
dependency: "direct dev"
description: flutter
@ -1120,18 +1240,18 @@ packages:
dependency: "direct main"
description:
name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.dev"
source: hosted
version: "4.8.1"
version: "4.9.0"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969
sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b
url: "https://pub.dev"
source: hosted
version: "6.7.1"
version: "6.8.0"
latlong2:
dependency: "direct main"
description:
@ -1208,18 +1328,18 @@ packages:
dependency: "direct main"
description:
name: local_auth_android
sha256: "3bcd732dda7c75fcb7ddaef12e131230f53dcc8c00790d0d6efb3aa0fbbeda57"
sha256: e0e5b1ea247c5a0951c13a7ee13dc1beae69750e6a2e1910d1ed6a3cd4d56943
url: "https://pub.dev"
source: hosted
version: "1.0.37"
version: "1.0.38"
local_auth_darwin:
dependency: transitive
description:
name: local_auth_darwin
sha256: "33381a15b0de2279523eca694089393bb146baebdce72a404555d03174ebc1e9"
sha256: "959145a4cf6f0de745b9ec9ac60101270eb4c5b8b7c2a0470907014adc1c618d"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
local_auth_ios:
dependency: "direct main"
description:
@ -1384,10 +1504,10 @@ packages:
dependency: "direct main"
description:
name: modal_bottom_sheet
sha256: "3bba63c62d35c931bce7f8ae23a47f9a05836d8cb3c11122ada64e0b2f3d718f"
sha256: eac66ef8cb0461bf069a38c5eb0fa728cee525a531a8304bd3f7b2185407c67e
url: "https://pub.dev"
source: hosted
version: "3.0.0-pre"
version: "3.0.0"
motion_photos:
dependency: "direct main"
description:
@ -1555,10 +1675,10 @@ packages:
dependency: transitive
description:
name: path_provider_foundation
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.4.0"
path_provider_linux:
dependency: transitive
description:
@ -1603,10 +1723,10 @@ packages:
dependency: transitive
description:
name: permission_handler_android
sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474"
sha256: "8bb852cd759488893805c3161d0b2b5db55db52f773dbb014420b304055ba2c5"
url: "https://pub.dev"
source: hosted
version: "12.0.5"
version: "12.0.6"
permission_handler_apple:
dependency: transitive
description:
@ -1651,10 +1771,10 @@ packages:
dependency: "direct main"
description:
name: photo_manager
sha256: df594f989f0c31cdb3ed48f3d49cb9ffadf11cc3700d2c3460b1912c93432621
sha256: "1ddee48659025df5c80153a2e85c3fa0f5b5733ecffcda9769a9447da2c51352"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
version: "3.1.1"
photo_manager_image_provider:
dependency: transitive
description:
@ -1699,10 +1819,10 @@ packages:
dependency: "direct main"
description:
name: pointycastle
sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333"
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev"
source: hosted
version: "3.8.0"
version: "3.9.1"
polylabel:
dependency: transitive
description:
@ -1779,10 +1899,10 @@ packages:
dependency: "direct main"
description:
name: receive_sharing_intent
sha256: fe02f858ac9f8d44d62e1964dadded000bb48dea424085ed280d542a61c4e8ba
sha256: f127989f8662ea15e193bd1e10605e5a0ab6bb92dffd51f3ce002feb0ce24c93
url: "https://pub.dev"
source: hosted
version: "1.7.0"
version: "1.8.0"
rxdart:
dependency: transitive
description:
@ -1859,18 +1979,18 @@ packages:
dependency: "direct main"
description:
name: sentry
sha256: fe99a06970b909a491b7f89d54c9b5119772e3a48a400308a6e129625b333f5b
sha256: "57514bc72d441ffdc463f498d6886aa586a2494fa467a1eb9d649c28010d7ee3"
url: "https://pub.dev"
source: hosted
version: "7.19.0"
version: "7.20.2"
sentry_flutter:
dependency: "direct main"
description:
name: sentry_flutter
sha256: fc013d4a753447320f62989b1871fdc1f20c77befcc8be3e38774dd7402e7a62
sha256: "9723d58470ca43a360681ddd26abb71ca7b815f706bc8d3747afd054cf639ded"
url: "https://pub.dev"
source: hosted
version: "7.19.0"
version: "7.20.2"
share_plus:
dependency: "direct main"
description:
@ -1907,10 +2027,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
url: "https://pub.dev"
source: hosted
version: "2.3.5"
version: "2.4.0"
shared_preferences_linux:
dependency: transitive
description:
@ -2032,18 +2152,18 @@ packages:
dependency: "direct main"
description:
name: sqflite
sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.3.3+1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5"
sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
version: "2.5.4"
sqflite_migration:
dependency: "direct main"
description:
@ -2056,18 +2176,18 @@ packages:
dependency: transitive
description:
name: sqlite3
sha256: "072128763f1547e3e9b4735ce846bfd226d68019ccda54db4cd427b12dfdedc9"
sha256: b384f598b813b347c5a7e5ffad82cbaff1bec3d1561af267041e66f6f0899295
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.3"
sqlite3_flutter_libs:
dependency: "direct main"
description:
name: sqlite3_flutter_libs
sha256: d6c31c8511c441d1f12f20b607343df1afe4eddf24a1cf85021677c8eea26060
sha256: fb2a106a2ea6042fe57de2c47074cc31539a941819c91e105b864744605da3f5
url: "https://pub.dev"
source: hosted
version: "0.5.20"
version: "0.5.21"
sqlite_async:
dependency: "direct main"
description:
@ -2192,10 +2312,10 @@ packages:
dependency: transitive
description:
name: timezone
sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0"
sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5
url: "https://pub.dev"
source: hosted
version: "0.9.2"
version: "0.9.3"
timing:
dependency: transitive
description:
@ -2204,6 +2324,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
transparent_image:
dependency: transitive
description:
name: transparent_image
sha256: e8991d955a2094e197ca24c645efec2faf4285772a4746126ca12875e54ca02f
url: "https://pub.dev"
source: hosted
version: "2.0.1"
tuple:
dependency: "direct main"
description:
@ -2296,10 +2424,10 @@ packages:
dependency: transitive
description:
name: url_launcher_ios
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
url: "https://pub.dev"
source: hosted
version: "6.2.5"
version: "6.3.0"
url_launcher_linux:
dependency: transitive
description:
@ -2312,10 +2440,10 @@ packages:
dependency: transitive
description:
name: url_launcher_macos
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.2.0"
url_launcher_platform_interface:
dependency: transitive
description:
@ -2328,10 +2456,10 @@ packages:
dependency: transitive
description:
name: url_launcher_web
sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d"
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.3.1"
url_launcher_windows:
dependency: transitive
description:
@ -2356,6 +2484,15 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
video_editor:
dependency: "direct main"
description:
path: "."
ref: HEAD
resolved-ref: "1eeb18e2b1ce36bd8ca70178c0d4b485e9982257"
url: "https://github.com/prateekmedia/video_editor.git"
source: git
version: "3.0.0"
video_player:
dependency: "direct main"
description:
@ -2369,18 +2506,18 @@ packages:
dependency: transitive
description:
name: video_player_android
sha256: "821cff3446bbde255e8d03c12fe1f9810c69fee2c26c394545b13d824ba63c2e"
sha256: "134e1ad410d67e18a19486ed9512c72dfc6d8ffb284d0e8f2e99e903d1ba8fa3"
url: "https://pub.dev"
source: hosted
version: "2.4.13"
version: "2.4.14"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
sha256: "00c49b1d68071341397cf760b982c1e26ed9232464c8506ee08378a5cca5070d"
sha256: d1e9a824f2b324000dc8fb2dcb2a3285b6c1c7c487521c63306cc5b394f68a7c
url: "https://pub.dev"
source: hosted
version: "2.5.7"
version: "2.6.1"
video_player_platform_interface:
dependency: transitive
description:
@ -2393,10 +2530,10 @@ packages:
dependency: transitive
description:
name: video_player_web
sha256: "34beb3a07d4331a24f7e7b2f75b8e2b103289038e07e65529699a671b6a6e2cb"
sha256: "41245cef5ef29c4585dbabcbcbe9b209e34376642c7576cabf11b4ad9289d6e4"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
version: "2.3.0"
video_thumbnail:
dependency: "direct main"
description:
@ -2433,18 +2570,18 @@ packages:
dependency: "direct main"
description:
name: wakelock_plus
sha256: f268ca2116db22e57577fb99d52515a24bdc1d570f12ac18bb762361d43b043d
sha256: "104d94837bb28c735894dcd592877e990149c380e6358b00c04398ca1426eed4"
url: "https://pub.dev"
source: hosted
version: "1.1.4"
version: "1.2.1"
wakelock_plus_platform_interface:
dependency: transitive
description:
name: wakelock_plus_platform_interface
sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385"
sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.2.1"
wallpaper_manager_flutter:
dependency: "direct main"
description:
@ -2473,10 +2610,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.5"
webdriver:
dependency: transitive
description:
@ -2505,26 +2642,26 @@ packages:
dependency: "direct main"
description:
name: widgets_to_image
sha256: e32c7b77267c01d319dc97333d4f3d894e9d81c8b3a408fd33862fa7775ee398
sha256: ed97b986af380a7eb9662b727d7ac610c3862c50bdc950346deea7a7eba12a84
url: "https://pub.dev"
source: hosted
version: "0.0.2"
version: "0.0.3"
win32:
dependency: transitive
description:
name: win32
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
url: "https://pub.dev"
source: hosted
version: "5.2.0"
version: "5.5.0"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a"
sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.1.3"
wkt_parser:
dependency: transitive
description:

View file

@ -12,7 +12,7 @@ description: ente photos application
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.8.96+616
version: 0.8.98+618
publish_to: none
environment:
@ -61,6 +61,7 @@ dependencies:
extended_image: ^8.1.1
fade_indexed_stack: ^0.2.2
fast_base58: ^0.2.1
ffmpeg_kit_flutter_min: ^6.0.3
figma_squircle: ^0.5.3
file_saver:
# Use forked version till this PR is merged: https://github.com/incrediblezayed/file_saver/pull/87
@ -90,6 +91,7 @@ dependencies:
flutter_sodium: ^0.2.0
flutter_staggered_grid_view: ^0.6.2
fluttertoast: ^8.0.6
fraction: ^5.0.2
freezed_annotation: ^2.4.1
google_nav_bar: ^5.0.5
home_widget: ^0.5.0
@ -97,6 +99,7 @@ dependencies:
http: ^1.1.0
image: ^4.0.17
image_editor: ^1.3.0
image_picker: ^1.1.1
in_app_purchase: ^3.0.7
intl: ^0.18.0
json_annotation: ^4.8.0
@ -159,6 +162,9 @@ dependencies:
uni_links: ^0.5.1
url_launcher: ^6.0.3
uuid: ^3.0.7
video_editor:
git:
url: https://github.com/prateekmedia/video_editor.git
video_player:
git:
url: https://github.com/ente-io/packages.git