mirror of
https://github.com/Iconica-Development/flutter_timeline.git
synced 2025-05-19 02:23:46 +02:00
feat: complete timeline userstory
This commit is contained in:
parent
a1ceee391a
commit
0035e1f4fb
6 changed files with 121 additions and 30 deletions
|
@ -4,5 +4,6 @@
|
|||
/// Flutter Timeline library
|
||||
library flutter_timeline;
|
||||
|
||||
export 'package:flutter_timeline/src/flutter_timeline_userstory.dart';
|
||||
export 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
|
||||
export 'package:flutter_timeline_view/flutter_timeline_view.dart';
|
||||
|
|
|
@ -5,9 +5,12 @@ import 'package:go_router/go_router.dart';
|
|||
|
||||
mixin TimelineUserStoryRoutes {
|
||||
static const String timelineHome = '/timeline';
|
||||
static String timelineCreate(String category) => '/timeline-create/$category';
|
||||
static const String timelineCreate = '/timeline-create/:category';
|
||||
static String timelineCreatePath(String category) =>
|
||||
'/timeline-create/$category';
|
||||
static const String timelineSelect = '/timeline-select';
|
||||
static String timelineView(String postId) => '/timeline-view/$postId';
|
||||
static const String timelineView = '/timeline-view/:post';
|
||||
static String timelineViewPath(String postId) => '/timeline-view/$postId';
|
||||
}
|
||||
|
||||
class TimelineUserStoryConfiguration {
|
||||
|
@ -15,22 +18,31 @@ class TimelineUserStoryConfiguration {
|
|||
required this.optionsBuilder,
|
||||
required this.userId,
|
||||
required this.service,
|
||||
this.pageBuilder,
|
||||
required this.userService,
|
||||
this.mainPageBuilder,
|
||||
this.postScreenBuilder,
|
||||
this.postCreationScreenBuilder,
|
||||
this.postSelectionScreenBuilder,
|
||||
this.onUserTap,
|
||||
this.timelinePostHeight,
|
||||
});
|
||||
|
||||
final String userId;
|
||||
|
||||
final double? timelinePostHeight;
|
||||
final Function(String userId)? onUserTap;
|
||||
|
||||
final Widget Function(Widget child)? pageBuilder;
|
||||
final Widget Function(Widget filterBar, Widget child)? mainPageBuilder;
|
||||
|
||||
final Widget Function(Widget child)? postScreenBuilder;
|
||||
|
||||
final Widget Function(Widget child)? postCreationScreenBuilder;
|
||||
|
||||
final Widget Function(Widget child)? postSelectionScreenBuilder;
|
||||
|
||||
final TimelineService service;
|
||||
|
||||
final TimelineOptions Function(BuildContext context)
|
||||
optionsBuilder; // New callback
|
||||
final TimelineUserService userService;
|
||||
|
||||
final TimelineOptions Function(BuildContext context) optionsBuilder;
|
||||
}
|
||||
|
||||
List<GoRoute> getTimelineStoryRoutes(
|
||||
|
@ -39,22 +51,93 @@ List<GoRoute> getTimelineStoryRoutes(
|
|||
<GoRoute>[
|
||||
GoRoute(
|
||||
path: TimelineUserStoryRoutes.timelineHome,
|
||||
pageBuilder: (context, state) => buildScreenWithoutTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: Scaffold(
|
||||
body: TimelineScreen(
|
||||
userId: configuration.userId,
|
||||
onUserTap: configuration.onUserTap,
|
||||
service: configuration.service,
|
||||
options: configuration.optionsBuilder(context),
|
||||
timelinePostHeight: configuration.timelinePostHeight,
|
||||
onPostTap: (_) async => context.push('/timeline-view/1'),
|
||||
timelineCategoryFilter: 'category',
|
||||
),
|
||||
),
|
||||
),
|
||||
pageBuilder: (context, state) {
|
||||
var timelineScreen = TimelineScreen(
|
||||
userId: configuration.userId,
|
||||
onUserTap: configuration.onUserTap,
|
||||
service: configuration.service,
|
||||
options: configuration.optionsBuilder(context),
|
||||
onPostTap: (post) async =>
|
||||
TimelineUserStoryRoutes.timelineViewPath(post.id),
|
||||
timelineCategoryFilter: 'news',
|
||||
);
|
||||
return buildScreenWithoutTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: configuration.mainPageBuilder?.call(
|
||||
Container(), // TODO(anyone): create a selection widget
|
||||
timelineScreen,
|
||||
) ??
|
||||
Scaffold(
|
||||
body: timelineScreen,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: TimelineUserStoryRoutes.timelineSelect,
|
||||
pageBuilder: (context, state) {
|
||||
var timelineSelectionWidget =
|
||||
Container(); // TODO(anyone): create timeline selection screen
|
||||
return buildScreenWithoutTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: configuration.postSelectionScreenBuilder?.call(
|
||||
timelineSelectionWidget,
|
||||
) ??
|
||||
Scaffold(
|
||||
body: timelineSelectionWidget,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: TimelineUserStoryRoutes.timelineCreate,
|
||||
pageBuilder: (context, state) {
|
||||
var timelineCreateWidget = TimelinePostCreationScreen(
|
||||
userId: configuration.userId,
|
||||
options: configuration.optionsBuilder(context),
|
||||
postCategory: state.pathParameters['category'] ?? '',
|
||||
service: configuration.service,
|
||||
onPostCreated: (post) => context.go(
|
||||
TimelineUserStoryRoutes.timelineViewPath(post.id),
|
||||
),
|
||||
);
|
||||
return buildScreenWithoutTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: configuration.postCreationScreenBuilder
|
||||
?.call(timelineCreateWidget) ??
|
||||
Scaffold(
|
||||
body: timelineCreateWidget,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: TimelineUserStoryRoutes.timelineView,
|
||||
pageBuilder: (context, state) {
|
||||
var timelinePostWidget = TimelinePostScreen(
|
||||
userId: configuration.userId,
|
||||
options: configuration.optionsBuilder(context),
|
||||
service: configuration.service,
|
||||
userService: configuration.userService,
|
||||
post: configuration.service.getPost(state.pathParameters['post']!)!,
|
||||
onPostDelete: () => context.go(
|
||||
TimelineUserStoryRoutes.timelineHome,
|
||||
),
|
||||
onUserTap: configuration.onUserTap,
|
||||
);
|
||||
return buildScreenWithoutTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: configuration.postScreenBuilder?.call(
|
||||
timelinePostWidget,
|
||||
) ??
|
||||
Scaffold(
|
||||
body: timelinePostWidget,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
/// Here come the other timeline screens that all use the same configuration
|
||||
];
|
||||
|
|
|
@ -115,6 +115,12 @@ class FirebaseTimelineService with ChangeNotifier implements TimelineService {
|
|||
return updatedPost;
|
||||
}
|
||||
|
||||
@override
|
||||
TimelinePost? getPost(String postId) =>
|
||||
(_posts.any((element) => element.id == postId))
|
||||
? _posts.firstWhere((element) => element.id == postId)
|
||||
: null;
|
||||
|
||||
@override
|
||||
List<TimelinePost> getPosts(String? category) => _posts
|
||||
.where((element) => category == null || element.category == category)
|
||||
|
|
|
@ -13,6 +13,7 @@ abstract class TimelineService with ChangeNotifier {
|
|||
Future<TimelinePost> createPost(TimelinePost post);
|
||||
Future<List<TimelinePost>> fetchPosts(String? category);
|
||||
Future<TimelinePost> fetchPost(TimelinePost post);
|
||||
TimelinePost? getPost(String postId);
|
||||
List<TimelinePost> getPosts(String? category);
|
||||
Future<TimelinePost> fetchPostDetails(TimelinePost post);
|
||||
Future<TimelinePost> reactToPost(
|
||||
|
|
|
@ -15,6 +15,7 @@ class TimelineOptions {
|
|||
this.translations = const TimelineTranslations(),
|
||||
this.imagePickerConfig = const ImagePickerConfig(),
|
||||
this.imagePickerTheme = const ImagePickerTheme(),
|
||||
this.timelinePostHeight,
|
||||
this.allowAllDeletion = false,
|
||||
this.sortCommentsAscending = true,
|
||||
this.sortPostsAscending = false,
|
||||
|
@ -44,6 +45,9 @@ class TimelineOptions {
|
|||
/// only the posts of the current user
|
||||
final bool allowAllDeletion;
|
||||
|
||||
/// The height of a post in the timeline
|
||||
final double? timelinePostHeight;
|
||||
|
||||
final TimelineTranslations translations;
|
||||
|
||||
final ButtonBuilder? buttonBuilder;
|
||||
|
|
|
@ -19,7 +19,6 @@ class TimelineScreen extends StatefulWidget {
|
|||
this.posts,
|
||||
this.controller,
|
||||
this.timelineCategoryFilter,
|
||||
this.timelinePostHeight,
|
||||
this.padding = const EdgeInsets.symmetric(vertical: 12.0),
|
||||
super.key,
|
||||
});
|
||||
|
@ -38,9 +37,6 @@ class TimelineScreen extends StatefulWidget {
|
|||
|
||||
final String? timelineCategoryFilter;
|
||||
|
||||
/// The height of a post in the timeline
|
||||
final double? timelinePostHeight;
|
||||
|
||||
/// This is used if you want to pass in a list of posts instead
|
||||
/// of fetching them from the service
|
||||
final List<TimelinePost>? posts;
|
||||
|
@ -106,7 +102,7 @@ class _TimelineScreenState extends State<TimelineScreen> {
|
|||
userId: widget.userId,
|
||||
options: widget.options,
|
||||
post: post,
|
||||
height: widget.timelinePostHeight,
|
||||
height: widget.options.timelinePostHeight,
|
||||
onTap: () => widget.onPostTap.call(post),
|
||||
onTapLike: () async =>
|
||||
widget.service.likePost(widget.userId, post),
|
||||
|
|
Loading…
Reference in a new issue