use media_gallery plugin
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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,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
@@ -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
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user