Skip to content

Commit

Permalink
✨ Video support (#50)
Browse files Browse the repository at this point in the history
* ♻️ add basic video player in crop_viewer

* ✨ show videos fake cropped in result view

* ♻️ update video widgets

* ♻️ show video in crop view

* 🐛 fix always hidden crop ratio button

* ✨ show crop video preview

* 🐛 fix `InstaAssetCropTransform`

* 🐛 fix `InstaAssetCropTransform` to fit aspect ratio

* 💄 fix crop loader

* 💄 fix video thumbnail size

* ♻️ export photo_manger

* 🚨 remove import

* 💄 improve placeholders and image loading/error

* 💄 fix cropview loading & error widgets

* ✨ add `skipCropOnComplete` options builder param

* 🐛 fix camera example crop view size issue

* ♻️ update CropResult page in example

* ✨ add `previewThumbnailSize` config parameter

* ♻️ update camera examples to supports video

* 🐛 fix camera example asset from picture broken size

* ➕ use git dependency

* ♻️ move cropDelegate into InstaAssetPickerConfig

* ✨ new `InstaAssetsExportData` class

* ✨ add `ffmpegCrop` and `ffmpegScale`, add ffmpeg in example

* ♻️ improve example export progress with ffmpeg statistics

* 🐛 fix camera video_player exception

* 🐛 fix iCloud video loading

* 💄 fix iCloud loading size

* 🐛 fix saving crop param on dispose

* 🐛 fix camera examples

* 📝 update doc

* ⬆️ use latest insta_assets_crop

* 📝 update changelog, readme and migration guide

* 📝 update doc

* 📝 update doc

* 📝 update doc

* 📝 update doc
  • Loading branch information
LeGoffMael authored Jul 14, 2024
1 parent 72247c0 commit 1bb91e3
Show file tree
Hide file tree
Showing 28 changed files with 1,628 additions and 364 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
# Changelog

## 3.0.0-dev.1

### Features

- Video support [#50](https://github.com/LeGoffMael/insta_assets_picker/pull/50)
- video processing must be handled manually
- new `requestType` param set to `RequestType.common` by default.
- new `previewThumbnailSize` & `skipCropOnComplete` config parameters.
- new `InstaAssetCropTransform` widget to preview the cropped asset.
- Crop view initialization time is now much faster.

### [Breaking changes](MIGRATION_GUIDE.md#3.0.0-dev.1)

- new `InstaAssetPickerConfig` config class to provide picker configuration [#48](https://github.com/LeGoffMael/insta_assets_picker/pull/48)
- new `gridThumbnailSize`, `themeColor` & `selectPredicate` parameters
- updated `InstaAssetsExportDetails` class, crop file are now nullable and all the crop parameters are provided in a new class called `InstaAssetsExportData`.

## 2.3.1

- bump `wechat_assets_picker` to 9.1.0
Expand Down
46 changes: 46 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Migration Guide

This document gathered all breaking changes and migrations requirement between major versions.

## 3.0.0-dev.1

### InstaAssetPickerConfig

The picker configuration parameters must not be provided into a `InstaAssetPickerConfig` class in `pickerConfig`

```diff
InstaAssetPicker.pickAssets(
context,
- title: 'Example title',
- pickerTheme: widget.getPickerTheme(context),
+ pickerConfig: InstaAssetPickerConfig(
+ title: 'Example title',
+ pickerTheme: widget.getPickerTheme(context),
+ ),
)
```

The picker is now showing image and video assets by default. To show only images, you can change the `requestType` param.
```diff
InstaAssetPicker.pickAssets(
context,
+ requestType: RequestType.image
)
```


The `InstaAssetsExportDetails` was also updated.
The cropped files are now nullable, an all the crop parameters are returned in a new class called `InstaAssetsExportData`.

```diff
+ class InstaAssetsExportData {
+ final File? croppedFile;
+ final InstaAssetsCropData selectedData;
+ }

InstaAssetsExportDetails {
- final List<File> croppedFiles;
+ final List<InstaAssetsExportData> data;
```


110 changes: 65 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@
</p>


An image picker based on Instagram picker UI. It is using the powerful [flutter_wechat_assets_picker](https://pub.dev/packages/wechat_assets_picker)
An image (also with videos) picker based on Instagram picker UI. It is using the powerful [flutter_wechat_assets_picker](https://pub.dev/packages/wechat_assets_picker)
package to handle the picker and a custom version of [image_crop](https://pub.dev/packages/image_crop) for crop.

## 🚀 Features

- ✅ Instagram layout
- Scroll behaviors, animation
- Preview, select, unselect action logic
- ✅ Image and Video ([but not video processing](#video)) support
- ✅ Theme and language customization
- ✅ Multiple images pick (with maximum limit)
- ✅ Single image pick mode
- ✅ Multiple assets pick (with maximum limit)
- ✅ Single asset pick mode
- ✅ Restore state of picker after pop
- ✅ Select aspect ratios to crop all images with (default to 1:1 & 4:5)
- ✅ Crop all images at once and receive a stream with a progress value
- ✅ Select aspect ratios to crop all assets with (default to 1:1 & 4:5)
- ✅ Crop all image assets at once and receive a stream with a progress value
- ✅ Prepend or append a custom item in the assets list
- ✅ Add custom action buttons
- ❌ Videos are not supported

## 📸 Screenshots

Expand All @@ -58,7 +58,9 @@ For more details check out the [example](https://github.com/LeGoffMael/insta_ass
```dart
Future<List<AssetEntity>?> callPicker() => InstaAssetPicker.pickAssets(
context,
title: 'Select images',
pickerConfig: InstaAssetPickerConfig(
title: 'Select assets',
),
maxAssets: 10,
onCompleted: (Stream<InstaAssetsExportDetails> stream) {
// TODO : handle crop stream result
Expand All @@ -73,13 +75,19 @@ Future<List<AssetEntity>?> callPicker() => InstaAssetPicker.pickAssets(

Fields in `InstaAssetsExportDetails`:

| Name | Type | Description |
| -------------- | ------------------- | ------------------------------------------------------- |
| croppedFiles | `List<File>` | List of all cropped files |
| selectedAssets | `List<AssetEntity>` | Selected assets without crop |
| aspectRatio | `double` | Selected aspect ratio (1 or 4/5) |
| progress | `double` | Progress indicator of the exportation (between 0 and 1) |
| Name | Type | Description |
| -------------- | ----------------------------- | --------------------------------------------------------------------- |
| data | `List<InstaAssetsExportData>` | Contains the selected assets, crop parameters and possible crop file. |
| selectedAssets | `List<AssetEntity>` | Selected assets without crop |
| aspectRatio | `double` | Selected aspect ratio (1 or 4/5) |
| progress | `double` | Progress indicator of the exportation (between 0 and 1) |

Fields in `InstaAssetsExportData`:

| Name | Type | Description |
| ------------ | --------------------- | ------------------------------------------------------------------ |
| croppedFile | `File?` | The cropped file. Can be null if video or if choose to skip crop. |
| selectedData | `InstaAssetsCropData` | The selected asset and it's crop parameter (area, scale, ratio...) |

### Picker configuration

Expand All @@ -98,24 +106,26 @@ Most of the components of the picker can be customized using theme.
final theme = InstaAssetPicker.themeData(Theme.of(context).primaryColor);
InstaAssetPicker.pickAssets(
context,
pickerTheme: theme.copyWith(
canvasColor: Colors.black, // body background color
splashColor: Color.grey, // ontap splash color
colorScheme: theme.colorScheme.copyWith(
background: Colors.black87, // albums list background color
),
appBarTheme: theme.appBarTheme.copyWith(
backgroundColor: Colors.black, // app bar background color
titleTextStyle: Theme.of(context)
.appBarTheme
.titleTextStyle
?.copyWith(color: Colors.white), // change app bar title text style to be like app theme
),
// edit `confirm` button style
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: Colors.blue,
disabledForegroundColor: Colors.red,
pickerConfig: InstaAssetPickerConfig(
pickerTheme: theme.copyWith(
canvasColor: Colors.black, // body background color
splashColor: Color.grey, // ontap splash color
colorScheme: theme.colorScheme.copyWith(
background: Colors.black87, // albums list background color
),
appBarTheme: theme.appBarTheme.copyWith(
backgroundColor: Colors.black, // app bar background color
titleTextStyle: Theme.of(context)
.appBarTheme
.titleTextStyle
?.copyWith(color: Colors.white), // change app bar title text style to be like app theme
),
// edit `confirm` button style
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: Colors.blue,
disabledForegroundColor: Colors.red,
),
),
),
),
Expand All @@ -126,24 +136,26 @@ InstaAssetPicker.pickAssets(
### Crop customization

You can set the list of crop aspect ratios available.
You can also set the preferred size, for the cropped images.
You can also set the preferred size, for the cropped assets.

```dart
InstaAssetPicker.pickAssets(
context,
cropDelegate: InstaAssetCropDelegate(
// allows you to set the preferred size used when cropping the image.
// the final size will depends on the scale used when cropping.
preferredSize: 1080,
cropRatios: [
// - allow you to set the list of aspect ratios selectable,
// the default values are [1/1, 4/5] like instagram.
// - if you want to disable cropping, you can set only one parameter,
// in this case, the "crop" button will not be displayed (#10).
// - if the value of cropRatios is different than the default value,
// the "crop" button will display the selected ratio value (i.e.: 1:1)
// instead of unfold arrows.
]),
pickerConfig: InstaAssetPickerConfig(
cropDelegate: InstaAssetCropDelegate(
// allows you to set the preferred size used when cropping the asset.
// the final size will depends on the scale used when cropping.
preferredSize: 1080,
cropRatios: [
// - allow you to set the list of aspect ratios selectable,
// the default values are [1/1, 4/5] like instagram.
// - if you want to disable cropping, you can set only one parameter,
// in this case, the "crop" button will not be displayed (#10).
// - if the value of cropRatios is different than the default value,
// the "crop" button will display the selected ratio value (i.e.: 1:1)
// instead of unfold arrows.
]),
),
onCompleted: (_) {},
);
```
Expand All @@ -158,6 +170,14 @@ However, since version `2.0.0`, it is now possible to trigger this action using
The ability to take a photo from the camera must be handled on your side, but the picker is now able to refresh the list and select the new photo.
New [examples](https://github.com/LeGoffMael/insta_assets_picker/tree/main/example/lib/pages/camera) have been written to show how to manage this process with the [camera](https://pub.dev/packages/camera) or [wechat_camera_picker](https://pub.dev/packages/wechat_camera_picker) package.

### Video

Video are now supported on version `3.0.0`. You can pick a video asset and select the crop area directly in the picker.
However, as video processing is a heavy operation it is not handled by this package.
Which means you must handle it yourself. If you want to preview the video result, you can use the `InstaAssetCropTransform` which will transform the Image or VideoPlayer to fit the selected crop area.

The example app has been updated to support videos (+ camera recording) and shows [how to process the video](https://github.com/LeGoffMael/insta_assets_picker/tree/main/example/lib/post_provider.dart#L84) using [ffmpeg_kit_flutter](https://pub.dev/packages/ffmpeg_kit_flutter).

## ✨ Credit

This package is based on [flutter_wechat_assets_picker](https://pub.dev/packages/wechat_assets_picker) by [AlexV525](https://github.com/AlexV525) and [image_crop](https://pub.dev/packages/image_crop) by [lykhonis](https://github.com/lykhonis).
4 changes: 2 additions & 2 deletions example/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ linter:
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# since it is an example app only let's keep it simple
depend_on_referenced_packages: ignore

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
5 changes: 2 additions & 3 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.insta_assets_picker.example"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 21
// minSdkVersion 21
minSdkVersion 24 // sdk version needed for ffmpeg
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
Expand Down
3 changes: 3 additions & 0 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"/>

<!-- Optional: Enable haptic feeback -->
<uses-permission android:name="android.permission.VIBRATE" />

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
platform :ios, '12.1' # target required by ffmpeg

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down
18 changes: 17 additions & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
PODS:
- camera_avfoundation (0.0.1):
- Flutter
- ffmpeg-kit-ios-min (6.0)
- ffmpeg_kit_flutter_min (6.0.3):
- ffmpeg_kit_flutter_min/min (= 6.0.3)
- Flutter
- ffmpeg_kit_flutter_min/min (6.0.3):
- ffmpeg-kit-ios-min (= 6.0)
- Flutter
- Flutter (1.0.0)
- insta_assets_crop (0.0.1):
- Flutter
Expand All @@ -18,16 +25,23 @@ PODS:

DEPENDENCIES:
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
- ffmpeg_kit_flutter_min (from `.symlinks/plugins/ffmpeg_kit_flutter_min/ios`)
- Flutter (from `Flutter`)
- insta_assets_crop (from `.symlinks/plugins/insta_assets_crop/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- sensors_plus (from `.symlinks/plugins/sensors_plus/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)

SPEC REPOS:
trunk:
- ffmpeg-kit-ios-min

EXTERNAL SOURCES:
camera_avfoundation:
:path: ".symlinks/plugins/camera_avfoundation/ios"
ffmpeg_kit_flutter_min:
:path: ".symlinks/plugins/ffmpeg_kit_flutter_min/ios"
Flutter:
:path: Flutter
insta_assets_crop:
Expand All @@ -43,13 +57,15 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
camera_avfoundation: 759172d1a77ae7be0de08fc104cfb79738b8a59e
ffmpeg-kit-ios-min: 4e9a088f4ee9629435960b9d68e54848975f1931
ffmpeg_kit_flutter_min: 5eff47f4965bf9d1150e98961eb6129f5ae3f28c
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
insta_assets_crop: 46c0be4cbfe48cff466b6924ec93b77f656ebaa8
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
sensors_plus: 18a9b346c43e157da17d2c8e99def703f9efb9d8
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3

PODFILE CHECKSUM: c4c93c5f6502fe2754f48404d3594bf779584011
PODFILE CHECKSUM: e4638883b73f42d1731a85e8757b8cd858a2954c

COCOAPODS: 1.15.2
31 changes: 21 additions & 10 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:insta_assets_picker_demo/pages/stateless_pickers.dart';
import 'package:insta_assets_picker_demo/pages/camera/camera_picker.dart';
import 'package:insta_assets_picker_demo/pages/camera/wechat_camera_picker.dart';
import 'package:insta_assets_picker_demo/pages/restorable_picker.dart';
import 'package:insta_assets_picker_demo/post_provider.dart';
import 'package:insta_assets_picker_demo/widgets/insta_picker_interface.dart';
import 'package:insta_assets_picker_demo/widgets/post.dart';
import 'package:provider/provider.dart';

const kDefaultColor = Colors.deepPurple;

late List<CameraDescription> _cameras;

Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
_cameras = await availableCameras();
runApp(const MyApp());
}
void main() => runApp(
ChangeNotifierProvider(
create: (context) => PostProvider(),
child: const MyApp(),
),
);

class MyApp extends StatelessWidget {
const MyApp({super.key});
Expand Down Expand Up @@ -67,12 +68,22 @@ class PickersScreen extends StatelessWidget {
const SinglePicker(),
const MultiplePicker(),
const RestorablePicker(),
CameraPicker(camera: _cameras.first),
const CameraPicker(),
const WeChatCameraPicker(),
];

return Scaffold(
appBar: AppBar(title: const Text('Insta pickers')),
appBar: AppBar(
title: const Text('Insta pickers'),
actions: [
IconButton(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const PostsPage()),
),
icon: Icon(Icons.feed, semanticLabel: 'Feed'),
)
],
),
body: ListView.separated(
padding: const EdgeInsets.all(16),
itemBuilder: (BuildContext context, int index) {
Expand Down
Loading

0 comments on commit 1bb91e3

Please sign in to comment.