[英]Call a method in one class from another class in flutter and dart
So i am trying to build a networking app like insta with flutter.所以我正在尝试使用 flutter 构建一个像 insta 这样的网络应用程序。 So when i try to delete the a post from my timeline it does get deleted but because the data is already at the client i am gettting a docsnapshot error.因此,当我尝试从我的时间线中删除帖子时,它确实会被删除,但因为数据已经在客户端,所以我遇到了 docsnapshot 错误。 But to rebuild my screen my buildTimeLine function is in the timeline page and the post is in a widget and i am unable to call the buildtimeline from there.但是要重建我的屏幕,我的 buildTimeLine function 位于时间线页面中,而帖子位于小部件中,我无法从那里调用 buildtimeline。 Any help please.请提供任何帮助。 Stuck on this for the last 3 days.在过去的 3 天里一直坚持这一点。
My Timeline page:我的时间轴页面:
class Timeline extends StatefulWidget {
final User currentUser;
Timeline({this.currentUser});
@override
_TimelineState createState() => _TimelineState();
}
class _TimelineState extends State<Timeline> {
List<Post> posts;
List<String> followingList = [];
@override
void initState() {
super.initState();
getTimeline();
getFollowing();
}
getTimeline() async {
QuerySnapshot snapshot = await timelineRef
.doc(widget.currentUser.id)
.collection('timelinePosts')
.orderBy('timestamp', descending: true)
.get();
List<Post> posts =
snapshot.docs.map((doc) => Post.fromDocument(doc)).toList();
setState(() {
this.posts = posts;
});
}
buildTimeline() {
if (posts == null) {
return MyIconSpinner();
} else if (posts.isEmpty) {
return buildUsersToFollow();
} else {
return ListView(children: posts);
}
}
getFollowing() async {
QuerySnapshot snapshot = await followingRef
.doc(currentUser.id)
.collection('userFollowing')
.get();
setState(() {
followingList = snapshot.docs.map((doc) => doc.id).toList();
});
}
buildUsersToFollow() {
return StreamBuilder(
stream:
usersRef.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return MyIconSpinner();
}
List<UserResult> userResults = [];
snapshot.data.documents.forEach((doc) {
User user = User.fromDocument(doc);
final bool isAuthUser = currentUser.id == user.id;
final bool isFollowingUser = followingList.contains(user.id);
// remove auth user from recommended list
if (isAuthUser) {
return;
} else if (isFollowingUser) {
return;
} else {
UserResult userResult = UserResult(user);
userResults.add(userResult);
}
});
return Container(
color: Theme.of(context).accentColor.withOpacity(0.2),
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.person_add,
color: Theme.of(context).primaryColor,
size: 30.0,
),
SizedBox(
width: 8.0,
),
Text(
"Users to Follow",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 30.0,
),
),
],
),
),
Column(children: userResults),
],
),
);
},
);
}
talkToAExpert() {
return Container(
padding: EdgeInsets.only(top: 20, bottom: 5),
child: FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Experts(currentUser: widget.currentUser)));
},
child: Container(
width: 250.0,
height: 50.0,
child: Text(
'Talk to a Expert',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.normal,
fontSize: 20,
),
),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.blue,
// border: Border.all(
// color: Colors.grey,
// ),
borderRadius: BorderRadius.circular(50.0),
),
),
),
);
}
@override
Widget build(context) {
return Scaffold(
appBar: header(context, isAppTitle: true),
//floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
body:
ListView(
children: [
talkToAExpert(),
Divider(
height: 1.0,
),
Container(
height: MediaQuery.of(context).size.height * 0.7,
child: RefreshIndicator(
onRefresh: () => getTimeline(), child: buildTimeline()),
),
],
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Upload(currentUser: widget.currentUser)));
},
),
);
}
}
My posts page:我的帖子页面:
import 'dart:async';
import 'package:animator/animator.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:momma_app/pages/social/activity_feed.dart';
import '../../models/user.dart';
import '../social/progress.dart';
import '../../pages/social/comments.dart';
import '../../pages/home.dart';
import '../../pages/social/timeline.dart';
class Post extends StatefulWidget {
final String postId;
final String ownerId;
final String username;
final String location;
final String description;
final String mediaUrl;
final dynamic likes;
final Function buildTimeline;
Post({
this.postId,
this.ownerId,
this.username,
this.location,
this.description,
this.mediaUrl,
this.likes,
this.buildTimeline,
});
factory Post.fromDocument(DocumentSnapshot doc) {
return Post(
postId: doc['postId'],
ownerId: doc['ownerId'],
username: doc['username'],
location: doc['location'],
description: doc['description'],
mediaUrl: doc['mediaUrl'],
likes: doc['likes'],
);
}
int getLikeCount(likes) {
// if no likes, return 0
if (likes == null) {
return 0;
}
int count = 0;
// if the key is explicitly set to true, add a like
likes.values.forEach((val) {
if (val == true) {
count += 1;
}
});
return count;
}
@override
_PostState createState() => _PostState(
postId: this.postId,
ownerId: this.ownerId,
username: this.username,
location: this.location,
description: this.description,
mediaUrl: this.mediaUrl,
likes: this.likes,
likeCount: getLikeCount(this.likes),
);
}
class _PostState extends State<Post> {
final String currentUserId = currentUser?.id;
final String postId;
final String ownerId;
final String username;
final String location;
final String description;
final String mediaUrl;
bool showHeart = false;
bool isLiked;
int likeCount;
Map likes;
_PostState({
this.postId,
this.ownerId,
this.username,
this.location,
this.description,
this.mediaUrl,
this.likes,
this.likeCount,
});
buildPostHeader() {
return FutureBuilder(
future: userRef.doc(ownerId).get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
User user = User.fromDocument(snapshot.data);
bool isPostOwner = currentUserId == ownerId;
return ListTile(
leading: CircleAvatar(
backgroundImage: user.userPhotoUrl == ''
? CachedNetworkImageProvider(user.photoUrl)
: CachedNetworkImageProvider(user.userPhotoUrl),
backgroundColor: Colors.grey,
),
title: GestureDetector(
onTap: () => showProfile(context, profileId: user.id),
child: Text(
user.username,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
subtitle: Text(location),
trailing: isPostOwner
? IconButton(
onPressed: () => handleDeletePost(context),
icon: Icon(Icons.more_vert),
)
: Text(''),
);
},
);
}
handleDeletePost(BuildContext parentContext) {
return showDialog(
context: parentContext,
builder: (context) {
return SimpleDialog(
title: Text("Remove this post?"),
children: <Widget>[
SimpleDialogOption(
onPressed: () {
Navigator.pop(context);
deletePost();
},
child: Text(
'Delete',
style: TextStyle(color: Colors.red),
)),
SimpleDialogOption(
onPressed: () => Navigator.pop(context),
child: Text('Cancel')),
],
);
});
}
// Note: To delete post, ownerId and currentUserId must be equal, so they can be used interchangeably
deletePost() async {
print('deletePost begining');
// delete post itself
postsRef.doc(ownerId).collection('userPosts').doc(postId).get().then((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
// delete uploaded image for thep ost
storageRef.child("post_$postId.jpg").delete();
// then delete all activity feed notifications
QuerySnapshot activityFeedSnapshot = await activityFeedRef
.doc(ownerId)
.collection("feedItems")
.where('postId', isEqualTo: postId)
.get();
activityFeedSnapshot.docs.forEach((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
// then delete all comments
QuerySnapshot commentsSnapshot =
await commentsRef.doc(postId).collection('comments').get();
commentsSnapshot.docs.forEach(
(doc) {
if (doc.exists) {
doc.reference.delete();
}
},
);
print('deletePost ending');
}
handleLikePost() {
bool _isLiked = likes[currentUserId] == true;
if (_isLiked) {
postsRef
.doc(ownerId)
.collection('userPosts')
.doc(postId)
.update({'likes.$currentUserId': false});
removeLikeFromActivityFeed();
setState(() {
likeCount -= 1;
isLiked = false;
likes[currentUserId] = false;
});
} else if (!_isLiked) {
postsRef
.doc(ownerId)
.collection('userPosts')
.doc(postId)
.update({'likes.$currentUserId': true});
addLikeToActivityFeed();
setState(() {
likeCount += 1;
isLiked = true;
likes[currentUserId] = true;
showHeart = true;
});
Timer(Duration(milliseconds: 500), () {
setState(() {
showHeart = false;
});
});
}
}
addLikeToActivityFeed() {
// add a notification to the postOwner's activity feed only if comment made by OTHER user (to avoid getting notification for our own like)
bool isNotPostOwner = currentUserId != ownerId;
if (isNotPostOwner) {
activityFeedRef.doc(ownerId).collection("feedItems").doc(postId).set({
"type": "like",
"commentData": '',
"username": currentUser.username,
"userId": currentUser.id,
"userProfileImg": currentUser.photoUrl,
"postId": postId,
"mediaUrl": mediaUrl,
"timestamp": timestamp,
});
}
}
removeLikeFromActivityFeed() {
bool isNotPostOwner = currentUserId != ownerId;
if (isNotPostOwner) {
activityFeedRef
.doc(ownerId)
.collection("feedItems")
.doc(postId)
.get()
.then((doc) {
if (doc.exists) {
doc.reference.delete();
}
});
}
}
buildPostImage() {
return GestureDetector(
onDoubleTap: handleLikePost,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.3,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: CachedNetworkImageProvider(mediaUrl),
),
),
),
// cachedNetworkImage(mediaUrl),
showHeart
? Animator(
duration: Duration(milliseconds: 300),
tween: Tween(begin: 0.8, end: 1.4),
curve: Curves.elasticOut,
cycles: 0,
builder: (context, animatorState, child) => Transform.scale(
scale: animatorState.value,
child: Icon(
Icons.favorite,
size: 80.0,
color: Colors.red,
),
),
)
: Text(""),
],
),
);
}
buildPostFooter() {
return StreamBuilder(
stream: commentsRef
.doc(postId)
.collection('comments')
.doc('counter')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
{
int counterValue = snapshot.data['counter'] - 1;
return Column(
children: <Widget>[
if (mediaUrl != 'No mediaUrl')
SizedBox(
height: 10,
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 20.0),
child: Text(
"$username ",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
Expanded(child: Text(description))
],
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 40.0, left: 20.0)),
GestureDetector(
onTap: handleLikePost,
child: Icon(
isLiked ? Icons.favorite : Icons.favorite_border,
size: 25.0,
color: Colors.pink,
),
),
Padding(padding: EdgeInsets.only(right: 25.0)),
GestureDetector(
onTap: () => showComments(
context,
postId: postId,
ownerId: ownerId,
mediaUrl: mediaUrl,
),
child: Icon(
Icons.chat,
size: 25.0,
color: Colors.blue[900],
),
),
],
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 20.0),
child: Text(
"$likeCount likes",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
Container(
margin: EdgeInsets.only(left: 10.0),
child: Text(
"$counterValue comment",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
],
),
],
);
}
});
}
@override
Widget build(BuildContext context) {
isLiked = (likes[currentUserId] == true);
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
buildPostHeader(),
if (mediaUrl != 'No mediaUrl') buildPostImage(),
buildPostFooter()
],
);
}
}
showComments(BuildContext context,
{String postId, String ownerId, String mediaUrl}) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return Comments(
postId: postId,
postOwnerId: ownerId,
postMediaUrl: mediaUrl,
);
}));
}
Please have a look at the deletePost method in the posts page and getTimeline() and buildTimeline() in the timeline page.请查看帖子页面中的 deletePost 方法以及时间线页面中的 getTimeline() 和 buildTimeline()。
You can extract your buildTimeline()
method to put it in service so snapshot
, posts
and followingList
will be Global variables您可以提取您的buildTimeline()
方法以将其投入使用,因此snapshot
、 posts
和followingList
将是全局变量
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.