feat:add namebuilder

This commit is contained in:
Tim 2023-12-14 11:37:03 +01:00
parent 03b14924a2
commit d60244fa3e
5 changed files with 180 additions and 108 deletions

View file

@ -26,6 +26,7 @@ class TimelinePost {
this.reactions, this.reactions,
this.imageUrl, this.imageUrl,
this.image, this.image,
this.data = const {},
}); });
factory TimelinePost.fromJson(String id, Map<String, dynamic> json) => factory TimelinePost.fromJson(String id, Map<String, dynamic> json) =>
@ -50,6 +51,7 @@ class TimelinePost {
.toList(), .toList(),
createdAt: DateTime.parse(json['created_at'] as String), createdAt: DateTime.parse(json['created_at'] as String),
reactionEnabled: json['reaction_enabled'] as bool, reactionEnabled: json['reaction_enabled'] as bool,
data: json['data'] ?? {},
); );
/// The unique identifier of the post. /// The unique identifier of the post.
@ -94,6 +96,9 @@ class TimelinePost {
/// If reacting is enabled on the post. /// If reacting is enabled on the post.
final bool reactionEnabled; final bool reactionEnabled;
/// Option to add extra data to a timelinepost that won't be shown anywhere
final Map<String, dynamic> data;
TimelinePost copyWith({ TimelinePost copyWith({
String? id, String? id,
String? creatorId, String? creatorId,
@ -109,6 +114,7 @@ class TimelinePost {
List<TimelinePostReaction>? reactions, List<TimelinePostReaction>? reactions,
DateTime? createdAt, DateTime? createdAt,
bool? reactionEnabled, bool? reactionEnabled,
Map<String, dynamic>? data,
}) => }) =>
TimelinePost( TimelinePost(
id: id ?? this.id, id: id ?? this.id,
@ -125,6 +131,7 @@ class TimelinePost {
reactions: reactions ?? this.reactions, reactions: reactions ?? this.reactions,
createdAt: createdAt ?? this.createdAt, createdAt: createdAt ?? this.createdAt,
reactionEnabled: reactionEnabled ?? this.reactionEnabled, reactionEnabled: reactionEnabled ?? this.reactionEnabled,
data: data ?? this.data,
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -140,5 +147,6 @@ class TimelinePost {
'reactions': reactions?.map((e) => e.toJson()).toList() ?? [], 'reactions': reactions?.map((e) => e.toJson()).toList() ?? [],
'created_at': createdAt.toIso8601String(), 'created_at': createdAt.toIso8601String(),
'reaction_enabled': reactionEnabled, 'reaction_enabled': reactionEnabled,
'data': data,
}; };
} }

View file

@ -24,6 +24,8 @@ class TimelineOptions {
this.buttonBuilder, this.buttonBuilder,
this.textInputBuilder, this.textInputBuilder,
this.userAvatarBuilder, this.userAvatarBuilder,
this.anonymousAvatarBuilder,
this.nameBuilder,
}); });
/// Theming options for the timeline /// Theming options for the timeline
@ -56,6 +58,12 @@ class TimelineOptions {
final UserAvatarBuilder? userAvatarBuilder; final UserAvatarBuilder? userAvatarBuilder;
/// When the imageUrl is null this anonymousAvatarBuilder will be used
/// You can use it to display a default avatarW
final UserAvatarBuilder? anonymousAvatarBuilder;
final String Function(TimelinePosterUserModel?)? nameBuilder;
/// ImagePickerTheme can be used to change the UI of the /// ImagePickerTheme can be used to change the UI of the
/// Image Picker Widget to change the text/icons to your liking. /// Image Picker Widget to change the text/icons to your liking.
final ImagePickerTheme imagePickerTheme; final ImagePickerTheme imagePickerTheme;
@ -78,7 +86,7 @@ typedef TextInputBuilder = Widget Function(
String hintText, String hintText,
); );
typedef UserAvatarBuilder = Widget Function( typedef UserAvatarBuilder = Widget? Function(
TimelinePosterUserModel user, TimelinePosterUserModel user,
double size, double size,
); );

View file

@ -123,6 +123,7 @@ class _TimelinePostCreationScreenState
height: 100, height: 100,
child: TextField( child: TextField(
controller: contentController, controller: contentController,
textCapitalization: TextCapitalization.sentences,
expands: true, expands: true,
maxLines: null, maxLines: null,
minLines: null, minLines: null,

View file

@ -153,17 +153,29 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
post.creator!.imageUrl!, post.creator!.imageUrl!,
), ),
), ),
] else ...[
widget.options.anonymousAvatarBuilder?.call(
post.creator!,
40,
) ??
const CircleAvatar(
radius: 20,
child: Icon(
Icons.person,
),
),
], ],
const SizedBox(width: 10), const SizedBox(width: 10),
if (post.creator!.fullName != null) ...[
Text( Text(
post.creator!.fullName!, widget.options.nameBuilder
?.call(post.creator) ??
post.creator?.fullName ??
widget.options.translations.anonymousUser,
style: widget.options.theme.textStyles style: widget.options.theme.textStyles
.postCreatorTitleStyle ?? .postCreatorTitleStyle ??
theme.textTheme.titleMedium, theme.textTheme.titleMedium,
), ),
], ],
],
), ),
), ),
const Spacer(), const Spacer(),
@ -206,19 +218,23 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
), ),
], ],
), ),
const SizedBox(height: 8),
// image of the post // image of the post
if (post.imageUrl != null) ...[ if (post.imageUrl != null) ...[
CachedNetworkImage( const SizedBox(height: 8),
imageUrl: post.imageUrl!, ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: CachedNetworkImage(
width: double.infinity, width: double.infinity,
imageUrl: post.imageUrl!,
fit: BoxFit.fitHeight, fit: BoxFit.fitHeight,
), ),
),
], ],
const SizedBox(
height: 8,
),
// post information // post information
Padding( Row(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [ children: [
if (post.likedBy?.contains(widget.userId) ?? false) ...[ if (post.likedBy?.contains(widget.userId) ?? false) ...[
InkWell( InkWell(
@ -262,7 +278,7 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
), ),
], ],
), ),
), const SizedBox(height: 8),
Text( Text(
'${post.likes} ${widget.options.translations.likesTitle}', '${post.likes} ${widget.options.translations.likesTitle}',
style: widget style: widget
@ -272,7 +288,8 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
const SizedBox(height: 4), const SizedBox(height: 4),
Text.rich( Text.rich(
TextSpan( TextSpan(
text: post.creator?.fullName ?? text: widget.options.nameBuilder?.call(post.creator) ??
post.creator?.fullName ??
widget.options.translations.anonymousUser, widget.options.translations.anonymousUser,
style: widget style: widget
.options.theme.textStyles.postCreatorNameStyle ?? .options.theme.textStyles.postCreatorNameStyle ??
@ -287,9 +304,8 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
), ),
], ],
), ),
overflow: TextOverflow.ellipsis,
), ),
const SizedBox(height: 4), const SizedBox(height: 20),
Html( Html(
data: post.content, data: post.content,
style: { style: {
@ -300,15 +316,20 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
'#': Style( '#': Style(
maxLines: 3, maxLines: 3,
textOverflow: TextOverflow.ellipsis, textOverflow: TextOverflow.ellipsis,
padding: HtmlPaddings.zero,
margin: Margins.zero,
), ),
'H1': Style( 'H1': Style(
margin: Margins.all(0), padding: HtmlPaddings.zero,
margin: Margins.zero,
), ),
'H2': Style( 'H2': Style(
margin: Margins.all(0), padding: HtmlPaddings.zero,
margin: Margins.zero,
), ),
'H3': Style( 'H3': Style(
margin: Margins.all(0), padding: HtmlPaddings.zero,
margin: Margins.zero,
), ),
}, },
), ),
@ -319,7 +340,7 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
'${timeFormat.format(post.createdAt)}', '${timeFormat.format(post.createdAt)}',
style: theme.textTheme.bodySmall, style: theme.textTheme.bodySmall,
), ),
const SizedBox(height: 12), const SizedBox(height: 20),
if (post.reactionEnabled) ...[ if (post.reactionEnabled) ...[
Text( Text(
widget.options.translations.commentsTitle, widget.options.translations.commentsTitle,
@ -381,6 +402,17 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
reaction.creator!.imageUrl!, reaction.creator!.imageUrl!,
), ),
), ),
] else ...[
widget.options.anonymousAvatarBuilder?.call(
reaction.creator!,
25,
) ??
const CircleAvatar(
radius: 20,
child: Icon(
Icons.person,
),
),
], ],
const SizedBox(width: 10), const SizedBox(width: 10),
if (reaction.imageUrl != null) ...[ if (reaction.imageUrl != null) ...[
@ -389,6 +421,8 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
widget.options.nameBuilder
?.call(post.creator) ??
reaction.creator?.fullName ?? reaction.creator?.fullName ??
widget.options.translations widget.options.translations
.anonymousUser, .anonymousUser,
@ -408,7 +442,9 @@ class _TimelinePostScreenState extends State<TimelinePostScreen> {
Expanded( Expanded(
child: Text.rich( child: Text.rich(
TextSpan( TextSpan(
text: reaction.creator?.fullName ?? text: widget.options.nameBuilder
?.call(post.creator) ??
reaction.creator?.fullName ??
widget widget
.options.translations.anonymousUser, .options.translations.anonymousUser,
style: theme.textTheme.titleSmall, style: theme.textTheme.titleSmall,

View file

@ -68,16 +68,27 @@ class TimelinePostWidget extends StatelessWidget {
post.creator!.imageUrl!, post.creator!.imageUrl!,
), ),
), ),
], ] else ...[
const SizedBox(width: 10), options.anonymousAvatarBuilder?.call(
if (post.creator!.fullName != null) ...[ post.creator!,
Text( 40,
post.creator!.fullName!, ) ??
style: options.theme.textStyles const CircleAvatar(
.listPostCreatorTitleStyle ?? radius: 20,
theme.textTheme.titleMedium, child: Icon(
Icons.person,
),
), ),
], ],
const SizedBox(width: 10),
Text(
options.nameBuilder?.call(post.creator) ??
post.creator?.fullName ??
options.translations.anonymousUser,
style:
options.theme.textStyles.postCreatorTitleStyle ??
theme.textTheme.titleMedium,
),
], ],
), ),
), ),
@ -118,22 +129,26 @@ class TimelinePostWidget extends StatelessWidget {
), ),
], ],
), ),
const SizedBox(height: 8),
// image of the post // image of the post
if (post.imageUrl != null) ...[ if (post.imageUrl != null) ...[
const SizedBox(height: 8),
Flexible( Flexible(
flex: height != null ? 1 : 0, flex: height != null ? 1 : 0,
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: CachedNetworkImage( child: CachedNetworkImage(
imageUrl: post.imageUrl!,
width: double.infinity, width: double.infinity,
imageUrl: post.imageUrl!,
fit: BoxFit.fitWidth, fit: BoxFit.fitWidth,
), ),
), ),
),
], ],
const SizedBox(
height: 8,
),
// post information // post information
Padding( Row(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [ children: [
if (post.likedBy?.contains(userId) ?? false) ...[ if (post.likedBy?.contains(userId) ?? false) ...[
InkWell( InkWell(
@ -163,7 +178,10 @@ class TimelinePostWidget extends StatelessWidget {
), ),
], ],
), ),
const SizedBox(
height: 8,
), ),
Text( Text(
'${post.likes} ${options.translations.likesTitle}', '${post.likes} ${options.translations.likesTitle}',
style: options.theme.textStyles.listPostLikeTitleAndAmount ?? style: options.theme.textStyles.listPostLikeTitleAndAmount ??
@ -172,7 +190,8 @@ class TimelinePostWidget extends StatelessWidget {
const SizedBox(height: 4), const SizedBox(height: 4),
Text.rich( Text.rich(
TextSpan( TextSpan(
text: post.creator?.fullName ?? text: options.nameBuilder?.call(post.creator) ??
post.creator?.fullName ??
options.translations.anonymousUser, options.translations.anonymousUser,
style: options.theme.textStyles.listCreatorNameStyle ?? style: options.theme.textStyles.listCreatorNameStyle ??
theme.textTheme.titleSmall, theme.textTheme.titleSmall,
@ -185,8 +204,8 @@ class TimelinePostWidget extends StatelessWidget {
), ),
], ],
), ),
overflow: TextOverflow.ellipsis,
), ),
const SizedBox(height: 4),
Text( Text(
options.translations.viewPost, options.translations.viewPost,
style: options.theme.textStyles.viewPostStyle ?? style: options.theme.textStyles.viewPostStyle ??