feat: Added download and sharing of images

This commit is contained in:
Deven Joshi
2020-11-20 16:36:29 +05:30
parent fbb1d52db9
commit 68e9f98b7f
6 changed files with 73 additions and 19 deletions
@@ -6,6 +6,7 @@
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"/>
<application <application
android:name=".Application" android:name=".Application"
android:label="ChatSample" android:label="ChatSample"
+2
View File
@@ -112,6 +112,8 @@ class _FullScreenImageState extends State<FullScreenImage>
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
message: widget.message, message: widget.message,
urls: widget.urls,
currentIndex: _currentPage,
), ),
ImageFooter( ImageFooter(
currentPage: _currentPage, currentPage: _currentPage,
+11 -3
View File
@@ -1,6 +1,7 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import '../stream_chat_flutter.dart'; import '../stream_chat_flutter.dart';
import 'stream_icons.dart'; import 'stream_icons.dart';
@@ -9,8 +10,11 @@ class ImageActionsModal extends StatelessWidget {
final Message message; final Message message;
final String userName; final String userName;
final String sentAt; final String sentAt;
final List<String> urls;
final currentIndex;
ImageActionsModal({this.message, this.userName, this.sentAt}); ImageActionsModal(
{this.message, this.userName, this.sentAt, this.urls, this.currentIndex});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -112,8 +116,12 @@ class ImageActionsModal extends StatelessWidget {
Navigator.pop(context); Navigator.pop(context);
Navigator.pop(context); Navigator.pop(context);
}), }),
_buildButton( _buildButton(context, 'Save Image', StreamIcons.save_1,
context, 'Save Image', StreamIcons.save_1, () {}), () async {
await GallerySaver.saveImage(
urls[currentIndex].split('?')[0]);
Navigator.pop(context);
}),
_buildButton(context, 'Copy', StreamIcons.copy, () {}), _buildButton(context, 'Copy', StreamIcons.copy, () {}),
if (StreamChat.of(context).user.id == message.user.id) if (StreamChat.of(context).user.id == message.user.id)
_buildButton(context, 'Delete', StreamIcons.delete, _buildButton(context, 'Delete', StreamIcons.delete,
+49 -15
View File
@@ -1,7 +1,12 @@
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:typed_data';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/back_button.dart'; import 'package:stream_chat_flutter/src/back_button.dart';
import 'package:stream_chat_flutter/src/channel_info.dart'; import 'package:stream_chat_flutter/src/channel_info.dart';
@@ -61,6 +66,7 @@ class _ImageFooterState extends State<ImageFooter> {
TextEditingController _messageController = TextEditingController(); TextEditingController _messageController = TextEditingController();
List<User> _selectedUsers = []; List<User> _selectedUsers = [];
bool _loading = false;
@override @override
void initState() { void initState() {
@@ -311,7 +317,8 @@ class _ImageFooterState extends State<ImageFooter> {
_selectedUsers _selectedUsers
.remove(user); .remove(user);
} else { } else {
_selectedUsers.add(user); _selectedUsers
.add(user);
} }
modalSetState(() {}); modalSetState(() {});
}, },
@@ -368,14 +375,23 @@ class _ImageFooterState extends State<ImageFooter> {
margin: EdgeInsets.symmetric( margin: EdgeInsets.symmetric(
horizontal: 8.0, horizontal: 8.0,
), ),
child: SizedBox.expand( child: Material(
child: Center( child: InkWell(
child: Text( onTap: () async {
'Save to Photos', await GallerySaver.saveImage(
style: TextStyle( widget.urls[widget.currentPage].split('?')[0]);
color: StreamChatTheme.of(modalContext) Navigator.pop(context);
.accentColor, },
fontWeight: FontWeight.bold, child: SizedBox.expand(
child: Center(
child: Text(
'Save to Photos',
style: TextStyle(
color: StreamChatTheme.of(modalContext)
.accentColor,
fontWeight: FontWeight.bold,
),
),
), ),
), ),
), ),
@@ -493,7 +509,14 @@ class _ImageFooterState extends State<ImageFooter> {
color: Colors.black, color: Colors.black,
), ),
iconSize: 24.0, iconSize: 24.0,
onPressed: () {}, onPressed: () async {
var url = widget.urls[widget.currentPage];
var type = url?.split('?')?.first?.split('.')?.last ?? 'jpg';
var request = await HttpClient().getUrl(Uri.parse(url));
var response = await request.close();
var bytes = await consolidateHttpClientResponseBytes(response);
await Share.file('File', 'image.$type', bytes, 'image/$type');
},
), ),
), ),
], ],
@@ -507,7 +530,12 @@ class _ImageFooterState extends State<ImageFooter> {
child: Container( child: Container(
color: Colors.white, color: Colors.white,
height: 56.0, height: 56.0,
child: Row( child: _loading ? Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CircularProgressIndicator(),
),
) : Row(
children: [ children: [
Expanded( Expanded(
child: Padding( child: Padding(
@@ -553,8 +581,14 @@ class _ImageFooterState extends State<ImageFooter> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: InkWell( child: InkWell(
onTap: () { onTap: () async {
sendMessage(); modalSetState(() {
_loading = true;
});
await sendMessage();
modalSetState(() {
_loading = false;
});
}, },
child: Transform.rotate( child: Transform.rotate(
angle: -pi / 2, angle: -pi / 2,
@@ -607,7 +641,7 @@ class _ImageFooterState extends State<ImageFooter> {
} }
/// Sends the current message /// Sends the current message
void sendMessage() async { Future sendMessage() async {
var text = _messageController.text.trim(); var text = _messageController.text.trim();
final attachments = widget.message.attachments; final attachments = widget.message.attachments;
@@ -616,7 +650,7 @@ class _ImageFooterState extends State<ImageFooter> {
final client = StreamChat.of(context).client; final client = StreamChat.of(context).client;
for(var user in _selectedUsers) { for (var user in _selectedUsers) {
var c = client.channel('messaging', extraData: { var c = client.channel('messaging', extraData: {
'members': [ 'members': [
user.id, user.id,
+7
View File
@@ -30,10 +30,15 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
final String userName; final String userName;
final String sentAt; final String sentAt;
final List<String> urls;
final currentIndex;
/// Creates a channel header /// Creates a channel header
ImageHeader({ ImageHeader({
Key key, Key key,
this.message, this.message,
this.urls,
this.currentIndex,
this.showBackButton = true, this.showBackButton = true,
this.onBackPressed, this.onBackPressed,
this.onTitleTap, this.onTitleTap,
@@ -117,6 +122,8 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
userName: userName, userName: userName,
sentAt: sentAt, sentAt: sentAt,
message: message, message: message,
urls: urls,
currentIndex: currentIndex,
), ),
); );
}); });
+2
View File
@@ -35,6 +35,8 @@ 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
gallery_saver: ^2.0.1
esys_flutter_share: ^1.0.2
flutter: flutter:
assets: assets: