mirror of
https://github.com/Iconica-Development/flutter_timeline.git
synced 2025-05-19 10:33:44 +02:00
feat: combine UI screens with service layer
This commit is contained in:
parent
4113e9fea2
commit
e8822d92a3
8 changed files with 97 additions and 33 deletions
|
@ -4,3 +4,7 @@
|
|||
|
||||
///
|
||||
library flutter_timeline_firebase;
|
||||
|
||||
export 'src/config/firebase_timeline_options.dart';
|
||||
export 'src/service/firebase_timeline_service.dart';
|
||||
export 'src/service/firebase_user_service.dart';
|
||||
|
|
|
@ -8,8 +8,9 @@ import 'package:cloud_firestore/cloud_firestore.dart';
|
|||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_storage/firebase_storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_timeline_firebase/config/firebase_timeline_options.dart';
|
||||
import 'package:flutter_timeline_firebase/src/config/firebase_timeline_options.dart';
|
||||
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class FirebaseTimelineService implements TimelineService {
|
||||
FirebaseTimelineService({
|
||||
|
@ -32,14 +33,17 @@ class FirebaseTimelineService implements TimelineService {
|
|||
List<TimelinePost> _posts = [];
|
||||
|
||||
@override
|
||||
Future<void> createPost(TimelinePost post) async {
|
||||
var imageRef = _storage.ref().child('timeline/${post.id}');
|
||||
Future<TimelinePost> createPost(TimelinePost post) async {
|
||||
var postId = const Uuid().v4();
|
||||
var imageRef = _storage.ref().child('timeline/$postId');
|
||||
var result = await imageRef.putData(post.image!);
|
||||
var imageUrl = await result.ref.getDownloadURL();
|
||||
var updatedPost = post.copyWith(imageUrl: imageUrl);
|
||||
var postRef = _db.collection(_options.timelineCollectionName).doc(post.id);
|
||||
var updatedPost = post.copyWith(imageUrl: imageUrl, id: postId);
|
||||
var postRef =
|
||||
_db.collection(_options.timelineCollectionName).doc(updatedPost.id);
|
||||
_posts.add(updatedPost);
|
||||
return postRef.set(updatedPost.toJson());
|
||||
await postRef.set(updatedPost.toJson());
|
||||
return updatedPost;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -56,15 +60,17 @@ class FirebaseTimelineService implements TimelineService {
|
|||
|
||||
@override
|
||||
Future<List<TimelinePost>> fetchPosts(String? category) async {
|
||||
var snapshot = await _db
|
||||
.collection(_options.timelineCollectionName)
|
||||
.where('category', isEqualTo: category)
|
||||
.get();
|
||||
var snapshot = (category != null)
|
||||
? await _db
|
||||
.collection(_options.timelineCollectionName)
|
||||
.where('category', isEqualTo: category)
|
||||
.get()
|
||||
: await _db.collection(_options.timelineCollectionName).get();
|
||||
|
||||
var posts = <TimelinePost>[];
|
||||
for (var doc in snapshot.docs) {
|
||||
var data = doc.data();
|
||||
var user = await _userService.getUser(data['user_id']);
|
||||
var user = await _userService.getUser(data['creator_id']);
|
||||
var post = TimelinePost.fromJson(doc.id, data).copyWith(creator: user);
|
||||
posts.add(post);
|
||||
}
|
||||
|
@ -72,6 +78,11 @@ class FirebaseTimelineService implements TimelineService {
|
|||
return posts;
|
||||
}
|
||||
|
||||
@override
|
||||
List<TimelinePost> getPosts(String? category) => _posts
|
||||
.where((element) => category == null || element.category == category)
|
||||
.toList();
|
||||
|
||||
@override
|
||||
Future<void> likePost(String userId, TimelinePost post) {
|
||||
// update the post with the new like
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter_timeline_firebase/config/firebase_timeline_options.dart';
|
||||
import 'package:flutter_timeline_firebase/models/firebase_user_document.dart';
|
||||
import 'package:flutter_timeline_firebase/src/config/firebase_timeline_options.dart';
|
||||
import 'package:flutter_timeline_firebase/src/models/firebase_user_document.dart';
|
||||
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
|
||||
|
||||
class FirebaseUserService implements TimelineUserService {
|
|
@ -9,8 +9,9 @@ import 'package:flutter_timeline_interface/src/model/timeline_reaction.dart';
|
|||
|
||||
abstract class TimelineService {
|
||||
Future<void> deletePost(TimelinePost post);
|
||||
Future<void> createPost(TimelinePost post);
|
||||
Future<TimelinePost> createPost(TimelinePost post);
|
||||
Future<List<TimelinePost>> fetchPosts(String? category);
|
||||
List<TimelinePost> getPosts(String? category);
|
||||
Future<TimelinePost> fetchPostDetails(TimelinePost post);
|
||||
Future<void> reactToPost(
|
||||
TimelinePost post,
|
||||
|
|
|
@ -7,15 +7,30 @@ import 'dart:typed_data';
|
|||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_image_picker/flutter_image_picker.dart';
|
||||
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
|
||||
import 'package:flutter_timeline_view/src/config/timeline_options.dart';
|
||||
|
||||
class TimelinePostCreationScreen extends StatefulWidget {
|
||||
const TimelinePostCreationScreen({
|
||||
required this.userId,
|
||||
required this.postCategory,
|
||||
required this.onPostCreated,
|
||||
required this.service,
|
||||
required this.options,
|
||||
this.padding = const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String userId;
|
||||
|
||||
final String postCategory;
|
||||
|
||||
/// called when the post is created
|
||||
final Function(TimelinePost) onPostCreated;
|
||||
|
||||
/// The service to use for creating the post
|
||||
final TimelineService service;
|
||||
|
||||
/// The options for the timeline
|
||||
final TimelineOptions options;
|
||||
|
||||
|
@ -59,6 +74,23 @@ class _TimelinePostCreationScreenState
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Future<void> onPostCreated() async {
|
||||
var post = TimelinePost(
|
||||
id: '',
|
||||
creatorId: widget.userId,
|
||||
title: titleController.text,
|
||||
category: widget.postCategory,
|
||||
content: contentController.text,
|
||||
likes: 0,
|
||||
reaction: 0,
|
||||
createdAt: DateTime.now(),
|
||||
reactionEnabled: allowComments,
|
||||
image: image,
|
||||
);
|
||||
var newPost = await widget.service.createPost(post);
|
||||
widget.onPostCreated.call(newPost);
|
||||
}
|
||||
|
||||
var theme = Theme.of(context);
|
||||
return Padding(
|
||||
padding: widget.padding,
|
||||
|
@ -214,12 +246,12 @@ class _TimelinePostCreationScreenState
|
|||
child: (widget.options.buttonBuilder != null)
|
||||
? widget.options.buttonBuilder!(
|
||||
context,
|
||||
() {},
|
||||
onPostCreated,
|
||||
widget.options.translations.checkPost,
|
||||
enabled: editingDone,
|
||||
)
|
||||
: ElevatedButton(
|
||||
onPressed: editingDone ? () {} : null,
|
||||
onPressed: editingDone ? onPostCreated : null,
|
||||
child: Text(
|
||||
widget.options.translations.checkPost,
|
||||
style: theme.textTheme.bodyMedium,
|
||||
|
|
|
@ -9,15 +9,21 @@ import 'package:flutter_timeline_view/src/widgets/timeline_post_widget.dart';
|
|||
|
||||
class TimelineScreen extends StatefulWidget {
|
||||
const TimelineScreen({
|
||||
required this.userId,
|
||||
required this.options,
|
||||
required this.posts,
|
||||
required this.onPostTap,
|
||||
required this.service,
|
||||
this.controller,
|
||||
this.timelineCategoryFilter,
|
||||
this.timelinePostHeight = 100.0,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String userId;
|
||||
|
||||
final TimelineService service;
|
||||
|
||||
final TimelineOptions options;
|
||||
|
||||
final ScrollController? controller;
|
||||
|
@ -44,22 +50,32 @@ class _TimelineScreenState extends State<TimelineScreen> {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
for (var post in widget.posts)
|
||||
if (widget.timelineCategoryFilter == null ||
|
||||
post.category == widget.timelineCategoryFilter)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: TimelinePostWidget(
|
||||
options: widget.options,
|
||||
post: post,
|
||||
height: widget.timelinePostHeight,
|
||||
onTap: () => widget.onPostTap.call(post),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Widget build(BuildContext context) => FutureBuilder(
|
||||
// ignore: discarded_futures
|
||||
future: widget.service.fetchPosts(widget.timelineCategoryFilter),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data != null) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
for (var post in snapshot.data!)
|
||||
if (widget.timelineCategoryFilter == null ||
|
||||
post.category == widget.timelineCategoryFilter)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: TimelinePostWidget(
|
||||
options: widget.options,
|
||||
post: post,
|
||||
height: widget.timelinePostHeight,
|
||||
onTap: () => widget.onPostTap.call(post),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue