I'm using Flutter's Image Picker
plugin in order to allow the user to change their avatar. When they go to their account page they see their regular avatar photo with a camera icon on top. Clicking the camera icon will allow them to either take a photo from their camera or choose a new avatar from their gallery. After choosing the new one, the avatar photo automatically updates. However, when navigating away from their account page, the old avatar is visible throughout the rest of the app. I'm using Provider
with a Change Notifier
and Consumers
for Avatars everywhere else. The problem though is that I can only access the Provider
within a build so I don't know where I can call the Provider
in my code. Add to this the fact that the Avatar I'm using all around the app comes from an internet url. After choosing with Image Picker, the new avatar photo gets uploaded to a server. The name of the new photo replaces the name of the old photo. Hence my app doesn't even know anything changed. Even reloading the pages doesn't work. However if I hot restart my app, the new avatar photo appears. Any ideas what I can do?
Here's the Image Picker code;
class Picker extends StatefulWidget {
Picker({Key key, this.title}) : super(key: key);
final String title;
@override
_PickerState createState() => _PickerState();
}
class _PickerState extends State<Picker>
with TickerProviderStateMixin,ImagePickerListener{
File _image;
AnimationController _controller;
ImagePickerHandler imagePicker;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
imagePicker= ImagePickerHandler(this,_controller);
imagePicker.init();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
var socialProvider = Provider.of<SocialProvider>(context);
return Container(
child: GestureDetector(
onTap: () => imagePicker.showDialog(context),
child: Center(
child: Stack(
children: <Widget>[
Center(
child: _image == null?
Consumer<SocialProvider>(
builder: (context, socialProvider, child) {
return
Image.network(socialProvider.currentavatar,
width: 200,
height: 200,
);
}) :
Container(
height: 200.0,
width: 200.0,
decoration: BoxDecoration(
color: Colors.grey,
image: DecorationImage(
image: FileImage(_image),
fit: BoxFit.cover,
),
),
),
),
Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Container(
color: Colors.black26,
child: Icon(Icons.camera_alt,
color: Colors.white,
size: 40,
),
),
),
),
,
)
),
),
);
}
@override
userImage(File _image) async{
setState(() {
this._image = _image;
});
}
}
Currently the Consumers
are correctly updating the avatars throughout the app whenever a user obtains a new avatar through logging in via social media. The new avatar is uploaded to the server and the ChangeNotifier
is informed. The code for the Provider
here is ;
Future<void> postSocialData(String avatar) async {
final url = "http://example.com/example.php¤tavatar=" + $avatar;
final response = await http.get(url);
if (response.statusCode == 200) {
currentavatar = "http://example.com/user.jpg";
var box = await Hive.openBox('currentuser');
box.put('currentavatar', "http://example.com/user.jpg",);
notifyListeners();
}
}
So I tried putting this into my Provider
and calling it from an onTap function in the Image Picker build. Here's the onTap function;
GestureDetector(
onTap: () async {
String avatar = await _listener.openGallery(socialProvider.currentuserid);
String updatedavatar = "http://example.com/" + avatar;
socialProvider.updateAvatar(updatedavatar);
},
child: roundedButton(
"Gallery",
EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
const Color(0xFF167F67),
const Color(0xFFFFFFFF)),
),
And here's the Provider
it calls;
Future<void> updateAvatar(String avatar) async {
var box = await Hive.openBox('currentuser');
box.put('currentavatar', avatar);
currentavatar = avatar;
notifyListeners();
}
But that didn't update the consumers with the new avatar. I guess because the external url for the avatar hasn't changed as the photo has simply been replaced and keeps the same name.
Using Hive's listener was a good idea. But it didn't help because it turns out the uploaded image - having the same URL as the replaced image - isn't being refreshed on the server-side. So the caching must be sorted out on the web server.