mirror of
https://github.com/Iconica-Development/flutter_timeline.git
synced 2025-05-19 02:23:46 +02:00
feat: add timeline selection screen
This commit is contained in:
parent
0035e1f4fb
commit
e523f52118
14 changed files with 187 additions and 63 deletions
|
@ -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';
|
||||
|
|
|
@ -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<GoRoute> getTimelineStoryRoutes(
|
||||
TimelineUserStoryConfiguration configuration,
|
||||
) =>
|
||||
|
@ -52,20 +16,23 @@ List<GoRoute> 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<GoRoute> 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<GoRoute> 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<GoRoute> 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,
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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<TimelineCategory> Function(BuildContext context) categoriesBuilder;
|
||||
}
|
13
packages/flutter_timeline/lib/src/routes.dart
Normal file
13
packages/flutter_timeline/lib/src/routes.dart
Normal file
|
@ -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';
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<TimelineCategory> 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue