use photo manager

This commit is contained in:
Salvatore Giordano
2020-11-26 17:14:30 +01:00
parent 953058e325
commit 5ac0c60d6f
6 changed files with 159 additions and 125 deletions
+6 -6
View File
@@ -108,8 +108,6 @@ PODS:
- GoogleUtilities/Logger
- image_picker (0.0.1):
- Flutter
- media_gallery (0.0.1):
- Flutter
- nanopb (1.30906.0):
- nanopb/decode (= 1.30906.0)
- nanopb/encode (= 1.30906.0)
@@ -119,6 +117,8 @@ PODS:
- Flutter
- "permission_handler (5.0.1+1)":
- Flutter
- photo_manager (0.0.1):
- Flutter
- PromisesObjC (1.2.11)
- Protobuf (3.13.0)
- SDWebImage (5.10.0):
@@ -171,9 +171,9 @@ DEPENDENCIES:
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
- media_gallery (from `.symlinks/plugins/media_gallery/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
@@ -226,12 +226,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
image_picker:
:path: ".symlinks/plugins/image_picker/ios"
media_gallery:
:path: ".symlinks/plugins/media_gallery/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
permission_handler:
:path: ".symlinks/plugins/permission_handler/ios"
photo_manager:
:path: ".symlinks/plugins/photo_manager/ios"
shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios"
sqflite:
@@ -269,10 +269,10 @@ SPEC CHECKSUMS:
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09
media_gallery: 834a04455a476b975c280aa1f24ed2853dfe36de
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
permission_handler: eac8e15b4a1a3fba55b761d19f3f4e6b005d15b6
photo_manager: f7c619c2cc8c2adb8d85c63363babac477de9c67
PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
SDWebImage: 9169792e9eec3e45bba2a0c02f74bf8bd922d1ee
+2 -2
View File
@@ -327,9 +327,9 @@
"${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework",
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
"${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework",
"${BUILT_PRODUCTS_DIR}/media_gallery/media_gallery.framework",
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
"${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework",
"${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework",
"${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework",
@@ -359,9 +359,9 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_gallery.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework",
+1 -1
View File
@@ -1,6 +1,6 @@
name: example
description: A new Flutter project.
version: 1.0.77+79
version: 1.0.78+80
environment:
sdk: ">=2.2.2 <3.0.0"
+140 -106
View File
@@ -1,11 +1,14 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:media_gallery/media_gallery.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'dart:ui' as ui;
class MediaListView extends StatefulWidget {
final List<String> selectedIds;
final void Function(Media media) onSelect;
final void Function(AssetEntity media) onSelect;
const MediaListView({
Key key,
@@ -17,88 +20,94 @@ class MediaListView extends StatefulWidget {
}
class _MediaListViewState extends State<MediaListView> {
final _media = <Media>[];
final _media = <AssetEntity>[];
final ScrollController _scrollController = ScrollController();
int _currentPage = 0;
bool _endPagination = false;
@override
Widget build(BuildContext context) {
return GridView.builder(
itemCount: _media.length,
controller: _scrollController,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
cacheExtent: 1000,
itemBuilder: (
context,
position,
) {
final media = _media.elementAt(position);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0),
child: InkWell(
child: Stack(
children: [
AspectRatio(
aspectRatio: 1.0,
child: FadeInImage(
fadeInDuration: Duration(milliseconds: 300),
placeholder: AssetImage(
'images/placeholder.png',
package: 'stream_chat_flutter',
return LazyLoadScrollView(
onEndOfPage: () {
_getMedia();
},
child: GridView.builder(
itemCount: _media.length,
controller: _scrollController,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
cacheExtent: 1000,
itemBuilder: (
context,
position,
) {
final media = _media.elementAt(position);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0),
child: InkWell(
child: Stack(
children: [
AspectRatio(
aspectRatio: 1.0,
child: FadeInImage(
fadeInDuration: Duration(milliseconds: 300),
placeholder: AssetImage(
'images/placeholder.png',
package: 'stream_chat_flutter',
),
image: MediaThumbnailProvider(
media: media,
),
fit: BoxFit.cover,
),
image: MediaThumbnailProvider(
media: media,
highQuality: true,
),
fit: BoxFit.cover,
),
),
Positioned.fill(
child: IgnorePointer(
child: AnimatedOpacity(
duration: Duration(milliseconds: 300),
opacity: widget.selectedIds.any((id) => id == media.id)
? 1.0
: 0.0,
child: Container(
color: Colors.black.withOpacity(0.5),
alignment: Alignment.topRight,
padding: const EdgeInsets.only(
top: 8,
right: 8,
),
child: CircleAvatar(
radius: 12,
backgroundColor: Colors.white,
child: StreamSvgIcon.check(
size: 24,
color: Colors.black,
Positioned.fill(
child: IgnorePointer(
child: AnimatedOpacity(
duration: Duration(milliseconds: 300),
opacity: widget.selectedIds.any((id) => id == media.id)
? 1.0
: 0.0,
child: Container(
color: Colors.black.withOpacity(0.5),
alignment: Alignment.topRight,
padding: const EdgeInsets.only(
top: 8,
right: 8,
),
child: CircleAvatar(
radius: 12,
backgroundColor: Colors.white,
child: StreamSvgIcon.check(
size: 24,
color: Colors.black,
),
),
),
),
),
),
),
if (media.mediaType == MediaType.video)
Positioned(
left: 8,
bottom: 10,
child: SvgPicture.asset(
'svgs/video_call_icon.svg',
package: 'stream_chat_flutter',
if (media.type == AssetType.video)
Positioned(
left: 8,
bottom: 10,
child: SvgPicture.asset(
'svgs/video_call_icon.svg',
package: 'stream_chat_flutter',
),
),
),
],
],
),
onTap: () {
if (widget.onSelect != null) {
widget.onSelect(media);
}
},
),
onTap: () {
if (widget.onSelect != null) {
widget.onSelect(media);
}
},
),
);
},
);
},
),
);
}
@@ -109,42 +118,67 @@ class _MediaListViewState extends State<MediaListView> {
}
void _getMedia() async {
final List<MediaCollection> collections =
await MediaGallery.listMediaCollections(
mediaTypes: [
MediaType.video,
MediaType.image,
],
);
final assetList = await PhotoManager.getAssetPathList(
hasAll: true,
).then((value) => value.singleWhere((element) => element.isAll));
if (collections.isEmpty) {
return;
final media = await assetList.getAssetListPaged(_currentPage, 50);
if (media.isEmpty) {
setState(() {
_endPagination = true;
});
} else {
setState(() {
_media.addAll(media);
});
}
final collection = collections.firstWhere(
(element) => element.isAllCollection,
orElse: () => collections.first,
);
final videoPage = await collection.getMedias(
mediaType: MediaType.video,
take: 500,
);
final imagePage = await collection.getMedias(
mediaType: MediaType.image,
take: 500,
);
final allItems = [
...videoPage.items,
...imagePage.items,
]..sort((
a,
b,
) =>
b.creationDate.compareTo(a.creationDate));
setState(() {
_media.addAll(allItems);
});
++_currentPage;
}
}
class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
const MediaThumbnailProvider({
@required this.media,
}) : assert(media != null);
final AssetEntity media;
@override
ImageStreamCompleter load(key, decode) {
return MultiFrameImageStreamCompleter(
codec: _loadAsync(key, decode),
scale: 1.0,
informationCollector: () sync* {
yield ErrorDescription('Id: ${media?.id}');
},
);
}
Future<ui.Codec> _loadAsync(
MediaThumbnailProvider key, DecoderCallback decode) async {
assert(key == this);
final bytes = await media.thumbData;
if (bytes.isEmpty) return null;
return await decode(bytes);
}
@override
Future<MediaThumbnailProvider> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture<MediaThumbnailProvider>(this);
}
@override
bool operator ==(dynamic other) {
if (other.runtimeType != runtimeType) return false;
final MediaThumbnailProvider typedOther = other;
return media?.id == typedOther.media?.id;
}
@override
int get hashCode => media?.id?.hashCode ?? 0;
@override
String toString() => '$runtimeType("${media?.id}")';
}
+9 -8
View File
@@ -10,9 +10,9 @@ import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:http_parser/http_parser.dart' as httpParser;
import 'package:image_picker/image_picker.dart';
import 'package:media_gallery/media_gallery.dart';
import 'package:mime/mime.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/compress_video_service.dart';
import 'package:stream_chat_flutter/src/media_list_view.dart';
@@ -845,7 +845,7 @@ class MessageInputState extends State<MessageInput> {
}
}
void _addAttachment(Media medium) async {
void _addAttachment(AssetEntity medium) async {
final attachment = _SendingAttachment(
id: medium.id,
);
@@ -853,16 +853,16 @@ class MessageInputState extends State<MessageInput> {
setState(() {
_attachments.add(attachment);
});
final mediaFile = await medium.getFile();
final mediaFile = await medium.file;
var file = PlatformFile(
path: mediaFile.path,
size: (await mediaFile.length()) ~/ 1024,
size: ((await mediaFile.length()) / 1024).ceil(),
bytes: mediaFile.readAsBytesSync(),
);
if (file.size > _kMaxAttachmentSize) {
if (medium.mediaType == MediaType.video) {
if (medium.type == AssetType.video) {
final mediaInfo = await CompressVideoService.compressVideo(file.path);
if (mediaInfo.filesize / (1024 * 1024) > _kMaxAttachmentSize) {
@@ -902,18 +902,18 @@ class MessageInputState extends State<MessageInput> {
..file = file
..attachment = Attachment(
localUri: file.path != null ? Uri.parse(file.path) : null,
type: medium.mediaType == MediaType.image ? 'image' : 'video',
type: medium.type == AssetType.image ? 'image' : 'video',
);
});
final url = await _uploadAttachment(
file,
medium.mediaType == MediaType.image
medium.type == AssetType.image
? DefaultAttachmentTypes.image
: DefaultAttachmentTypes.video,
channel);
final fileType = medium.mediaType == MediaType.image
final fileType = medium.type == AssetType.image
? DefaultAttachmentTypes.image
: DefaultAttachmentTypes.video;
@@ -936,6 +936,7 @@ class MessageInputState extends State<MessageInput> {
setState(() {
_attachments.remove(attachment);
});
print(e);
print(s);
Scaffold.of(context).showSnackBar(
SnackBar(
+1 -2
View File
@@ -38,8 +38,7 @@ dependencies:
flutter_slidable: ^0.5.4
carousel_slider: ^2.2.1
clipboard: ^0.1.2+8
media_gallery:
git: https://github.com/imtoori/media_gallery.git
photo_manager: ^0.5.8
permission_handler: ^5.0.1+1
transparent_image: ^1.0.0
ezanimation: ^0.4.1