use media_gallery plugin

This commit is contained in:
Salvatore Giordano
2020-11-11 16:35:58 +01:00
parent ae0316fe4f
commit 42e746fed7
6 changed files with 83 additions and 58 deletions
@@ -6,10 +6,14 @@
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here. -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application <application
android:name=".Application" android:name=".Application"
android:label="ChatSample" android:label="ChatSample"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true"
>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
+8 -2
View File
@@ -38,7 +38,7 @@ PODS:
- Firebase/Messaging (6.33.0): - Firebase/Messaging (6.33.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseMessaging (~> 4.7.0) - FirebaseMessaging (~> 4.7.0)
- firebase_core (0.5.1): - firebase_core (0.5.2):
- Firebase/CoreOnly (~> 6.33.0) - Firebase/CoreOnly (~> 6.33.0)
- Flutter - Flutter
- firebase_messaging (7.0.3): - firebase_messaging (7.0.3):
@@ -113,6 +113,8 @@ PODS:
- nanopb/encode (1.30906.0) - nanopb/encode (1.30906.0)
- path_provider (0.0.1): - path_provider (0.0.1):
- Flutter - Flutter
- photo_gallery (0.0.1):
- Flutter
- PromisesObjC (1.2.11) - PromisesObjC (1.2.11)
- Protobuf (3.13.0) - Protobuf (3.13.0)
- SDWebImage (5.9.4): - SDWebImage (5.9.4):
@@ -163,6 +165,7 @@ DEPENDENCIES:
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`)
- photo_gallery (from `.symlinks/plugins/photo_gallery/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
@@ -214,6 +217,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/image_picker/ios" :path: ".symlinks/plugins/image_picker/ios"
path_provider: path_provider:
:path: ".symlinks/plugins/path_provider/ios" :path: ".symlinks/plugins/path_provider/ios"
photo_gallery:
:path: ".symlinks/plugins/photo_gallery/ios"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios" :path: ".symlinks/plugins/shared_preferences/ios"
sqflite: sqflite:
@@ -232,7 +237,7 @@ SPEC CHECKSUMS:
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
firebase_core: aa25a5dc6b492ecab37587c53d8420135f0cac90 firebase_core: 350ba329d1641211bc6183a3236893cafdacfea7
firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
@@ -250,6 +255,7 @@ SPEC CHECKSUMS:
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
photo_gallery: 9f95e57747cd22c10676ece3660d1ffe6c603ee5
PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
SDWebImage: b69257f4ab14e9b6a2ef53e910fdf914d8f757c1 SDWebImage: b69257f4ab14e9b6a2ef53e910fdf914d8f757c1
@@ -328,6 +328,7 @@
"${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework",
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
"${BUILT_PRODUCTS_DIR}/photo_gallery/photo_gallery.framework",
"${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework",
"${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework",
"${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework",
@@ -357,6 +358,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_gallery.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework",
+1 -1
View File
@@ -1,7 +1,7 @@
name: example name: example
description: A new Flutter project. description: A new Flutter project.
version: 1.0.43+45 version: 1.0.44+46
environment: environment:
sdk: ">=2.2.2 <3.0.0" sdk: ">=2.2.2 <3.0.0"
+64 -53
View File
@@ -8,15 +8,17 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:http_parser/http_parser.dart'; import 'package:http_parser/http_parser.dart' as httpParser;
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:media_gallery/media_gallery.dart';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
import 'package:photo_gallery/photo_gallery.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/message_list_view.dart';
import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart';
import 'package:substring_highlight/substring_highlight.dart'; import 'package:substring_highlight/substring_highlight.dart';
import 'package:transparent_image/transparent_image.dart';
import '../stream_chat_flutter.dart'; import '../stream_chat_flutter.dart';
import 'stream_channel.dart'; import 'stream_channel.dart';
@@ -181,7 +183,7 @@ class MessageInputState extends State<MessageInput> {
int _filePickerIndex = 0; int _filePickerIndex = 0;
double _filePickerSize = 250.0; double _filePickerSize = 250.0;
Tuple2<List<Medium>, List<dynamic>> _mediaData = Tuple2([], []); Iterable<Media> _media = [];
/// The editing controller passed to the input TextField /// The editing controller passed to the input TextField
TextEditingController textEditingController; TextEditingController textEditingController;
@@ -716,7 +718,7 @@ class MessageInputState extends State<MessageInput> {
switch (_filePickerIndex) { switch (_filePickerIndex) {
case 0: case 0:
return GridView.builder( return GridView.builder(
itemCount: _mediaData.item2.length, itemCount: _media.length,
gridDelegate: gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (context, position) { itemBuilder: (context, position) {
@@ -728,24 +730,29 @@ class MessageInputState extends State<MessageInput> {
children: [ children: [
AspectRatio( AspectRatio(
aspectRatio: 1.0, aspectRatio: 1.0,
child: Image.memory( child: FadeInImage(
_mediaData.item2[position], placeholder: MemoryImage(kTransparentImage),
fit: _mediaData.item1[position].height > image: MediaThumbnailProvider(
_mediaData.item1[position].width media: _media.elementAt(position),
? BoxFit.fitWidth ),
: BoxFit.fitHeight, fit: BoxFit.fill,
), ),
), ),
IgnorePointer( Positioned.fill(
child: AnimatedOpacity( child: IgnorePointer(
duration: Duration(milliseconds: 300), child: AnimatedOpacity(
opacity: _attachments.any((element) => duration: Duration(milliseconds: 300),
element.id == _mediaData.item1[position].id) opacity: _attachments.any((element) =>
? 1.0 element.id == _media.elementAt(position).id)
: 0.0, ? 1.0
child: Container( : 0.0,
color: Colors.black.withOpacity(0.5), child: Container(
child: Center( color: Colors.black.withOpacity(0.5),
alignment: Alignment.topRight,
padding: const EdgeInsets.only(
top: 8,
right: 8,
),
child: CircleAvatar( child: CircleAvatar(
maxRadius: 12.0, maxRadius: 12.0,
backgroundColor: Colors.white, backgroundColor: Colors.white,
@@ -762,11 +769,11 @@ class MessageInputState extends State<MessageInput> {
), ),
onTap: () { onTap: () {
if (!_attachments.any((element) => if (!_attachments.any((element) =>
element.id == _mediaData.item1[position].id)) { element.id == _media.elementAt(position).id)) {
_addAttachment(_mediaData.item1[position]); _addAttachment(_media.elementAt(position));
} else { } else {
_attachments.removeWhere((element) => _attachments.removeWhere((element) =>
element.id == _mediaData.item1[position].id); element.id == _media.elementAt(position).id);
setState(() {}); setState(() {});
} }
}, },
@@ -782,10 +789,10 @@ class MessageInputState extends State<MessageInput> {
} }
} }
void _addAttachment(Medium medium) async { void _addAttachment(Media medium) async {
var mediaFile = await PhotoGallery.getFile(mediumId: medium.id); final mediaFile = await medium.getFile();
var file = PlatformFile( final file = PlatformFile(
path: mediaFile.path, path: mediaFile.path,
bytes: mediaFile.readAsBytesSync(), bytes: mediaFile.readAsBytesSync(),
); );
@@ -803,7 +810,7 @@ class MessageInputState extends State<MessageInput> {
file: file, file: file,
attachment: Attachment( attachment: Attachment(
localUri: file.path != null ? Uri.parse(file.path) : null, localUri: file.path != null ? Uri.parse(file.path) : null,
type: medium.mediumType == MediumType.image ? 'image' : 'video', type: medium.mediaType == MediaType.image ? 'image' : 'video',
), ),
id: medium.id, id: medium.id,
); );
@@ -814,12 +821,12 @@ class MessageInputState extends State<MessageInput> {
final url = await _uploadAttachment( final url = await _uploadAttachment(
file, file,
medium.mediumType == MediumType.image medium.mediaType == MediaType.image
? DefaultAttachmentTypes.image ? DefaultAttachmentTypes.image
: DefaultAttachmentTypes.video, : DefaultAttachmentTypes.video,
channel); channel);
var fileType = medium.mediumType == MediumType.image final fileType = medium.mediaType == MediaType.image
? DefaultAttachmentTypes.image ? DefaultAttachmentTypes.image
: DefaultAttachmentTypes.video; : DefaultAttachmentTypes.video;
@@ -839,32 +846,28 @@ class MessageInputState extends State<MessageInput> {
} }
void _getAllMedia() async { void _getAllMedia() async {
var allAlbums = await PhotoGallery.listAlbums(mediumType: MediumType.image); final List<MediaCollection> collections =
var allVideoAlbums = await MediaGallery.listMediaCollections(mediaTypes: [
await PhotoGallery.listAlbums(mediumType: MediumType.video); MediaType.image,
List<Medium> resultList = []; MediaType.video,
List<List<dynamic>> resultThumbnailList = []; ]);
for (var album in allAlbums) { if (collections.isEmpty) {
var data = await album.listMedia(); return;
resultList.addAll(data.items);
} }
for (var album in allVideoAlbums) { final page = await collections
var data = await album.listMedia(); .firstWhere(
resultList.addAll(data.items); (element) => element.name == 'All',
} orElse: () => collections.first,
)
resultList.sort((a, b) => a.modifiedDate.compareTo(b.modifiedDate)); .getMedias(
resultList = resultList.toSet().toList(); take: 50,
);
for (var e in resultList) {
resultThumbnailList.add(await PhotoGallery.getThumbnail(mediumId: e.id));
}
print('page.items.length: ${page.items.length}');
setState(() { setState(() {
_mediaData = _media = page.items;
Tuple2<List<Medium>, List<dynamic>>(resultList, resultThumbnailList);
}); });
} }
@@ -1271,13 +1274,21 @@ class MessageInputState extends State<MessageInput> {
color: Color(0xFF000000).withAlpha(128), color: Color(0xFF000000).withAlpha(128),
), ),
), ),
onTap: () { onTap: () async {
if (_openFilePickerSection) { if (_openFilePickerSection) {
setState(() { setState(() {
_openFilePickerSection = false; _openFilePickerSection = false;
_filePickerSize = 250.0; _filePickerSize = 250.0;
}); });
} else { } else {
final status = await Permission.storage.request();
print('status: ${status}');
if (status.isDenied || status.isPermanentlyDenied) {
final res = await openAppSettings();
if (!res) {
return;
}
}
_getAllMedia(); _getAllMedia();
showAttachmentModal(); showAttachmentModal();
} }
@@ -1494,7 +1505,7 @@ class MessageInputState extends State<MessageInput> {
MultipartFile.fromBytes( MultipartFile.fromBytes(
bytes, bytes,
filename: filename, filename: filename,
contentType: MediaType.parse(lookupMimeType(filename)), contentType: httpParser.MediaType.parse(lookupMimeType(filename)),
), ),
); );
return res.file; return res.file;
@@ -1507,7 +1518,7 @@ class MessageInputState extends State<MessageInput> {
MultipartFile.fromBytes( MultipartFile.fromBytes(
bytes, bytes,
filename: filename, filename: filename,
contentType: MediaType.parse(lookupMimeType(filename)), contentType: httpParser.MediaType.parse(lookupMimeType(filename)),
), ),
); );
return res.file; return res.file;
+3 -1
View File
@@ -35,7 +35,9 @@ dependencies:
flutter_slidable: ^0.5.4 flutter_slidable: ^0.5.4
carousel_slider: ^2.2.1 carousel_slider: ^2.2.1
clipboard: ^0.1.2+8 clipboard: ^0.1.2+8
photo_gallery: ^0.3.0 media_gallery: ^0.1.5
permission_handler: ^5.0.1+1
transparent_image: ^1.0.0
flutter: flutter:
assets: assets: