1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-25 22:39:22 +00:00

Can upload new custom emojies

This commit is contained in:
Pierre HUBERT 2020-04-29 13:42:01 +02:00
parent e6df696077
commit 225df61aa0
5 changed files with 162 additions and 1 deletions

View File

@ -4,6 +4,7 @@ import 'package:comunic/enums/user_page_visibility.dart';
import 'package:comunic/models/account_image_settings.dart';
import 'package:comunic/models/api_request.dart';
import 'package:comunic/models/general_settings.dart';
import 'package:comunic/models/new_emoji.dart';
/// Settings helper
///
@ -123,4 +124,14 @@ class SettingsHelper {
(await APIRequest(uri: "settings/delete_account_image", needLogin: true)
.exec())
.isOK;
/// Upload a new emoji
static Future<void> uploadNewCustomEmoji(NewEmoji newEmoji) async =>
(await APIRequest(
uri: "settings/upload_custom_emoji",
needLogin: true,
args: {"shortcut": newEmoji.shortcut})
.addFile("image", newEmoji.image)
.execWithFiles())
.assertOk();
}

View File

@ -73,7 +73,8 @@ class UsersHelper {
/// of failure
Future<UsersList> getListWithThrow(Set<int> users,
{bool forceDownload = false}) async {
final list = await getUsersInfo(users.toList());
final list =
await getUsersInfo(users.toList(), forceDownload: forceDownload);
if (list == null)
throw Exception(

18
lib/models/new_emoji.dart Normal file
View File

@ -0,0 +1,18 @@
import 'dart:io';
import 'package:flutter/material.dart';
/// New emoji information
///
/// @author Pierre HUBERT
class NewEmoji {
final String shortcut;
final File image;
const NewEmoji({
@required this.shortcut,
@required this.image,
}) : assert(shortcut != null),
assert(image != null);
}

View File

@ -1,9 +1,16 @@
import 'dart:io';
import 'package:comunic/helpers/settings_helper.dart';
import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/models/new_emoji.dart';
import 'package:comunic/models/user.dart';
import 'package:comunic/ui/widgets/async_screen_widget.dart';
import 'package:comunic/ui/widgets/network_image_widget.dart';
import 'package:comunic/utils/account_utils.dart';
import 'package:comunic/utils/files_utils.dart';
import 'package:comunic/utils/input_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';
/// Emojies account settings
@ -30,6 +37,8 @@ class _EmojiesAccountBody extends StatefulWidget {
class __EmojiesAccountBodyState extends State<_EmojiesAccountBody> {
User _user;
final _key = GlobalKey<AsyncScreenWidgetState>();
Future<void> _reload() async {
_user = await UsersHelper().getSingleWithThrow(
userID(),
@ -40,13 +49,21 @@ class __EmojiesAccountBodyState extends State<_EmojiesAccountBody> {
@override
Widget build(BuildContext context) {
return AsyncScreenWidget(
key: _key,
onReload: _reload,
onBuild: _buildSettings,
errorMessage: tr("Could not refresh user information!"),
showOldDataWhileUpdating: true,
);
}
Widget _buildSettings() {
return Stack(
children: [_buildList(), _buildAddButton()],
);
}
Widget _buildList() {
return ListView(
children: _user.customEmojies
.map((u) => ListTile(
@ -55,4 +72,114 @@ class __EmojiesAccountBodyState extends State<_EmojiesAccountBody> {
))
.toList());
}
Widget _buildAddButton() {
return Positioned(
child: FloatingActionButton(
onPressed: _addEmoji,
child: Icon(Icons.add),
),
right: 20,
bottom: 20,
);
}
/// Add a custom emoji
void _addEmoji() async {
try {
final newEmoji = await showDialog<NewEmoji>(
context: context,
builder: (c) => _NewEmojiDialog(),
);
await SettingsHelper.uploadNewCustomEmoji(newEmoji);
} catch (e, stack) {
print("Could not add a new emoji: $e\n$stack");
showSimpleSnack(context, tr("Could not upload emoji!"));
}
_key.currentState.refresh();
}
}
class _NewEmojiDialog extends StatefulWidget {
@override
__NewEmojiDialogState createState() => __NewEmojiDialogState();
}
class __NewEmojiDialogState extends State<_NewEmojiDialog> {
final _controller = TextEditingController();
File _file;
bool get _hasImage => _file != null;
String get _shortcut => _controller.text;
bool get _shortcutValid =>
_shortcut.isNotEmpty && validateShortcut(_shortcut);
bool get _valid => _hasImage && _shortcutValid;
NewEmoji get _emoji => NewEmoji(shortcut: _shortcut, image: _file);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(tr("Add new emoji")),
content: ConstrainedBox(
constraints:
BoxConstraints(maxHeight: MediaQuery.of(context).size.height - 50),
child: SingleChildScrollView(
child: _buildBody(),
),
),
actions: <Widget>[
MaterialButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(tr("Cancel").toUpperCase()),
),
MaterialButton(
onPressed: _valid ? () => Navigator.of(context).pop(_emoji) : null,
child: Text(tr("Add").toUpperCase()),
),
],
);
}
Widget _buildBody() {
return Column(
children: <Widget>[
TextField(
controller: _controller,
onChanged: (s) => setState(() {}),
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: tr("Shortcut"),
hintText: tr(":yourShortcut:"),
errorText: _shortcut.isNotEmpty && !_shortcutValid
? tr("Invalid shortcut!")
: null,
),
),
MaterialButton(
onPressed: _pickImage,
child: Text(_hasImage ? tr("Replace image") : tr("Add image")),
)
],
);
}
void _pickImage() async {
try {
final image = await pickImage(context);
if (image == null) return;
setState(() {
_file = image;
});
} catch (e, stack) {
print("Could not pick an image! $e\n$stack");
}
}
}

View File

@ -31,3 +31,7 @@ bool validateUrl(String url) {
/// Validate directory reference
bool validateDirectoryReference(String ref) =>
RegExp(r'@[a-zA-Z0-9]+').hasMatch(ref);
/// Validated a shortcut
bool validateShortcut(String shortcut) =>
RegExp(r'^:[a-zA-Z0-9]+:$').hasMatch(shortcut);