Fix: Display of ProfilePicture for Web

master
Rafael 2024-06-02 18:58:43 +02:00
parent cad532da0b
commit d121aa3c77
5 changed files with 69 additions and 55 deletions

View File

@ -2,9 +2,15 @@ import 'package:flutter/material.dart';
class UserTile extends StatelessWidget {
final String text;
final String? profileImageUrl;
final void Function()? onTap;
const UserTile({super.key, required this.text, required this.onTap});
const UserTile({
super.key,
required this.text,
this.profileImageUrl,
required this.onTap,
});
@override
Widget build(BuildContext context) {
@ -19,7 +25,14 @@ class UserTile extends StatelessWidget {
padding: const EdgeInsets.all(20),
child: Row(
children: [
// icon
// Profile image
if (profileImageUrl != null && profileImageUrl!.isNotEmpty)
CircleAvatar(
backgroundImage: NetworkImage(profileImageUrl!),
radius: 24,
),
// Icon if profile image is not set
if (profileImageUrl == null || profileImageUrl!.isEmpty)
const Icon(Icons.person),
const SizedBox(width: 20),

View File

@ -70,6 +70,7 @@ class ConversationsPage extends StatelessWidget {
Map<String, dynamic> userData, BuildContext context) {
return UserTile(
text: userData[Constants.dbFieldUsersEmail],
profileImageUrl: userData[Constants.dbFieldUsersProfilePic],
onTap: () {
// tapped on a user -> go to chat page
Navigator.push(

View File

@ -6,10 +6,10 @@ import 'package:firebase_storage/firebase_storage.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io' as io;
import 'dart:typed_data';
import '../constants.dart';
import '../models/user_profile.dart';
import '../utils/helper.dart';
class EditProfilePage extends StatefulWidget {
final UserProfile userData;
@ -25,7 +25,8 @@ class EditProfilePageState extends State<EditProfilePage> {
late TextEditingController _nameController;
late TextEditingController _bioController;
String? profileImageUrl;
io.File? _profileImage;
io.File? _profileImage; // for android/ios
Uint8List? _webProfileImage; // for web
@override
void initState() {
@ -38,12 +39,6 @@ class EditProfilePageState extends State<EditProfilePage> {
}
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 =
await ImagePicker().pickImage(source: ImageSource.gallery);
@ -57,7 +52,7 @@ class EditProfilePageState extends State<EditProfilePage> {
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
CropAspectRatioPreset.ratio16x9,
],
uiSettings: [
AndroidUiSettings(
@ -71,33 +66,43 @@ class EditProfilePageState extends State<EditProfilePage> {
title: 'Cropper',
minimumAspectRatio: 1.0,
),
/* WebUiSettings(
if (kIsWeb)
WebUiSettings(
context: context,
presentStyle: CropperPresentStyle.page,
boundary: const CroppieBoundary(
width: 400,
height: 400,
),
viewPort:
const CroppieViewPort(width: 360, height: 360, type: 'circle'),
viewPort: const CroppieViewPort(
width: 360, height: 360, type: 'circle'),
enableExif: true,
enableZoom: true,
showZoomer: true,
),*/
),
],
);
if (croppedFile != null) {
if (kIsWeb) {
// web specific
Uint8List webProfileImage = await croppedFile.readAsBytes();
setState(() {
_webProfileImage = webProfileImage;
});
} else {
setState(() {
_profileImage = io.File(croppedFile.path); // convert cropped file
});
}
}
}
}
void _clearProfileImage() {
setState(() {
_profileImage = null;
_webProfileImage = null; // web only
profileImageUrl = null;
widget.userData.profilePictureUrl = null;
});
@ -110,13 +115,16 @@ class EditProfilePageState extends State<EditProfilePage> {
if (_formKey.currentState!.validate()) {
String uid = FirebaseAuth.instance.currentUser!.uid;
if (_profileImage != null) {
if (_profileImage != null || _webProfileImage != null) {
final storageRef = FirebaseStorage.instance
.ref()
.child(Constants.dbStoragePathProfiles)
.child(uid); // filename = userid
if (!kIsWeb) {
if (kIsWeb && _webProfileImage != null) {
await storageRef.putData(_webProfileImage!);
profileImageUrl = await storageRef.getDownloadURL();
} else if (_profileImage != null) {
await storageRef.putFile(_profileImage!);
profileImageUrl = await storageRef.getDownloadURL();
}
@ -165,6 +173,7 @@ class EditProfilePageState extends State<EditProfilePage> {
children: [
buildAvatar(context),
if (_profileImage != null ||
_webProfileImage != null ||
widget.userData.profilePictureUrl != null)
IconButton(
icon: Ink(
@ -221,29 +230,20 @@ class EditProfilePageState extends State<EditProfilePage> {
radius: 50,
backgroundImage: _profileImage != null
? FileImage(_profileImage!) as ImageProvider
: ((widget.userData.profilePictureUrl != null &&
widget.userData.profilePictureUrl!.isNotEmpty)
: _webProfileImage != null
? MemoryImage(_webProfileImage!)
as ImageProvider // web specific
: (widget.userData.profilePictureUrl != null &&
widget.userData.profilePictureUrl!.isNotEmpty
? NetworkImage(widget.userData.profilePictureUrl!)
as ImageProvider
: null),
child: ClipOval(
child: _profileImage == null &&
_webProfileImage == null &&
widget.userData.profilePictureUrl == null
? const Icon(Icons.person, size: 50)
: SizedBox(
width: 100,
height: 100,
child: _profileImage != null
? (kIsWeb
? Image.network(_profileImage!.path)
: Image.file(_profileImage!, fit: BoxFit.cover))
: ((widget.userData.profilePictureUrl != null &&
widget.userData.profilePictureUrl!.isNotEmpty)
? Image.network(
widget.userData.profilePictureUrl!,
fit: BoxFit.cover)
: null),
),
: null,
),
),
Positioned(

View File

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

View File

@ -53,7 +53,8 @@
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: function(engineInitializer) {
engineInitializer.initializeEngine().then(function(appRunner) {
let config = { renderer: 'html' };
engineInitializer.initializeEngine(config).then(function(appRunner) {
appRunner.runApp();
});
}