diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index a29f813..1037ebf 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -28,11 +28,6 @@
-
-
changeImage() async {
- final result = await FilePicker.platform.pickFiles(
- allowMultiple: false,
- type: FileType.image,
+ Future changeImage(BuildContext context) async {
+ final picker = ImagePicker();
+ final result = await picker.pickImage(source: ImageSource.gallery);
+ final bytes = await result?.readAsBytes();
+
+ if (result == null || bytes == null || !context.mounted) {
+ return;
+ }
+
+ final controller = CropController();
+
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (context) => CropView(
+ bytes: bytes,
+ controller: controller,
+ ),
+ ),
);
+ }
- if (result != null) {
- final path = result.files.single.path!;
-
- final croppedFile = await ImageCropper().cropImage(
- sourcePath: path,
- uiSettings: [
- AndroidUiSettings(
- cropStyle: CropStyle.circle,
- initAspectRatio: CropAspectRatioPreset.square,
- ),
- IOSUiSettings(
- cropStyle: CropStyle.circle,
- aspectRatioPresets: [CropAspectRatioPreset.square],
- ),
- ],
- );
-
- final response = await HttpRequest().postMultipart(
- '/v1/members/image',
- member!.token,
- croppedFile!.path,
- );
-
- if (response.statusCode != 200) {
- throw HttpException('Failed to change image ${response.body}');
- }
+ Future increaseImageVersion() async {
+ imageVersion++;
+ await _sharedPreferences.setInt('imageVersion', imageVersion);
- imageVersion++;
- await _sharedPreferences.setInt('imageVersion', imageVersion);
- Future.delayed(const Duration(seconds: 1), () {
- streamController.add(member!);
- });
- }
+ Future.delayed(const Duration(seconds: 1), () {
+ streamController.add(member!);
+ });
}
Future associateEmail(String email) async {
diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb
index eb7d3e6..361d1a3 100644
--- a/lib/l10n/app_fr.arb
+++ b/lib/l10n/app_fr.arb
@@ -68,5 +68,8 @@
"animesAdded": "Animés ajoutés",
"episodesWatched": "Épisodes vus",
- "watchTime": "Temps de visionnage"
+ "watchTime": "Temps de visionnage",
+ "accountCreatedAt": "Compte créé le {date}",
+ "crop": "Recadrer",
+ "next": "Suivant"
}
diff --git a/lib/utils/http_request.dart b/lib/utils/http_request.dart
index 23ff95c..487367b 100644
--- a/lib/utils/http_request.dart
+++ b/lib/utils/http_request.dart
@@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:application/dtos/pageable_dto.dart';
import 'package:application/utils/constant.dart';
+import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
class HttpRequest {
@@ -65,7 +66,7 @@ class HttpRequest {
Future postMultipart(
String endpoint,
String token,
- String path,
+ Uint8List bytes,
) async {
final request = http.MultipartRequest(
'POST',
@@ -76,10 +77,10 @@ class HttpRequest {
request.headers.putIfAbsent('Authorization', () => 'Bearer $token');
request.files.add(
- await http.MultipartFile.fromPath(
+ http.MultipartFile.fromBytes(
'file',
- path,
- filename: path.split('/').last,
+ bytes,
+ filename: 'image.jpg',
),
);
diff --git a/lib/views/account_view.dart b/lib/views/account_view.dart
index d1a6969..201e8f1 100644
--- a/lib/views/account_view.dart
+++ b/lib/views/account_view.dart
@@ -38,7 +38,7 @@ class AccountView extends StatelessWidget {
right: 0,
child: GestureDetector(
onTap: () {
- MemberController.instance.changeImage();
+ MemberController.instance.changeImage(context);
},
child: Container(
decoration: const BoxDecoration(
@@ -170,7 +170,8 @@ class AccountView extends StatelessWidget {
),
const SizedBox(height: 32),
Text(
- 'Compte créé le ${beautifyDate(context, member?.creationDateTime ?? '')}',
+ appLocalizations.accountCreatedAt(
+ beautifyDate(context, member?.creationDateTime ?? '')),
style: const TextStyle(
fontSize: 14,
),
diff --git a/lib/views/crop_view.dart b/lib/views/crop_view.dart
new file mode 100644
index 0000000..16764cd
--- /dev/null
+++ b/lib/views/crop_view.dart
@@ -0,0 +1,61 @@
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:application/controllers/member_controller.dart';
+import 'package:application/utils/http_request.dart';
+import 'package:crop_your_image/crop_your_image.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+class CropView extends StatelessWidget {
+ final Uint8List bytes;
+ final CropController controller;
+
+ const CropView({
+ super.key,
+ required this.bytes,
+ required this.controller,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: Text(AppLocalizations.of(context)!.crop),
+ ),
+ body: Column(
+ children: [
+ Expanded(
+ child: Crop(
+ controller: controller,
+ image: bytes,
+ withCircleUi: true,
+ baseColor: Colors.black,
+ onCropped: (value) async {
+ Navigator.of(context).pop();
+
+ final response = await HttpRequest().postMultipart(
+ '/v1/members/image',
+ MemberController.instance.member!.token,
+ value,
+ );
+
+ if (response.statusCode != 200) {
+ throw HttpException(
+ 'Failed to change image ${response.body}');
+ }
+
+ MemberController.instance.increaseImageVersion();
+ },
+ ),
+ ),
+ // Rotate button
+ ElevatedButton(
+ onPressed: controller.crop,
+ child: Text(AppLocalizations.of(context)!.next),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/pubspec.lock b/pubspec.lock
index 1980a3a..747cec9 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -217,6 +217,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.1"
+ crop_your_image:
+ dependency: "direct main"
+ description:
+ name: crop_your_image
+ sha256: "9ae3b33042de5bda5321fc48aad41054c196bf2cc28350cd30cb8a85c1a7b1bd"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
cross_file:
dependency: transitive
description:
@@ -297,14 +305,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.1.4"
- file_picker:
- dependency: "direct main"
+ file_selector_linux:
+ dependency: transitive
+ description:
+ name: file_selector_linux
+ sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.9.2+1"
+ file_selector_macos:
+ dependency: transitive
description:
- name: file_picker
- sha256: "2ca051989f69d1b2ca012b2cf3ccf78c70d40144f0861ff2c063493f7c8c3d45"
+ name: file_selector_macos
+ sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385
url: "https://pub.dev"
source: hosted
- version: "8.0.5"
+ version: "0.9.4"
+ file_selector_platform_interface:
+ dependency: transitive
+ description:
+ name: file_selector_platform_interface
+ sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.6.2"
+ file_selector_windows:
+ dependency: transitive
+ description:
+ name: file_selector_windows
+ sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.9.3+1"
firebase_core:
dependency: "direct main"
description:
@@ -433,10 +465,10 @@ packages:
dependency: "direct main"
description:
name: freezed_annotation
- sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
+ sha256: f54946fdb1fa7b01f780841937b1a80783a20b393485f3f6cdf336fd6f4705f2
url: "https://pub.dev"
source: hosted
- version: "2.4.1"
+ version: "2.4.2"
frontend_server_client:
dependency: transitive
description:
@@ -501,30 +533,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.2.0"
- image_cropper:
+ image_picker:
dependency: "direct main"
description:
- name: image_cropper
- sha256: ee0485e232ca7e41f9397526bd911feb1996440e1e14e3d5f5240664fa435936
+ name: image_picker
+ sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.2"
+ image_picker_android:
+ dependency: transitive
+ description:
+ name: image_picker_android
+ sha256: "4161e1f843d8480d2e9025ee22411778c3c9eb7e40076dcf2da23d8242b7b51c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.8.12+3"
+ image_picker_for_web:
+ dependency: transitive
+ description:
+ name: image_picker_for_web
+ sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.4"
+ image_picker_ios:
+ dependency: transitive
+ description:
+ name: image_picker_ios
+ sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.8.12"
+ image_picker_linux:
+ dependency: transitive
+ description:
+ name: image_picker_linux
+ sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.1+1"
+ image_picker_macos:
+ dependency: transitive
+ description:
+ name: image_picker_macos
+ sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62"
url: "https://pub.dev"
source: hosted
- version: "7.0.5"
- image_cropper_for_web:
+ version: "0.2.1+1"
+ image_picker_platform_interface:
dependency: transitive
description:
- name: image_cropper_for_web
- sha256: ae3a307f970d1d2c286bce4519f8cb20c3f0a5332867a912366e1843e24bc8d3
+ name: image_picker_platform_interface
+ sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80"
url: "https://pub.dev"
source: hosted
- version: "5.0.4"
- image_cropper_platform_interface:
+ version: "2.10.0"
+ image_picker_windows:
dependency: transitive
description:
- name: image_cropper_platform_interface
- sha256: "04d0eebd5f901a4109f486d211c888f1fb25c6b70704a405fb1505cb742b05f0"
+ name: image_picker_windows
+ sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
url: "https://pub.dev"
source: hosted
- version: "6.0.3"
+ version: "0.2.1+1"
intl:
dependency: "direct main"
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 8a32b0f..093104d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -10,16 +10,16 @@ environment:
dependencies:
cached_network_image: ^3.3.1
- file_picker: ^8.0.5
+ crop_your_image: ^1.1.0
firebase_core: ^3.1.1
firebase_messaging: ^15.0.2
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
- freezed_annotation: ^2.4.1
+ freezed_annotation: ^2.4.2
http: ^1.2.1
- image_cropper: ^7.0.5
+ image_picker: ^1.1.2
intl: any
json_annotation: ^4.9.0
like_button: ^2.0.5