Skip to content

Commit 174d2e4

Browse files
bart-iconicaFreek van de Ven
authored andcommitted
feat: add a grid overview layout
1 parent dd76282 commit 174d2e4

4 files changed

Lines changed: 120 additions & 46 deletions

File tree

packages/flutter_feed_utils/lib/flutter_feed_utils.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export "src/config/feed_styles.dart";
99
export "src/config/feed_theme.dart";
1010
export "src/config/feed_translations.dart";
1111
export "src/widgets/feed_item_widget.dart";
12+
export "src/widgets/overview_layout.dart";

packages/flutter_feed_utils/lib/src/widgets/feed_item_widget.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ class _PostHeader extends StatelessWidget {
109109
var deleteItemButtonText = localizationDeleteItemButtonText;
110110

111111
return SizedBox(
112-
width: double.infinity,
113112
height: 40.0,
114113
child: Row(
115114
mainAxisAlignment: MainAxisAlignment.start,
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import "package:flutter/cupertino.dart";
2+
import "package:flutter/material.dart";
3+
import "package:flutter/widgets.dart";
4+
5+
enum OverviewLayoutOption {
6+
list,
7+
grid;
8+
}
9+
10+
class OverviewLayout extends StatelessWidget {
11+
const OverviewLayout._({
12+
required OverviewLayoutOption activeLayout,
13+
required this.items,
14+
this.columnCount = 1,
15+
}) : _activeLayout = activeLayout;
16+
17+
factory OverviewLayout.list({required List<Widget> children}) =>
18+
OverviewLayout._(
19+
activeLayout: OverviewLayoutOption.list,
20+
items: children,
21+
);
22+
23+
factory OverviewLayout.grid({
24+
required int columnCount,
25+
required List<Widget> children,
26+
}) =>
27+
OverviewLayout._(
28+
activeLayout: OverviewLayoutOption.grid,
29+
columnCount: columnCount,
30+
items: children,
31+
);
32+
33+
final List<Widget> items;
34+
final OverviewLayoutOption _activeLayout;
35+
final int columnCount;
36+
37+
@override
38+
Widget build(BuildContext context) => switch (_activeLayout) {
39+
OverviewLayoutOption.list => SingleChildScrollView(
40+
child: Padding(
41+
padding: const EdgeInsets.symmetric(horizontal: 12.0),
42+
child: Column(
43+
crossAxisAlignment: CrossAxisAlignment.start,
44+
mainAxisSize: MainAxisSize.min,
45+
children: items,
46+
),
47+
),
48+
),
49+
OverviewLayoutOption.grid => SingleChildScrollView(
50+
child: Padding(
51+
padding: const EdgeInsets.symmetric(horizontal: 12.0),
52+
child: Column(
53+
children: [
54+
// We use a manual column + wrap approach rather than a
55+
// gridview as this way we can wrap when the screen becomes
56+
// too small
57+
for (var i = 0; i < items.length; i += columnCount) ...[
58+
SizedBox(
59+
width: double.infinity,
60+
child: Wrap(
61+
spacing: 8.0,
62+
runSpacing: 8.0,
63+
children: [
64+
for (var x = 0; x < columnCount; x++) ...[
65+
if (i + x < items.length) ...[
66+
items[i + x],
67+
],
68+
],
69+
],
70+
),
71+
),
72+
if (i + columnCount < items.length) ...[
73+
const SizedBox(height: 8.0),
74+
],
75+
],
76+
],
77+
),
78+
),
79+
),
80+
};
81+
}

packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -69,55 +69,48 @@ class _FlutterFeedTimelineUserstoryState
6969

7070
return Scaffold(
7171
appBar: AppBar(),
72-
body: SingleChildScrollView(
73-
child: Column(
74-
crossAxisAlignment: CrossAxisAlignment.start,
75-
mainAxisSize: MainAxisSize.min,
76-
children: [
77-
for (var item in items) ...[
78-
Padding(
79-
padding: const EdgeInsets.symmetric(horizontal: 12.0),
80-
child: FeedViewItem(
81-
title: item.title,
82-
authorName: item.authorName,
83-
authorAvatarUrl: item.authorAvatarUrl,
84-
imageUrl: item.media.isNotEmpty ? item.media.first : null,
85-
localizationDeleteItemButtonText:
86-
localizations.timelinePostDeleteButtonText,
87-
localizationLikeCount:
88-
localizations.timelinePostLikeCount(item.likeCount),
89-
localizationViewItemButtonText:
90-
localizations.timelinePostViewButtonText,
91-
actionBuilder: () => Row(
92-
mainAxisAlignment: MainAxisAlignment.start,
93-
mainAxisSize: MainAxisSize.min,
94-
children: [
95-
IconButton(
96-
padding: EdgeInsets.zero,
97-
constraints: const BoxConstraints(),
98-
onPressed: () async => likeItem(item),
99-
icon: Icon(
100-
item.likedByUser
101-
? Icons.favorite_rounded
102-
: Icons.favorite_outline_rounded,
103-
),
104-
),
105-
],
72+
body: OverviewLayout.list(
73+
children: [
74+
for (var item in items) ...[
75+
FeedViewItem(
76+
title: item.title,
77+
authorName: item.authorName,
78+
authorAvatarUrl: item.authorAvatarUrl,
79+
imageUrl: item.media.isNotEmpty ? item.media.first : null,
80+
localizationDeleteItemButtonText:
81+
localizations.timelinePostDeleteButtonText,
82+
localizationLikeCount:
83+
localizations.timelinePostLikeCount(item.likeCount),
84+
localizationViewItemButtonText:
85+
localizations.timelinePostViewButtonText,
86+
actionBuilder: () => Row(
87+
mainAxisAlignment: MainAxisAlignment.start,
88+
mainAxisSize: MainAxisSize.min,
89+
children: [
90+
IconButton(
91+
padding: EdgeInsets.zero,
92+
constraints: const BoxConstraints(),
93+
onPressed: () async => likeItem(item),
94+
icon: Icon(
95+
item.likedByUser
96+
? Icons.favorite_rounded
97+
: Icons.favorite_outline_rounded,
98+
),
10699
),
107-
onTap: () async => onItemPressed(item),
108-
),
100+
],
109101
),
110-
],
111-
if (items.isEmpty) ...[
112-
Center(
113-
child: Padding(
114-
padding: const EdgeInsets.all(8.0),
115-
child: Text(localizations.timelineEmptyLabel),
116-
),
102+
onTap: () async => onItemPressed(item),
103+
),
104+
],
105+
if (items.isEmpty) ...[
106+
Center(
107+
child: Padding(
108+
padding: const EdgeInsets.all(8.0),
109+
child: Text(localizations.timelineEmptyLabel),
117110
),
118-
],
111+
),
119112
],
120-
),
113+
],
121114
),
122115
);
123116
}

0 commit comments

Comments
 (0)