diff --git a/packages/flutter_feed_utils/lib/flutter_feed_utils.dart b/packages/flutter_feed_utils/lib/flutter_feed_utils.dart index 974e7cc..b105246 100644 --- a/packages/flutter_feed_utils/lib/flutter_feed_utils.dart +++ b/packages/flutter_feed_utils/lib/flutter_feed_utils.dart @@ -9,3 +9,4 @@ export "src/config/feed_styles.dart"; export "src/config/feed_theme.dart"; export "src/config/feed_translations.dart"; export "src/widgets/feed_item_widget.dart"; +export "src/widgets/overview_layout.dart"; diff --git a/packages/flutter_feed_utils/lib/src/widgets/feed_item_widget.dart b/packages/flutter_feed_utils/lib/src/widgets/feed_item_widget.dart index dd234ae..b84b393 100644 --- a/packages/flutter_feed_utils/lib/src/widgets/feed_item_widget.dart +++ b/packages/flutter_feed_utils/lib/src/widgets/feed_item_widget.dart @@ -109,7 +109,6 @@ class _PostHeader extends StatelessWidget { var deleteItemButtonText = localizationDeleteItemButtonText; return SizedBox( - width: double.infinity, height: 40.0, child: Row( mainAxisAlignment: MainAxisAlignment.start, diff --git a/packages/flutter_feed_utils/lib/src/widgets/overview_layout.dart b/packages/flutter_feed_utils/lib/src/widgets/overview_layout.dart new file mode 100644 index 0000000..1c3ab03 --- /dev/null +++ b/packages/flutter_feed_utils/lib/src/widgets/overview_layout.dart @@ -0,0 +1,81 @@ +import "package:flutter/cupertino.dart"; +import "package:flutter/material.dart"; +import "package:flutter/widgets.dart"; + +enum OverviewLayoutOption { + list, + grid; +} + +class OverviewLayout extends StatelessWidget { + const OverviewLayout._({ + required OverviewLayoutOption activeLayout, + required this.items, + this.columnCount = 1, + }) : _activeLayout = activeLayout; + + factory OverviewLayout.list({required List children}) => + OverviewLayout._( + activeLayout: OverviewLayoutOption.list, + items: children, + ); + + factory OverviewLayout.grid({ + required int columnCount, + required List children, + }) => + OverviewLayout._( + activeLayout: OverviewLayoutOption.grid, + columnCount: columnCount, + items: children, + ); + + final List items; + final OverviewLayoutOption _activeLayout; + final int columnCount; + + @override + Widget build(BuildContext context) => switch (_activeLayout) { + OverviewLayoutOption.list => SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: items, + ), + ), + ), + OverviewLayoutOption.grid => SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Column( + children: [ + // We use a manual column + wrap approach rather than a + // gridview as this way we can wrap when the screen becomes + // too small + for (var i = 0; i < items.length; i += columnCount) ...[ + SizedBox( + width: double.infinity, + child: Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: [ + for (var x = 0; x < columnCount; x++) ...[ + if (i + x < items.length) ...[ + items[i + x], + ], + ], + ], + ), + ), + if (i + columnCount < items.length) ...[ + const SizedBox(height: 8.0), + ], + ], + ], + ), + ), + ), + }; +} diff --git a/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart b/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart index 91e617b..75eb245 100644 --- a/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart +++ b/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart @@ -69,55 +69,48 @@ class _FlutterFeedTimelineUserstoryState return Scaffold( appBar: AppBar(), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - for (var item in items) ...[ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: FeedViewItem( - title: item.title, - authorName: item.authorName, - authorAvatarUrl: item.authorAvatarUrl, - imageUrl: item.media.isNotEmpty ? item.media.first : null, - localizationDeleteItemButtonText: - localizations.timelinePostDeleteButtonText, - localizationLikeCount: - localizations.timelinePostLikeCount(item.likeCount), - localizationViewItemButtonText: - localizations.timelinePostViewButtonText, - actionBuilder: () => Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - onPressed: () async => likeItem(item), - icon: Icon( - item.likedByUser - ? Icons.favorite_rounded - : Icons.favorite_outline_rounded, - ), - ), - ], + body: OverviewLayout.list( + children: [ + for (var item in items) ...[ + FeedViewItem( + title: item.title, + authorName: item.authorName, + authorAvatarUrl: item.authorAvatarUrl, + imageUrl: item.media.isNotEmpty ? item.media.first : null, + localizationDeleteItemButtonText: + localizations.timelinePostDeleteButtonText, + localizationLikeCount: + localizations.timelinePostLikeCount(item.likeCount), + localizationViewItemButtonText: + localizations.timelinePostViewButtonText, + actionBuilder: () => Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + onPressed: () async => likeItem(item), + icon: Icon( + item.likedByUser + ? Icons.favorite_rounded + : Icons.favorite_outline_rounded, + ), ), - onTap: () async => onItemPressed(item), - ), + ], ), - ], - if (items.isEmpty) ...[ - Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text(localizations.timelineEmptyLabel), - ), + onTap: () async => onItemPressed(item), + ), + ], + if (items.isEmpty) ...[ + Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(localizations.timelineEmptyLabel), ), - ], + ), ], - ), + ], ), ); }