Factor out showFilePicker into a generic controller
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Sarah Jamie Lewis 2022-02-07 11:30:17 -08:00
parent 3d85883f8e
commit c6192ef736
4 changed files with 64 additions and 69 deletions

3
lib/constants.dart Normal file
View File

@ -0,0 +1,3 @@
const int MaxImageFileSharingSize = 20971520;
const int MaxGeneralImageFileSharingSize = 10737418240;

View File

@ -0,0 +1,30 @@
import 'dart:io';
import 'package:cwtch/models/appstate.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
void showFilePicker(BuildContext ctx, int maxBytes, Function(File) onSuccess, Function onCancel, Function onError) async {
// only allow one file picker at a time
// note: ideally we would destroy file picker when leaving a conversation
// but we don't currently have that option.
// we need to store AppState in a variable because ctx might be destroyed
// while awaiting for pickFiles.
var appstate = Provider.of<AppState>(ctx, listen: false);
appstate.disableFilePicker = true;
// currently lockParentWindow only works on Windows...
FilePickerResult? result = await FilePicker.platform.pickFiles(lockParentWindow: true);
appstate.disableFilePicker = false;
if (result != null && result.files.first.path != null) {
File file = File(result.files.first.path!);
// We have a maximum number of bytes we can represent in terms of
// a manifest (see : https://git.openprivacy.ca/cwtch.im/cwtch/src/branch/master/protocol/files/manifest.go#L25)
if (file.lengthSync() <= maxBytes) {
onSuccess(file);
} else {
onError();
}
} else {
onCancel();
}
}

View File

@ -1,12 +1,10 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:cwtch/config.dart';
import 'package:cwtch/cwtch/cwtch.dart';
import 'package:cwtch/models/appstate.dart';
import 'package:cwtch/models/profile.dart';
import 'package:file_picker/file_picker.dart';
import 'package:cwtch/controllers/filesharing.dart' as filesharing;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cwtch/widgets/buttontextfield.dart';
@ -17,6 +15,7 @@ import 'package:cwtch/widgets/textfield.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../constants.dart';
import '../cwtch_icons_icons.dart';
import '../errorHandler.dart';
import '../main.dart';
@ -68,37 +67,6 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
});
}
void _showFilePicker(BuildContext ctx) async {
// only allow one file picker at a time
// note: ideally we would destroy file picker when leaving a conversation
// but we don't currently have that option.
// we need to store AppState in a variable because ctx might be destroyed
// while awaiting for pickFiles.
var appstate = Provider.of<AppState>(ctx, listen: false);
appstate.disableFilePicker = true;
// currently lockParentWindow only works on Windows...
FilePickerResult? result = await FilePicker.platform.pickFiles(lockParentWindow: true);
appstate.disableFilePicker = false;
if (result != null && result.files.first.path != null) {
File file = File(result.files.first.path!);
// We have a maximum number of bytes we can represent in terms of
// a manifest (see : https://git.openprivacy.ca/cwtch.im/cwtch/src/branch/master/protocol/files/manifest.go#L25)
if (file.lengthSync() <= 10737418240) {
var profile = Provider.of<ProfileInfoState>(context, listen: false).onion;
// Share this image publically (conversation handle == -1)
Provider.of<FlwtchState>(context, listen: false).cwtch.ShareFile(profile, -1, file.path);
// update the image cache locally
Provider.of<ProfileInfoState>(context, listen: false).imagePath = file.path;
} else {
final snackBar = SnackBar(
content: Text(AppLocalizations.of(context)!.msgFileTooBig),
duration: Duration(seconds: 4),
);
ScaffoldMessenger.of(ctx).showSnackBar(snackBar);
}
}
}
// A few implementation notes
// We use Visibility to hide optional structures when they are not requested.
// We used SizedBox for inter-widget height padding in columns, otherwise elements can render a little too close together.
@ -125,9 +93,23 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
_showFilePicker(context);
},
onTap: Provider.of<AppState>(context).disableFilePicker
? null
: () {
filesharing.showFilePicker(context, MaxImageFileSharingSize, (File file) {
var profile = Provider.of<ProfileInfoState>(context, listen: false).onion;
// Share this image publicly (conversation handle == -1)
Provider.of<FlwtchState>(context, listen: false).cwtch.ShareFile(profile, -1, file.path);
// update the image cache locally
Provider.of<ProfileInfoState>(context, listen: false).imagePath = file.path;
}, () {
final snackBar = SnackBar(
content: Text(AppLocalizations.of(context)!.msgFileTooBig),
duration: Duration(seconds: 4),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}, () {});
},
child: ProfileImage(
imagePath: Provider.of<ProfileInfoState>(context).imagePath,
diameter: 120,

View File

@ -11,7 +11,7 @@ import 'package:cwtch/models/profile.dart';
import 'package:cwtch/widgets/malformedbubble.dart';
import 'package:cwtch/widgets/messageloadingbubble.dart';
import 'package:cwtch/widgets/profileimage.dart';
import 'package:cwtch/controllers/filesharing.dart' as filesharing;
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
@ -23,6 +23,7 @@ import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import '../constants.dart';
import '../main.dart';
import '../settings.dart';
import '../widgets/messagelist.dart';
@ -92,7 +93,16 @@ class _MessageViewState extends State<MessageView> {
onPressed: Provider.of<AppState>(context).disableFilePicker
? null
: () {
_showFilePicker(context);
imagePreview = null;
filesharing.showFilePicker(context, MaxGeneralImageFileSharingSize, (File file) {
_confirmFileSend(context, file.path);
}, () {
final snackBar = SnackBar(
content: Text(AppLocalizations.of(context)!.msgFileTooBig),
duration: Duration(seconds: 4),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}, () {});
},
));
}
@ -415,36 +425,6 @@ class _MessageViewState extends State<MessageView> {
});
}
void _showFilePicker(BuildContext ctx) async {
imagePreview = null;
// only allow one file picker at a time
// note: ideally we would destroy file picker when leaving a conversation
// but we don't currently have that option.
// we need to store AppState in a variable because ctx might be destroyed
// while awaiting for pickFiles.
var appstate = Provider.of<AppState>(ctx, listen: false);
appstate.disableFilePicker = true;
// currently lockParentWindow only works on Windows...
FilePickerResult? result = await FilePicker.platform.pickFiles(lockParentWindow: true);
appstate.disableFilePicker = false;
if (result != null && result.files.first.path != null) {
File file = File(result.files.first.path!);
// We have a maximum number of bytes we can represent in terms of
// a manifest (see : https://git.openprivacy.ca/cwtch.im/cwtch/src/branch/master/protocol/files/manifest.go#L25)
if (file.lengthSync() <= 10737418240) {
print("Sending " + file.path);
_confirmFileSend(ctx, file.path);
} else {
final snackBar = SnackBar(
content: Text(AppLocalizations.of(context)!.msgFileTooBig),
duration: Duration(seconds: 4),
);
ScaffoldMessenger.of(ctx).showSnackBar(snackBar);
}
}
}
void _confirmFileSend(BuildContext ctx, String path) async {
showModalBottomSheet<void>(
context: ctx,