added image_cropper
parent
731601e9c0
commit
97863bff2d
|
@ -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
|
||||||
|
|
|
@ -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,14 +38,62 @@ 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) {
|
||||||
|
CroppedFile? croppedFile = await ImageCropper().cropImage(
|
||||||
|
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(() {
|
setState(() {
|
||||||
_profileImage = File(pickedFile.path);
|
_profileImage = io.File(croppedFile.path); // convert cropped file
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _clearProfileImage() {
|
void _clearProfileImage() {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -64,9 +115,12 @@ class EditProfilePageState extends State<EditProfilePage> {
|
||||||
.ref()
|
.ref()
|
||||||
.child(Constants.dbStoragePathProfiles)
|
.child(Constants.dbStoragePathProfiles)
|
||||||
.child(uid); // filename = userid
|
.child(uid); // filename = userid
|
||||||
|
|
||||||
|
if (!kIsWeb) {
|
||||||
await storageRef.putFile(_profileImage!);
|
await storageRef.putFile(_profileImage!);
|
||||||
profileImageUrl = await storageRef.getDownloadURL();
|
profileImageUrl = await storageRef.getDownloadURL();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, dynamic> resultValues = {
|
Map<String, dynamic> resultValues = {
|
||||||
Constants.dbFieldUsersName: nameTrim,
|
Constants.dbFieldUsersName: nameTrim,
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -201,7 +255,8 @@ class EditProfilePageState extends State<EditProfilePage> {
|
||||||
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,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -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)),
|
||||||
|
|
32
pubspec.lock
32
pubspec.lock
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue