Last active
June 25, 2021 16:56
-
-
Save knollyy/817cd6011fb01bc3fed6956792fb4e87 to your computer and use it in GitHub Desktop.
Social Media App
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
cachedNetworkImage(mediaUrl) { | |
return Text('cached network image'); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
AppBar header(context, {bool isAppTitle=false, String strTitle, disappearedBlackButton=false}) { | |
return AppBar( | |
iconTheme: IconThemeData( | |
color: Colors.white, | |
), | |
automaticallyImplyLeading: disappearedBlackButton ? false : true, | |
title: Text( | |
isAppTitle ? 'BuddiesGram' : strTitle, | |
style: TextStyle( | |
color: Colors.white, | |
fontFamily: isAppTitle ? 'Signatra' : '', | |
fontSize: isAppTitle ? 45.0 : 22.0, | |
), | |
), | |
centerTitle: true, | |
backgroundColor: Theme.of(context).accentColor, | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:io'; | |
import 'package:buddiesgram/models/user.dart'; | |
import 'package:buddiesgram/pages/CreateAccountPage.dart'; | |
import 'package:buddiesgram/pages/NotificationsPage.dart'; | |
import 'package:buddiesgram/pages/ProfilePage.dart'; | |
import 'package:buddiesgram/pages/SearchPage.dart'; | |
import 'package:buddiesgram/pages/TimeLinePage.dart'; | |
import 'package:buddiesgram/pages/UploadPage.dart'; | |
import 'package:cloud_firestore/cloud_firestore.dart'; | |
import 'package:firebase_messaging/firebase_messaging.dart'; | |
import 'package:firebase_storage/firebase_storage.dart'; | |
import 'package:flutter/cupertino.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:google_sign_in/google_sign_in.dart'; | |
final GoogleSignIn gSignIn = GoogleSignIn(); | |
final usersReference = Firestore.instance.collection("users"); | |
final StorageReference storageReference = FirebaseStorage.instance.ref().child("Posts Pictures"); | |
final postsReference = Firestore.instance.collection("posts"); | |
final activityFeedReference = Firestore.instance.collection("feed"); | |
final commentsReference = Firestore.instance.collection("comments"); | |
final followersReference = Firestore.instance.collection("followers"); | |
final followingReference = Firestore.instance.collection("following"); | |
final timelineReference = Firestore.instance.collection("timeline"); | |
final DateTime timestamp = DateTime.now(); | |
User currentUser; | |
class HomePage extends StatefulWidget { | |
@override | |
_HomePageState createState() => _HomePageState(); | |
} | |
class _HomePageState extends State<HomePage> | |
{ | |
bool isSignedIn = false; | |
PageController pageController; | |
int getPageIndex = 0; | |
FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); | |
final _scaffoldKey = GlobalKey<ScaffoldState>(); | |
void initState(){ | |
super.initState(); | |
pageController = PageController(); | |
gSignIn.onCurrentUserChanged.listen((gSigninAccount){ | |
controlSignIn(gSigninAccount); | |
}, onError: (gError){ | |
print("Error Message: " + gError); | |
}); | |
gSignIn.signInSilently(suppressErrors: false).then((gSignInAccount){ | |
controlSignIn(gSignInAccount); | |
}).catchError((gError){ | |
print("Error Message: " + gError); | |
}); | |
} | |
controlSignIn(GoogleSignInAccount signInAccount) async | |
{ | |
if(signInAccount != null) | |
{ | |
await saveUserInfoToFireStore(); | |
setState(() { | |
isSignedIn = true; | |
}); | |
configureRealTimePushNotifications(); | |
} | |
else | |
{ | |
setState(() { | |
isSignedIn = false; | |
}); | |
} | |
} | |
configureRealTimePushNotifications() | |
{ | |
final GoogleSignInAccount gUser = gSignIn.currentUser; | |
if(Platform.isIOS) | |
{ | |
getIOSPermissions(); | |
} | |
_firebaseMessaging.getToken().then((token){ | |
usersReference.document(gUser.id).updateData({"androidNotificationToken": token}); | |
}); | |
_firebaseMessaging.configure( | |
onMessage: (Map<String, dynamic> msg) async | |
{ | |
final String recipientId = msg["data"]["recipient"]; | |
final String body = msg["notification"]["body"]; | |
if(recipientId == gUser.id) | |
{ | |
SnackBar snackBar = SnackBar( | |
backgroundColor: Colors.grey, | |
content: Text(body, style: TextStyle(color: Colors.black), overflow: TextOverflow.ellipsis,), | |
); | |
_scaffoldKey.currentState.showSnackBar(snackBar); | |
} | |
}, | |
); | |
} | |
getIOSPermissions() | |
{ | |
_firebaseMessaging.requestNotificationPermissions(IosNotificationSettings(alert: true, badge: true, sound: true)); | |
_firebaseMessaging.onIosSettingsRegistered.listen((settings){ | |
print("Settings Registered : $settings"); | |
}); | |
} | |
saveUserInfoToFireStore() async { | |
final GoogleSignInAccount gCurrentUser = gSignIn.currentUser; | |
DocumentSnapshot documentSnapshot = await usersReference.document(gCurrentUser.id).get(); | |
if(!documentSnapshot.exists){ | |
final username = await Navigator.push(context, MaterialPageRoute(builder: (context) => CreateAccountPage())); | |
usersReference.document(gCurrentUser.id).setData({ | |
"id": gCurrentUser.id, | |
"profileName": gCurrentUser.displayName, | |
"username": username, | |
"url": gCurrentUser.photoUrl, | |
"email": gCurrentUser.email, | |
"bio": "", | |
"timestamp": timestamp, | |
}); | |
await followersReference.document(gCurrentUser.id).collection("userFollowers").document(gCurrentUser.id).setData({}); | |
documentSnapshot = await usersReference.document(gCurrentUser.id).get(); | |
} | |
currentUser = User.fromDocument(documentSnapshot); | |
} | |
void dispose(){ | |
pageController.dispose(); | |
super.dispose(); | |
} | |
loginUser(){ | |
gSignIn.signIn(); | |
} | |
logoutUser(){ | |
gSignIn.signOut(); | |
} | |
whenPageChanges(int pageIndex){ | |
setState(() { | |
this.getPageIndex = pageIndex; | |
}); | |
} | |
onTapChangePage(int pageIndex){ | |
pageController.animateToPage(pageIndex, duration: Duration(milliseconds: 400), curve: Curves.bounceInOut,); | |
} | |
Scaffold buildHomeScreen(){ | |
return Scaffold( | |
key: _scaffoldKey, | |
body: PageView( | |
children: <Widget>[ | |
TimeLinePage(gCurrentUser: currentUser,), | |
SearchPage(), | |
UploadPage(gCurrentUser: currentUser,), | |
NotificationsPage(), | |
ProfilePage(userProfileId: currentUser?.id), | |
], | |
controller: pageController, | |
onPageChanged: whenPageChanges, | |
physics: NeverScrollableScrollPhysics(), | |
), | |
bottomNavigationBar: CupertinoTabBar( | |
currentIndex: getPageIndex, | |
onTap: onTapChangePage, | |
backgroundColor: Theme.of(context).accentColor, | |
activeColor: Colors.white, | |
inactiveColor: Colors.blueGrey, | |
items: [ | |
BottomNavigationBarItem(icon: Icon(Icons.home)), | |
BottomNavigationBarItem(icon: Icon(Icons.search)), | |
BottomNavigationBarItem(icon: Icon(Icons.photo_camera, size: 37.0,)), | |
BottomNavigationBarItem(icon: Icon(Icons.favorite)), | |
BottomNavigationBarItem(icon: Icon(Icons.person)), | |
], | |
), | |
); | |
} | |
Scaffold buildSignInScreen(){ | |
return Scaffold( | |
body: Container( | |
decoration: BoxDecoration( | |
gradient: LinearGradient( | |
begin: Alignment.topRight, | |
end: Alignment.bottomLeft, | |
colors: [Theme.of(context).accentColor, Theme.of(context).primaryColor], | |
), | |
), | |
alignment: Alignment.center, | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
crossAxisAlignment: CrossAxisAlignment.center, | |
children: <Widget>[ | |
Text( | |
"BuddiesGram", | |
style: TextStyle(fontSize: 92.0, color: Colors.white, fontFamily: "Signatra"), | |
), | |
GestureDetector( | |
onTap: loginUser, | |
child: Container( | |
width: 270.0, | |
height: 65.0, | |
decoration: BoxDecoration( | |
image: DecorationImage( | |
image: AssetImage("assets/images/google_signin_button.png"), | |
fit: BoxFit.cover, | |
), | |
), | |
), | |
), | |
], | |
), | |
), | |
); | |
} | |
@override | |
Widget build(BuildContext context) { | |
if(isSignedIn) | |
{ | |
return buildHomeScreen(); | |
} | |
else | |
{ | |
return buildSignInScreen(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:buddiesgram/pages/HomePage.dart'; | |
import 'package:cloud_firestore/cloud_firestore.dart'; | |
import 'package:flutter/material.dart'; | |
void main() | |
{ | |
WidgetsFlutterBinding.ensureInitialized(); | |
Firestore.instance.settings(timestampsInSnapshotsEnabled: true); | |
runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'BuddiesGram', | |
debugShowCheckedModeBanner: false, | |
theme: ThemeData | |
( | |
scaffoldBackgroundColor: Colors.black, | |
dialogBackgroundColor: Colors.black, | |
primarySwatch: Colors.grey, | |
cardColor: Colors.white70, | |
accentColor: Colors.black, | |
), | |
home: HomePage(), | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:buddiesgram/pages/PostScreenPage.dart'; | |
import 'package:buddiesgram/widgets/PostWidget.dart'; | |
import 'package:flutter/material.dart'; | |
class PostTile extends StatelessWidget | |
{ | |
final Post post; | |
PostTile(this.post); | |
displayFullPost(context) | |
{ | |
Navigator.push(context, MaterialPageRoute(builder: (context)=>PostScreenPage(postId: post.postId, userId: post.ownerId))); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return GestureDetector | |
( | |
onTap: () => displayFullPost(context), | |
child: Image.network(post.url), | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:buddiesgram/models/user.dart'; | |
import 'package:buddiesgram/pages/CommentsPage.dart'; | |
import 'package:buddiesgram/pages/HomePage.dart'; | |
import 'package:buddiesgram/pages/ProfilePage.dart'; | |
import 'package:buddiesgram/widgets/CImageWidget.dart'; | |
import 'package:buddiesgram/widgets/ProgressWidget.dart'; | |
import 'package:cached_network_image/cached_network_image.dart'; | |
import 'package:cloud_firestore/cloud_firestore.dart'; | |
import 'package:flutter/material.dart'; | |
class Post extends StatefulWidget | |
{ | |
final String postId; | |
final String ownerId; | |
//final String timestamp; | |
final dynamic likes; | |
final String username; | |
final String description; | |
final String location; | |
final String url; | |
Post({ | |
this.postId, | |
this.ownerId, | |
//this.timestamp, | |
this.likes, | |
this.username, | |
this.description, | |
this.location, | |
this.url, | |
}); | |
factory Post.fromDocument(DocumentSnapshot documentSnapshot){ | |
return Post( | |
postId: documentSnapshot['postId'], | |
ownerId: documentSnapshot['ownerId'], | |
likes: documentSnapshot['likes'], | |
username: documentSnapshot['username'], | |
description: documentSnapshot['description'], | |
location: documentSnapshot['location'], | |
url: documentSnapshot['url'], | |
); | |
} | |
int getTotalNumberOfLikes(likes){ | |
if(likes == null) | |
{ | |
return 0; | |
} | |
int counter = 0; | |
likes.values.forEach((eachValue){ | |
if(eachValue == true) | |
{ | |
counter = counter + 1; | |
} | |
}); | |
return counter; | |
} | |
@override | |
_PostState createState() => _PostState( | |
postId: this.postId, | |
ownerId: this.ownerId, | |
//timestamp: this.timestamp, | |
likes: this.likes, | |
username: this.username, | |
description: this.description, | |
location: this.location, | |
url: this.url, | |
likeCount: getTotalNumberOfLikes(this.likes), | |
); | |
} | |
class _PostState extends State<Post> | |
{ | |
final String postId; | |
final String ownerId; | |
//final String timestamp; | |
Map likes; | |
final String username; | |
final String description; | |
final String location; | |
final String url; | |
int likeCount; | |
bool isLiked; | |
bool showHeart = false; | |
final String currentOnlineUserId = currentUser?.id; | |
_PostState({ | |
this.postId, | |
this.ownerId, | |
//this.timestamp, | |
this.likes, | |
this.username, | |
this.description, | |
this.location, | |
this.url, | |
this.likeCount, | |
}); | |
@override | |
Widget build(BuildContext context) | |
{ | |
isLiked = (likes[currentOnlineUserId] == true); | |
return Padding( | |
padding: EdgeInsets.only(bottom: 12.0), | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: <Widget> | |
[ | |
createPostHead(), | |
createPostPicture(), | |
createPostFooter(), | |
], | |
), | |
); | |
} | |
createPostHead(){ | |
return FutureBuilder( | |
future: usersReference.document(ownerId).get(), | |
builder: (context, dataSnapshot){ | |
if(!dataSnapshot.hasData) | |
{ | |
return circularProgress(); | |
} | |
User user = User.fromDocument(dataSnapshot.data); | |
bool isPostOwner = currentOnlineUserId == ownerId; | |
return ListTile( | |
leading: CircleAvatar(backgroundImage: CachedNetworkImageProvider(user.url), backgroundColor: Colors.grey,), | |
title: GestureDetector( | |
onTap: ()=> displayUserProfile(context, userProfileId: user.id), | |
child: Text( | |
user.username, | |
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), | |
), | |
), | |
subtitle: Text(location, style: TextStyle(color: Colors.white),), | |
trailing: isPostOwner ? IconButton( | |
icon: Icon(Icons.more_vert, color: Colors.white,), | |
onPressed: ()=> print('deleted'), | |
) : Text(''), | |
); | |
}, | |
); | |
} | |
displayUserProfile(BuildContext context, {String userProfileId}) | |
{ | |
Navigator.push(context, MaterialPageRoute(builder: (context) => ProfilePage(userProfileId: userProfileId,))); | |
} | |
removeLike() | |
{ | |
bool isNotPostOwner = currentOnlineUserId != ownerId; | |
if(isNotPostOwner){ | |
activityFeedReference.document(ownerId).collection('feedItems').document(postId).get().then((document){ | |
if(document.exists) | |
{ | |
document.reference.delete(); | |
} | |
}); | |
} | |
} | |
addLike() | |
{ | |
bool isNotPostOwner = currentOnlineUserId != ownerId; | |
if(isNotPostOwner) | |
{ | |
activityFeedReference.document(ownerId).collection('feedItems').document(postId).setData({ | |
'type': 'like', | |
'username': currentUser.username, | |
'userId': currentUser.id, | |
'timestamp': DateTime.now(), | |
'url': url, | |
'postId': postId, | |
'userProfileImage': currentUser.url, | |
}); | |
} | |
} | |
controlUserLikePost(){ | |
bool _liked = likes[currentOnlineUserId] == true; | |
if(_liked) | |
{ | |
postsReference.document(ownerId).collection("usersPosts").document(postId).updateData({"likes.$currentOnlineUserId": false}); | |
removeLike(); | |
setState(() { | |
likeCount = likeCount -1; | |
isLiked = false; | |
likes[currentOnlineUserId] = false; | |
}); | |
} | |
else if(!_liked) | |
{ | |
postsReference.document(ownerId).collection('usersPosts').document(postId).updateData( | |
{'likes.$currentOnlineUserId': true}); | |
addLike(); | |
setState(() { | |
likeCount = likeCount + 1; | |
isLiked = true; | |
likes[currentOnlineUserId] = true; | |
showHeart = true; | |
}); | |
Timer(Duration(milliseconds: 800), (){ | |
setState(() { | |
showHeart = false; | |
}); | |
}); | |
} | |
} | |
createPostPicture() | |
{ | |
return GestureDetector( | |
onDoubleTap: ()=> controlUserLikePost, | |
child: Stack( | |
alignment: Alignment.center, | |
children: <Widget> | |
[ | |
Image.network(url), | |
showHeart ? Text("") : Text(''), | |
], | |
), | |
); | |
} | |
createPostFooter() | |
{ | |
return Column( | |
children: <Widget>[ | |
Row( | |
mainAxisAlignment: MainAxisAlignment.start, | |
children: <Widget>[ | |
Padding(padding: EdgeInsets.only(top: 40.0, left: 20.0)), | |
GestureDetector( | |
onTap: ()=> controlUserLikePost(), | |
child: Icon( | |
isLiked ? Icons.favorite : Icons.favorite_border, | |
size: 28.0, | |
color: Colors.pink, | |
), | |
), | |
Padding(padding: EdgeInsets.only(right: 20.0)), | |
GestureDetector( | |
onTap: ()=> displayComments(context, postId: postId, ownerId: ownerId, url: url), | |
child: Icon(Icons.chat_bubble_outline, size: 28.0, color: Colors.white,), | |
), | |
], | |
), | |
Row( | |
children: <Widget>[ | |
Container( | |
margin: EdgeInsets.only(left: 20.0), | |
child: Text( | |
'$likeCount likes', | |
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), | |
), | |
), | |
], | |
), | |
Row( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Container( | |
margin: EdgeInsets.only(left: 20.0), | |
child: Text('$username ', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),), | |
), | |
Expanded( | |
child: Text(description, style: TextStyle(color: Colors.white),), | |
), | |
], | |
), | |
], | |
); | |
} | |
displayComments(BuildContext context, {String postId, String ownerId, String url}) | |
{ | |
Navigator.push(context, MaterialPageRoute(builder: (context) | |
{ | |
return CommentsPage(postId: postId, postOwnerId: ownerId, postImageUrl: url,); | |
} | |
)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/cupertino.dart'; | |
import 'package:flutter/material.dart'; | |
circularProgress() { | |
return Container( | |
alignment: Alignment.center, | |
padding: EdgeInsets.only(top: 12.0), | |
child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.lightGreenAccent),), | |
); | |
} | |
linearProgress() { | |
return Container( | |
alignment: Alignment.center, | |
padding: EdgeInsets.only(top: 12.0), | |
child: LinearProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.lightGreenAccent),), | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:buddiesgram/models/user.dart'; | |
import 'package:buddiesgram/pages/HomePage.dart'; | |
import 'package:buddiesgram/widgets/HeaderWidget.dart'; | |
import 'package:buddiesgram/widgets/PostWidget.dart'; | |
import 'package:buddiesgram/widgets/ProgressWidget.dart'; | |
import 'package:cloud_firestore/cloud_firestore.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:geolocator/geolocator.dart'; | |
class TimeLinePage extends StatefulWidget | |
{ | |
final User gCurrentUser; | |
TimeLinePage({this.gCurrentUser}); | |
@override | |
_TimeLinePageState createState() => _TimeLinePageState(); | |
} | |
class _TimeLinePageState extends State<TimeLinePage> | |
{ | |
List<Post> postsList; | |
List<String> followingsList = []; | |
final _scaffoldKey = GlobalKey<ScaffoldState>(); | |
retrieveTimeLine() async | |
{ | |
QuerySnapshot querySnapshot = await timelineReference.document(widget.gCurrentUser.id) | |
.collection("timelinePosts").orderBy("timestamp", descending: true).getDocuments(); | |
List<Post> allPosts = querySnapshot.documents.map((document) => Post.fromDocument(document)).toList(); | |
setState(() { | |
this.postsList = allPosts; | |
}); | |
} | |
retrieveFollowings() async | |
{ | |
QuerySnapshot querySnapshot = await followingReference.document(currentUser.id).collection("userFollowing").getDocuments(); | |
setState(() { | |
followingsList = querySnapshot.documents.map((document) => document.documentID).toList(); | |
}); | |
} | |
@override | |
void initState() { | |
// TODO: implement initState | |
super.initState(); | |
retrieveTimeLine(); | |
retrieveFollowings(); | |
} | |
createUserTimeLine() | |
{ | |
if(postsList == null) | |
{ | |
return circularProgress(); | |
} | |
else if(postsList.isEmpty) | |
{ | |
return Text("test"); | |
} | |
else | |
{ | |
return ListView(children: postsList,); | |
} | |
} | |
@override | |
Widget build(context) { | |
return Scaffold( | |
key: _scaffoldKey, | |
appBar: header(context, isAppTitle: true, ), | |
body: RefreshIndicator(child: createUserTimeLine(), onRefresh: () => retrieveTimeLine()), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment