Implement file picker web

This commit is contained in:
Christian Pauly 2020-06-20 09:32:49 +00:00
parent bcda0bbd5f
commit 2d83df34c0
9 changed files with 90 additions and 68 deletions

View file

@ -2,6 +2,7 @@
### Features: ### Features:
- New room list app bar design - New room list app bar design
- Chat app bar transparent - Chat app bar transparent
- Implement web file picker
### Changes: ### Changes:
- Show presences of users sharing a direct chat - Show presences of users sharing a direct chat
- Big refactoring - Big refactoring

View file

@ -3,7 +3,6 @@ import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:file_picker/file_picker.dart';
import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart';
import 'package:fluffychat/components/avatar.dart'; import 'package:fluffychat/components/avatar.dart';
import 'package:fluffychat/components/chat_settings_popup_menu.dart'; import 'package:fluffychat/components/chat_settings_popup_menu.dart';
@ -20,9 +19,9 @@ import 'package:fluffychat/utils/room_status_extension.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:bot_toast/bot_toast.dart'; import 'package:memoryfilepicker/memoryfilepicker.dart';
import 'package:image_picker/image_picker.dart';
import 'package:pedantic/pedantic.dart'; import 'package:pedantic/pedantic.dart';
import 'package:image_picker/image_picker.dart';
import 'chat_details.dart'; import 'chat_details.dart';
import 'chat_list.dart'; import 'chat_list.dart';
@ -187,25 +186,17 @@ class _ChatState extends State<_Chat> {
} }
void sendFileAction(BuildContext context) async { void sendFileAction(BuildContext context) async {
if (kIsWeb) { var file = await MemoryFilePicker.getFile();
BotToast.showText(text: L10n.of(context).notSupportedInWeb);
return;
}
var file = await FilePicker.getFile();
if (file == null) return; if (file == null) return;
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
room.sendFileEvent( room.sendFileEvent(
MatrixFile(bytes: await file.readAsBytes(), path: file.path), MatrixFile(bytes: file.bytes, path: file.path),
), ),
); );
} }
void sendImageAction(BuildContext context) async { void sendImageAction(BuildContext context) async {
if (kIsWeb) { var file = await MemoryFilePicker.getImage(
BotToast.showText(text: L10n.of(context).notSupportedInWeb);
return;
}
var file = await ImagePicker.pickImage(
source: ImageSource.gallery, source: ImageSource.gallery,
imageQuality: 50, imageQuality: 50,
maxWidth: 1600, maxWidth: 1600,
@ -213,17 +204,13 @@ class _ChatState extends State<_Chat> {
if (file == null) return; if (file == null) return;
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
room.sendImageEvent( room.sendImageEvent(
MatrixFile(bytes: await file.readAsBytes(), path: file.path), MatrixFile(bytes: await file.bytes, path: file.path),
), ),
); );
} }
void openCameraAction(BuildContext context) async { void openCameraAction(BuildContext context) async {
if (kIsWeb) { var file = await MemoryFilePicker.getImage(
BotToast.showText(text: L10n.of(context).notSupportedInWeb);
return;
}
var file = await ImagePicker.pickImage(
source: ImageSource.camera, source: ImageSource.camera,
imageQuality: 50, imageQuality: 50,
maxWidth: 1600, maxWidth: 1600,
@ -231,7 +218,7 @@ class _ChatState extends State<_Chat> {
if (file == null) return; if (file == null) return;
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
room.sendImageEvent( room.sendImageEvent(
MatrixFile(bytes: await file.readAsBytes(), path: file.path), MatrixFile(bytes: file.bytes, path: file.path),
), ),
); );
} }
@ -650,7 +637,7 @@ class _ChatState extends State<_Chat> {
: Container(), : Container(),
] ]
: <Widget>[ : <Widget>[
if (!kIsWeb && inputText.isEmpty) if (inputText.isEmpty)
PopupMenuButton<String>( PopupMenuButton<String>(
icon: Icon(Icons.add), icon: Icon(Icons.add),
onSelected: (String choice) async { onSelected: (String choice) async {
@ -694,32 +681,34 @@ class _ChatState extends State<_Chat> {
contentPadding: EdgeInsets.all(0), contentPadding: EdgeInsets.all(0),
), ),
), ),
PopupMenuItem<String>( if (!kIsWeb)
value: 'camera', PopupMenuItem<String>(
child: ListTile( value: 'camera',
leading: CircleAvatar( child: ListTile(
backgroundColor: Colors.purple, leading: CircleAvatar(
foregroundColor: Colors.white, backgroundColor: Colors.purple,
child: Icon(Icons.camera_alt), foregroundColor: Colors.white,
child: Icon(Icons.camera_alt),
),
title: Text(
L10n.of(context).openCamera),
contentPadding: EdgeInsets.all(0),
), ),
title:
Text(L10n.of(context).openCamera),
contentPadding: EdgeInsets.all(0),
), ),
), if (!kIsWeb)
PopupMenuItem<String>( PopupMenuItem<String>(
value: 'voice', value: 'voice',
child: ListTile( child: ListTile(
leading: CircleAvatar( leading: CircleAvatar(
backgroundColor: Colors.red, backgroundColor: Colors.red,
foregroundColor: Colors.white, foregroundColor: Colors.white,
child: Icon(Icons.mic), child: Icon(Icons.mic),
),
title: Text(
L10n.of(context).voiceMessage),
contentPadding: EdgeInsets.all(0),
), ),
title: Text(
L10n.of(context).voiceMessage),
contentPadding: EdgeInsets.all(0),
), ),
),
], ],
), ),
EncryptionButton(room), EncryptionButton(room),

View file

@ -15,6 +15,7 @@ import 'package:flutter/services.dart';
import 'package:bot_toast/bot_toast.dart'; import 'package:bot_toast/bot_toast.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:link_text/link_text.dart'; import 'package:link_text/link_text.dart';
import 'package:memoryfilepicker/memoryfilepicker.dart';
import './settings_emotes.dart'; import './settings_emotes.dart';
class ChatDetails extends StatefulWidget { class ChatDetails extends StatefulWidget {
@ -100,7 +101,7 @@ class _ChatDetailsState extends State<ChatDetails> {
} }
void setAvatarAction(BuildContext context) async { void setAvatarAction(BuildContext context) async {
final tempFile = await ImagePicker.pickImage( final tempFile = await MemoryFilePicker.getImage(
source: ImageSource.gallery, source: ImageSource.gallery,
imageQuality: 50, imageQuality: 50,
maxWidth: 1600, maxWidth: 1600,
@ -109,7 +110,7 @@ class _ChatDetailsState extends State<ChatDetails> {
final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( final success = await SimpleDialogs(context).tryRequestWithLoadingDialog(
widget.room.setAvatar( widget.room.setAvatar(
MatrixFile( MatrixFile(
bytes: await tempFile.readAsBytes(), bytes: tempFile.bytes,
path: tempFile.path, path: tempFile.path,
), ),
), ),

View file

@ -1,9 +1,12 @@
import 'dart:io';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/settings_themes.dart'; import 'package:fluffychat/components/settings_themes.dart';
import 'package:fluffychat/views/settings_devices.dart'; import 'package:fluffychat/views/settings_devices.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:memoryfilepicker/memoryfilepicker.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'app_info.dart'; import 'app_info.dart';
@ -81,7 +84,7 @@ class _SettingsState extends State<Settings> {
} }
void setAvatarAction(BuildContext context) async { void setAvatarAction(BuildContext context) async {
final tempFile = await ImagePicker.pickImage( final tempFile = await MemoryFilePicker.getImage(
source: ImageSource.gallery, source: ImageSource.gallery,
imageQuality: 50, imageQuality: 50,
maxWidth: 1600, maxWidth: 1600,
@ -91,7 +94,7 @@ class _SettingsState extends State<Settings> {
final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( final success = await SimpleDialogs(context).tryRequestWithLoadingDialog(
matrix.client.setAvatar( matrix.client.setAvatar(
MatrixFile( MatrixFile(
bytes: await tempFile.readAsBytes(), bytes: tempFile.bytes,
path: tempFile.path, path: tempFile.path,
), ),
), ),
@ -105,9 +108,9 @@ class _SettingsState extends State<Settings> {
} }
void setWallpaperAction(BuildContext context) async { void setWallpaperAction(BuildContext context) async {
final wallpaper = await ImagePicker.pickImage(source: ImageSource.gallery); final wallpaper = await ImagePicker().getImage(source: ImageSource.gallery);
if (wallpaper == null) return; if (wallpaper == null) return;
Matrix.of(context).wallpaper = wallpaper; Matrix.of(context).wallpaper = File(wallpaper.path);
await Matrix.of(context) await Matrix.of(context)
.store .store
.setItem('chat.fluffy.wallpaper', wallpaper.path); .setItem('chat.fluffy.wallpaper', wallpaper.path);

View file

@ -4,6 +4,7 @@ import 'package:flutter_advanced_networkimage/provider.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:bot_toast/bot_toast.dart'; import 'package:bot_toast/bot_toast.dart';
import 'package:memoryfilepicker/memoryfilepicker.dart';
import 'chat_list.dart'; import 'chat_list.dart';
import '../components/adaptive_page_layout.dart'; import '../components/adaptive_page_layout.dart';
@ -367,14 +368,13 @@ class _EmoteImagePickerState extends State<_EmoteImagePicker> {
BotToast.showText(text: L10n.of(context).notSupportedInWeb); BotToast.showText(text: L10n.of(context).notSupportedInWeb);
return; return;
} }
var file = await ImagePicker.pickImage( var file = await MemoryFilePicker.getImage(
source: ImageSource.gallery, source: ImageSource.gallery,
imageQuality: 50, imageQuality: 50,
maxWidth: 128, maxWidth: 128,
maxHeight: 128); maxHeight: 128);
if (file == null) return; if (file == null) return;
final matrixFile = final matrixFile = MatrixFile(bytes: file.bytes, path: file.path);
MatrixFile(bytes: await file.readAsBytes(), path: file.path);
final uploadResp = final uploadResp =
await SimpleDialogs(context).tryRequestWithLoadingDialog( await SimpleDialogs(context).tryRequestWithLoadingDialog(
Matrix.of(context) Matrix.of(context)

View file

@ -1,4 +1,3 @@
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
@ -10,6 +9,7 @@ import 'package:fluffychat/views/sign_up_password.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:memoryfilepicker/memoryfilepicker.dart';
class SignUp extends StatefulWidget { class SignUp extends StatefulWidget {
@override @override
@ -20,10 +20,10 @@ class _SignUpState extends State<SignUp> {
final TextEditingController usernameController = TextEditingController(); final TextEditingController usernameController = TextEditingController();
String usernameError; String usernameError;
bool loading = false; bool loading = false;
File avatar; MemoryFile avatar;
void setAvatarAction() async { void setAvatarAction() async {
var file = await ImagePicker.pickImage( var file = await MemoryFilePicker.getImage(
source: ImageSource.gallery, source: ImageSource.gallery,
maxHeight: 512, maxHeight: 512,
maxWidth: 512, maxWidth: 512,
@ -92,7 +92,8 @@ class _SignUpState extends State<SignUp> {
), ),
ListTile( ListTile(
leading: CircleAvatar( leading: CircleAvatar(
backgroundImage: avatar == null ? null : FileImage(avatar), backgroundImage:
avatar == null ? null : MemoryImage(avatar.bytes),
backgroundColor: avatar == null backgroundColor: avatar == null
? Theme.of(context).brightness == Brightness.dark ? Theme.of(context).brightness == Brightness.dark
? Color(0xff121212) ? Color(0xff121212)

View file

@ -1,4 +1,3 @@
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
@ -8,11 +7,12 @@ import 'package:fluffychat/utils/app_route.dart';
import 'package:fluffychat/views/auth_web_view.dart'; import 'package:fluffychat/views/auth_web_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:bot_toast/bot_toast.dart'; import 'package:bot_toast/bot_toast.dart';
import 'package:memoryfilepicker/memoryfilepicker.dart';
import 'chat_list.dart'; import 'chat_list.dart';
class SignUpPassword extends StatefulWidget { class SignUpPassword extends StatefulWidget {
final File avatar; final MemoryFile avatar;
final String username; final String username;
final String displayname; final String displayname;
const SignUpPassword(this.username, {this.avatar, this.displayname}); const SignUpPassword(this.username, {this.avatar, this.displayname});
@ -100,7 +100,7 @@ class _SignUpPasswordState extends State<SignUpPassword> {
try { try {
await matrix.client.setAvatar( await matrix.client.setAvatar(
MatrixFile( MatrixFile(
bytes: await widget.avatar.readAsBytes(), bytes: widget.avatar.bytes,
path: widget.avatar.path, path: widget.avatar.path,
), ),
); );

View file

@ -160,12 +160,19 @@ packages:
source: hosted source: hosted
version: "0.1.3" version: "0.1.3"
file_picker: file_picker:
dependency: "direct main" dependency: transitive
description: description:
name: file_picker name: file_picker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.4.3+2" version: "1.12.0"
file_picker_platform_interface:
dependency: transitive
description:
name: file_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
firebase_messaging: firebase_messaging:
dependency: "direct main" dependency: "direct main"
description: description:
@ -225,6 +232,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.0" version: "0.1.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.8"
flutter_secure_storage: flutter_secure_storage:
dependency: "direct main" dependency: "direct main"
description: description:
@ -327,12 +341,19 @@ packages:
source: hosted source: hosted
version: "2.1.12" version: "2.1.12"
image_picker: image_picker:
dependency: "direct main" dependency: transitive
description: description:
name: image_picker name: image_picker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.2+3" version: "0.6.7+2"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@ -405,6 +426,13 @@ packages:
url: "https://gitlab.com/famedly/libraries/matrix_file_e2ee.git" url: "https://gitlab.com/famedly/libraries/matrix_file_e2ee.git"
source: git source: git
version: "1.0.3" version: "1.0.3"
memoryfilepicker:
dependency: "direct main"
description:
name: memoryfilepicker
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -553,7 +581,7 @@ packages:
name: plugin_platform_interface name: plugin_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1" version: "1.0.2"
pointycastle: pointycastle:
dependency: transitive dependency: transitive
description: description:
@ -740,7 +768,7 @@ packages:
name: universal_html name: universal_html
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.12" version: "1.2.3"
universal_io: universal_io:
dependency: transitive dependency: transitive
description: description:

View file

@ -31,8 +31,7 @@ dependencies:
localstorage: ^3.0.1+4 localstorage: ^3.0.1+4
bubble: ^1.1.9+1 bubble: ^1.1.9+1
file_picker: ^1.4.3+2 memoryfilepicker: ^0.1.1
image_picker: ^0.6.2+3
flutter_speed_dial: ^1.2.5 flutter_speed_dial: ^1.2.5
url_launcher: ^5.4.1 url_launcher: ^5.4.1
url_launcher_web: ^0.1.0 url_launcher_web: ^0.1.0