1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-10-23 06:53:23 +00:00

Simplify image picking code

This commit is contained in:
Pierre HUBERT 2021-03-13 18:03:20 +01:00
parent ea45bf828c
commit e70aaabbc9
14 changed files with 85 additions and 105 deletions

View File

@ -60,17 +60,6 @@ class APIHelper {
contentType: v.type, contentType: v.type,
))); )));
} }
// Process picked files
for (final key in request.pickedFiles.keys) {
var v = request.pickedFiles[key];
data.files.add(MapEntry(
key,
MultipartFile.fromBytes(
await v.readAsBytes(),
filename: v.path.split("/").last,
)));
}
} }
// Execute the request // Execute the request

View File

@ -17,7 +17,7 @@ class CommentsHelper {
"content": comment.hasContent ? comment.content : "", "content": comment.hasContent ? comment.content : "",
}); });
if (comment.hasImage) request.addPickedFile("image", comment.image); if (comment.hasImage) request.addBytesFile("image", comment.image);
final response = await request.execWithFiles(); final response = await request.execWithFiles();

View File

@ -142,7 +142,7 @@ class PostsHelper {
break; break;
case PostKind.IMAGE: case PostKind.IMAGE:
request.addPickedFile("image", post.image); request.addBytesFile("image", post.image);
break; break;
case PostKind.WEB_LINK: case PostKind.WEB_LINK:

View File

@ -5,7 +5,8 @@ import 'package:comunic/models/data_conservation_policy_settings.dart';
import 'package:comunic/models/general_settings.dart'; import 'package:comunic/models/general_settings.dart';
import 'package:comunic/models/new_emoji.dart'; import 'package:comunic/models/new_emoji.dart';
import 'package:comunic/models/security_settings.dart'; import 'package:comunic/models/security_settings.dart';
import 'package:image_picker/image_picker.dart';
import '../models/api_request.dart';
/// Settings helper /// Settings helper
/// ///
@ -92,11 +93,10 @@ class SettingsHelper {
} }
/// Upload a new account image /// Upload a new account image
static Future<bool> uploadAccountImage(PickedFile newImage) async => static Future<void> uploadAccountImage(BytesFile newImage) async =>
(await APIRequest(uri: "settings/upload_account_image", needLogin: true) await APIRequest(uri: "settings/upload_account_image", needLogin: true)
.addPickedFile("picture", newImage) .addBytesFile("picture", newImage)
.execWithFiles()) .execWithFilesAndThrow();
.isOK;
/// Upload a new account image from memory /// Upload a new account image from memory
static Future<bool> uploadAccountImageFromMemory(List<int> bytes) async => static Future<bool> uploadAccountImageFromMemory(List<int> bytes) async =>
@ -128,13 +128,12 @@ class SettingsHelper {
/// Upload a new custom emoji /// Upload a new custom emoji
static Future<void> uploadNewCustomEmoji(NewEmoji newEmoji) async => static Future<void> uploadNewCustomEmoji(NewEmoji newEmoji) async =>
(await APIRequest( await APIRequest(
uri: "settings/upload_custom_emoji", uri: "settings/upload_custom_emoji",
needLogin: true, needLogin: true,
args: {"shortcut": newEmoji.shortcut}) args: {"shortcut": newEmoji.shortcut})
.addPickedFile("image", newEmoji.image) .addBytesFile("image", newEmoji.image)
.execWithFiles()) .execWithFilesAndThrow();
.assertOk();
/// Delete a custom emoji /// Delete a custom emoji
/// ///
@ -220,7 +219,8 @@ class SettingsHelper {
/// Throws in case of failure /// Throws in case of failure
static Future<void> setDataConservationPolicy( static Future<void> setDataConservationPolicy(
String password, DataConservationPolicySettings newSettings) async { String password, DataConservationPolicySettings newSettings) async {
await APIRequest(uri: "settings/set_data_conservation_policy", needLogin: true) await APIRequest(
uri: "settings/set_data_conservation_policy", needLogin: true)
.addString("password", password) .addString("password", password)
.addInt("inactive_account_lifetime", .addInt("inactive_account_lifetime",
newSettings.inactiveAccountLifeTime ?? 0) newSettings.inactiveAccountLifeTime ?? 0)

View File

@ -4,7 +4,6 @@ import 'package:comunic/helpers/api_helper.dart';
import 'package:comunic/models/api_response.dart'; import 'package:comunic/models/api_response.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:http_parser/http_parser.dart'; import 'package:http_parser/http_parser.dart';
import 'package:image_picker/image_picker.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
/// API Request model /// API Request model
@ -32,7 +31,6 @@ class APIRequest {
CancelToken cancelToken; CancelToken cancelToken;
Map<String, String> args; Map<String, String> args;
Map<String, File> files = Map(); Map<String, File> files = Map();
Map<String, PickedFile> pickedFiles = Map();
Map<String, BytesFile> bytesFiles = Map(); Map<String, BytesFile> bytesFiles = Map();
APIRequest({@required this.uri, this.needLogin = false, this.args}) APIRequest({@required this.uri, this.needLogin = false, this.args})
@ -73,11 +71,6 @@ class APIRequest {
return this; return this;
} }
APIRequest addPickedFile(String name, PickedFile file) {
pickedFiles[name] = file;
return this;
}
APIRequest addBytesFile(String name, BytesFile file) { APIRequest addBytesFile(String name, BytesFile file) {
this.bytesFiles[name] = file; this.bytesFiles[name] = file;
return this; return this;

View File

@ -1,6 +1,7 @@
import 'package:image_picker/image_picker.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'api_request.dart';
/// New comment information /// New comment information
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
@ -8,7 +9,7 @@ import 'package:meta/meta.dart';
class NewComment { class NewComment {
final int postID; final int postID;
final String content; final String content;
final PickedFile image; final BytesFile image;
const NewComment({ const NewComment({
@required this.postID, @required this.postID,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'api_request.dart';
/// New emoji information /// New emoji information
/// ///
@ -7,7 +8,7 @@ import 'package:image_picker/image_picker.dart';
class NewEmoji { class NewEmoji {
final String shortcut; final String shortcut;
final PickedFile image; final BytesFile image;
const NewEmoji({ const NewEmoji({
@required this.shortcut, @required this.shortcut,

View File

@ -1,9 +1,10 @@
import 'package:comunic/enums/post_kind.dart'; import 'package:comunic/enums/post_kind.dart';
import 'package:comunic/enums/post_target.dart'; import 'package:comunic/enums/post_target.dart';
import 'package:comunic/enums/post_visibility_level.dart'; import 'package:comunic/enums/post_visibility_level.dart';
import 'package:image_picker/image_picker.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'api_request.dart';
/// New post information /// New post information
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
@ -27,7 +28,7 @@ class NewPost {
final int targetID; final int targetID;
final PostVisibilityLevel visibility; final PostVisibilityLevel visibility;
final String content; final String content;
final PickedFile image; final BytesFile image;
final String url; final String url;
final List<int> pdf; final List<int> pdf;
final PostKind kind; final PostKind kind;

View File

@ -15,6 +15,9 @@ import 'package:identicon/identicon.dart';
import 'package:random_string/random_string.dart'; import 'package:random_string/random_string.dart';
import 'package:settings_ui/settings_ui.dart'; import 'package:settings_ui/settings_ui.dart';
import '../../../utils/log_utils.dart';
import '../../../utils/ui_utils.dart';
/// Account image settings section /// Account image settings section
/// ///
/// @author Pierre Hubert /// @author Pierre Hubert
@ -156,15 +159,16 @@ class _AccountImageSettingsScreenState
/// Upload a new account image /// Upload a new account image
void _uploadAccountImage() async { void _uploadAccountImage() async {
try {
final image = await pickImage(context); final image = await pickImage(context);
if (image == null) return; if (image == null) return;
if (!await SettingsHelper.uploadAccountImage(image)) { await SettingsHelper.uploadAccountImage(image);
showSimpleSnack(context, tr("Could not upload your account image!")); } catch (e, s) {
return; logError(e, s);
snack(context, tr("Failed to upload new account image!"));
} }
_key.currentState.refresh(); _key.currentState.refresh();
} }

View File

@ -12,7 +12,9 @@ import 'package:comunic/utils/input_utils.dart';
import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart'; import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../../../models/api_request.dart';
import '../../../utils/ui_utils.dart';
/// Emojies account settings /// Emojies account settings
/// ///
@ -136,7 +138,7 @@ class _NewCustomEmojiDialog extends StatefulWidget {
class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> { class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> {
final _controller = TextEditingController(); final _controller = TextEditingController();
PickedFile _file; BytesFile _file;
bool get _hasImage => _file != null; bool get _hasImage => _file != null;
@ -209,6 +211,7 @@ class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> {
}); });
} catch (e, stack) { } catch (e, stack) {
print("Could not pick an image! $e\n$stack"); print("Could not pick an image! $e\n$stack");
snack(context, tr("Failed to pick an image!"));
} }
} }
} }

View File

@ -259,19 +259,19 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
// Upload a new logo // Upload a new logo
SettingsTile( SettingsTile(
title: tr("Upload a new logo"), title: tr("Upload a new logo"),
onPressed: (_) => _uploadNewLogo, onPressed: (_) => _uploadNewLogo(),
), ),
// Generate a new random logo // Generate a new random logo
SettingsTile( SettingsTile(
title: tr("Generate a new random logo"), title: tr("Generate a new random logo"),
onPressed: (_) => _generateRandomLogo, onPressed: (_) => _generateRandomLogo(),
), ),
// Delete current logo // Delete current logo
SettingsTile( SettingsTile(
title: tr("Delete logo"), title: tr("Delete logo"),
onPressed: (_) => _deleteLogo, onPressed: (_) => _deleteLogo(),
), ),
], ],
); );
@ -281,8 +281,8 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
void _uploadNewLogo() async { void _uploadNewLogo() async {
try { try {
final logo = await pickImage(context); final logo = await pickImage(context);
final bytes = await logo.readAsBytes(); if (logo == null) return;
await _doUploadLogo(bytes); await _doUploadLogo(logo.bytes);
} catch (e, stack) { } catch (e, stack) {
print("Could not upload new logo! $e\n$stack"); print("Could not upload new logo! $e\n$stack");
showSimpleSnack(context, tr("Could not upload new logo!")); showSimpleSnack(context, tr("Could not upload new logo!"));
@ -328,7 +328,7 @@ class _GroupSettingsScreenState extends SafeState<GroupSettingsScreen> {
tiles: [ tiles: [
SettingsTile( SettingsTile(
title: tr("Delete group"), title: tr("Delete group"),
onPressed: (_) => _deleteGroup, onPressed: (_) => _deleteGroup(),
), ),
], ],
); );

View File

@ -26,9 +26,11 @@ import 'package:comunic/utils/post_utils.dart';
import 'package:comunic/utils/ui_utils.dart'; import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:image_picker/image_picker.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../../models/api_request.dart';
import '../../utils/log_utils.dart';
/// Single posts tile /// Single posts tile
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
@ -77,7 +79,7 @@ class _PostTileState extends State<PostTile> {
// Class members // Class members
TextEditingController _commentController = TextEditingController(); TextEditingController _commentController = TextEditingController();
PickedFile _commentImage; BytesFile _commentImage;
bool _submitting = false; bool _submitting = false;
int _maxNumberOfCommentToShow = 10; int _maxNumberOfCommentToShow = 10;
@ -493,11 +495,16 @@ class _PostTileState extends State<PostTile> {
return; return;
} }
try {
// Pick a new image // Pick a new image
final newImage = await pickImage(context); final newImage = await pickImage(context);
setState(() { setState(() {
_commentImage = newImage; _commentImage = newImage;
}); });
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to choose an image!"));
}
} }
/// Submit comment entered by the user /// Submit comment entered by the user

View File

@ -13,7 +13,10 @@ import 'package:comunic/utils/post_utils.dart';
import 'package:comunic/utils/ui_utils.dart'; import 'package:comunic/utils/ui_utils.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../../models/api_request.dart';
import '../../utils/log_utils.dart';
import '../../utils/ui_utils.dart';
/// Widget that allows to create posts /// Widget that allows to create posts
/// ///
@ -48,7 +51,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
bool _isCreating = false; bool _isCreating = false;
final TextEditingController _postTextController = TextEditingController(); final TextEditingController _postTextController = TextEditingController();
PostVisibilityLevel _postVisibilityLevel; PostVisibilityLevel _postVisibilityLevel;
PickedFile _postImage; BytesFile _postImage;
String _postURL; String _postURL;
List<int> _postPDF; List<int> _postPDF;
DateTime _timeEnd; DateTime _timeEnd;
@ -239,6 +242,7 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
/// Pick an image for the new post /// Pick an image for the new post
Future<void> _pickImageForPost() async { Future<void> _pickImageForPost() async {
try {
final image = await pickImage(context); final image = await pickImage(context);
if (image == null) return; if (image == null) return;
@ -248,6 +252,10 @@ class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
setState(() { setState(() {
this._postImage = image; this._postImage = image;
}); });
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to pick image for post!"));
}
} }
/// Choose a new URL for the post /// Choose a new URL for the post

View File

@ -1,54 +1,27 @@
import 'dart:io'; import 'dart:io';
import 'package:comunic/utils/intl_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:random_string/random_string.dart'; import 'package:random_string/random_string.dart';
import '../models/api_request.dart';
import '../ui/dialogs/pick_file_dialog.dart';
/// Files utilities /// Files utilities
/// ///
/// @author Pierre HUBERT /// @author Pierre HUBERT
enum _ChooseImageSource { GALLERY, CAMERA }
/// Ask the user to choose an image, either from the gallery or using the camera /// Ask the user to choose an image, either from the gallery or using the camera
/// ///
/// Returns null in case of failure /// Throws an exception null in case of failure
Future<PickedFile> pickImage(BuildContext context) async { Future<BytesFile> pickImage(BuildContext context) async {
/// First, we ask the user to choose between image picker and camera return await showPickFileDialog(
final result = await showDialog<_ChooseImageSource>(
context: context, context: context,
builder: (c) { allowedMimeTypes: ["image/png", "image/jpeg", "image/gif"],
return AlertDialog( imageMaxHeight: 10000,
title: Text(tr("Choose an image")), imageMaxWidth: 10000,
actions: <Widget>[
//Gallery
TextButton(
onPressed: () => Navigator.pop(context, _ChooseImageSource.GALLERY),
child: Text(
tr("Image gallery").toUpperCase(),
),
),
// Camera
TextButton(
onPressed: () => Navigator.pop(context, _ChooseImageSource.CAMERA),
child: Text(
tr("Camera").toUpperCase(),
),
),
],
); );
},
);
if (result == null) return null;
return await ImagePicker().getImage(
source: result == _ChooseImageSource.CAMERA
? ImageSource.camera
: ImageSource.gallery);
} }
/// Generate a new temporary file /// Generate a new temporary file