From e523f521185f22a3386444527441aafb932d9d87 Mon Sep 17 00:00:00 2001 From: Freek van de Ven Date: Sun, 3 Dec 2023 20:18:41 +0100 Subject: [PATCH] feat: add timeline selection screen --- .../lib/flutter_timeline.dart | 3 + .../lib/src/flutter_timeline_userstory.dart | 84 +++++++------------ .../flutter_timeline/lib/src/go_router.dart | 4 + .../src/models/timeline_configuration.dart | 46 ++++++++++ packages/flutter_timeline/lib/src/routes.dart | 13 +++ packages/flutter_timeline/pubspec.yaml | 4 +- .../flutter_timeline_firebase/pubspec.yaml | 2 +- .../lib/flutter_timeline_interface.dart | 2 +- .../lib/src/model/timeline_category.dart | 17 ++++ .../flutter_timeline_interface/pubspec.yaml | 4 - .../lib/flutter_timeline_view.dart | 1 + .../lib/src/config/timeline_translations.dart | 3 + .../screens/timeline_selection_screen.dart | 65 ++++++++++++++ packages/flutter_timeline_view/pubspec.yaml | 2 +- 14 files changed, 187 insertions(+), 63 deletions(-) create mode 100644 packages/flutter_timeline/lib/src/models/timeline_configuration.dart create mode 100644 packages/flutter_timeline/lib/src/routes.dart create mode 100644 packages/flutter_timeline_interface/lib/src/model/timeline_category.dart create mode 100644 packages/flutter_timeline_view/lib/src/screens/timeline_selection_screen.dart diff --git a/packages/flutter_timeline/lib/flutter_timeline.dart b/packages/flutter_timeline/lib/flutter_timeline.dart index 9de6fe8..b4af6ca 100644 --- a/packages/flutter_timeline/lib/flutter_timeline.dart +++ b/packages/flutter_timeline/lib/flutter_timeline.dart @@ -1,9 +1,12 @@ // SPDX-FileCopyrightText: 2023 Iconica // // SPDX-License-Identifier: BSD-3-Clause + /// Flutter Timeline library library flutter_timeline; export 'package:flutter_timeline/src/flutter_timeline_userstory.dart'; +export 'package:flutter_timeline/src/models/timeline_configuration.dart'; +export 'package:flutter_timeline/src/routes.dart'; export 'package:flutter_timeline_interface/flutter_timeline_interface.dart'; export 'package:flutter_timeline_view/flutter_timeline_view.dart'; diff --git a/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart b/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart index 1cae699..87d0dcc 100644 --- a/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart +++ b/packages/flutter_timeline/lib/src/flutter_timeline_userstory.dart @@ -1,50 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + import 'package:flutter/material.dart'; -import 'package:flutter_timeline/flutter_timeline.dart'; import 'package:flutter_timeline/src/go_router.dart'; +import 'package:flutter_timeline/src/models/timeline_configuration.dart'; +import 'package:flutter_timeline/src/routes.dart'; +import 'package:flutter_timeline_view/flutter_timeline_view.dart'; import 'package:go_router/go_router.dart'; -mixin TimelineUserStoryRoutes { - static const String timelineHome = '/timeline'; - static const String timelineCreate = '/timeline-create/:category'; - static String timelineCreatePath(String category) => - '/timeline-create/$category'; - static const String timelineSelect = '/timeline-select'; - static const String timelineView = '/timeline-view/:post'; - static String timelineViewPath(String postId) => '/timeline-view/$postId'; -} - -class TimelineUserStoryConfiguration { - const TimelineUserStoryConfiguration({ - required this.optionsBuilder, - required this.userId, - required this.service, - required this.userService, - this.mainPageBuilder, - this.postScreenBuilder, - this.postCreationScreenBuilder, - this.postSelectionScreenBuilder, - this.onUserTap, - }); - - final String userId; - - final Function(String userId)? onUserTap; - - 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 TimelineUserService userService; - - final TimelineOptions Function(BuildContext context) optionsBuilder; -} - List getTimelineStoryRoutes( TimelineUserStoryConfiguration configuration, ) => @@ -52,20 +16,23 @@ List getTimelineStoryRoutes( GoRoute( path: TimelineUserStoryRoutes.timelineHome, pageBuilder: (context, state) { + var timelineFilter = + Container(); // TODO(anyone): create a filter widget var timelineScreen = TimelineScreen( userId: configuration.userId, - onUserTap: configuration.onUserTap, + onUserTap: (user) => configuration.onUserTap?.call(context, user), service: configuration.service, options: configuration.optionsBuilder(context), onPostTap: (post) async => TimelineUserStoryRoutes.timelineViewPath(post.id), - timelineCategoryFilter: 'news', + timelineCategoryFilter: null, ); return buildScreenWithoutTransition( context: context, state: state, child: configuration.mainPageBuilder?.call( - Container(), // TODO(anyone): create a selection widget + context, + timelineFilter, timelineScreen, ) ?? Scaffold( @@ -77,12 +44,18 @@ List getTimelineStoryRoutes( GoRoute( path: TimelineUserStoryRoutes.timelineSelect, pageBuilder: (context, state) { - var timelineSelectionWidget = - Container(); // TODO(anyone): create timeline selection screen + var timelineSelectionWidget = TimelineSelectionScreen( + options: configuration.optionsBuilder(context), + categories: configuration.categoriesBuilder(context), + onCategorySelected: (category) async => context.push( + TimelineUserStoryRoutes.timelineCreatePath(category.name), + ), + ); return buildScreenWithoutTransition( context: context, state: state, child: configuration.postSelectionScreenBuilder?.call( + context, timelineSelectionWidget, ) ?? Scaffold( @@ -106,8 +79,10 @@ List getTimelineStoryRoutes( return buildScreenWithoutTransition( context: context, state: state, - child: configuration.postCreationScreenBuilder - ?.call(timelineCreateWidget) ?? + child: configuration.postCreationScreenBuilder?.call( + context, + timelineCreateWidget, + ) ?? Scaffold( body: timelineCreateWidget, ), @@ -123,16 +98,17 @@ List getTimelineStoryRoutes( service: configuration.service, userService: configuration.userService, post: configuration.service.getPost(state.pathParameters['post']!)!, - onPostDelete: () => context.go( - TimelineUserStoryRoutes.timelineHome, - ), - onUserTap: configuration.onUserTap, + onPostDelete: () => context.pop(), + onUserTap: (user) => configuration.onUserTap?.call(context, user), ); + var category = configuration.categoriesBuilder(context).first; return buildScreenWithoutTransition( context: context, state: state, child: configuration.postScreenBuilder?.call( + context, timelinePostWidget, + category, ) ?? Scaffold( body: timelinePostWidget, diff --git a/packages/flutter_timeline/lib/src/go_router.dart b/packages/flutter_timeline/lib/src/go_router.dart index 2190721..c9113db 100644 --- a/packages/flutter_timeline/lib/src/go_router.dart +++ b/packages/flutter_timeline/lib/src/go_router.dart @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; diff --git a/packages/flutter_timeline/lib/src/models/timeline_configuration.dart b/packages/flutter_timeline/lib/src/models/timeline_configuration.dart new file mode 100644 index 0000000..0904981 --- /dev/null +++ b/packages/flutter_timeline/lib/src/models/timeline_configuration.dart @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2023 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +import 'package:flutter/material.dart'; +import 'package:flutter_timeline_interface/flutter_timeline_interface.dart'; +import 'package:flutter_timeline_view/flutter_timeline_view.dart'; + +@immutable +class TimelineUserStoryConfiguration { + const TimelineUserStoryConfiguration({ + required this.categoriesBuilder, + required this.optionsBuilder, + required this.userId, + required this.service, + required this.userService, + this.mainPageBuilder, + this.postScreenBuilder, + this.postCreationScreenBuilder, + this.postSelectionScreenBuilder, + this.onUserTap, + }); + + final String userId; + + final Function(BuildContext context, String userId)? onUserTap; + + final Widget Function(BuildContext context, Widget filterBar, Widget child)? + mainPageBuilder; + + final Widget Function(BuildContext context, Widget child, TimelineCategory category)? postScreenBuilder; + + final Widget Function(BuildContext context, Widget child)? + postCreationScreenBuilder; + + final Widget Function(BuildContext context, Widget child)? + postSelectionScreenBuilder; + + final TimelineService service; + + final TimelineUserService userService; + + final TimelineOptions Function(BuildContext context) optionsBuilder; + + final List Function(BuildContext context) categoriesBuilder; +} diff --git a/packages/flutter_timeline/lib/src/routes.dart b/packages/flutter_timeline/lib/src/routes.dart new file mode 100644 index 0000000..3196bea --- /dev/null +++ b/packages/flutter_timeline/lib/src/routes.dart @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +mixin TimelineUserStoryRoutes { + static const String timelineHome = '/timeline'; + static const String timelineCreate = '/timeline-create/:category'; + static String timelineCreatePath(String category) => + '/timeline-create/$category'; + static const String timelineSelect = '/timeline-select'; + static const String timelineView = '/timeline-view/:post'; + static String timelineViewPath(String postId) => '/timeline-view/$postId'; +} diff --git a/packages/flutter_timeline/pubspec.yaml b/packages/flutter_timeline/pubspec.yaml index bc07dfd..201604b 100644 --- a/packages/flutter_timeline/pubspec.yaml +++ b/packages/flutter_timeline/pubspec.yaml @@ -16,12 +16,12 @@ dependencies: go_router: ^12.1.1 flutter_timeline_view: git: - url: https://github.com/Iconica-Development/flutter_timeline.git + url: https://github.com/Iconica-Development/flutter_timeline path: packages/flutter_timeline_view ref: 1.0.0 flutter_timeline_interface: git: - url: https://github.com/Iconica-Development/flutter_timeline.git + url: https://github.com/Iconica-Development/flutter_timeline path: packages/flutter_timeline_interface ref: 1.0.0 diff --git a/packages/flutter_timeline_firebase/pubspec.yaml b/packages/flutter_timeline_firebase/pubspec.yaml index 702f27c..39d238d 100644 --- a/packages/flutter_timeline_firebase/pubspec.yaml +++ b/packages/flutter_timeline_firebase/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: flutter_timeline_interface: git: - url: https://github.com/Iconica-Development/flutter_timeline.git + url: https://github.com/Iconica-Development/flutter_timeline path: packages/flutter_timeline_interface ref: 1.0.0 diff --git a/packages/flutter_timeline_interface/lib/flutter_timeline_interface.dart b/packages/flutter_timeline_interface/lib/flutter_timeline_interface.dart index 6004105..9676ad0 100644 --- a/packages/flutter_timeline_interface/lib/flutter_timeline_interface.dart +++ b/packages/flutter_timeline_interface/lib/flutter_timeline_interface.dart @@ -4,9 +4,9 @@ /// library flutter_timeline_interface; +export 'src/model/timeline_category.dart'; export 'src/model/timeline_post.dart'; export 'src/model/timeline_poster.dart'; export 'src/model/timeline_reaction.dart'; - export 'src/services/timeline_service.dart'; export 'src/services/user_service.dart'; diff --git a/packages/flutter_timeline_interface/lib/src/model/timeline_category.dart b/packages/flutter_timeline_interface/lib/src/model/timeline_category.dart new file mode 100644 index 0000000..430e14c --- /dev/null +++ b/packages/flutter_timeline_interface/lib/src/model/timeline_category.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +@immutable +class TimelineCategory { + const TimelineCategory({ + required this.name, + required this.title, + required this.icon, + this.canCreate = true, + this.canView = true, + }); + final String name; + final String title; + final Widget icon; + final bool canCreate; + final bool canView; +} diff --git a/packages/flutter_timeline_interface/pubspec.yaml b/packages/flutter_timeline_interface/pubspec.yaml index b1e437a..051b746 100644 --- a/packages/flutter_timeline_interface/pubspec.yaml +++ b/packages/flutter_timeline_interface/pubspec.yaml @@ -14,10 +14,6 @@ environment: dependencies: flutter: sdk: flutter - flutter_data_interface: - git: - url: https://github.com/Iconica-Development/flutter_data_interface.git - ref: 1.0.0 dev_dependencies: flutter_lints: ^2.0.0 diff --git a/packages/flutter_timeline_view/lib/flutter_timeline_view.dart b/packages/flutter_timeline_view/lib/flutter_timeline_view.dart index 196be36..99c5da1 100644 --- a/packages/flutter_timeline_view/lib/flutter_timeline_view.dart +++ b/packages/flutter_timeline_view/lib/flutter_timeline_view.dart @@ -10,4 +10,5 @@ export 'src/config/timeline_translations.dart'; export 'src/screens/timeline_post_creation_screen.dart'; export 'src/screens/timeline_post_screen.dart'; export 'src/screens/timeline_screen.dart'; +export 'src/screens/timeline_selection_screen.dart'; export 'src/widgets/timeline_post_widget.dart'; diff --git a/packages/flutter_timeline_view/lib/src/config/timeline_translations.dart b/packages/flutter_timeline_view/lib/src/config/timeline_translations.dart index c24f96f..d0508ae 100644 --- a/packages/flutter_timeline_view/lib/src/config/timeline_translations.dart +++ b/packages/flutter_timeline_view/lib/src/config/timeline_translations.dart @@ -27,6 +27,7 @@ class TimelineTranslations { this.writeComment = 'Write your comment here...', this.postAt = 'at', this.postLoadingError = 'Something went wrong while loading the post', + this.timelineSelectionDescription = 'Choose a category', }); final String noPosts; @@ -50,4 +51,6 @@ class TimelineTranslations { final String writeComment; final String firstComment; final String postLoadingError; + + final String timelineSelectionDescription; } diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_selection_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_selection_screen.dart new file mode 100644 index 0000000..7e7a61a --- /dev/null +++ b/packages/flutter_timeline_view/lib/src/screens/timeline_selection_screen.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_timeline_interface/flutter_timeline_interface.dart'; +import 'package:flutter_timeline_view/src/config/timeline_options.dart'; + +class TimelineSelectionScreen extends StatelessWidget { + const TimelineSelectionScreen({ + required this.options, + required this.categories, + required this.onCategorySelected, + super.key, + }); + + final List categories; + + final TimelineOptions options; + + final Function(TimelineCategory) onCategorySelected; + + @override + Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; + var theme = Theme.of(context); + return Padding( + padding: EdgeInsets.symmetric( + horizontal: size.width * 0.05, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: size.height * 0.05, bottom: 8), + child: Text( + options.translations.timelineSelectionDescription, + style: theme.textTheme.displayMedium, + ), + ), + const SizedBox(height: 4), + for (var category in categories.where( + (element) => element.canCreate, + )) ...[ + InkWell( + onTap: () => onCategorySelected.call(category), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + color: Colors.grey, + borderRadius: BorderRadius.circular(10), + ), + padding: const EdgeInsets.symmetric( + vertical: 26, + horizontal: 16, + ), + margin: const EdgeInsets.symmetric(vertical: 8), + child: Text( + category.title, + style: theme.textTheme.displaySmall, + ), + ), + ), + ], + ], + ), + ); + } +} diff --git a/packages/flutter_timeline_view/pubspec.yaml b/packages/flutter_timeline_view/pubspec.yaml index 3aec802..96ade42 100644 --- a/packages/flutter_timeline_view/pubspec.yaml +++ b/packages/flutter_timeline_view/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: flutter_timeline_interface: git: - url: https://github.com/Iconica-Development/flutter_timeline.git + url: https://github.com/Iconica-Development/flutter_timeline path: packages/flutter_timeline_interface ref: 1.0.0 flutter_image_picker: