diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
index a90d828e..ca0d2720 100644
--- a/example/android/app/src/main/AndroidManifest.xml
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
+
Navigator.of(context).pop();
},
message: widget.message,
+ urls: widget.urls,
+ currentIndex: _currentPage,
),
ImageFooter(
currentPage: _currentPage,
diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart
index 8b39737d..f07efcb6 100644
--- a/lib/src/image_actions_modal.dart
+++ b/lib/src/image_actions_modal.dart
@@ -1,6 +1,7 @@
import 'dart:ui';
import 'package:flutter/material.dart';
+import 'package:gallery_saver/gallery_saver.dart';
import '../stream_chat_flutter.dart';
import 'stream_icons.dart';
@@ -9,8 +10,11 @@ class ImageActionsModal extends StatelessWidget {
final Message message;
final String userName;
final String sentAt;
+ final List urls;
+ final currentIndex;
- ImageActionsModal({this.message, this.userName, this.sentAt});
+ ImageActionsModal(
+ {this.message, this.userName, this.sentAt, this.urls, this.currentIndex});
@override
Widget build(BuildContext context) {
@@ -112,8 +116,12 @@ class ImageActionsModal extends StatelessWidget {
Navigator.pop(context);
Navigator.pop(context);
}),
- _buildButton(
- context, 'Save Image', StreamIcons.save_1, () {}),
+ _buildButton(context, 'Save Image', StreamIcons.save_1,
+ () async {
+ await GallerySaver.saveImage(
+ urls[currentIndex].split('?')[0]);
+ Navigator.pop(context);
+ }),
_buildButton(context, 'Copy', StreamIcons.copy, () {}),
if (StreamChat.of(context).user.id == message.user.id)
_buildButton(context, 'Delete', StreamIcons.delete,
diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart
index 83960091..57119f8e 100644
--- a/lib/src/image_footer.dart
+++ b/lib/src/image_footer.dart
@@ -1,7 +1,12 @@
+import 'dart:io';
import 'dart:math';
+import 'dart:typed_data';
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:gallery_saver/gallery_saver.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/back_button.dart';
import 'package:stream_chat_flutter/src/channel_info.dart';
@@ -61,6 +66,7 @@ class _ImageFooterState extends State {
TextEditingController _messageController = TextEditingController();
List _selectedUsers = [];
+ bool _loading = false;
@override
void initState() {
@@ -311,7 +317,8 @@ class _ImageFooterState extends State {
_selectedUsers
.remove(user);
} else {
- _selectedUsers.add(user);
+ _selectedUsers
+ .add(user);
}
modalSetState(() {});
},
@@ -368,14 +375,23 @@ class _ImageFooterState extends State {
margin: EdgeInsets.symmetric(
horizontal: 8.0,
),
- child: SizedBox.expand(
- child: Center(
- child: Text(
- 'Save to Photos',
- style: TextStyle(
- color: StreamChatTheme.of(modalContext)
- .accentColor,
- fontWeight: FontWeight.bold,
+ child: Material(
+ child: InkWell(
+ onTap: () async {
+ await GallerySaver.saveImage(
+ widget.urls[widget.currentPage].split('?')[0]);
+ Navigator.pop(context);
+ },
+ 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 {
color: Colors.black,
),
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 {
child: Container(
color: Colors.white,
height: 56.0,
- child: Row(
+ child: _loading ? Center(
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: CircularProgressIndicator(),
+ ),
+ ) : Row(
children: [
Expanded(
child: Padding(
@@ -553,8 +581,14 @@ class _ImageFooterState extends State {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
- onTap: () {
- sendMessage();
+ onTap: () async {
+ modalSetState(() {
+ _loading = true;
+ });
+ await sendMessage();
+ modalSetState(() {
+ _loading = false;
+ });
},
child: Transform.rotate(
angle: -pi / 2,
@@ -607,7 +641,7 @@ class _ImageFooterState extends State {
}
/// Sends the current message
- void sendMessage() async {
+ Future sendMessage() async {
var text = _messageController.text.trim();
final attachments = widget.message.attachments;
@@ -615,8 +649,8 @@ class _ImageFooterState extends State {
_messageController.clear();
final client = StreamChat.of(context).client;
-
- for(var user in _selectedUsers) {
+
+ for (var user in _selectedUsers) {
var c = client.channel('messaging', extraData: {
'members': [
user.id,
diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart
index 29c36ad9..707750c5 100644
--- a/lib/src/image_header.dart
+++ b/lib/src/image_header.dart
@@ -30,10 +30,15 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
final String userName;
final String sentAt;
+ final List urls;
+ final currentIndex;
+
/// Creates a channel header
ImageHeader({
Key key,
this.message,
+ this.urls,
+ this.currentIndex,
this.showBackButton = true,
this.onBackPressed,
this.onTitleTap,
@@ -117,6 +122,8 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
userName: userName,
sentAt: sentAt,
message: message,
+ urls: urls,
+ currentIndex: currentIndex,
),
);
});
diff --git a/pubspec.yaml b/pubspec.yaml
index 241025d0..78add1a5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -35,6 +35,8 @@ dependencies:
flutter_slidable: ^0.5.4
carousel_slider: ^2.2.1
clipboard: ^0.1.2+8
+ gallery_saver: ^2.0.1
+ esys_flutter_share: ^1.0.2
flutter:
assets: