diff --git a/packages/flutter_timeline/example/lib/post_screen.dart b/packages/flutter_timeline/example/lib/post_screen.dart index b72369d..3c5f05a 100644 --- a/packages/flutter_timeline/example/lib/post_screen.dart +++ b/packages/flutter_timeline/example/lib/post_screen.dart @@ -22,7 +22,7 @@ class _PostScreenState extends State { body: TimelinePostScreen( userId: 'test_user', service: widget.service, - options: const TimelineOptions(), + options: TimelineOptions(), post: widget.post, onPostDelete: () { print('delete post'); diff --git a/packages/flutter_timeline/example/lib/timeline_service.dart b/packages/flutter_timeline/example/lib/timeline_service.dart index f4e2099..fe69001 100644 --- a/packages/flutter_timeline/example/lib/timeline_service.dart +++ b/packages/flutter_timeline/example/lib/timeline_service.dart @@ -11,11 +11,12 @@ import 'package:flutter_timeline/flutter_timeline.dart'; import 'package:uuid/uuid.dart'; class TestTimelineService with ChangeNotifier implements TimelineService { - List _posts = []; + @override + List posts = []; @override Future createPost(TimelinePost post) async { - _posts.add( + posts.add( post.copyWith( creator: const TimelinePosterUserModel(userId: 'test_user'), ), @@ -26,7 +27,7 @@ class TestTimelineService with ChangeNotifier implements TimelineService { @override Future deletePost(TimelinePost post) async { - _posts = _posts.where((element) => element.id != post.id).toList(); + posts = posts.where((element) => element.id != post.id).toList(); notifyListeners(); } @@ -43,7 +44,7 @@ class TestTimelineService with ChangeNotifier implements TimelineService { reaction: post.reaction - 1, reactions: (post.reactions ?? [])..remove(reaction), ); - _posts = _posts + posts = posts .map( (p) => p.id == post.id ? updatedPost : p, ) @@ -64,7 +65,7 @@ class TestTimelineService with ChangeNotifier implements TimelineService { creator: const TimelinePosterUserModel(userId: 'test_user'))); } var updatedPost = post.copyWith(reactions: updatedReactions); - _posts = _posts.map((p) => (p.id == post.id) ? updatedPost : p).toList(); + posts = posts.map((p) => (p.id == post.id) ? updatedPost : p).toList(); notifyListeners(); return updatedPost; } @@ -72,7 +73,6 @@ class TestTimelineService with ChangeNotifier implements TimelineService { @override Future> fetchPosts(String? category) async { var posts = getMockedPosts(); - _posts = posts; notifyListeners(); return posts; } @@ -83,7 +83,7 @@ class TestTimelineService with ChangeNotifier implements TimelineService { int limit, ) async { notifyListeners(); - return _posts; + return posts; } @override @@ -94,32 +94,31 @@ class TestTimelineService with ChangeNotifier implements TimelineService { @override Future> refreshPosts(String? category) async { - var posts = []; + var newPosts = []; - _posts = [...posts, ..._posts]; + posts = [...posts, ...newPosts]; notifyListeners(); return posts; } @override TimelinePost? getPost(String postId) => - (_posts.any((element) => element.id == postId)) - ? _posts.firstWhere((element) => element.id == postId) + (posts.any((element) => element.id == postId)) + ? posts.firstWhere((element) => element.id == postId) : null; @override - List getPosts(String? category) => _posts + List getPosts(String? category) => posts .where((element) => category == null || element.category == category) .toList(); @override Future likePost(String userId, TimelinePost post) async { - print(userId); var updatedPost = post.copyWith( likes: post.likes + 1, likedBy: (post.likedBy ?? [])..add(userId), ); - _posts = _posts + posts = posts .map( (p) => p.id == post.id ? updatedPost : p, ) @@ -135,7 +134,7 @@ class TestTimelineService with ChangeNotifier implements TimelineService { likes: post.likes - 1, likedBy: post.likedBy?..remove(userId), ); - _posts = _posts + posts = posts .map( (p) => p.id == post.id ? updatedPost : p, ) @@ -161,7 +160,7 @@ class TestTimelineService with ChangeNotifier implements TimelineService { reactions: post.reactions?..add(updatedReaction), ); - _posts = _posts + posts = posts .map( (p) => p.id == post.id ? updatedPost : p, ) diff --git a/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart b/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart index b666a73..ffb4612 100644 --- a/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart +++ b/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart @@ -25,7 +25,6 @@ List getTimelineStoryRoutes( options: configuration.optionsBuilder(context), onPostTap: (post) async => TimelineUserStoryRoutes.timelineViewPath(post.id), - timelineCategoryFilter: null, ); return buildScreenWithoutTransition( context: context, diff --git a/packages/flutter_timeline_firebase/lib/src/service/firebase_timeline_service.dart b/packages/flutter_timeline_firebase/lib/src/service/firebase_timeline_service.dart index d171c34..b74ff5d 100644 --- a/packages/flutter_timeline_firebase/lib/src/service/firebase_timeline_service.dart +++ b/packages/flutter_timeline_firebase/lib/src/service/firebase_timeline_service.dart @@ -13,9 +13,7 @@ import 'package:flutter_timeline_firebase/src/models/firebase_user_document.dart import 'package:flutter_timeline_interface/flutter_timeline_interface.dart'; import 'package:uuid/uuid.dart'; -class FirebaseTimelineService - with ChangeNotifier - implements TimelineService, TimelineUserService { +class FirebaseTimelineService extends TimelineService with TimelineUserService { FirebaseTimelineService({ required TimelineUserService userService, FirebaseApp? app, @@ -35,8 +33,6 @@ class FirebaseTimelineService final Map _users = {}; - List _posts = []; - @override Future createPost(TimelinePost post) async { var postId = const Uuid().v4(); @@ -52,14 +48,14 @@ class FirebaseTimelineService var postRef = _db.collection(_options.timelineCollectionName).doc(updatedPost.id); await postRef.set(updatedPost.toJson()); - _posts.add(updatedPost); + posts.add(updatedPost); notifyListeners(); return updatedPost; } @override Future deletePost(TimelinePost post) async { - _posts = _posts.where((element) => element.id != post.id).toList(); + posts = posts.where((element) => element.id != post.id).toList(); var postRef = _db.collection(_options.timelineCollectionName).doc(post.id); await postRef.delete(); notifyListeners(); @@ -77,7 +73,7 @@ class FirebaseTimelineService reaction: post.reaction - 1, reactions: (post.reactions ?? [])..remove(reaction), ); - _posts = _posts + posts = posts .map( (p) => p.id == post.id ? updatedPost : p, ) @@ -107,7 +103,7 @@ class FirebaseTimelineService } } var updatedPost = post.copyWith(reactions: updatedReactions); - _posts = _posts.map((p) => (p.id == post.id) ? updatedPost : p).toList(); + posts = posts.map((p) => (p.id == post.id) ? updatedPost : p).toList(); notifyListeners(); return updatedPost; } @@ -129,7 +125,7 @@ class FirebaseTimelineService var post = TimelinePost.fromJson(doc.id, data).copyWith(creator: user); posts.add(post); } - _posts = posts; + notifyListeners(); return posts; } @@ -140,12 +136,12 @@ class FirebaseTimelineService int limit, ) async { // only take posts that are in our category - var oldestPost = _posts + var oldestPost = posts .where( (element) => category == null || element.category == category, ) .fold( - _posts.first, + posts.first, (previousValue, element) => (previousValue.createdAt.isBefore(element.createdAt)) ? previousValue @@ -166,16 +162,16 @@ class FirebaseTimelineService .limit(limit) .get(); // add the new posts to the list - var posts = []; + var newPosts = []; for (var doc in snapshot.docs) { var data = doc.data(); var user = await _userService.getUser(data['creator_id']); var post = TimelinePost.fromJson(doc.id, data).copyWith(creator: user); - posts.add(post); + newPosts.add(post); } - _posts = [..._posts, ...posts]; + posts = [...posts, ...newPosts]; notifyListeners(); - return posts; + return newPosts; } @override @@ -190,7 +186,7 @@ class FirebaseTimelineService var updatedPost = TimelinePost.fromJson(doc.id, data).copyWith( creator: user, ); - _posts = _posts.map((p) => (p.id == post.id) ? updatedPost : p).toList(); + posts = posts.map((p) => (p.id == post.id) ? updatedPost : p).toList(); notifyListeners(); return updatedPost; } @@ -198,12 +194,12 @@ class FirebaseTimelineService @override Future> refreshPosts(String? category) async { // fetch all posts between now and the newest posts we have - var newestPostWeHave = _posts + var newestPostWeHave = posts .where( (element) => category == null || element.category == category, ) .fold( - _posts.first, + posts.first, (previousValue, element) => (previousValue.createdAt.isAfter(element.createdAt)) ? previousValue @@ -220,26 +216,26 @@ class FirebaseTimelineService .orderBy('created_at', descending: true) .endBefore([newestPostWeHave.createdAt]).get(); // add the new posts to the list - var posts = []; + var newPosts = []; for (var doc in snapshot.docs) { var data = doc.data(); var user = await _userService.getUser(data['creator_id']); var post = TimelinePost.fromJson(doc.id, data).copyWith(creator: user); - posts.add(post); + newPosts.add(post); } - _posts = [...posts, ..._posts]; + posts = [...posts, ...newPosts]; notifyListeners(); - return posts; + return newPosts; } @override TimelinePost? getPost(String postId) => - (_posts.any((element) => element.id == postId)) - ? _posts.firstWhere((element) => element.id == postId) + (posts.any((element) => element.id == postId)) + ? posts.firstWhere((element) => element.id == postId) : null; @override - List getPosts(String? category) => _posts + List getPosts(String? category) => posts .where((element) => category == null || element.category == category) .toList(); @@ -250,7 +246,7 @@ class FirebaseTimelineService likes: post.likes + 1, likedBy: post.likedBy?..add(userId), ); - _posts = _posts + posts = posts .map( (p) => p.id == post.id ? updatedPost : p, ) @@ -271,7 +267,7 @@ class FirebaseTimelineService likes: post.likes - 1, likedBy: post.likedBy?..remove(userId), ); - _posts = _posts + posts = posts .map( (p) => p.id == post.id ? updatedPost : p, ) @@ -314,7 +310,7 @@ class FirebaseTimelineService 'reaction': FieldValue.increment(1), 'reactions': FieldValue.arrayUnion([updatedReaction.toJson()]), }); - _posts = _posts + posts = posts .map( (p) => p.id == post.id ? updatedPost : p, ) diff --git a/packages/flutter_timeline_interface/lib/flutter_timeline_interface.dart b/packages/flutter_timeline_interface/lib/flutter_timeline_interface.dart index 9676ad0..d0da25d 100644 --- a/packages/flutter_timeline_interface/lib/flutter_timeline_interface.dart +++ b/packages/flutter_timeline_interface/lib/flutter_timeline_interface.dart @@ -8,5 +8,6 @@ export 'src/model/timeline_category.dart'; export 'src/model/timeline_post.dart'; export 'src/model/timeline_poster.dart'; export 'src/model/timeline_reaction.dart'; +export 'src/services/filter_service.dart'; export 'src/services/timeline_service.dart'; export 'src/services/user_service.dart'; diff --git a/packages/flutter_timeline_interface/lib/src/services/filter_service.dart b/packages/flutter_timeline_interface/lib/src/services/filter_service.dart new file mode 100644 index 0000000..dc3441f --- /dev/null +++ b/packages/flutter_timeline_interface/lib/src/services/filter_service.dart @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2024 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +import 'package:flutter_timeline_interface/flutter_timeline_interface.dart'; + +mixin TimelineFilterService on TimelineService { + List filterPosts( + String filterWord, + Map options, + ) { + var filteredPosts = posts + .where( + (post) => post.title.toLowerCase().contains( + filterWord.toLowerCase(), + ), + ) + .toList(); + + return filteredPosts; + } +} diff --git a/packages/flutter_timeline_interface/lib/src/services/timeline_service.dart b/packages/flutter_timeline_interface/lib/src/services/timeline_service.dart index d872eb2..6f4907d 100644 --- a/packages/flutter_timeline_interface/lib/src/services/timeline_service.dart +++ b/packages/flutter_timeline_interface/lib/src/services/timeline_service.dart @@ -9,6 +9,8 @@ import 'package:flutter_timeline_interface/src/model/timeline_post.dart'; import 'package:flutter_timeline_interface/src/model/timeline_reaction.dart'; abstract class TimelineService with ChangeNotifier { + List posts = []; + Future deletePost(TimelinePost post); Future deletePostReaction(TimelinePost post, String reactionId); Future createPost(TimelinePost post); diff --git a/packages/flutter_timeline_view/lib/src/config/timeline_options.dart b/packages/flutter_timeline_view/lib/src/config/timeline_options.dart index d68c3a5..1acfaba 100644 --- a/packages/flutter_timeline_view/lib/src/config/timeline_options.dart +++ b/packages/flutter_timeline_view/lib/src/config/timeline_options.dart @@ -8,9 +8,8 @@ import 'package:flutter_timeline_view/src/config/timeline_theme.dart'; import 'package:flutter_timeline_view/src/config/timeline_translations.dart'; import 'package:intl/intl.dart'; -@immutable class TimelineOptions { - const TimelineOptions({ + TimelineOptions({ this.theme = const TimelineTheme(), this.translations = const TimelineTranslations.empty(), this.imagePickerConfig = const ImagePickerConfig(), @@ -18,7 +17,7 @@ class TimelineOptions { this.timelinePostHeight, this.allowAllDeletion = false, this.sortCommentsAscending = true, - this.sortPostsAscending = false, + this.sortPostsAscending, this.doubleTapTolike = false, this.iconsWithValues = false, this.likeAndDislikeIconsForDoubleTap = const ( @@ -44,6 +43,10 @@ class TimelineOptions { this.categories, this.categoryButtonBuilder, this.catergoryLabelBuilder, + this.categorySelectorHorizontalPadding, + this.filterEnabled = false, + this.initialFilterWord, + this.searchBarBuilder, }); /// Theming options for the timeline @@ -59,7 +62,7 @@ class TimelineOptions { final bool sortCommentsAscending; /// Whether to sort posts ascending or descending - final bool sortPostsAscending; + final bool? sortPostsAscending; /// Allow all posts to be deleted instead of /// only the posts of the current user @@ -132,6 +135,23 @@ class TimelineOptions { /// Ability to set an proper label for the category selectors. /// Default to category key. final String Function(String? categoryKey)? catergoryLabelBuilder; + + /// Overides the standard horizontal padding of the whole category selector. + final double? categorySelectorHorizontalPadding; + + /// if true the filter textfield is enabled. + bool filterEnabled; + + /// Set a value to search through posts. When set the searchbar is shown. + /// If null no searchbar is shown. + final String? initialFilterWord; + + final Widget Function( + Future> Function( + String filterWord, + Map options, + ) search, + )? searchBarBuilder; } typedef ButtonBuilder = Widget Function( diff --git a/packages/flutter_timeline_view/lib/src/config/timeline_translations.dart b/packages/flutter_timeline_view/lib/src/config/timeline_translations.dart index f01b1bc..f43a3a4 100644 --- a/packages/flutter_timeline_view/lib/src/config/timeline_translations.dart +++ b/packages/flutter_timeline_view/lib/src/config/timeline_translations.dart @@ -28,6 +28,7 @@ class TimelineTranslations { required this.postAt, required this.postLoadingError, required this.timelineSelectionDescription, + required this.searchHint, }); const TimelineTranslations.empty() @@ -52,7 +53,8 @@ class TimelineTranslations { writeComment = 'Write your comment here...', postAt = 'at', postLoadingError = 'Something went wrong while loading the post', - timelineSelectionDescription = 'Choose a category'; + timelineSelectionDescription = 'Choose a category', + searchHint = 'Search...'; final String noPosts; final String noPostsWithFilter; @@ -79,6 +81,8 @@ class TimelineTranslations { final String timelineSelectionDescription; + final String searchHint; + TimelineTranslations copyWith({ String? noPosts, String? noPostsWithFilter, @@ -101,6 +105,7 @@ class TimelineTranslations { String? firstComment, String? postLoadingError, String? timelineSelectionDescription, + String? searchHint, }) => TimelineTranslations( noPosts: noPosts ?? this.noPosts, @@ -127,5 +132,6 @@ class TimelineTranslations { postLoadingError: postLoadingError ?? this.postLoadingError, timelineSelectionDescription: timelineSelectionDescription ?? this.timelineSelectionDescription, + searchHint: searchHint ?? this.searchHint, ); } diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_screen.dart index b71b15e..cf8b8b7 100644 --- a/packages/flutter_timeline_view/lib/src/screens/timeline_screen.dart +++ b/packages/flutter_timeline_view/lib/src/screens/timeline_screen.dart @@ -18,7 +18,7 @@ class TimelineScreen extends StatefulWidget { this.onPostTap, this.onUserTap, this.posts, - this.timelineCategoryFilter, + this.timelineCategory, this.postWidget, super.key, }); @@ -36,7 +36,7 @@ class TimelineScreen extends StatefulWidget { final ScrollController? scrollController; /// The string to filter the timeline by category - final String? timelineCategoryFilter; + final String? timelineCategory; /// This is used if you want to pass in a list of posts instead /// of fetching them from the service @@ -57,11 +57,15 @@ class TimelineScreen extends StatefulWidget { class _TimelineScreenState extends State { late ScrollController controller; + late var textFieldController = + TextEditingController(text: widget.options.initialFilterWord); late var service = widget.service; bool isLoading = true; - late var filter = widget.timelineCategoryFilter; + late var category = widget.timelineCategory; + + late var filterWord = widget.options.initialFilterWord; @override void initState() { @@ -80,32 +84,109 @@ class _TimelineScreenState extends State { return ListenableBuilder( listenable: service, builder: (context, _) { - var posts = widget.posts ?? service.getPosts(filter); + var posts = widget.posts ?? service.getPosts(category); + posts = posts .where( - (p) => filter == null || p.category == filter, + (p) => category == null || p.category == category, ) .toList(); + if (widget.options.filterEnabled && filterWord != null) { + if (service is TimelineFilterService?) { + posts = + (service as TimelineFilterService).filterPosts(filterWord!, {}); + } else { + debugPrint('Timeline service needs to mixin' + ' with TimelineFilterService'); + } + } + // sort posts by date - posts.sort( - (a, b) => widget.options.sortPostsAscending - ? a.createdAt.compareTo(b.createdAt) - : b.createdAt.compareTo(a.createdAt), - ); + if (widget.options.sortPostsAscending != null) { + posts.sort( + (a, b) => widget.options.sortPostsAscending! + ? a.createdAt.compareTo(b.createdAt) + : b.createdAt.compareTo(a.createdAt), + ); + } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox( + height: widget.options.padding.top, + ), + if (widget.options.filterEnabled) ...[ + Padding( + padding: EdgeInsets.symmetric( + horizontal: widget.options.padding.horizontal, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: TextField( + controller: textFieldController, + onChanged: (value) { + setState(() { + filterWord = value; + }); + }, + decoration: InputDecoration( + hintText: widget.options.translations.searchHint, + suffixIconConstraints: + const BoxConstraints(maxHeight: 14), + contentPadding: const EdgeInsets.only( + left: 12, + right: 12, + bottom: -10, + ), + suffixIcon: const Padding( + padding: EdgeInsets.only(right: 12), + child: Icon(Icons.search), + ), + ), + ), + ), + const SizedBox( + width: 8, + ), + InkWell( + onTap: () { + setState(() { + textFieldController.clear(); + widget.options.filterEnabled = false; + filterWord = null; + }); + }, + child: const Padding( + padding: EdgeInsets.all(8), + child: Icon( + Icons.close, + color: Color(0xFF000000), + ), + ), + ), + ], + ), + ), + const SizedBox( + height: 24, + ), + ], CategorySelector( - filter: filter, + filter: category, options: widget.options, onTapCategory: (categoryKey) { setState(() { - filter = categoryKey; + category = categoryKey; }); }, ), + const SizedBox( + height: 12, + ), Expanded( child: SingleChildScrollView( controller: controller, @@ -159,7 +240,7 @@ class _TimelineScreenState extends State { child: Padding( padding: const EdgeInsets.all(8.0), child: Text( - filter == null + category == null ? widget.options.translations.noPosts : widget.options.translations.noPostsWithFilter, style: widget.options.theme.textStyles.noPostsStyle, @@ -170,6 +251,9 @@ class _TimelineScreenState extends State { ), ), ), + SizedBox( + height: widget.options.padding.bottom, + ), ], ); }, @@ -179,7 +263,7 @@ class _TimelineScreenState extends State { Future loadPosts() async { if (widget.posts != null) return; try { - await service.fetchPosts(filter); + await service.fetchPosts(category); setState(() { isLoading = false; }); diff --git a/packages/flutter_timeline_view/lib/src/widgets/category_selector.dart b/packages/flutter_timeline_view/lib/src/widgets/category_selector.dart index bed2303..817090a 100644 --- a/packages/flutter_timeline_view/lib/src/widgets/category_selector.dart +++ b/packages/flutter_timeline_view/lib/src/widgets/category_selector.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:flutter_timeline_view/flutter_timeline_view.dart'; import 'package:flutter_timeline_view/src/widgets/category_selector_button.dart'; @@ -22,49 +24,51 @@ class CategorySelector extends StatelessWidget { return SingleChildScrollView( scrollDirection: Axis.horizontal, - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: options.padding.horizontal, - ), - child: Row( - children: [ - options.categoryButtonBuilder?.call( - categoryKey: null, - categoryName: - options.catergoryLabelBuilder?.call(null) ?? 'All', - onTap: () => onTapCategory(null), + child: Row( + children: [ + SizedBox( + width: options.categorySelectorHorizontalPadding ?? + max(options.padding.horizontal - 4, 0), + ), + options.categoryButtonBuilder?.call( + categoryKey: null, + categoryName: + options.catergoryLabelBuilder?.call(null) ?? 'All', + onTap: () => onTapCategory(null), + selected: filter == null, + ) ?? + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: CategorySelectorButton( + category: null, selected: filter == null, + onTap: () => onTapCategory(null), + labelBuilder: options.catergoryLabelBuilder, + ), + ), + for (var category in options.categories!) ...[ + options.categoryButtonBuilder?.call( + categoryKey: category, + categoryName: + options.catergoryLabelBuilder?.call(category) ?? category, + onTap: () => onTapCategory(category), + selected: filter == category, ) ?? Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: CategorySelectorButton( - category: null, - selected: filter == null, - onTap: () => onTapCategory(null), + category: category, + selected: filter == category, + onTap: () => onTapCategory(category), labelBuilder: options.catergoryLabelBuilder, ), ), - for (var category in options.categories!) ...[ - options.categoryButtonBuilder?.call( - categoryKey: category, - categoryName: - options.catergoryLabelBuilder?.call(category) ?? - category, - onTap: () => onTapCategory(category), - selected: filter == category, - ) ?? - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: CategorySelectorButton( - category: category, - selected: filter == category, - onTap: () => onTapCategory(category), - labelBuilder: options.catergoryLabelBuilder, - ), - ), - ], ], - ), + SizedBox( + width: options.categorySelectorHorizontalPadding ?? + max(options.padding.horizontal - 4, 0), + ), + ], ), ); } diff --git a/packages/flutter_timeline_view/lib/src/widgets/category_selector_button.dart b/packages/flutter_timeline_view/lib/src/widgets/category_selector_button.dart index cf0ae7d..8b1a5db 100644 --- a/packages/flutter_timeline_view/lib/src/widgets/category_selector_button.dart +++ b/packages/flutter_timeline_view/lib/src/widgets/category_selector_button.dart @@ -21,6 +21,7 @@ class CategorySelectorButton extends StatelessWidget { return TextButton( onPressed: onTap, style: ButtonStyle( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, padding: const MaterialStatePropertyAll( EdgeInsets.symmetric( vertical: 5, 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 06ec2ae..5c50d31 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 @@ -49,7 +49,9 @@ class _TimelinePostWidgetState extends State { return InkWell( onTap: widget.onTap, child: SizedBox( - height: widget.post.imageUrl != null ? widget.options.postWidgetheight : null, + height: widget.post.imageUrl != null + ? widget.options.postWidgetheight + : null, width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start,