mirror of
https://github.com/Iconica-Development/flutter_profile.git
synced 2025-05-19 01:03:45 +02:00
Merge pull request #4 from Iconica-Development/feat/image-url-support
Feat/image url support
This commit is contained in:
commit
a910c4d381
10 changed files with 130 additions and 109 deletions
|
@ -5,3 +5,7 @@
|
|||
## 0.0.2
|
||||
|
||||
* Add prioritizedItems option to display items at the top of the page.
|
||||
|
||||
## 0.0.3
|
||||
|
||||
* Add support for image URL (instead of in-memory image using image parameter from User model)
|
|
@ -37,12 +37,12 @@ class _ProfileExampleState extends State<ProfileExample> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
_user = User(
|
||||
'Firstname',
|
||||
'Lastname',
|
||||
Uint8List.fromList(
|
||||
firstName: 'Firstname',
|
||||
lastName: 'Lastname',
|
||||
image: Uint8List.fromList(
|
||||
[],
|
||||
),
|
||||
profileData,
|
||||
profileData: profileData,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -53,10 +53,10 @@ class _ProfileExampleState extends State<ProfileExample> {
|
|||
bottomActionText: 'Log out',
|
||||
itemBuilderOptions: ItemBuilderOptions(
|
||||
inputDecorationField: {
|
||||
'firstName': const InputDecoration(
|
||||
'first_name': const InputDecoration(
|
||||
label: Text('First name'),
|
||||
),
|
||||
'lastName': const InputDecoration(
|
||||
'last_name': const InputDecoration(
|
||||
label: Text('Last name'),
|
||||
),
|
||||
'email': const InputDecoration(
|
||||
|
@ -64,13 +64,13 @@ class _ProfileExampleState extends State<ProfileExample> {
|
|||
),
|
||||
},
|
||||
validators: {
|
||||
'firstName': (String? value) {
|
||||
'first_name': (String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Field empty';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
'lastName': (String? value) {
|
||||
'last_name': (String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Field empty';
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ library flutter_profile;
|
|||
|
||||
export 'src/widgets/profile/profile_page.dart';
|
||||
export 'src/widgets/profile/profile_style.dart';
|
||||
export 'src/widgets/avatar/avatar_wrapper.dart';
|
||||
export 'src/widgets/avatar/avatar.dart';
|
||||
export 'src/widgets/avatar/avatar_style.dart';
|
||||
export 'src/services/profile_service.dart';
|
||||
|
|
|
@ -2,39 +2,42 @@ import 'dart:typed_data';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// User is used to contain all user data. It consists of three standard fields: firstName, lastName and image.
|
||||
/// User is used to contain all user data. It consists of three standard fields: firstName, lastName and image/imageUrl.
|
||||
///
|
||||
/// For additional data profileData can be used.
|
||||
class User {
|
||||
String? firstName;
|
||||
String? lastName;
|
||||
Uint8List? image;
|
||||
String? imageUrl;
|
||||
ProfileData? profileData;
|
||||
|
||||
User(
|
||||
User({
|
||||
this.firstName,
|
||||
this.lastName,
|
||||
this.image,
|
||||
this.imageUrl,
|
||||
this.profileData,
|
||||
);
|
||||
});
|
||||
|
||||
factory User.fromMap(Map<String, dynamic> data) {
|
||||
return User(
|
||||
data['firstName'],
|
||||
data['lastName'],
|
||||
data['image'],
|
||||
data['profileData'],
|
||||
);
|
||||
}
|
||||
String get displayName => '${firstName ?? ''} ${lastName ?? ''}';
|
||||
String get initials => '${firstName?[0] ?? ''}${lastName?[0] ?? ''}';
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'firstName': firstName,
|
||||
'lastName': lastName,
|
||||
'image': image,
|
||||
'profileData': profileData,
|
||||
};
|
||||
}
|
||||
factory User.fromMap(Map<String, dynamic> data) => User(
|
||||
firstName: data['first_name'],
|
||||
lastName: data['last_name'],
|
||||
image: data['image'],
|
||||
imageUrl: data['image_url'],
|
||||
profileData: data['profile_data'],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
'first_name': firstName,
|
||||
'last_name': lastName,
|
||||
'image': image,
|
||||
'image_url': image,
|
||||
'profile_data': profileData,
|
||||
};
|
||||
}
|
||||
|
||||
/// ProfileData is used to store custom/addintional data for a user.
|
||||
|
|
|
@ -1,79 +1,60 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_profile/src/models/user.dart';
|
||||
import 'package:flutter_profile/src/widgets/avatar/avatar_style.dart';
|
||||
|
||||
class Avatar extends StatelessWidget {
|
||||
const Avatar({
|
||||
Key? key,
|
||||
this.image,
|
||||
this.firstName,
|
||||
this.lastName,
|
||||
this.avatar,
|
||||
required this.user,
|
||||
this.style = const AvatarStyle(),
|
||||
}) : super(key: key);
|
||||
|
||||
final Uint8List? image;
|
||||
final String? firstName;
|
||||
final String? lastName;
|
||||
final Widget? avatar;
|
||||
final User user;
|
||||
final AvatarStyle style;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
_avatar(),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
if (firstName != null || lastName != null)
|
||||
Text(
|
||||
'${firstName ?? ''} ${lastName ?? ''}',
|
||||
style: style.displayNameStyle,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
var imageProvider = _getImageProvider();
|
||||
|
||||
Widget _avatar() {
|
||||
if (avatar != null) {
|
||||
return avatar!;
|
||||
}
|
||||
if (image != null && image!.isNotEmpty) {
|
||||
if (imageProvider != null) {
|
||||
return Container(
|
||||
width: style.width,
|
||||
height: style.height,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(
|
||||
image: MemoryImage(image!),
|
||||
image: imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (firstName != null || lastName != null) {
|
||||
} else if (user.firstName != null || user.lastName != null) {
|
||||
return Container(
|
||||
width: style.width,
|
||||
height: style.height,
|
||||
decoration: BoxDecoration(
|
||||
color: _generateColorWithIntials(firstName, lastName),
|
||||
color: _generateColorWithIntials(user.firstName, user.lastName),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
style: const TextStyle(fontSize: 40),
|
||||
_getInitials(firstName, lastName),
|
||||
user.initials,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
|
||||
return Container();
|
||||
}
|
||||
|
||||
String _getInitials(String? firstName, String? lastName) {
|
||||
return (firstName?[0] ?? '') + (lastName?[0] ?? '');
|
||||
ImageProvider? _getImageProvider() {
|
||||
if (user.image != null) {
|
||||
return MemoryImage(user.image!);
|
||||
} else if (user.imageUrl != null) {
|
||||
return NetworkImage(user.imageUrl!);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Color _generateColorWithIntials(String? firstName, String? lastName) {
|
||||
|
|
|
@ -13,12 +13,16 @@ class AvatarStyle {
|
|||
const AvatarStyle({
|
||||
this.width = 100,
|
||||
this.height = 100,
|
||||
this.displayName = true,
|
||||
this.initialStyle = const TextStyle(),
|
||||
this.displayNamePadding = const EdgeInsets.only(top: 16),
|
||||
this.displayNameStyle = const TextStyle(),
|
||||
});
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final TextStyle initialStyle;
|
||||
final bool displayName;
|
||||
final EdgeInsets displayNamePadding;
|
||||
final TextStyle displayNameStyle;
|
||||
}
|
||||
|
|
44
lib/src/widgets/avatar/avatar_wrapper.dart
Normal file
44
lib/src/widgets/avatar/avatar_wrapper.dart
Normal file
|
@ -0,0 +1,44 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_profile/src/models/user.dart';
|
||||
import 'package:flutter_profile/src/widgets/avatar/avatar.dart';
|
||||
import 'package:flutter_profile/src/widgets/avatar/avatar_style.dart';
|
||||
|
||||
class AvaterWrapper extends StatelessWidget {
|
||||
const AvaterWrapper({
|
||||
Key? key,
|
||||
required this.user,
|
||||
this.avatar,
|
||||
this.style = const AvatarStyle(),
|
||||
}) : super(key: key);
|
||||
|
||||
final User user;
|
||||
final Widget? avatar;
|
||||
final AvatarStyle style;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var avatar = this.avatar ??
|
||||
Avatar(
|
||||
user: user,
|
||||
style: style,
|
||||
);
|
||||
|
||||
if (!style.displayName) {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
avatar,
|
||||
if (user.firstName != null || user.firstName != null)
|
||||
Padding(
|
||||
padding: style.displayNamePadding,
|
||||
child: Text(
|
||||
user.displayName,
|
||||
style: style.displayNameStyle,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_profile/src/models/user.dart';
|
||||
import 'package:flutter_profile/src/services/profile_service.dart';
|
||||
import 'package:flutter_profile/src/widgets/avatar/avatar.dart';
|
||||
import 'package:flutter_profile/src/widgets/avatar/avatar_wrapper.dart';
|
||||
import 'package:flutter_profile/src/widgets/item_builder/item_builder.dart';
|
||||
import 'package:flutter_profile/src/widgets/item_builder/item_builder_options.dart';
|
||||
import 'package:flutter_profile/src/widgets/item_builder/item_list.dart';
|
||||
|
@ -56,14 +56,14 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
);
|
||||
defaultItems.add(
|
||||
builder.build(
|
||||
'firstName',
|
||||
'first_name',
|
||||
firstNameKey,
|
||||
widget.user.firstName,
|
||||
null,
|
||||
(v) {
|
||||
widget.user.firstName = v;
|
||||
|
||||
widget.service.editProfile(widget.user, 'firstName', v);
|
||||
widget.service.editProfile(widget.user, 'first_name', v);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -74,14 +74,14 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
);
|
||||
defaultItems.add(
|
||||
builder.build(
|
||||
'lastName',
|
||||
'last_name',
|
||||
lastNameKey,
|
||||
widget.user.lastName,
|
||||
null,
|
||||
(v) {
|
||||
widget.user.lastName = v;
|
||||
|
||||
widget.service.editProfile(widget.user, 'lastName', v);
|
||||
widget.service.editProfile(widget.user, 'last_name', v);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -93,14 +93,14 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
} else {
|
||||
defaultItems.add(
|
||||
widget.itemBuilder!.build(
|
||||
'firstName',
|
||||
'first_name',
|
||||
firstNameKey,
|
||||
widget.user.firstName,
|
||||
null,
|
||||
(v) {
|
||||
widget.user.firstName = v;
|
||||
|
||||
widget.service.editProfile(widget.user, 'firstname', v);
|
||||
widget.service.editProfile(widget.user, 'first_name', v);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -111,14 +111,14 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
);
|
||||
defaultItems.add(
|
||||
widget.itemBuilder!.build(
|
||||
'lastName',
|
||||
'last_name',
|
||||
lastNameKey,
|
||||
widget.user.lastName,
|
||||
null,
|
||||
(v) {
|
||||
widget.user.lastName = v;
|
||||
|
||||
widget.service.editProfile(widget.user, 'lastName', v);
|
||||
widget.service.editProfile(widget.user, 'last_name', v);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -143,12 +143,10 @@ class _ProfileWrapperState extends State<ProfileWrapper> {
|
|||
onTap: () async {
|
||||
await widget.service.uploadImage(context);
|
||||
},
|
||||
child: Avatar(
|
||||
firstName: widget.user.firstName,
|
||||
lastName: widget.user.lastName,
|
||||
child: AvaterWrapper(
|
||||
user: widget.user,
|
||||
style: widget.style.avatarStyle,
|
||||
avatar: widget.customAvatar,
|
||||
image: widget.user.image,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_profile/flutter_profile.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'test_classes/test_profile_data.dart';
|
||||
import 'test_classes/test_profile_service.dart';
|
||||
|
||||
|
@ -13,10 +11,9 @@ void main() {
|
|||
home: Material(
|
||||
child: ProfilePage(
|
||||
user: User(
|
||||
'Firstname',
|
||||
'Lastname',
|
||||
Uint8List.fromList([]),
|
||||
TestProfileData(email: 'test@email.com'),
|
||||
firstName: 'Firstname',
|
||||
lastName: 'Lastname',
|
||||
profileData: TestProfileData(email: 'test@email.com'),
|
||||
),
|
||||
service: TestProfileService(),
|
||||
),
|
||||
|
@ -39,10 +36,7 @@ void main() {
|
|||
home: Material(
|
||||
child: ProfilePage(
|
||||
user: User(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
TestProfileData(email: null),
|
||||
profileData: TestProfileData(email: null),
|
||||
),
|
||||
service: TestProfileService(),
|
||||
),
|
||||
|
@ -58,10 +52,9 @@ void main() {
|
|||
home: Material(
|
||||
child: ProfilePage(
|
||||
user: User(
|
||||
'Firstname',
|
||||
'Lastname',
|
||||
null,
|
||||
TestProfileData(email: 'test@email.com'),
|
||||
firstName: 'Firstname',
|
||||
lastName: 'Lastname',
|
||||
profileData: TestProfileData(email: 'test@email.com'),
|
||||
),
|
||||
service: TestProfileService(),
|
||||
),
|
||||
|
|
|
@ -12,28 +12,21 @@ class TestProfileData extends ProfileData {
|
|||
Map<String, dynamic> mapWidget(
|
||||
VoidCallback update,
|
||||
BuildContext context,
|
||||
) {
|
||||
return {
|
||||
'email': null,
|
||||
};
|
||||
}
|
||||
) =>
|
||||
{
|
||||
'email': null,
|
||||
};
|
||||
|
||||
@override
|
||||
ProfileData fromMap(Map<String, dynamic> data) {
|
||||
return TestProfileData(
|
||||
email: data['email'],
|
||||
);
|
||||
}
|
||||
ProfileData fromMap(Map<String, dynamic> data) => TestProfileData(
|
||||
email: data['email'],
|
||||
);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'email': email,
|
||||
};
|
||||
}
|
||||
Map<String, dynamic> toMap() => {
|
||||
'email': email,
|
||||
};
|
||||
|
||||
@override
|
||||
ProfileData create() {
|
||||
return TestProfileData();
|
||||
}
|
||||
ProfileData create() => TestProfileData();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue