mirror of
https://github.com/Iconica-Development/flutter_timeline.git
synced 2025-05-19 10:33:44 +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
|
/// Flutter Timeline library
|
||||||
library flutter_timeline;
|
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_interface/flutter_timeline_interface.dart';
|
||||||
export 'package:flutter_timeline_view/flutter_timeline_view.dart';
|
export 'package:flutter_timeline_view/flutter_timeline_view.dart';
|
||||||
|
|
|
@ -5,9 +5,12 @@ import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
mixin TimelineUserStoryRoutes {
|
mixin TimelineUserStoryRoutes {
|
||||||
static const String timelineHome = '/timeline';
|
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 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 {
|
class TimelineUserStoryConfiguration {
|
||||||
|
@ -15,22 +18,31 @@ class TimelineUserStoryConfiguration {
|
||||||
required this.optionsBuilder,
|
required this.optionsBuilder,
|
||||||
required this.userId,
|
required this.userId,
|
||||||
required this.service,
|
required this.service,
|
||||||
this.pageBuilder,
|
required this.userService,
|
||||||
|
this.mainPageBuilder,
|
||||||
|
this.postScreenBuilder,
|
||||||
|
this.postCreationScreenBuilder,
|
||||||
|
this.postSelectionScreenBuilder,
|
||||||
this.onUserTap,
|
this.onUserTap,
|
||||||
this.timelinePostHeight,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final String userId;
|
final String userId;
|
||||||
|
|
||||||
final double? timelinePostHeight;
|
|
||||||
final Function(String userId)? onUserTap;
|
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 TimelineService service;
|
||||||
|
|
||||||
final TimelineOptions Function(BuildContext context)
|
final TimelineUserService userService;
|
||||||
optionsBuilder; // New callback
|
|
||||||
|
final TimelineOptions Function(BuildContext context) optionsBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GoRoute> getTimelineStoryRoutes(
|
List<GoRoute> getTimelineStoryRoutes(
|
||||||
|
@ -39,22 +51,93 @@ List<GoRoute> getTimelineStoryRoutes(
|
||||||
<GoRoute>[
|
<GoRoute>[
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: TimelineUserStoryRoutes.timelineHome,
|
path: TimelineUserStoryRoutes.timelineHome,
|
||||||
pageBuilder: (context, state) => buildScreenWithoutTransition(
|
pageBuilder: (context, state) {
|
||||||
context: context,
|
var timelineScreen = TimelineScreen(
|
||||||
state: state,
|
userId: configuration.userId,
|
||||||
child: Scaffold(
|
onUserTap: configuration.onUserTap,
|
||||||
body: TimelineScreen(
|
service: configuration.service,
|
||||||
userId: configuration.userId,
|
options: configuration.optionsBuilder(context),
|
||||||
onUserTap: configuration.onUserTap,
|
onPostTap: (post) async =>
|
||||||
service: configuration.service,
|
TimelineUserStoryRoutes.timelineViewPath(post.id),
|
||||||
options: configuration.optionsBuilder(context),
|
timelineCategoryFilter: 'news',
|
||||||
timelinePostHeight: configuration.timelinePostHeight,
|
);
|
||||||
onPostTap: (_) async => context.push('/timeline-view/1'),
|
return buildScreenWithoutTransition(
|
||||||
timelineCategoryFilter: 'category',
|
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;
|
return updatedPost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TimelinePost? getPost(String postId) =>
|
||||||
|
(_posts.any((element) => element.id == postId))
|
||||||
|
? _posts.firstWhere((element) => element.id == postId)
|
||||||
|
: null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<TimelinePost> getPosts(String? category) => _posts
|
List<TimelinePost> getPosts(String? category) => _posts
|
||||||
.where((element) => category == null || element.category == category)
|
.where((element) => category == null || element.category == category)
|
||||||
|
|
|
@ -13,6 +13,7 @@ abstract class TimelineService with ChangeNotifier {
|
||||||
Future<TimelinePost> createPost(TimelinePost post);
|
Future<TimelinePost> createPost(TimelinePost post);
|
||||||
Future<List<TimelinePost>> fetchPosts(String? category);
|
Future<List<TimelinePost>> fetchPosts(String? category);
|
||||||
Future<TimelinePost> fetchPost(TimelinePost post);
|
Future<TimelinePost> fetchPost(TimelinePost post);
|
||||||
|
TimelinePost? getPost(String postId);
|
||||||
List<TimelinePost> getPosts(String? category);
|
List<TimelinePost> getPosts(String? category);
|
||||||
Future<TimelinePost> fetchPostDetails(TimelinePost post);
|
Future<TimelinePost> fetchPostDetails(TimelinePost post);
|
||||||
Future<TimelinePost> reactToPost(
|
Future<TimelinePost> reactToPost(
|
||||||
|
|
|
@ -15,6 +15,7 @@ class TimelineOptions {
|
||||||
this.translations = const TimelineTranslations(),
|
this.translations = const TimelineTranslations(),
|
||||||
this.imagePickerConfig = const ImagePickerConfig(),
|
this.imagePickerConfig = const ImagePickerConfig(),
|
||||||
this.imagePickerTheme = const ImagePickerTheme(),
|
this.imagePickerTheme = const ImagePickerTheme(),
|
||||||
|
this.timelinePostHeight,
|
||||||
this.allowAllDeletion = false,
|
this.allowAllDeletion = false,
|
||||||
this.sortCommentsAscending = true,
|
this.sortCommentsAscending = true,
|
||||||
this.sortPostsAscending = false,
|
this.sortPostsAscending = false,
|
||||||
|
@ -44,6 +45,9 @@ class TimelineOptions {
|
||||||
/// only the posts of the current user
|
/// only the posts of the current user
|
||||||
final bool allowAllDeletion;
|
final bool allowAllDeletion;
|
||||||
|
|
||||||
|
/// The height of a post in the timeline
|
||||||
|
final double? timelinePostHeight;
|
||||||
|
|
||||||
final TimelineTranslations translations;
|
final TimelineTranslations translations;
|
||||||
|
|
||||||
final ButtonBuilder? buttonBuilder;
|
final ButtonBuilder? buttonBuilder;
|
||||||
|
|
|
@ -19,7 +19,6 @@ class TimelineScreen extends StatefulWidget {
|
||||||
this.posts,
|
this.posts,
|
||||||
this.controller,
|
this.controller,
|
||||||
this.timelineCategoryFilter,
|
this.timelineCategoryFilter,
|
||||||
this.timelinePostHeight,
|
|
||||||
this.padding = const EdgeInsets.symmetric(vertical: 12.0),
|
this.padding = const EdgeInsets.symmetric(vertical: 12.0),
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
@ -38,9 +37,6 @@ class TimelineScreen extends StatefulWidget {
|
||||||
|
|
||||||
final String? timelineCategoryFilter;
|
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
|
/// This is used if you want to pass in a list of posts instead
|
||||||
/// of fetching them from the service
|
/// of fetching them from the service
|
||||||
final List<TimelinePost>? posts;
|
final List<TimelinePost>? posts;
|
||||||
|
@ -106,7 +102,7 @@ class _TimelineScreenState extends State<TimelineScreen> {
|
||||||
userId: widget.userId,
|
userId: widget.userId,
|
||||||
options: widget.options,
|
options: widget.options,
|
||||||
post: post,
|
post: post,
|
||||||
height: widget.timelinePostHeight,
|
height: widget.options.timelinePostHeight,
|
||||||
onTap: () => widget.onPostTap.call(post),
|
onTap: () => widget.onPostTap.call(post),
|
||||||
onTapLike: () async =>
|
onTapLike: () async =>
|
||||||
widget.service.likePost(widget.userId, post),
|
widget.service.likePost(widget.userId, post),
|
||||||
|
|
Loading…
Reference in a new issue