fix: Fix comments like readme and one service instead of multiple

This commit is contained in:
Jacques 2024-01-29 11:52:23 +01:00
parent 80df20c323
commit 93a184802d
22 changed files with 211 additions and 147 deletions

View file

@ -23,6 +23,11 @@ If you are going to use Firebase as the back-end of the Timeline, you should als
path: packages/flutter_timeline_firebase
```
Add the following code in your `main` function, before the runApp().
```
initializeDateFormatting();
```
## How to use
To use the module within your Flutter-application with predefined `Go_router` routes you should add the following:

View file

@ -1,13 +1,12 @@
import 'package:example/config/config.dart';
import 'package:example/services/timeline_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter_timeline/flutter_timeline.dart';
import 'package:go_router/go_router.dart';
List<GoRoute> getTimelineRoutes() => getTimelineStoryRoutes(
getConfig(
TestTimelineService(),
),
getConfig(TimelineService(
postService: LocalTimelinePostService(),
)),
);
final _router = GoRouter(

View file

@ -1,5 +1,4 @@
import 'package:example/config/config.dart';
import 'package:example/services/timeline_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter_timeline/flutter_timeline.dart';
@ -32,7 +31,8 @@ class MyHomePage extends StatefulWidget {
}
class _MyHomePageState extends State<MyHomePage> {
var timelineService = TestTimelineService();
var timelineService =
TimelineService(postService: LocalTimelinePostService());
var timelineOptions = options;
@override
@ -64,7 +64,11 @@ class _MyHomePageState extends State<MyHomePage> {
],
),
body: SafeArea(
child: timeLineNavigatorUserStory(getConfig(timelineService), context),
child: timeLineNavigatorUserStory(
getConfig(
timelineService,
),
context),
),
);
}

View file

@ -1,5 +1,5 @@
import 'package:example/config/config.dart';
import 'package:example/services/timeline_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter_timeline/flutter_timeline.dart';
@ -32,7 +32,8 @@ class MyHomePage extends StatefulWidget {
}
class _MyHomePageState extends State<MyHomePage> {
var timelineService = TestTimelineService();
var timelineService =
TimelineService(postService: LocalTimelinePostService());
var timelineOptions = options;
@override
@ -42,6 +43,7 @@ class _MyHomePageState extends State<MyHomePage> {
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
heroTag: 'btn1',
onPressed: () {
createPost(context, timelineService, timelineOptions);
},
@ -54,6 +56,7 @@ class _MyHomePageState extends State<MyHomePage> {
height: 8,
),
FloatingActionButton(
heroTag: 'btn2',
onPressed: () {
generatePost(timelineService);
},
@ -64,31 +67,8 @@ class _MyHomePageState extends State<MyHomePage> {
),
],
),
body: SafeArea(
child: TimelineScreen(
userId: 'test_user',
service: timelineService,
options: timelineOptions,
onPostTap: (post) async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
body: TimelinePostScreen(
userId: 'test_user',
service: timelineService,
options: timelineOptions,
post: post,
onPostDelete: () {
timelineService.deletePost(post);
Navigator.of(context).pop();
},
),
),
),
);
},
),
body: const SafeArea(
child: TimelineScreen(),
),
);
}

View file

@ -1,11 +1,9 @@
import 'package:example/apps/widgets/screens/post_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_timeline/flutter_timeline.dart';
TimelineUserStoryConfiguration getConfig(TimelineService service) {
return TimelineUserStoryConfiguration(
service: service,
userService: TestUserService(),
userId: 'test_user',
optionsBuilder: (context) => options);
}
@ -56,9 +54,9 @@ void createPost(BuildContext context, TimelineService service,
}
void generatePost(TimelineService service) {
var amountOfPosts = service.getPosts(null).length;
var amountOfPosts = service.postService.getPosts(null).length;
service.createPost(
service.postService.createPost(
TimelinePost(
id: 'Post$amountOfPosts',
creatorId: 'test_user',

View file

@ -46,6 +46,6 @@ Widget _postDetailScreenRoute(
post: post,
onPostDelete: () async {
configuration.onPostDelete?.call(context, post) ??
await configuration.service.deletePost(post);
await configuration.service.postService.deletePost(post);
},
);

View file

@ -46,8 +46,8 @@ List<GoRoute> getTimelineStoryRoutes(
GoRoute(
path: TimelineUserStoryRoutes.timelineView,
pageBuilder: (context, state) {
var post =
configuration.service.getPost(state.pathParameters['post']!)!;
var post = configuration.service.postService
.getPost(state.pathParameters['post']!)!;
var timelinePostWidget = TimelinePostScreen(
userId: configuration.userId,

View file

@ -11,7 +11,6 @@ class TimelineUserStoryConfiguration {
const TimelineUserStoryConfiguration({
required this.userId,
required this.service,
required this.userService,
required this.optionsBuilder,
this.openPageBuilder,
this.onPostTap,
@ -25,8 +24,6 @@ class TimelineUserStoryConfiguration {
final TimelineService service;
final TimelineUserService userService;
final TimelineOptions Function(BuildContext context) optionsBuilder;
final Function(BuildContext context, String userId)? onUserTap;

View file

@ -16,16 +16,18 @@ dependencies:
go_router: any
flutter_timeline_view:
git:
url: https://github.com/Iconica-Development/flutter_timeline
path: packages/flutter_timeline_view
ref: 2.0.0
path: ../flutter_timeline_view
# git:
# url: https://github.com/Iconica-Development/flutter_timeline
# path: packages/flutter_timeline_view
# ref: 2.0.0
flutter_timeline_interface:
git:
url: https://github.com/Iconica-Development/flutter_timeline
path: packages/flutter_timeline_interface
ref: 2.0.0
path: ../flutter_timeline_interface
# git:
# url: https://github.com/Iconica-Development/flutter_timeline
# path: packages/flutter_timeline_view
# ref: 2.0.0
dev_dependencies:
flutter_lints: ^2.0.0

View file

@ -13,7 +13,8 @@ import 'package:flutter_timeline_firebase/src/models/firebase_user_document.dart
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
import 'package:uuid/uuid.dart';
class FirebaseTimelineService extends TimelineService with TimelineUserService {
class FirebaseTimelineService extends TimelinePostService
with TimelineUserService {
FirebaseTimelineService({
required TimelineUserService userService,
FirebaseApp? app,

View file

@ -20,10 +20,11 @@ dependencies:
uuid: ^4.2.1
flutter_timeline_interface:
git:
url: https://github.com/Iconica-Development/flutter_timeline
path: packages/flutter_timeline_interface
ref: 2.0.0
path: ../flutter_timeline_interface
# git:
# url: https://github.com/Iconica-Development/flutter_timeline
# path: packages/flutter_timeline_interface
# ref: 2.0.0
dev_dependencies:
flutter_lints: ^2.0.0

View file

@ -9,5 +9,6 @@ export 'src/model/timeline_post.dart';
export 'src/model/timeline_poster.dart';
export 'src/model/timeline_reaction.dart';
export 'src/services/filter_service.dart';
export 'src/services/timeline_post_service.dart';
export 'src/services/timeline_service.dart';
export 'src/services/user_service.dart';

View file

@ -4,7 +4,7 @@
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
mixin TimelineFilterService on TimelineService {
mixin TimelineFilterService on TimelinePostService {
List<TimelinePost> filterPosts(
String filterWord,
Map<String, dynamic> options,

View file

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: 2023 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_timeline_interface/src/model/timeline_post.dart';
import 'package:flutter_timeline_interface/src/model/timeline_reaction.dart';
abstract class TimelinePostService with ChangeNotifier {
List<TimelinePost> posts = [];
Future<void> deletePost(TimelinePost post);
Future<TimelinePost> deletePostReaction(TimelinePost post, String reactionId);
Future<TimelinePost> createPost(TimelinePost post);
Future<List<TimelinePost>> fetchPosts(String? category);
Future<TimelinePost> fetchPost(TimelinePost post);
Future<List<TimelinePost>> fetchPostsPaginated(String? category, int limit);
TimelinePost? getPost(String postId);
List<TimelinePost> getPosts(String? category);
Future<List<TimelinePost>> refreshPosts(String? category);
Future<TimelinePost> fetchPostDetails(TimelinePost post);
Future<TimelinePost> reactToPost(
TimelinePost post,
TimelinePostReaction reaction, {
Uint8List image,
});
Future<TimelinePost> likePost(String userId, TimelinePost post);
Future<TimelinePost> unlikePost(String userId, TimelinePost post);
}

View file

@ -1,31 +1,12 @@
// SPDX-FileCopyrightText: 2023 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter_timeline_interface/src/services/timeline_post_service.dart';
import 'package:flutter_timeline_interface/src/services/user_service.dart';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_timeline_interface/src/model/timeline_post.dart';
import 'package:flutter_timeline_interface/src/model/timeline_reaction.dart';
abstract class TimelineService with ChangeNotifier {
List<TimelinePost> posts = [];
Future<void> deletePost(TimelinePost post);
Future<TimelinePost> deletePostReaction(TimelinePost post, String reactionId);
Future<TimelinePost> createPost(TimelinePost post);
Future<List<TimelinePost>> fetchPosts(String? category);
Future<TimelinePost> fetchPost(TimelinePost post);
Future<List<TimelinePost>> fetchPostsPaginated(String? category, int limit);
TimelinePost? getPost(String postId);
List<TimelinePost> getPosts(String? category);
Future<List<TimelinePost>> refreshPosts(String? category);
Future<TimelinePost> fetchPostDetails(TimelinePost post);
Future<TimelinePost> reactToPost(
TimelinePost post,
TimelinePostReaction reaction, {
Uint8List image,
class TimelineService {
TimelineService({
required this.postService,
this.userService,
});
Future<TimelinePost> likePost(String userId, TimelinePost post);
Future<TimelinePost> unlikePost(String userId, TimelinePost post);
final TimelinePostService postService;
final TimelineUserService? userService;
}

View file

@ -12,6 +12,7 @@ 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/services/local_post_service.dart';
export 'src/widgets/category_selector.dart';
export 'src/widgets/category_selector_button.dart';
export 'src/widgets/timeline_post_widget.dart';

View file

@ -82,7 +82,7 @@ class _TimelinePostCreationScreenState
reactionEnabled: allowComments,
image: image,
);
var newPost = await widget.service.createPost(post);
var newPost = await widget.service.postService.createPost(post);
widget.onPostCreated.call(newPost);
}

View file

@ -106,7 +106,8 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
Future<void> loadPostDetails() async {
try {
var loadedPost = await widget.service.fetchPostDetails(widget.post);
var loadedPost =
await widget.service.postService.fetchPostDetails(widget.post);
setState(() {
post = loadedPost;
isLoading = false;
@ -157,8 +158,8 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
RefreshIndicator(
onRefresh: () async {
updatePost(
await widget.service.fetchPostDetails(
await widget.service.fetchPost(
await widget.service.postService.fetchPostDetails(
await widget.service.postService.fetchPost(
post,
),
),
@ -269,12 +270,14 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
late TimelinePost result;
if (!liked) {
result = await widget.service.likePost(
result =
await widget.service.postService.likePost(
userId,
post,
);
} else {
result = await widget.service.unlikePost(
result = await widget.service.postService
.unlikePost(
userId,
post,
);
@ -303,7 +306,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
InkWell(
onTap: () async {
updatePost(
await widget.service.unlikePost(
await widget.service.postService.unlikePost(
widget.userId,
post,
),
@ -322,7 +325,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
InkWell(
onTap: () async {
updatePost(
await widget.service.likePost(
await widget.service.postService.likePost(
widget.userId,
post,
),
@ -450,7 +453,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
if (value == 'delete') {
// Call service to delete reaction
updatePost(
await widget.service
await widget.service.postService
.deletePostReaction(post, reaction.id),
);
}
@ -568,7 +571,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
);
if (result != null) {
updatePost(
await widget.service.reactToPost(
await widget.service.postService.reactToPost(
post,
TimelinePostReaction(
id: '',
@ -582,7 +585,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> {
}
},
onReactionSubmit: (reaction) async => updatePost(
await widget.service.reactToPost(
await widget.service.postService.reactToPost(
post,
TimelinePostReaction(
id: '',

View file

@ -10,10 +10,10 @@ import 'package:flutter_timeline_view/flutter_timeline_view.dart';
class TimelineScreen extends StatefulWidget {
const TimelineScreen({
required this.userId,
required this.service,
required this.options,
required this.onPostTap,
this.userId = 'test_user',
this.service,
this.options = const TimelineOptions(),
this.onPostTap,
this.scrollController,
this.onUserTap,
this.posts,
@ -27,7 +27,7 @@ class TimelineScreen extends StatefulWidget {
final String userId;
/// The service to use for fetching and manipulating posts
final TimelineService service;
final TimelineService? service;
/// All the configuration options for the timelinescreens and widgets
final TimelineOptions options;
@ -43,7 +43,7 @@ class TimelineScreen extends StatefulWidget {
final List<TimelinePost>? posts;
/// Called when a post is tapped
final Function(TimelinePost) onPostTap;
final Function(TimelinePost)? onPostTap;
/// If this is not null, the user can tap on the user avatar or name
final Function(String userId)? onUserTap;
@ -63,7 +63,10 @@ class _TimelineScreenState extends State<TimelineScreen> {
late var textFieldController = TextEditingController(
text: widget.options.filterOptions.initialFilterWord,
);
late var service = widget.service;
late var service = widget.service ??
TimelineService(
postService: LocalTimelinePostService(),
);
bool isLoading = true;
@ -86,9 +89,9 @@ class _TimelineScreenState extends State<TimelineScreen> {
// Build the list of posts
return ListenableBuilder(
listenable: service,
listenable: service.postService,
builder: (context, _) {
var posts = widget.posts ?? service.getPosts(category);
var posts = widget.posts ?? service.postService.getPosts(category);
if (widget.filterEnabled && filterWord != null) {
if (service is TimelineFilterService?) {
@ -203,17 +206,41 @@ class _TimelineScreenState extends State<TimelineScreen> {
padding: widget.options.postPadding,
child: widget.postWidgetBuilder?.call(post) ??
TimelinePostWidget(
service: widget.service,
service: service,
userId: widget.userId,
options: widget.options,
post: post,
onTap: () => widget.onPostTap(post),
onTapLike: () async =>
service.likePost(widget.userId, post),
onTapUnlike: () async =>
service.unlikePost(widget.userId, post),
onTap: () async {
if (widget.onPostTap != null) {
widget.onPostTap!.call(post);
return;
}
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
body: TimelinePostScreen(
userId: 'test_user',
service: service,
options: widget.options,
post: post,
onPostDelete: () {
service.postService.deletePost(post);
Navigator.of(context).pop();
},
),
),
),
);
},
onTapLike: () async => service.postService
.likePost(widget.userId, post),
onTapUnlike: () async => service.postService
.unlikePost(widget.userId, post),
onPostDelete: () async =>
service.deletePost(post),
service.postService.deletePost(post),
onUserTap: widget.onUserTap,
),
),
@ -246,7 +273,7 @@ class _TimelineScreenState extends State<TimelineScreen> {
Future<void> loadPosts() async {
if (widget.posts != null) return;
try {
await service.fetchPosts(category);
await service.postService.fetchPosts(category);
setState(() {
isLoading = false;
});

View file

@ -5,12 +5,11 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_timeline/flutter_timeline.dart';
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
// ignore: depend_on_referenced_packages
import 'package:uuid/uuid.dart';
class TestTimelineService with ChangeNotifier implements TimelineService {
class LocalTimelinePostService
with ChangeNotifier
implements TimelinePostService {
@override
List<TimelinePost> posts = [];
@ -61,8 +60,11 @@ class TestTimelineService with ChangeNotifier implements TimelineService {
var reactions = post.reactions ?? [];
var updatedReactions = <TimelinePostReaction>[];
for (var reaction in reactions) {
updatedReactions.add(reaction.copyWith(
creator: const TimelinePosterUserModel(userId: 'test_user')));
updatedReactions.add(
reaction.copyWith(
creator: const TimelinePosterUserModel(userId: 'test_user'),
),
);
}
var updatedPost = post.copyWith(reactions: updatedReactions);
posts = posts.map((p) => (p.id == post.id) ? updatedPost : p).toList();
@ -150,10 +152,12 @@ class TestTimelineService with ChangeNotifier implements TimelineService {
TimelinePostReaction reaction, {
Uint8List? image,
}) async {
var reactionId = const Uuid().v4();
var reactionId = DateTime.now().millisecondsSinceEpoch.toString();
var updatedReaction = reaction.copyWith(
id: reactionId,
creator: const TimelinePosterUserModel(userId: 'test_user'));
creator: const TimelinePosterUserModel(userId: 'test_user'),
);
var updatedPost = post.copyWith(
reaction: post.reaction + 1,
@ -169,19 +173,45 @@ class TestTimelineService with ChangeNotifier implements TimelineService {
return updatedPost;
}
List<TimelinePost> getMockedPosts() {
return [
List<TimelinePost> getMockedPosts() => [
TimelinePost(
id: 'Post0',
creatorId: 'test_user',
title: 'Post 0',
category: null,
content: "Post 0 content",
content: 'Standard post without image made by the current user',
likes: 0,
reaction: 0,
createdAt: DateTime.now(),
reactionEnabled: false,
)
),
TimelinePost(
id: 'Post1',
creatorId: 'test_user2',
title: 'Post 1',
category: null,
content: 'Standard post with image made by a different user and '
'reactions enabled',
likes: 0,
reaction: 0,
createdAt: DateTime.now(),
reactionEnabled: false,
imageUrl:
'https://s3-eu-west-1.amazonaws.com/sortlist-core-api/6qpvvqjtmniirpkvp8eg83bicnc2',
),
TimelinePost(
id: 'Post2',
creatorId: 'test_user',
title: 'Post 2',
category: null,
content: 'Standard post with image made by the current user and'
' reactions enabled',
likes: 0,
reaction: 0,
createdAt: DateTime.now(),
reactionEnabled: true,
imageUrl:
'https://s3-eu-west-1.amazonaws.com/sortlist-core-api/6qpvvqjtmniirpkvp8eg83bicnc2',
),
];
}
}

View file

@ -160,12 +160,14 @@ class _TimelinePostWidgetState extends State<TimelinePostWidget> {
late TimelinePost result;
if (!liked) {
result = await widget.service.likePost(
result =
await widget.service.postService.likePost(
userId,
widget.post,
);
} else {
result = await widget.service.unlikePost(
result =
await widget.service.postService.unlikePost(
userId,
widget.post,
);
@ -197,12 +199,12 @@ class _TimelinePostWidgetState extends State<TimelinePostWidget> {
widget.post.likedBy?.contains(userId) ?? false;
if (!liked) {
await widget.service.likePost(
await widget.service.postService.likePost(
userId,
widget.post,
);
} else {
await widget.service.unlikePost(
await widget.service.postService.unlikePost(
userId,
widget.post,
);

View file

@ -20,10 +20,11 @@ dependencies:
flutter_html: ^3.0.0-beta.2
flutter_timeline_interface:
git:
url: https://github.com/Iconica-Development/flutter_timeline
path: packages/flutter_timeline_interface
ref: 2.0.0
path: ../flutter_timeline_interface
# git:
# url: https://github.com/Iconica-Development/flutter_timeline
# path: packages/flutter_timeline_interface
# ref: 2.0.0
flutter_image_picker:
git:
url: https://github.com/Iconica-Development/flutter_image_picker