mirror of
https://gitlab.com/comunic/comunicmobile
synced 2024-11-22 21:09:21 +00:00
217 lines
5.8 KiB
Dart
217 lines
5.8 KiB
Dart
import 'package:comunic/helpers/settings_helper.dart';
|
|
import 'package:comunic/helpers/users_helper.dart';
|
|
import 'package:comunic/lists/custom_emojies_list.dart';
|
|
import 'package:comunic/models/custom_emoji.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';
|
|
|
|
import '../../../models/api_request.dart';
|
|
import '../../../utils/ui_utils.dart';
|
|
|
|
/// Emojies account settings
|
|
///
|
|
/// @author Pierre Hubert
|
|
|
|
class CustomEmojisAccountSettings extends StatefulWidget {
|
|
@override
|
|
_CustomEmojisAccountSettingsState createState() =>
|
|
_CustomEmojisAccountSettingsState();
|
|
}
|
|
|
|
class _CustomEmojisAccountSettingsState
|
|
extends State<CustomEmojisAccountSettings> {
|
|
late User _user;
|
|
|
|
final _key = GlobalKey<AsyncScreenWidgetState>();
|
|
|
|
Future<void> _reload() async {
|
|
_user = await UsersHelper().getSingleWithThrow(
|
|
userID(),
|
|
forceDownload: true,
|
|
);
|
|
}
|
|
|
|
@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 Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Stack(
|
|
children: [_buildList(), _buildAddButton()],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildList() {
|
|
return ListView(
|
|
children: _user.customEmojies
|
|
.map((u) => ListTile(
|
|
leading: NetworkImageWidget(url: u.url!, width: 50),
|
|
title: Text(u.shortcut!),
|
|
trailing: IconButton(
|
|
icon: Icon(Icons.delete),
|
|
onPressed: () => _deleteEmoji(u)),
|
|
))
|
|
.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) => _NewCustomEmojiDialog(
|
|
currentList: _user.customEmojies,
|
|
),
|
|
);
|
|
|
|
if (newEmoji == null) return;
|
|
|
|
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();
|
|
}
|
|
|
|
/// Ask for confirmation before deleting permanently an emoji
|
|
void _deleteEmoji(CustomEmoji u) async {
|
|
try {
|
|
if (!await showConfirmDialog(
|
|
context: context,
|
|
message: tr("Do you really want to delete this custom emoji ?")))
|
|
return;
|
|
|
|
await SettingsHelper.deleteCustomEmoji(u.id);
|
|
} catch (e, stack) {
|
|
print("Could not delete custom emoji! $e\n$stack");
|
|
showSimpleSnack(context, tr("Could not delete custom emoji!")!);
|
|
}
|
|
|
|
_key.currentState!.refresh();
|
|
}
|
|
}
|
|
|
|
/// Dialog used to upload new custom emojies
|
|
class _NewCustomEmojiDialog extends StatefulWidget {
|
|
final CustomEmojiesList currentList;
|
|
|
|
const _NewCustomEmojiDialog({
|
|
Key? key,
|
|
required this.currentList,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
_NewCustomEmojiDialogState createState() => _NewCustomEmojiDialogState();
|
|
}
|
|
|
|
class _NewCustomEmojiDialogState extends State<_NewCustomEmojiDialog> {
|
|
final _controller = TextEditingController();
|
|
BytesFile? _file;
|
|
|
|
bool get _hasImage => _file != null;
|
|
|
|
String get _shortcut => _controller.text;
|
|
|
|
bool get _shortcutValid =>
|
|
_shortcut.isNotEmpty &&
|
|
validateShortcut(_shortcut) &&
|
|
!widget.currentList.hasShortcut(_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");
|
|
snack(context, tr("Failed to pick an image!")!);
|
|
}
|
|
}
|
|
}
|