Reputation: 527
I have a Provider
which changes my UI
if the value isLiked
is true
or false
. The function works fine but I noticed that every time I restart the app the UI
returns to its original state. How can I save its state so it doesn't restart when I kill the app?
here is my class:
class Selfie extends ChangeNotifier {
Selfie.fromDocument(DocumentSnapshot doc) {
selfieId = doc['selfieId'] as String;
ownerId = doc['ownerId'] as String;
displayName = doc['displayName'] as String;
photoUrl = doc['photoUrl'] as String;
mediaUrl = doc['mediaUrl'] as String;
timestamp = doc['timestamp'] as Timestamp;
likes = doc['likes'] as Map;
likesCount = doc['likesCount'] as int;
}
String selfieId;
String ownerId;
String displayName;
String photoUrl;
String mediaUrl;
Timestamp timestamp;
Map likes;
int likesCount;
bool _isLiked = false;
bool get isLiked => _isLiked;
set isLiked(bool value) {
_isLiked = value;
notifyListeners();
}
bool _showHeart = false;
bool get showHeart => _showHeart;
set showHeart(bool value) {
_showHeart = value;
notifyListeners();
}
void handleLikePost(String userId, AuthUser authUser) {
bool _isLiked = likes[userId] == true;
if (_isLiked) {
selfiesRef.doc(selfieId).update({
'likes.$userId': false,
'likesCount': FieldValue.increment(-1),
});
//removeLikeFromActivityFeed();
//likeCount -= 1;
isLiked = false;
likes[userId] = false;
selfiesRef.doc(selfieId).collection('likes').doc(userId).delete();
} else if (!_isLiked) {
selfiesRef.doc(selfieId).update({
'likes.$userId': true,
'likesCount': FieldValue.increment(1),
});
selfiesRef.doc(selfieId).collection('likes').doc(userId).set({
'displayName': authUser.displayName,
'userId': userId,
'photoUrl': authUser.photoUrl
});
//addLikeToActivityFed();
//likeCount += 1;
isLiked = true;
likes[userId] = true;
showHeart = true;
Timer(Duration(milliseconds: 500), () {
showHeart = false;
});
}
notifyListeners();
}
}
here is my UI
:
class SelfieCard extends StatelessWidget {
final Selfie selfie;
final String userId;
SelfieCard({this.selfie, this.userId});
@override
Widget build(BuildContext context) {
final AuthUser authUser =
Provider.of<UserManager>(context, listen: false).authUser;
return ChangeNotifierProvider.value(
value: selfie,
child: Consumer<Selfie>(
builder: (_, selfie, __) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
clipBehavior: Clip.antiAliasWithSaveLayer,
elevation: 7,
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Consumer<UserManager>(
builder: (_, userManager, __) {
bool isPostOwner = userManager.isLoggedIn
? userManager.authUser.id == selfie.ownerId
: null;
return Padding(
padding: const EdgeInsets.only(top: 0.0, bottom: 0),
child: GestureDetector(
onTap: () {},
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.grey,
backgroundImage: NetworkImage(selfie.photoUrl),
),
title: Text(
selfie.displayName,
style: TextStyle(
fontFamily: 'BebasNeue',
fontSize: 19,
color: Colors.black,
),
),
trailing: userManager.isLoggedIn && isPostOwner
? IconButton(
onPressed: () {},
icon: Icon(Icons.more_vert),
)
: Text('')),
),
);
},
),
GestureDetector(
onDoubleTap: () {},
child: Stack(
alignment: Alignment.center,
children: <Widget>[
cachedNetworkImage(selfie.mediaUrl),
selfie.showHeart
? Animator(
duration: Duration(milliseconds: 500),
tween: Tween(begin: 0.8, end: 1.4),
cycles: 0,
curve: Curves.bounceOut,
builder: (context, animatorState, chil) =>
Transform.scale(
scale: animatorState.value,
child: Icon(
Icons.favorite,
color: Colors.red,
size: 80,
),
),
)
: Text('')
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: Text(
timeago.format(selfie.timestamp.toDate(),
locale: 'en_short'),
style:
TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(
child: Container(),
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LikesScreen(
postId: selfie.selfieId)));
},
child: Container(
margin: EdgeInsets.only(right: 10),
child: Text(
selfie.likesCount.toString(),
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold),
),
),
),
Padding(
padding: EdgeInsets.only(
top: 40,
),
),
GestureDetector(
onTap: () {
selfie.handleLikePost(userId, authUser);
},
child: Icon(
selfie.isLiked
? Icons.favorite
: Icons.favorite_border,
color: Colors.red,
size: 25,
),
),
Padding(
padding: EdgeInsets.only(top: 40, right: 10),
),
SizedBox(
width: 20,
)
],
),
],
)),
],
),
)
],
),
);
},
));
}
}
I know I should have it on initState
but I also know that initState
can't access the context
. Do you guys have any idea how I can solve it?
Upvotes: 0
Views: 2027
Reputation: 600
you can use it the same way you've done in the build method... the only thing is you must set listen to false
final provider = Provider.of<T>(context, listen: false);
here T
is the type of State you're expecting
check this for further explanation
Upvotes: 0
Reputation: 1037
The problem is that your isLiked
variable will initially be false always. After the user likes the image, it is being stored but you're only storing it locally and temporarily.
In order to keep it consistent, you can store it permanently either locally or in your Firestore. If you want to store it locally, you can store it using "Shared Preferences", "SQfLite", "Hive", etc. However, it won't be efficient as if the user deletes the app or clears data, all of the data might get lost.
Upvotes: 0