feat: avatar cropping
This commit is contained in:
parent
f043e191d2
commit
c0888d47be
5 changed files with 102 additions and 12 deletions
|
|
@ -161,10 +161,8 @@ class MessageContent extends StatelessWidget {
|
||||||
case MessageTypes.Audio:
|
case MessageTypes.Audio:
|
||||||
if (PlatformInfos.isMobile ||
|
if (PlatformInfos.isMobile ||
|
||||||
PlatformInfos.isMacOS ||
|
PlatformInfos.isMacOS ||
|
||||||
PlatformInfos.isWeb
|
PlatformInfos.isWeb ||
|
||||||
// Disabled until https://github.com/bleonard252/just_audio_mpv/issues/3
|
PlatformInfos.isLinux
|
||||||
// is fixed
|
|
||||||
// || PlatformInfos.isLinux
|
|
||||||
) {
|
) {
|
||||||
return AudioPlayerWidget(
|
return AudioPlayerWidget(
|
||||||
event,
|
event,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
@ -15,6 +16,7 @@ import 'package:fluffychat/utils/platform_infos.dart';
|
||||||
import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart';
|
import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart';
|
||||||
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
|
||||||
import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart';
|
import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart';
|
||||||
|
import 'package:fluffychat/widgets/avatar_crop_dialog.dart';
|
||||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||||
import '../../widgets/matrix.dart';
|
import '../../widgets/matrix.dart';
|
||||||
import 'settings_view.dart';
|
import 'settings_view.dart';
|
||||||
|
|
@ -126,6 +128,8 @@ class SettingsController extends State<Settings> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MatrixFile file;
|
MatrixFile file;
|
||||||
|
Uint8List bytes;
|
||||||
|
String name;
|
||||||
if (PlatformInfos.isMobile) {
|
if (PlatformInfos.isMobile) {
|
||||||
final result = await ImagePicker().pickImage(
|
final result = await ImagePicker().pickImage(
|
||||||
source: action == AvatarAction.camera
|
source: action == AvatarAction.camera
|
||||||
|
|
@ -134,16 +138,25 @@ class SettingsController extends State<Settings> {
|
||||||
imageQuality: 50,
|
imageQuality: 50,
|
||||||
);
|
);
|
||||||
if (result == null) return;
|
if (result == null) return;
|
||||||
file = MatrixFile(bytes: await result.readAsBytes(), name: result.path);
|
bytes = await result.readAsBytes();
|
||||||
|
name = result.path;
|
||||||
} else {
|
} else {
|
||||||
final result = await selectFiles(context, type: FileType.image);
|
final result = await selectFiles(context, type: FileType.image);
|
||||||
final pickedFile = result.firstOrNull;
|
final pickedFile = result.firstOrNull;
|
||||||
if (pickedFile == null) return;
|
if (pickedFile == null) return;
|
||||||
file = MatrixFile(
|
bytes = await pickedFile.readAsBytes();
|
||||||
bytes: await pickedFile.readAsBytes(),
|
name = pickedFile.name;
|
||||||
name: pickedFile.name,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
final cropped = await showDialog<Uint8List>(
|
||||||
|
context: context,
|
||||||
|
builder: (contect) => AvatarCropDialog(image: bytes),
|
||||||
|
);
|
||||||
|
if (cropped == null) return;
|
||||||
|
bytes = cropped;
|
||||||
|
file = MatrixFile(
|
||||||
|
bytes: bytes,
|
||||||
|
name: name,
|
||||||
|
);
|
||||||
final success = await showFutureLoadingDialog(
|
final success = await showFutureLoadingDialog(
|
||||||
context: context,
|
context: context,
|
||||||
future: () => matrix.client.setAvatar(file),
|
future: () => matrix.client.setAvatar(file),
|
||||||
|
|
|
||||||
70
lib/widgets/avatar_crop_dialog.dart
Normal file
70
lib/widgets/avatar_crop_dialog.dart
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
import 'package:crop_image/crop_image.dart';
|
||||||
|
import 'package:fluffychat/l10n/l10n.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class AvatarCropDialog extends StatefulWidget {
|
||||||
|
final Uint8List image;
|
||||||
|
|
||||||
|
const AvatarCropDialog({super.key, required this.image});
|
||||||
|
|
||||||
|
@override
|
||||||
|
AvatarCropDialogController createState() => AvatarCropDialogController();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AvatarCropDialogController extends State<AvatarCropDialog> {
|
||||||
|
final controller = CropController(
|
||||||
|
aspectRatio: 1,
|
||||||
|
defaultCrop: const Rect.fromLTWH(0.1, 0.1, 0.8, 0.8),
|
||||||
|
);
|
||||||
|
|
||||||
|
void onCancelAction() => Navigator.of(context).pop();
|
||||||
|
|
||||||
|
Future<void> onCropAction() async {
|
||||||
|
final image = await controller.croppedBitmap();
|
||||||
|
if (mounted) {
|
||||||
|
final data = await image.toByteData(format: ui.ImageByteFormat.png);
|
||||||
|
Navigator.of(context).pop(data?.buffer.asUint8List());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => AvatarCropDialogView(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AvatarCropDialogView extends StatelessWidget {
|
||||||
|
final AvatarCropDialogController controller;
|
||||||
|
|
||||||
|
const AvatarCropDialogView(this.controller, {super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(L10n.of(context).changeYourAvatar),
|
||||||
|
content: SizedBox(
|
||||||
|
width: 400,
|
||||||
|
height: 400,
|
||||||
|
child: CropImage(
|
||||||
|
controller: controller.controller,
|
||||||
|
image: Image.memory(controller.widget.image),
|
||||||
|
gridColor: Colors.white,
|
||||||
|
gridCornerSize: 20,
|
||||||
|
touchSize: 20,
|
||||||
|
alwaysShowThirdLines: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: controller.onCancelAction,
|
||||||
|
child: Text(L10n.of(context).cancel),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: controller.onCropAction,
|
||||||
|
child: Text(L10n.of(context).ok),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -217,6 +217,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0"
|
version: "1.15.0"
|
||||||
|
crop_image:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: crop_image
|
||||||
|
sha256: "27cbce1685a595efee62caab81c98b49b636f765c1da86353f58f5b2bf2775d8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.17"
|
||||||
cross_file:
|
cross_file:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ dependencies:
|
||||||
blurhash_dart: ^1.2.1
|
blurhash_dart: ^1.2.1
|
||||||
chewie: ^1.13.0
|
chewie: ^1.13.0
|
||||||
collection: ^1.18.0
|
collection: ^1.18.0
|
||||||
|
crop_image: ^1.0.17
|
||||||
cross_file: ^0.3.5
|
cross_file: ^0.3.5
|
||||||
desktop_drop: ^0.7.0
|
desktop_drop: ^0.7.0
|
||||||
desktop_notifications: ^0.6.3
|
desktop_notifications: ^0.6.3
|
||||||
|
|
@ -50,9 +51,10 @@ dependencies:
|
||||||
just_audio: ^0.10.5
|
just_audio: ^0.10.5
|
||||||
just_audio_media_kit: ^2.1.0
|
just_audio_media_kit: ^2.1.0
|
||||||
latlong2: ^0.9.1
|
latlong2: ^0.9.1
|
||||||
matrix: ^6.2.0
|
|
||||||
linkify: ^5.0.0
|
linkify: ^5.0.0
|
||||||
|
matrix: ^6.2.0
|
||||||
media_kit_libs_linux: ^1.2.1
|
media_kit_libs_linux: ^1.2.1
|
||||||
|
media_kit_libs_windows_video: ^1.0.11
|
||||||
mime: ^2.0.0
|
mime: ^2.0.0
|
||||||
native_imaging: ^0.4.0
|
native_imaging: ^0.4.0
|
||||||
opus_caf_converter_dart: ^1.0.1
|
opus_caf_converter_dart: ^1.0.1
|
||||||
|
|
@ -80,10 +82,9 @@ dependencies:
|
||||||
url_launcher: ^6.3.2
|
url_launcher: ^6.3.2
|
||||||
video_compress: ^3.1.4
|
video_compress: ^3.1.4
|
||||||
video_player: ^2.11.1
|
video_player: ^2.11.1
|
||||||
|
video_player_media_kit: ^2.0.0
|
||||||
wakelock_plus: ^1.5.0
|
wakelock_plus: ^1.5.0
|
||||||
webrtc_interface: ^1.3.0
|
webrtc_interface: ^1.3.0
|
||||||
media_kit_libs_windows_video: ^1.0.11
|
|
||||||
video_player_media_kit: ^2.0.0
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
dart_code_linter: ^3.2.1
|
dart_code_linter: ^3.2.1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue