diff --git a/packages/flutter_timeline_view/assets/Comment.svg b/packages/flutter_timeline_view/assets/Comment.svg
new file mode 100644
index 0000000..35a7950
--- /dev/null
+++ b/packages/flutter_timeline_view/assets/Comment.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/flutter_timeline_view/assets/send.svg b/packages/flutter_timeline_view/assets/send.svg
new file mode 100644
index 0000000..0293ec9
--- /dev/null
+++ b/packages/flutter_timeline_view/assets/send.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_post_creation_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_post_creation_screen.dart
index 0406314..36164b4 100644
--- a/packages/flutter_timeline_view/lib/src/screens/timeline_post_creation_screen.dart
+++ b/packages/flutter_timeline_view/lib/src/screens/timeline_post_creation_screen.dart
@@ -148,7 +148,7 @@ class _TimelinePostCreationScreenState
hintText: widget.options.translations.titleHintText,
textMaxLength: widget.options.maxTitleLength,
decoration: widget.options.titleInputDecoration,
- textCapitalization: null,
+ textCapitalization: TextCapitalization.sentences,
expands: null,
minLines: null,
maxLines: 1,
@@ -354,17 +354,20 @@ class _TimelinePostCreationScreenState
widget.options.translations.checkPost,
enabled: editingDone,
) ??
- DefaultFilledButton(
- onPressed: editingDone
- ? () async {
- await onPostCreated();
- await widget.service.postService
- .fetchPosts(null);
- }
- : null,
- buttonText: widget.enablePostOverviewScreen
- ? widget.options.translations.checkPost
- : widget.options.translations.postCreation,
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 48),
+ child: DefaultFilledButton(
+ onPressed: editingDone
+ ? () async {
+ await onPostCreated();
+ await widget.service.postService
+ .fetchPosts(null);
+ }
+ : null,
+ buttonText: widget.enablePostOverviewScreen
+ ? widget.options.translations.checkPost
+ : widget.options.translations.postCreation,
+ ),
),
),
),
diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_post_overview_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_post_overview_screen.dart
index 3d20c59..9336226 100644
--- a/packages/flutter_timeline_view/lib/src/screens/timeline_post_overview_screen.dart
+++ b/packages/flutter_timeline_view/lib/src/screens/timeline_post_overview_screen.dart
@@ -27,6 +27,7 @@ class TimelinePostOverviewScreen extends StatelessWidget {
?.title ??
timelinePost.category;
var buttonText = '${options.translations.postIn} $timelineCategoryName';
+ var isSubmitted = false;
return Column(
mainAxisSize: MainAxisSize.max,
children: [
@@ -55,11 +56,20 @@ class TimelinePostOverviewScreen extends StatelessWidget {
buttonText,
enabled: true,
) ??
- DefaultFilledButton(
- onPressed: () async => onPostSubmit(timelinePost),
- buttonText: buttonText,
+ SafeArea(
+ bottom: true,
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 80),
+ child: DefaultFilledButton(
+ onPressed: () async {
+ if (isSubmitted) return;
+ isSubmitted = true;
+ onPostSubmit(timelinePost);
+ },
+ buttonText: buttonText,
+ ),
+ ),
),
- SizedBox(height: options.paddings.postOverviewButtonBottomPadding),
],
);
}
diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_post_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_post_screen.dart
index ffc1c02..cfde054 100644
--- a/packages/flutter_timeline_view/lib/src/screens/timeline_post_screen.dart
+++ b/packages/flutter_timeline_view/lib/src/screens/timeline_post_screen.dart
@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
import 'package:flutter_timeline_view/src/config/timeline_options.dart';
import 'package:flutter_timeline_view/src/widgets/reaction_bottom.dart';
@@ -355,10 +356,13 @@ class _TimelinePostScreenState extends State {
const SizedBox(width: 8),
if (post.reactionEnabled)
widget.options.theme.commentIcon ??
- Icon(
- Icons.chat_bubble_outline_rounded,
+ SvgPicture.asset(
+ 'assets/Comment.svg',
+ package: 'flutter_timeline_view',
+ // ignore: deprecated_member_use
color: widget.options.theme.iconColor,
- size: widget.options.iconSize,
+ width: widget.options.iconSize,
+ height: widget.options.iconSize,
),
],
),
@@ -454,9 +458,7 @@ class _TimelinePostScreenState extends State {
}
},
child: Row(
- crossAxisAlignment: reaction.imageUrl != null
- ? CrossAxisAlignment.start
- : CrossAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (reaction.creator?.imageUrl != null &&
reaction.creator!.imageUrl!.isNotEmpty) ...[
diff --git a/packages/flutter_timeline_view/lib/src/widgets/default_filled_button.dart b/packages/flutter_timeline_view/lib/src/widgets/default_filled_button.dart
index 2eb6d4e..7581003 100644
--- a/packages/flutter_timeline_view/lib/src/widgets/default_filled_button.dart
+++ b/packages/flutter_timeline_view/lib/src/widgets/default_filled_button.dart
@@ -24,6 +24,7 @@ class DefaultFilledButton extends StatelessWidget {
padding: const EdgeInsets.all(8),
child: Text(
buttonText,
+ overflow: TextOverflow.ellipsis,
style: theme.textTheme.displayLarge,
),
),
diff --git a/packages/flutter_timeline_view/lib/src/widgets/reaction_bottom.dart b/packages/flutter_timeline_view/lib/src/widgets/reaction_bottom.dart
index 1e3f39d..a13dfbe 100644
--- a/packages/flutter_timeline_view/lib/src/widgets/reaction_bottom.dart
+++ b/packages/flutter_timeline_view/lib/src/widgets/reaction_bottom.dart
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_timeline_view/src/config/timeline_options.dart';
import 'package:flutter_timeline_view/src/config/timeline_translations.dart';
@@ -43,8 +44,10 @@ class _ReactionBottomState extends State {
_textEditingController.clear();
}
},
- icon: Icon(
- Icons.send,
+ icon: SvgPicture.asset(
+ 'assets/send.svg',
+ package: 'flutter_timeline_view',
+ // ignore: deprecated_member_use
color: widget.iconColor,
),
),
diff --git a/packages/flutter_timeline_view/lib/src/widgets/timeline_post_widget.dart b/packages/flutter_timeline_view/lib/src/widgets/timeline_post_widget.dart
index 597309d..07b9c22 100644
--- a/packages/flutter_timeline_view/lib/src/widgets/timeline_post_widget.dart
+++ b/packages/flutter_timeline_view/lib/src/widgets/timeline_post_widget.dart
@@ -4,6 +4,7 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
import 'package:flutter_timeline_view/src/config/timeline_options.dart';
import 'package:flutter_timeline_view/src/widgets/tappable_image.dart';
@@ -53,303 +54,306 @@ class _TimelinePostWidgetState extends State {
Widget build(BuildContext context) {
var theme = Theme.of(context);
var isLikedByUser = widget.post.likedBy?.contains(widget.userId) ?? false;
- return InkWell(
- onTap: widget.onTap,
- child: SizedBox(
- height: widget.post.imageUrl != null || widget.post.image != null
- ? widget.options.postWidgetHeight
- : null,
- width: double.infinity,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- children: [
- if (widget.post.creator != null)
- InkWell(
- onTap: widget.onUserTap != null
- ? () =>
- widget.onUserTap?.call(widget.post.creator!.userId)
- : null,
- child: Row(
- children: [
- if (widget.post.creator!.imageUrl != null) ...[
- widget.options.userAvatarBuilder?.call(
- widget.post.creator!,
- 28,
- ) ??
- CircleAvatar(
- radius: 14,
- backgroundImage: CachedNetworkImageProvider(
- widget.post.creator!.imageUrl!,
- ),
+ return SizedBox(
+ height: widget.post.imageUrl != null || widget.post.image != null
+ ? widget.options.postWidgetHeight
+ : null,
+ width: double.infinity,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ if (widget.post.creator != null)
+ InkWell(
+ onTap: widget.onUserTap != null
+ ? () =>
+ widget.onUserTap?.call(widget.post.creator!.userId)
+ : null,
+ child: Row(
+ children: [
+ if (widget.post.creator!.imageUrl != null) ...[
+ widget.options.userAvatarBuilder?.call(
+ widget.post.creator!,
+ 28,
+ ) ??
+ CircleAvatar(
+ radius: 14,
+ backgroundImage: CachedNetworkImageProvider(
+ widget.post.creator!.imageUrl!,
),
- ] else ...[
- widget.options.anonymousAvatarBuilder?.call(
- widget.post.creator!,
- 28,
- ) ??
- const CircleAvatar(
- radius: 14,
- child: Icon(
- Icons.person,
- ),
- ),
- ],
- const SizedBox(width: 10),
- Text(
- widget.options.nameBuilder
- ?.call(widget.post.creator) ??
- widget.post.creator?.fullName ??
- widget.options.translations.anonymousUser,
- style: widget.options.theme.textStyles
- .postCreatorTitleStyle ??
- theme.textTheme.titleSmall!.copyWith(
- color: Colors.black,
- ),
- ),
- ],
- ),
- ),
- const Spacer(),
- if (widget.allowAllDeletion ||
- widget.post.creator?.userId == widget.userId)
- PopupMenuButton(
- onSelected: (value) async {
- if (value == 'delete') {
- await showPostDeletionConfirmationDialog(
- widget.options,
- context,
- widget.onPostDelete,
- );
- }
- },
- itemBuilder: (BuildContext context) =>
- >[
- PopupMenuItem(
- value: 'delete',
- child: Row(
- children: [
- Text(
- widget.options.translations.deletePost,
- style: widget.options.theme.textStyles
- .deletePostStyle ??
- theme.textTheme.bodyMedium,
),
- const SizedBox(width: 8),
- widget.options.theme.deleteIcon ??
- Icon(
- Icons.delete,
- color: widget.options.theme.iconColor,
- ),
- ],
- ),
+ ] else ...[
+ widget.options.anonymousAvatarBuilder?.call(
+ widget.post.creator!,
+ 28,
+ ) ??
+ const CircleAvatar(
+ radius: 14,
+ child: Icon(
+ Icons.person,
+ ),
+ ),
+ ],
+ const SizedBox(width: 10),
+ Text(
+ widget.options.nameBuilder?.call(widget.post.creator) ??
+ widget.post.creator?.fullName ??
+ widget.options.translations.anonymousUser,
+ style: widget.options.theme.textStyles
+ .postCreatorTitleStyle ??
+ theme.textTheme.titleSmall!.copyWith(
+ color: Colors.black,
+ ),
),
],
- child: widget.options.theme.moreIcon ??
- Icon(
- Icons.more_horiz_rounded,
- color: widget.options.theme.iconColor,
- ),
),
- ],
- ),
- // image of the post
- if (widget.post.imageUrl != null || widget.post.image != null) ...[
- const SizedBox(height: 8),
- Flexible(
- flex: widget.options.postWidgetHeight != null ? 1 : 0,
- child: ClipRRect(
- borderRadius: const BorderRadius.all(Radius.circular(8)),
- child: widget.options.doubleTapTolike
- ? TappableImage(
- likeAndDislikeIcon:
- widget.options.likeAndDislikeIconsForDoubleTap,
- post: widget.post,
- userId: widget.userId,
- onLike: ({required bool liked}) async {
- var userId = widget.userId;
-
- late TimelinePost result;
-
- if (!liked) {
- result =
- await widget.service.postService.likePost(
- userId,
- widget.post,
- );
- } else {
- result =
- await widget.service.postService.unlikePost(
- userId,
- widget.post,
- );
- }
-
- return result.likedBy?.contains(userId) ?? false;
- },
- )
- : widget.post.imageUrl != null
- ? CachedNetworkImage(
- width: double.infinity,
- imageUrl: widget.post.imageUrl!,
- fit: BoxFit.fitWidth,
- )
- : Image.memory(
- width: double.infinity,
- widget.post.image!,
- fit: BoxFit.fitWidth,
- ),
),
- ),
+ const Spacer(),
+ if (widget.allowAllDeletion ||
+ widget.post.creator?.userId == widget.userId)
+ PopupMenuButton(
+ onSelected: (value) async {
+ if (value == 'delete') {
+ await showPostDeletionConfirmationDialog(
+ widget.options,
+ context,
+ widget.onPostDelete,
+ );
+ }
+ },
+ itemBuilder: (BuildContext context) =>
+ >[
+ PopupMenuItem(
+ value: 'delete',
+ child: Row(
+ children: [
+ Text(
+ widget.options.translations.deletePost,
+ style: widget
+ .options.theme.textStyles.deletePostStyle ??
+ theme.textTheme.bodyMedium,
+ ),
+ const SizedBox(width: 8),
+ widget.options.theme.deleteIcon ??
+ Icon(
+ Icons.delete,
+ color: widget.options.theme.iconColor,
+ ),
+ ],
+ ),
+ ),
+ ],
+ child: widget.options.theme.moreIcon ??
+ Icon(
+ Icons.more_horiz_rounded,
+ color: widget.options.theme.iconColor,
+ ),
+ ),
],
- const SizedBox(
- height: 8,
+ ),
+ // image of the post
+ if (widget.post.imageUrl != null || widget.post.image != null) ...[
+ const SizedBox(height: 8),
+ Flexible(
+ flex: widget.options.postWidgetHeight != null ? 1 : 0,
+ child: ClipRRect(
+ borderRadius: const BorderRadius.all(Radius.circular(8)),
+ child: widget.options.doubleTapTolike
+ ? TappableImage(
+ likeAndDislikeIcon:
+ widget.options.likeAndDislikeIconsForDoubleTap,
+ post: widget.post,
+ userId: widget.userId,
+ onLike: ({required bool liked}) async {
+ var userId = widget.userId;
+
+ late TimelinePost result;
+
+ if (!liked) {
+ result = await widget.service.postService.likePost(
+ userId,
+ widget.post,
+ );
+ } else {
+ result =
+ await widget.service.postService.unlikePost(
+ userId,
+ widget.post,
+ );
+ }
+
+ return result.likedBy?.contains(userId) ?? false;
+ },
+ )
+ : widget.post.imageUrl != null
+ ? CachedNetworkImage(
+ width: double.infinity,
+ imageUrl: widget.post.imageUrl!,
+ fit: BoxFit.fitWidth,
+ )
+ : Image.memory(
+ width: double.infinity,
+ widget.post.image!,
+ fit: BoxFit.fitWidth,
+ ),
+ ),
),
- // post information
- if (widget.options.iconsWithValues) ...[
- Row(
- children: [
+ ],
+ const SizedBox(
+ height: 8,
+ ),
+ // post information
+ if (widget.options.iconsWithValues) ...[
+ Row(
+ children: [
+ IconButton(
+ padding: EdgeInsets.zero,
+ constraints: const BoxConstraints(),
+ onPressed: () async {
+ var userId = widget.userId;
+
+ if (!isLikedByUser) {
+ await widget.service.postService.likePost(
+ userId,
+ widget.post,
+ );
+ } else {
+ await widget.service.postService.unlikePost(
+ userId,
+ widget.post,
+ );
+ }
+ },
+ icon: widget.options.theme.likeIcon ??
+ Icon(
+ isLikedByUser
+ ? Icons.favorite_rounded
+ : Icons.favorite_outline_outlined,
+ color: widget.options.theme.iconColor,
+ size: widget.options.iconSize,
+ ),
+ ),
+ const SizedBox(
+ width: 4,
+ ),
+ Text('${widget.post.likes}'),
+ if (widget.post.reactionEnabled) ...[
+ const SizedBox(
+ width: 8,
+ ),
IconButton(
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
- onPressed: () async {
- var userId = widget.userId;
-
- if (!isLikedByUser) {
- await widget.service.postService.likePost(
- userId,
- widget.post,
- );
- } else {
- await widget.service.postService.unlikePost(
- userId,
- widget.post,
- );
- }
- },
- icon: widget.options.theme.likeIcon ??
- Icon(
- isLikedByUser
- ? Icons.favorite_rounded
- : Icons.favorite_outline_outlined,
+ onPressed: widget.onTap,
+ icon: widget.options.theme.commentIcon ??
+ SvgPicture.asset(
+ 'assets/Comment.svg',
+ package: 'flutter_timeline_view',
+ // ignore: deprecated_member_use
color: widget.options.theme.iconColor,
- size: widget.options.iconSize,
+ width: widget.options.iconSize,
+ height: widget.options.iconSize,
),
),
const SizedBox(
width: 4,
),
- Text('${widget.post.likes}'),
- if (widget.post.reactionEnabled) ...[
- const SizedBox(
- width: 8,
- ),
- IconButton(
- padding: EdgeInsets.zero,
- constraints: const BoxConstraints(),
- onPressed: widget.onTap,
- icon: widget.options.theme.commentIcon ??
- Icon(
- Icons.chat_bubble_outline_outlined,
- color: widget.options.theme.iconColor,
- size: widget.options.iconSize,
- ),
- ),
- const SizedBox(
- width: 4,
- ),
- Text('${widget.post.reaction}'),
- ],
+ Text('${widget.post.reaction}'),
],
- ),
- ] else ...[
- Row(
- children: [
+ ],
+ ),
+ ] else ...[
+ Row(
+ children: [
+ IconButton(
+ padding: EdgeInsets.zero,
+ constraints: const BoxConstraints(),
+ onPressed:
+ isLikedByUser ? widget.onTapUnlike : widget.onTapLike,
+ icon: (isLikedByUser
+ ? widget.options.theme.likedIcon
+ : widget.options.theme.likeIcon) ??
+ Icon(
+ isLikedByUser
+ ? Icons.favorite_rounded
+ : Icons.favorite_outline,
+ color: widget.options.theme.iconColor,
+ size: widget.options.iconSize,
+ ),
+ ),
+ const SizedBox(width: 8),
+ if (widget.post.reactionEnabled) ...[
IconButton(
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
- onPressed:
- isLikedByUser ? widget.onTapUnlike : widget.onTapLike,
- icon: (isLikedByUser
- ? widget.options.theme.likedIcon
- : widget.options.theme.likeIcon) ??
- Icon(
- isLikedByUser
- ? Icons.favorite_rounded
- : Icons.favorite_outline,
+ onPressed: widget.onTap,
+ icon: widget.options.theme.commentIcon ??
+ SvgPicture.asset(
+ 'assets/Comment.svg',
+ package: 'flutter_timeline_view',
+ // ignore: deprecated_member_use
color: widget.options.theme.iconColor,
- size: widget.options.iconSize,
+ width: widget.options.iconSize,
+ height: widget.options.iconSize,
),
),
- const SizedBox(width: 8),
- if (widget.post.reactionEnabled) ...[
- IconButton(
- padding: EdgeInsets.zero,
- constraints: const BoxConstraints(),
- onPressed: widget.onTap,
- icon: widget.options.theme.commentIcon ??
- Icon(
- Icons.chat_bubble_outline_outlined,
- color: widget.options.theme.iconColor,
- size: widget.options.iconSize,
- ),
- ),
- ],
],
- ),
- ],
-
- const SizedBox(
- height: 8,
+ ],
),
+ ],
- if (widget.options.itemInfoBuilder != null) ...[
- widget.options.itemInfoBuilder!(
- post: widget.post,
- ),
- ] else ...[
- Text(
- '${widget.post.likes} '
- '${widget.options.translations.likesTitle}',
- style: widget
- .options.theme.textStyles.listPostLikeTitleAndAmount ??
- theme.textTheme.titleSmall!.copyWith(
- color: Colors.black,
- ),
- ),
- Text.rich(
- TextSpan(
- text: widget.options.nameBuilder?.call(widget.post.creator) ??
- widget.post.creator?.fullName ??
- widget.options.translations.anonymousUser,
- style: widget.options.theme.textStyles.listCreatorNameStyle ??
+ const SizedBox(
+ height: 8,
+ ),
+
+ if (widget.options.itemInfoBuilder != null) ...[
+ widget.options.itemInfoBuilder!(
+ post: widget.post,
+ ),
+ ] else ...[
+ Text(
+ '${widget.post.likes} '
+ '${widget.options.translations.likesTitle}',
+ style:
+ widget.options.theme.textStyles.listPostLikeTitleAndAmount ??
theme.textTheme.titleSmall!.copyWith(
color: Colors.black,
),
- children: [
- TextSpan(
- text: widget.post.title,
- style:
- widget.options.theme.textStyles.listPostTitleStyle ??
- theme.textTheme.bodySmall,
+ ),
+ Text.rich(
+ TextSpan(
+ text: widget.options.nameBuilder?.call(widget.post.creator) ??
+ widget.post.creator?.fullName ??
+ widget.options.translations.anonymousUser,
+ style: widget.options.theme.textStyles.listCreatorNameStyle ??
+ theme.textTheme.titleSmall!.copyWith(
+ color: Colors.black,
),
- ],
- ),
+ children: [
+ TextSpan(
+ text: widget.post.title,
+ style: widget.options.theme.textStyles.listPostTitleStyle ??
+ theme.textTheme.bodySmall,
+ ),
+ ],
),
- const SizedBox(height: 4),
- Text(
+ ),
+ const SizedBox(height: 4),
+ InkWell(
+ onTap: widget.onTap,
+ child: Text(
widget.options.translations.viewPost,
style: widget.options.theme.textStyles.viewPostStyle ??
theme.textTheme.titleSmall!.copyWith(
color: const Color(0xFF8D8D8D),
),
),
- ],
- if (widget.options.dividerBuilder != null)
- widget.options.dividerBuilder!(),
+ ),
],
- ),
+ if (widget.options.dividerBuilder != null)
+ widget.options.dividerBuilder!(),
+ ],
),
);
}
diff --git a/packages/flutter_timeline_view/pubspec.yaml b/packages/flutter_timeline_view/pubspec.yaml
index 018785c..b16f14c 100644
--- a/packages/flutter_timeline_view/pubspec.yaml
+++ b/packages/flutter_timeline_view/pubspec.yaml
@@ -17,7 +17,6 @@ dependencies:
intl: any
cached_network_image: ^3.2.2
dotted_border: ^2.1.0
- flutter_html: ^3.0.0-beta.2
flutter_timeline_interface:
git:
@@ -29,6 +28,7 @@ dependencies:
url: https://github.com/Iconica-Development/flutter_image_picker
ref: 1.0.5
collection: any
+ flutter_svg: ^2.0.10+1
dependency_overrides:
flutter_timeline_interface:
@@ -42,3 +42,6 @@ dev_dependencies:
ref: 6.0.0
flutter:
+ assets:
+ - assets/
+