added image_cropper

master
Rafael 2024-06-02 01:07:39 +02:00
parent 731601e9c0
commit 97863bff2d
6 changed files with 125 additions and 25 deletions

View File

@ -26,6 +26,10 @@
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data <meta-data

View File

@ -1,12 +1,15 @@
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart'; import 'package:firebase_storage/firebase_storage.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'dart:io'; import 'dart:io' as io;
import '../constants.dart'; import '../constants.dart';
import '../models/user_profile.dart'; import '../models/user_profile.dart';
import '../utils/helper.dart';
class EditProfilePage extends StatefulWidget { class EditProfilePage extends StatefulWidget {
final UserProfile userData; final UserProfile userData;
@ -21,8 +24,8 @@ class EditProfilePageState extends State<EditProfilePage> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
late TextEditingController _nameController; late TextEditingController _nameController;
late TextEditingController _bioController; late TextEditingController _bioController;
late String? profileImageUrl; String? profileImageUrl;
File? _profileImage; io.File? _profileImage;
@override @override
void initState() { void initState() {
@ -35,12 +38,60 @@ class EditProfilePageState extends State<EditProfilePage> {
} }
Future<void> _pickImage() async { Future<void> _pickImage() async {
if (kIsWeb) {
showMsg(context, 'Limitation of the web version',
'Due to limitations of the component used in the web version, setting a profile picture is currently available only on Android and iOS.');
return;
}
final pickedFile = final pickedFile =
await ImagePicker().pickImage(source: ImageSource.gallery); await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) { if (pickedFile != null) {
setState(() { CroppedFile? croppedFile = await ImageCropper().cropImage(
_profileImage = File(pickedFile.path); sourcePath: pickedFile.path,
}); //compressFormat: ImageCompressFormat.jpg,
//compressQuality: 100,
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
uiSettings: [
AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false,
),
IOSUiSettings(
title: 'Cropper',
minimumAspectRatio: 1.0,
),
/* WebUiSettings(
context: context,
presentStyle: CropperPresentStyle.page,
boundary: const CroppieBoundary(
width: 400,
height: 400,
),
viewPort:
const CroppieViewPort(width: 360, height: 360, type: 'circle'),
enableExif: true,
enableZoom: true,
showZoomer: true,
),*/
],
);
if (croppedFile != null) {
setState(() {
_profileImage = io.File(croppedFile.path); // convert cropped file
});
}
} }
} }
@ -64,8 +115,11 @@ class EditProfilePageState extends State<EditProfilePage> {
.ref() .ref()
.child(Constants.dbStoragePathProfiles) .child(Constants.dbStoragePathProfiles)
.child(uid); // filename = userid .child(uid); // filename = userid
await storageRef.putFile(_profileImage!);
profileImageUrl = await storageRef.getDownloadURL(); if (!kIsWeb) {
await storageRef.putFile(_profileImage!);
profileImageUrl = await storageRef.getDownloadURL();
}
} }
Map<String, dynamic> resultValues = { Map<String, dynamic> resultValues = {
@ -167,7 +221,8 @@ class EditProfilePageState extends State<EditProfilePage> {
radius: 50, radius: 50,
backgroundImage: _profileImage != null backgroundImage: _profileImage != null
? FileImage(_profileImage!) as ImageProvider ? FileImage(_profileImage!) as ImageProvider
: (widget.userData.profilePictureUrl != null : ((widget.userData.profilePictureUrl != null &&
widget.userData.profilePictureUrl!.isNotEmpty)
? NetworkImage(widget.userData.profilePictureUrl!) ? NetworkImage(widget.userData.profilePictureUrl!)
as ImageProvider as ImageProvider
: null), : null),
@ -179,15 +234,14 @@ class EditProfilePageState extends State<EditProfilePage> {
width: 100, width: 100,
height: 100, height: 100,
child: _profileImage != null child: _profileImage != null
? Image.file( ? (kIsWeb
_profileImage!, ? Image.network(_profileImage!.path)
fit: BoxFit.cover, : Image.file(_profileImage!, fit: BoxFit.cover))
) : ((widget.userData.profilePictureUrl != null &&
: (widget.userData.profilePictureUrl != null widget.userData.profilePictureUrl!.isNotEmpty)
? Image.network( ? Image.network(
widget.userData.profilePictureUrl!, widget.userData.profilePictureUrl!,
fit: BoxFit.cover, fit: BoxFit.cover)
)
: null), : null),
), ),
), ),
@ -197,11 +251,12 @@ class EditProfilePageState extends State<EditProfilePage> {
right: 0, right: 0,
child: IconButton( child: IconButton(
icon: Ink( icon: Ink(
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
shape: const CircleBorder(), shape: const CircleBorder(),
), ),
child: const Icon(Icons.edit)), child: const Icon(Icons.edit),
),
onPressed: _pickImage, onPressed: _pickImage,
), ),
), ),

View File

@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_auth/firebase_auth.dart';
@ -609,11 +610,13 @@ class _UserProfilePageState extends State<UserProfilePage> {
), ),
CircleAvatar( CircleAvatar(
radius: 50, radius: 50,
backgroundImage: backgroundImage: (!kIsWeb &&
profileImageUrl != null ? NetworkImage(profileImageUrl!) : null, (profileImageUrl != null && profileImageUrl!.isNotEmpty))
child: profileImageUrl == null ? NetworkImage(profileImageUrl!)
? const Icon(Icons.person, size: 50)
: null, : null,
child: (profileImageUrl == null || profileImageUrl!.isEmpty)
? const Icon(Icons.person, size: 50)
: (kIsWeb ? const Icon(Icons.broken_image, size: 50) : null),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Text(myData.name, style: const TextStyle(fontSize: 24)), Text(myData.name, style: const TextStyle(fontSize: 24)),

View File

@ -360,6 +360,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
image_cropper:
dependency: "direct main"
description:
name: image_cropper
sha256: db779a8b620cd509874cb0e2a8bdc8649177f8f5ca46c13273ceaffe071e3f4a
url: "https://pub.dev"
source: hosted
version: "6.0.0"
image_cropper_for_web:
dependency: transitive
description:
name: image_cropper_for_web
sha256: ba67de40a98b3294084eed0b025b557cb594356e1171c9a830b340527dbd5e5f
url: "https://pub.dev"
source: hosted
version: "4.0.0"
image_cropper_platform_interface:
dependency: transitive
description:
name: image_cropper_platform_interface
sha256: ee160d686422272aa306125f3b6fb1c1894d9b87a5e20ed33fa008e7285da11e
url: "https://pub.dev"
source: hosted
version: "5.0.0"
image_picker: image_picker:
dependency: "direct main" dependency: "direct main"
description: description:
@ -424,6 +448,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.1+1" version: "0.2.1+1"
js:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.7.1"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:

View File

@ -46,6 +46,7 @@ dependencies:
swipable_stack: ^2.0.0 swipable_stack: ^2.0.0
image_picker: ^1.1.1 image_picker: ^1.1.1
firebase_storage: ^11.7.7 firebase_storage: ^11.7.7
image_cropper: ^6.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -32,6 +32,11 @@
<title>cofounderella</title> <title>cofounderella</title>
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
<!-- Croppie -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.css" />
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.3.0/exif.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.5/croppie.min.js"></script>
<script> <script>
// The value below is injected by flutter build, do not touch. // The value below is injected by flutter build, do not touch.
const serviceWorkerVersion = null; const serviceWorkerVersion = null;