Skip to content

Commit 0700258

Browse files
authored
add profile page with followers (#14)
1 parent 39397b1 commit 0700258

File tree

7 files changed

+398
-85
lines changed

7 files changed

+398
-85
lines changed

packages/stream_feeds/lib/stream_feeds.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export 'package:stream_core/stream_core.dart';
33
export 'src/feeds_client.dart';
44
export 'src/generated/api/api.dart' hide User;
55
export 'src/models/activity_data.dart';
6+
export 'src/models/feed_data.dart';
67
export 'src/models/feed_id.dart';
78
export 'src/models/feed_input_data.dart';
89
export 'src/models/feed_member_request_data.dart';

sample_app/lib/screens/home/home_screen.dart

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import 'dart:ui';
2+
13
import 'package:auto_route/auto_route.dart';
24
import 'package:flutter/material.dart';
5+
import 'package:stream_feeds/stream_feeds.dart';
36

47
import '../../app/content/auth_controller.dart';
58
import '../../core/di/di_initializer.dart';
69
import '../../theme/theme.dart';
710
import '../../widgets/user_avatar.dart';
11+
import '../profile/profile_widget.dart';
812
import 'widgets/user_feed_appbar.dart';
913
import 'widgets/user_feed_view.dart';
1014

@@ -21,29 +25,20 @@ class HomeScreen extends StatelessWidget {
2125
_ => throw Exception('User not authenticated'),
2226
};
2327

24-
return Scaffold(
25-
backgroundColor: context.appColors.appBg,
26-
appBar: UserFeedAppbar(
27-
leading: Center(
28-
child: UserAvatar.appBar(user: user),
29-
),
30-
title: Text(
31-
'Stream Feeds',
32-
style: context.appTextStyles.headlineBold,
33-
),
34-
actions: [
35-
IconButton(
36-
onPressed: authController.disconnect,
37-
icon: Icon(
38-
Icons.logout,
39-
color: context.appColors.textLowEmphasis,
40-
),
41-
),
42-
],
28+
final wideScreen = MediaQuery.sizeOf(context).width > 600;
29+
30+
return ScrollConfiguration(
31+
behavior: ScrollConfiguration.of(context).copyWith(
32+
dragDevices: {
33+
PointerDeviceKind.touch,
34+
PointerDeviceKind.mouse,
35+
},
4336
),
44-
body: UserFeedView(
37+
child: UserFeedView(
4538
client: client,
4639
currentUser: user,
40+
wideScreen: wideScreen,
41+
onLogout: authController.disconnect,
4742
),
4843
);
4944
}

sample_app/lib/screens/home/widgets/user_feed_view.dart

Lines changed: 134 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
import 'dart:ui';
2-
31
import 'package:flutter/material.dart';
42
import 'package:flutter_state_notifier/flutter_state_notifier.dart';
53
import 'package:stream_feeds/stream_feeds.dart';
64

75
import '../../../theme/extensions/theme_extensions.dart';
6+
import '../../../widgets/user_avatar.dart';
7+
import '../../profile/profile_widget.dart';
88
import 'activity_comments_view.dart';
99
import 'activity_content.dart';
10+
import 'user_feed_appbar.dart';
1011

1112
class UserFeedView extends StatefulWidget {
1213
const UserFeedView({
1314
super.key,
1415
required this.client,
1516
required this.currentUser,
17+
required this.wideScreen,
18+
required this.onLogout,
1619
});
1720

1821
final User currentUser;
1922
final StreamFeedsClient client;
23+
final bool wideScreen;
24+
final VoidCallback onLogout;
2025

2126
@override
2227
State<UserFeedView> createState() => _UserFeedViewState();
@@ -53,74 +58,131 @@ class _UserFeedViewState extends State<UserFeedView> {
5358
final activities = state.activities;
5459
final canLoadMore = state.canLoadMoreActivities;
5560

56-
if (activities.isEmpty) return const EmptyActivities();
57-
58-
return RefreshIndicator(
59-
onRefresh: () => feed.getOrCreate(),
60-
child: ScrollConfiguration(
61-
behavior: ScrollConfiguration.of(context).copyWith(
62-
dragDevices: {
63-
PointerDeviceKind.touch,
64-
PointerDeviceKind.mouse,
65-
},
66-
),
67-
child: ListView.separated(
68-
itemCount: activities.length + 1,
69-
separatorBuilder: (context, index) => Divider(
70-
height: 1,
71-
color: context.appColors.borders,
72-
),
73-
itemBuilder: (context, index) {
74-
if (index == activities.length) {
75-
return canLoadMore
76-
? TextButton(
77-
onPressed: () => feed.queryMoreActivities(),
78-
child: const Text('Load more...'),
79-
)
80-
: const Text('End of feed');
81-
}
82-
83-
final activity = activities[index];
84-
final parentActivity = activity.parent;
85-
final baseActivity = activity.parent ?? activity;
86-
87-
return Padding(
88-
padding: const EdgeInsets.all(8),
89-
child: Column(
90-
children: [
91-
if (parentActivity != null) ...[
92-
ActivityRepostIndicator(
93-
user: activity.user,
94-
data: parentActivity,
95-
),
96-
const SizedBox(height: 8),
97-
],
98-
ActivityContent(
99-
user: baseActivity.user,
100-
text: baseActivity.text ?? '',
101-
attachments: baseActivity.attachments,
102-
data: activity,
103-
currentUserId: widget.client.user.id,
104-
onCommentClick: () =>
105-
_onCommentClick(context, activity),
106-
onHeartClick: (isAdding) =>
107-
_onHeartClick(activity, isAdding),
108-
onRepostClick: (message) {},
109-
onBookmarkClick: () {},
110-
onDeleteClick: () {},
111-
onEditSave: (text) {},
112-
),
113-
],
61+
final feedWidget = activities.isEmpty
62+
? const EmptyActivities()
63+
: RefreshIndicator(
64+
onRefresh: () => feed.getOrCreate(),
65+
child: ListView.separated(
66+
itemCount: activities.length + 1,
67+
separatorBuilder: (context, index) => Divider(
68+
height: 1,
69+
color: context.appColors.borders,
11470
),
115-
);
116-
},
117-
),
71+
itemBuilder: (context, index) {
72+
if (index == activities.length) {
73+
return canLoadMore
74+
? TextButton(
75+
onPressed: () => feed.queryMoreActivities(),
76+
child: const Text('Load more...'),
77+
)
78+
: const Text('End of feed');
79+
}
80+
81+
final activity = activities[index];
82+
final parentActivity = activity.parent;
83+
final baseActivity = activity.parent ?? activity;
84+
85+
return Padding(
86+
padding: const EdgeInsets.all(8),
87+
child: Column(
88+
children: [
89+
if (parentActivity != null) ...[
90+
ActivityRepostIndicator(
91+
user: activity.user,
92+
data: parentActivity,
93+
),
94+
const SizedBox(height: 8),
95+
],
96+
ActivityContent(
97+
user: baseActivity.user,
98+
text: baseActivity.text ?? '',
99+
attachments: baseActivity.attachments,
100+
data: activity,
101+
currentUserId: widget.client.user.id,
102+
onCommentClick: () =>
103+
_onCommentClick(context, activity),
104+
onHeartClick: (isAdding) =>
105+
_onHeartClick(activity, isAdding),
106+
onRepostClick: (message) {},
107+
onBookmarkClick: () {},
108+
onDeleteClick: () {},
109+
onEditSave: (text) {},
110+
),
111+
],
112+
),
113+
);
114+
},
115+
),
116+
);
117+
118+
if (!widget.wideScreen) {
119+
return _buildScaffold(
120+
context,
121+
feedWidget,
122+
onProfileTap: () {
123+
_showProfileBottomSheet(context, widget.client, feed);
124+
},
125+
);
126+
}
127+
return _buildScaffold(
128+
context,
129+
Row(
130+
children: [
131+
SizedBox(
132+
width: 250,
133+
child: ProfileWidget(feedsClient: widget.client, feed: feed),
134+
),
135+
const SizedBox(width: 16),
136+
Expanded(child: feedWidget),
137+
],
118138
),
119139
);
120140
},
121141
);
122142
}
123143

144+
Widget _buildScaffold(
145+
BuildContext context,
146+
Widget body, {
147+
VoidCallback? onProfileTap,
148+
}) {
149+
return Scaffold(
150+
appBar: UserFeedAppbar(
151+
leading: GestureDetector(
152+
onTap: onProfileTap,
153+
child: Center(
154+
child: UserAvatar.appBar(user: widget.currentUser),
155+
),
156+
),
157+
title: Text(
158+
'Stream Feeds',
159+
style: context.appTextStyles.headlineBold,
160+
),
161+
actions: [
162+
IconButton(
163+
onPressed: widget.onLogout,
164+
icon: Icon(
165+
Icons.logout,
166+
color: context.appColors.textLowEmphasis,
167+
),
168+
),
169+
],
170+
),
171+
body: body,
172+
);
173+
}
174+
175+
void _showProfileBottomSheet(
176+
BuildContext context,
177+
StreamFeedsClient client,
178+
Feed feed,
179+
) {
180+
showModalBottomSheet<void>(
181+
context: context,
182+
builder: (context) => ProfileWidget(feedsClient: client, feed: feed),
183+
);
184+
}
185+
124186
void _onCommentClick(BuildContext context, ActivityData activity) {
125187
showModalBottomSheet<void>(
126188
context: context,
@@ -147,6 +209,15 @@ class _UserFeedViewState extends State<UserFeedView> {
147209
}
148210
}
149211

212+
class _FeedWidget extends StatelessWidget {
213+
const _FeedWidget({super.key});
214+
215+
@override
216+
Widget build(BuildContext context) {
217+
return const Placeholder();
218+
}
219+
}
220+
150221
class ActivityRepostIndicator extends StatelessWidget {
151222
const ActivityRepostIndicator({
152223
super.key,

0 commit comments

Comments
 (0)