I have a 64 base image that am getting from my database , which I want to store locally and reuse offline. am using local storage package , the image works perfectly fine when I call it online but fades away offline . here is where am storing it :
String baseUrl = await GetSharedPrefs.getBaseURl();
_imageLogoPath =
(await SettingsServices().fetchLogoImage(baseUrl: baseUrl, id: 1));
storage.setItem('logoImage', _imageLogoPath);
notifyListeners();
and this is where am calling it :
class _LogoViewState extends State<Logo> {
void initState() {
Provider.of<SettingsViewModel>(context, listen: false).fetchLogoPath();
super.initState();
}
#override
Widget build(BuildContext context) {
final LocalStorage storage = new LocalStorage('deepnrise');
var settings = Provider.of<SettingsViewModel>(context);
String? image = settings.imagepath;
int i = 1;
String im = storage.getItem('logoImage');
if (im!.isNotEmpty) {
i +=1;
print("soy image $im");
final UriData? data = Uri.parse(im).data;
print(image);
Uint8List? myImage = data?.contentAsBytes();
return Padding(
padding: EdgeInsets.all(10.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image.memory(
myImage!,
fit: BoxFit.contain,
width: 50,
)),
);
} else if (im.isEmpty || im == null) {
return Padding(
padding: EdgeInsets.all(16.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image.asset(
"assets/images/deepn.png",
fit: BoxFit.contain,
width: 35,
)),
);
}
return Padding(
padding: EdgeInsets.all(16.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image.asset(
"assets/images/deepn.png",
fit: BoxFit.contain,
width: 35,
)),
);
}
}
every time I get a null exception (null is not subtype of type string) , so I tried to call my provider in another widget , which resulted in the image fading away when offline . I want to be able to call the image from local storage , when off/ online . I have tried shared preferences package and the same thing happens if anyone please know how to help don't hesitate thanks in advance.
Related
I made a social media application using Flutter Firebase, and like every social media application, I have a stream of posts shared by users on the home screen. At first, I didn't have any problems, but as the number of data increased, I started to have problems especially getting photos. Later I found out that this was because I was getting all the data at once and decided to use Pagination. I have successfully used Pagination and I also started using Cached Network Image to load my photos faster. But I still have such a problem in the flow. When I scroll the screen to the bottom, the data is loaded at the limit I set, in the example my limit is 12, so I have no problem when scrolling down the screen, but when I want to quickly scroll the screen up, it tries to load all the data again, the system is having too much difficulty, I can't load it at the end and the application gives a lost connection error and closes itself.
In my opinion, the same thing should happen when we swipe the screen up, just as the data is loaded piece by piece as much as the limit number we set when swiping down the screen.
Otherwise, this problem that I am experiencing occurs.
Do you know any solution for this?
This is my code for Pagination;
getData() async {
var Ref1 = (widget.post != null)
? _firestore
.collection("users")
.doc(widget.post["profileID"])
.collection("Datas")
.orderBy("uploadTime", descending: true)
.limit(perpage)
: null;
setState(() {
loadingProducts = true;
});
var reponse = await Ref1.get();
listt = reponse.docs;
lastDocument = reponse.docs[reponse.docs.length - 1];
setState(() {
loadingProducts = false;
});
}
getmoreData() async {
if (moreDataAvailable == false) {
return;
}
if (gettingmoreData == true) {
return;
}
setState(() {
gettingmoreData = true;
});
var Ref1 = (widget.post != null)
? _firestore
.collection("users")
.doc(widget.post["profileID"])
.collection("Datas")
.orderBy("uploadTime", descending: true)
.startAfterDocument(lastDocument)
.limit(perpage)
: null;
var reponse = await Ref1.get();
if (reponse.docs.length < perpage) {
moreDataAvailable = false;
}
lastDocument = reponse.docs[reponse.docs.length - 1];
listt.addAll(reponse.docs);
setState(() {});
setState(() {
gettingmoreData = false;
});
}
And this is my Builder;
GridView.builder(
controller: scrollController,
physics: ScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemCount: listt.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () =>
navigateToDetail(listt[index]),
child: Hero(
tag: (listt[index]["foto"] != null)
? NetworkImage(
listt[index]["foto"])
: AssetImage(
"assets/images/n_image.jpg"),
child: Container(
child: Column(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Container(
height: size.height * 0.078,
width: double.infinity,
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(
bottomRight:
Radius.circular(
10.0),
bottomLeft:
Radius.circular(
10.0),
),
color: Colors.grey[600]
.withOpacity(0.5)),
child: Center(
child: AutoSizeText(
"${listt[index]["name"]}",
textAlign:
TextAlign.center,
style: GoogleFonts.lora(
textStyle: TextStyle(
color: Colors.white,
fontSize: 15,
),
),
maxLines: 2,
),
),
),
],
),
margin: EdgeInsets.all(5.0),
decoration: BoxDecoration(
image: DecorationImage(
image: (listt[index]
["foto"] !=
null)
? OptimizedCacheImageProvider(
listt[index]["foto"])
: AssetImage(
"assets/images/n_image.jpg"),
fit: BoxFit.cover,
),
color: Colors.white,
borderRadius:
BorderRadius.circular(10.0),
),
),
),
);
},
),
And im listening controller in initstate with this;
scrollController.addListener(() {
double maxScroll = scrollController.position.maxScrollExtent;
double currentScroll = scrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.25;
if (maxScroll - currentScroll <= delta) {
getmoreTarif();
}
});
Your current code tracks the last document of the current results and then calls startAfterDocument with that document to get the next set of results. This works for scrolling forward, but not when scrolling backward. To paginate backwards, you'll also need to track the first document of the current results and then call endBeforeDocument with that document.
I am using image picker to get image from user then displayed in "CreateCard" UI.
The issue occur when i try using condition in my UI file, i need the condition so i can check if the file image is null before i can display it.
I am working with flutter GetX..
"CreateCard "UI Code:
GetBuilder<CreateCardContollerImp>(builder: (controller) =>UploadImage(
ontap: () {
showModalBottomSheet(
context: context,
builder: (context) {
return CreateCardBottomSheet(
uploadImageGallery: () {
controller.uploadImageGallery();
});
});
},
image: controller.image == null // Error occur here !
? AssetImage(AppImageAsset.profileimage)
: FileImage(controller.image),
),),
"UploadImage" Deifiniton:
class UploadImage extends StatelessWidget {
final void Function() ontap;
final ImageProvider<Object> image;
const UploadImage({super.key, required this.ontap, required this.image});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: ontap,
child: Stack(children: [
Container(
width: 170,
height: 170,
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
offset: Offset(0, 0),
color: AppColor.primaryColor,
blurRadius: 0,
),
],
borderRadius: BorderRadius.circular(100),
),
padding: const EdgeInsets.symmetric(vertical: 5),
child: CircleAvatar(
backgroundImage: image,
radius: MediaQuery.of(context).size.width - 310,
),
),
]),
);
}
}
"CreateCard" Controller:
class CreateCardContollerImp extends CreateCardContoller {
GlobalKey<FormState> formstate = GlobalKey<FormState>();
final imagepicker = ImagePicker();
late String imagePath;
late File image;
#override
uploadImageGallery() async {
final pickedimage = await imagepicker.getImage(source: ImageSource.gallery);
if (pickedimage != null) {
image = File(pickedimage.path);
imagePath = pickedimage.path;
update();
} else {
printError(info: "No image selected");
}
}
I was expecting this method will work fine.
you're logic looks fine, try casting the as ImageProvider:
controller.image == null
? AssetImage(AppImageAsset.profileimage) as ImageProvider
: FileImage(controller.image) as ImageProvider,
Another alternative is to try just using ImageProvider directly without unnecessary casting.
controller.image == null
? AssetImage(AppImageAsset.profileimage)
: NetworkImage(controller.image),
TheAssetImage is used in getting the avatar profile image from the app's asset.
The NetworkImage is used in getting the avatar profile image from the online DB or API.
I am working on uploading the uint8List type image to Firestore and get it again.
I have converted to String to upload to Firestore.
Future _pageDrawScreen() async {
// screenshot pakage
Uint8List? _previewImage = await _testController.capture(); // get uint8List image data
if (_previewImage == null) {
logger.d("_previewImage null");
}
// convert to String
_pageModel!.previewImage = _previewImage.toString();
// Firestore update
}
Then, I take the image data again, convert it, and output it as a memory image.
Widget _pageContainer(int index, PageModel pageModel) {
// get image and convert
Uint8List? previewImage;
if (pageModel.previewImage != null) {
List<int> list = pageModel.previewImage!.codeUnits;
previewImage = Uint8List.fromList(list);
// logger.d(previewImage);
}
return ListTile(
title: pageModel.previewImage != null
? ExtendedImage.memory(
previewImage!,// error!
width: 125,
height: 125,
fit: BoxFit.cover,
// check image state
loadStateChanged: (state) {
switch (state.extendedImageLoadState) {
case LoadState.loading:
return const SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(
color: Colors.red,
),
);
case LoadState.completed:
return null;
// Failed error!!
case LoadState.failed:
return const Material(
color: Colors.white,
child: Icon(
Icons.cancel,
color: Colors.red,
size: 50,
),
);
}
},
)
: Container(
width: 125,
height: 125,
color: Colors.white,
child: const Center(
child: CircularProgressIndicator(),
),
),
);
}
However, this image is checked as an error state. Is the conversion of Uint8List wrong?
Expected Results (When using the uint8list image as it is,
):
Actual Results:
import
import 'dart:convert';
for uploading
Uint8List? _previewImage = await _testController.capture();
if(_previewImage != null){
String previewImage = base64.encode(_previewImage);
}
after fetching the image data
Uint8List previewImage = base64.decode(previewImage);
I need to display gif in my Flutter application. From the backend I get the gif as an Uint8List list from the response. Can you help me please how can I display this in the screen?
My code is here:
widget.session
.get('/api/caff/getCaff/' + widget.gifId.toString())
.then((response) async {
if (response.statusCode == 200) {
Uint8List bytes = response.bodyBytes;
_gifFile = File.fromRawPath(bytes); // tried this but didn't work
} else {
CaffToast.showError(
'Something went wrong! Please check your network connection!');
}
});
And I tried to display it as a file image but it didnt work:
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
_gifFile == null ? Container() : Container(
decoration: BoxDecoration(
image: DecorationImage(
image: FileImage(_gifFile!))),
),
],
),
);
}
Do you have any suggestions how can I solve this problem?
There's no need to write your data to a file. The image data is already in memory so just display it. Just use a MemoryImage image provider instead
I'm not sure how you're getting the data from your network call to your build method so I'm using placeholders, but just do it the same was that you did when you were using a file.
_bytes = response.bodyBytes;
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
_gifFile == null ? Container() : Container(
decoration: BoxDecoration(
image: DecorationImage(
image: MemoryImage(_bytes!))),
),
],
),
);
}
I'm having an issue with my app, I'm creating a flutter app to track cryptocurrency prices.
The issue is that I get the data properly from the API, then I print it into the counsel but when I try to display it inside the app, it displays null.
Here is the code I use to get the data from the API
class CurrencyData { var decodedData;
Future getCoinsData() async {
http.Response response =
await http.get(coinUrl);
if (response.statusCode == 200) {
decodedData = jsonDecode(response.body);
} else {
print(response.statusCode);
throw 'Problem with the request, try again later!';
}
return decodedData;
}
}
Here is the code where I call the data to display it.
class _DashboardPageState extends State<DashboardPage> {
CurrencyData currencyData = CurrencyData();
var btcPrice;
var btcChange24h;
void cryptoCurrencyData() async {
var data = await currencyData.getCoinsData();
print(btcPrice = data['data'][0]['priceUsd']);
print(btcChange24h = data['data'][0]['changePercent24Hr']);
}
#override
void initState() {
super.initState();
cryptoCurrencyData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
// the top bar
Container(
padding: EdgeInsets.all(40),
constraints: BoxConstraints.expand(height: 175),
decoration: BoxDecoration(
color: Colors.lightBlue,
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 20.0,
// has the effect of softening the shadow
spreadRadius:
5.0, // has the effect of extending the shadow
),
],
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
),
child: Container(
padding: EdgeInsets.only(top: 25),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Text(
'Crypto Tracker',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 30.0,
fontWeight: FontWeight.bold,
),
),
)
],
),
),
),
// the body part
CurrencyWidget(
currencyIconUrl: 'assets/images/btc.png',
currencyName: 'Bitcoin',
currencyShortName: 'BTC',
currencyPrice: btcPrice,
currencyChange24h: btcChange24h,
),
I get the data printed into the console but I also get Null displayed in the emulator as shown in the below screenshot.
The image where null is displayed
A screenshot of the data being printed in the console
Any idea what the issue may be?
The problem is that getting api data is async task so it takes time, while build method build screen in that time, so it is printing null.
1) You can call setState at the end of function which change null to actual data when it gets from API.
void cryptoCurrencyData() async {
var data = await currencyData.getCoinsData();
btcPrice = data['data'][0]['priceUsd']; // assign
btcChange24h = data['data'][0]['changePercent24Hr']; // aasign
print(btcPrice = data['data'][0]['priceUsd']);
print(btcChange24h = data['data'][0]['changePercent24Hr']);
setState(() {}); // added
}
2) However, FutureBuilder is more better option where you can show loading indicator or something which shows data is loading and display when arrives.
Note: in this way you don't need cryptoCurrencyData method and also you don't need to store value in different variable.
FutureBuilder(
future: currencyData.getCoinsData(),
builder: (_, sanpshot) {
if (!sanpshot.hasData) {
return CircularProgressIndicator();
}
return CurrencyWidget(
currencyIconUrl: 'assets/images/btc.png',
currencyName: 'Bitcoin',
currencyShortName: 'BTC',
currencyPrice: data['data'][0]['priceUsd'],
currencyChange24h: data['data'][0]['changePercent24Hr'],
);
},
),