Skip to content

Commit

Permalink
Merge pull request #21 from ieeeuoft/blogModel
Browse files Browse the repository at this point in the history
IEEE 11: update blog model
  • Loading branch information
thomaslin2020 authored Nov 17, 2023
2 parents e48cde7 + 7dbcc09 commit 575316b
Show file tree
Hide file tree
Showing 6 changed files with 441 additions and 10 deletions.
49 changes: 49 additions & 0 deletions app/lib/core/models/blog_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'package:cloud_firestore/cloud_firestore.dart';

class BlogModel {
final String id;
final List<dynamic> tags;
final String title;
final String description;
final String memberID;
final Timestamp createdTime;
final Timestamp updatedTime;
final String image;

BlogModel(
{required this.id,
required this.tags,
required this.title,
required this.description,
required this.memberID,
required this.createdTime,
required this.updatedTime,
required this.image});

// Converts a Firestore Document to a UserModel
factory BlogModel.fromDocument(Map<String, dynamic> doc, String id) {
return BlogModel(
id: id,
tags: doc['tags'],
title: doc['title'],
description: doc['description'],
memberID: doc['memberID'],
createdTime: doc['createdTime'],
updatedTime: doc['updatedTime'],
image: doc['image'],
);
}

// Converts a UserModel to a Firestore Document
Map<String, dynamic> toDocument() {
return {// The 'id' field is added here to prevent errors when creating a new post
'tags': tags,
'title': title,
'description': description,
'memberID': memberID,
'createdTime': createdTime,
'updatedTime': updatedTime,
'image': image,
};
}
}
120 changes: 120 additions & 0 deletions app/lib/features/blog/blog_page_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:app/core/models/blog_model.dart';
import 'package:provider/provider.dart';
import 'blog_viewmodel.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:html_editor_enhanced/html_editor.dart';

class BlogPage extends StatefulWidget {
const BlogPage({Key? key}) : super(key: key);

@override
BlogPageState createState() => BlogPageState();
}

class BlogPageState extends State<BlogPage> {
HtmlEditorController controller = HtmlEditorController();
final ScrollController _scrollController = ScrollController();
String htmlContent = '';
Future<void> saveContent() async {
htmlContent = await controller.getText();
}

@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<BlogViewModel>(
create: (context) => BlogViewModel(),
child: Scaffold(
appBar: AppBar(
title: const Text('Profile'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Consumer<BlogViewModel>(
builder: (context, blogViewModel, child) {
Provider.of<BlogViewModel>(context, listen: false)
.fetchAll();
final blogs = blogViewModel.blogPosts;

return Column(
children: [
HtmlEditor(
controller: controller,
htmlEditorOptions:const HtmlEditorOptions(
hint: "Insert the blog description here...",
//initalText: "text content initial, if any",
),
otherOptions: const OtherOptions(
height: 200,
),
),
Expanded(
child: blogs.isEmpty
? const Center(
child: Text(
'No blog posts found. Click the button below to create one.'),
)
: ListView.builder(
controller: _scrollController,
itemCount: blogs.length,
itemBuilder: (context, index) {
final blog = blogs[index];
return ListTile(
title: Text(blog.title),
subtitle: Html(data: blog.description),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
blogViewModel.delete(blog.id);
},
),
);
},
),
),
ElevatedButton(
onPressed: () async {
await saveContent();
BlogModel newBlog = BlogModel(
id: '1', // The 'id' should be generated by Firestore when creating a new post
tags: ['Flutter', 'Firebase'],
title: 'New Blog Post',
description: htmlContent,
memberID: 'member123',
createdTime: Timestamp.now(),
updatedTime: Timestamp.now(),
image: 'url_to_image',
);
// Call createBlog method from BlogViewModel
Provider.of<BlogViewModel>(context, listen: false)
.createBlog((blogs.length+1).toString(), newBlog);
},
child: const Text('Create Blog'),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
await saveContent();
// Call createBlog method from BlogViewModel
Provider.of<BlogViewModel>(context, listen: false)
.updateBlog("1", htmlContent);
},
child: const Text('Update Blog 1 Description'),
),
const SizedBox(height: 20),
],
);
},
),
),
],
),
),
),
);
}
}
75 changes: 75 additions & 0 deletions app/lib/features/blog/blog_viewmodel.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import 'package:flutter/foundation.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:app/core/models/blog_model.dart';

class BlogViewModel with ChangeNotifier {
List<BlogModel> _blogPosts = [];
List<BlogModel> get blogPosts => _blogPosts;

BlogModel? _blogPost;
BlogModel? get blogPost => _blogPost;

Future<void> fetchAll() async {
// Fetch all documents from Firestore
var querySnapshot =
await FirebaseFirestore.instance.collection('blogPosts').get();
// Map the documents to BlogModel instances
_blogPosts = querySnapshot.docs
.map((doc) => BlogModel.fromDocument(doc.data(), doc.id))
.toList();
// Notify listeners that the blog posts have been updated
notifyListeners();
}

Future<void> fetchById(String id) async {
var doc =
await FirebaseFirestore.instance.collection('blogPosts').doc(id).get();
if (doc.exists) {
_blogPost = BlogModel.fromDocument(doc.data()!, doc.id);
}
notifyListeners();
}

Future<void> delete(String id) async {
await FirebaseFirestore.instance.collection('blogPosts').doc(id).delete();
// Remove the blog post from the list
_blogPosts.removeWhere((blog) => blog.id == id);
// Notify listeners that the blog posts have been updated
notifyListeners();
}

Future<void> createBlog(String id, BlogModel blog) async {
await FirebaseFirestore.instance
.collection('blogPosts')
.doc(id)
.set(blog.toDocument());
notifyListeners();
}

Future<void> updateBlog(String id, String description) async {
var doc =
await FirebaseFirestore.instance.collection('blogPosts').doc(id).get();
if (doc.exists) {
BlogModel currentBlog = BlogModel.fromDocument(doc.data()!, doc.id);
BlogModel updatedBlog = BlogModel(
id: currentBlog.id,
tags: currentBlog.tags,
title: currentBlog.title,
description: description, // update the description
memberID: currentBlog.memberID,
createdTime: currentBlog.createdTime,
updatedTime: Timestamp.now(), // update the updatedTime
image: currentBlog.image,
);
await FirebaseFirestore.instance
.collection('blogPosts')
.doc(id)
.set(updatedBlog.toDocument());
int indexToUpdate = _blogPosts.indexWhere((blog) => blog.id == id);
if (indexToUpdate != -1) {
_blogPosts[indexToUpdate] = updatedBlog;
}
}
notifyListeners();
}
}
15 changes: 8 additions & 7 deletions app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:app/app/app_routes.dart';
import 'package:app/features/home/home_page.dart';
import 'package:app/features/profile/profile_page.dart';
import 'package:app/features/blog/blog_page_test.dart';
import 'package:app/features/team/team_page.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
Expand All @@ -26,7 +27,7 @@ class MyApp extends StatelessWidget {
);
}
}
enum AppTab { Home, Notification, Team, Profile }
enum AppTab { Home, Blog, Team, Profile }

class MainScaffold extends StatefulWidget {
const MainScaffold({super.key});
Expand All @@ -53,10 +54,10 @@ class _MainScaffoldState extends State<MainScaffold> {
icon: Icon(Icons.home),
label: 'Home',
),
// BottomNavigationBarItem(
// icon: Icon(Icons.notifications),
// label: 'Notifications',
// ),
BottomNavigationBarItem(
icon: Icon(Icons.notifications),
label: 'Blog',
),
BottomNavigationBarItem(
icon: Icon(Icons.group),
label: 'Team',
Expand All @@ -77,8 +78,8 @@ class _MainScaffoldState extends State<MainScaffold> {
switch (_selectedTab) {
case AppTab.Home:
return const HomePage();
// case AppTab.Notification:
// return const NotificationsPage();
case AppTab.Blog:
return const BlogPage();
case AppTab.Team:
return const TeamPage();
case AppTab.Profile:
Expand Down
Loading

0 comments on commit 575316b

Please sign in to comment.