Convert the image get in to :
final prefs = await SharedPreferences.getInstance();
var image = ((prefs.getString('photo')));
var send = {'name': usu, 'email': email, 'image': photo};
In widget:
Widget _buildDrawer(BuildContext context) { return FutureBuilder<Map>(
future: getFutureDates(), // function where you call your api
builder: (BuildContext context, AsyncSnapshot<Map> snapshot) {
if(!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
Uint8List profile = base64.decode(snapshot.data['image']); new UserAccountsDrawerHeader(
accountName: new Text((json.encode(snapshot.data['name']).toString().replaceAll('"', ''))),
accountEmail: new Text((json.encode(snapshot.data['email']).toString().replaceAll('"', ''))),
currentAccountPicture: new CircleAvatar(
backgroundImage: MemoryImage((profile)),
),
), } }
The Name and email is ok, but Photo give me a error:
Invalid character (at charact
er 5)
data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBw8PDw8PDxAPDw4PD...
Reason:
base64 string contains data:image/png;base64, cause error
data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBw8PDw8PDxAPDw4PD
Solution:
remove string data:image/png;base64, , you can use substring(22) and only keep
/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBw8PDw8PDxAPDw4PD...
code snippet
void main() {
String base64str = '''data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBw8PDw8PDxAPDw4PD''';
String newString = base64str.substring(22);
print(newString);
}
output
/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBw8PDw8PDxAPDw4PD
Related
I have to fetch ta video URL store in FireStore before displaying the video itself.
I used a FutureBuilderin my build to do so:
if (ad.videoUrl != null)
FutureBuilder(
future: Video.videoUrl("blabla"), //ad.videoUrl!),
builder: (context, snapshot) {
if (snapshot.hasData) {
final url = snapshot.data;
return Text(url ?? "No video found");
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
Text("Searching the video on the cloud"),
CircularProgressIndicator()
]);
}
}),
The future itself is straightforward:
/// Fetches the video url from the video [name]
static Future<String?> videoUrl(String name) {
final videoBucket =
FirebaseStorage.instanceFor(bucket: Globals.storageBucketUrl);
final videoBucketRef = videoBucket.ref();
final item = videoBucketRef.child(name);
return item.getDownloadURL();
}
And like this, I've got what I want. Perfect.
But now, I want to handle the exception within the future so that it returns null when any occur.
I've updated my code as follows:
/// Fetches the video url from the video [name]
static Future<String?> videoUrl(String name) async {
final videoBucket =
FirebaseStorage.instanceFor(bucket: Globals.storageBucketUrl);
final videoBucketRef = videoBucket.ref();
try {
final item = videoBucketRef.child(name);
return await item.getDownloadURL();
} catch (e) {
return null;
}
Though the exception is caught as expected (when I fetch a video name that does not exist), it looks like the future never returns a value (neither null or the URL when it exists.
Therefore what's wrong in my code?
Note: Btw, I have also tried this without success when the exception occurs, though it is ok for an existing video name.
/// Fetches the video url from the video [name]
static Future<String?> videoUrl(String name) async {
final videoBucket =
FirebaseStorage.instanceFor(bucket: Globals.storageBucketUrl);
final videoBucketRef = videoBucket.ref();
try {
final item = videoBucketRef.child(name);
final url = await item.getDownloadURL();
return Future<String?>.value(name);
} catch (e) {
return Future<String?>.value(null);
}
instead of returning null, you can throw an exception like this:
catch (e) {
throw Exception("some error here");
}
inside the FutureBuilder you can use the hasError to show some widget based on it:
FutureBuilder(
future: Video.videoUrl("blabla"), //ad.videoUrl!),
builder: (context, snapshot) {
if (snapshot.hasData) {
final url = snapshot.data;
return Text(url ?? "No video found");
} else if(snapshot.hasError) {
return Text("error ${snapshot.error}");
} else{
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
Text("Searching the video on the cloud"),
CircularProgressIndicator()
]);
}
}),
I have this future builder which loads a list of movies in my provider class. Whenever I reload my screen, the movies do not get returned. Below is the future builder
FutureBuilder(
future: movieData.getTrendingMovies(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.hasData) {
return Swiper(
itemBuilder: (BuildContext context, i) {
return ChangeNotifierProvider(
create: (context) => Movie(),
child: MovieContainer(
imageUrl: movieData.movies[i].imageUrl,
id: movieData.movies[i].id,
rate: movieData.movies[i].rate,
title: movieData.movies[i].title,
),
);
},
itemCount: movieData.movies.length,
viewportFraction: 0.25,
scale: 0.4,
);
} else {
return Text(snapshot.error.toString()); // it returns null on the screen
}
}),
Also in my homescreen where I display my movies, after the build method, I create a listener(moviesData) to listen to all changes in the movies provider.
final movieData = Provider.of<Movies>(context, listen: false);
Below is also the methos which fetches the movies from a restfulAPI using http get request
Future<void> getTrendingMovies() async {
List<String> movieTitles = [];
List<String> movieImageUrls = [];
List<String> movieDescriptions = [];
List<String> movieReleaseDates = [];
List<String> movieRates = [];
List<String> movieIds = [];
const _apiKey = '******************************';
const url =
'https://api.themoviedb.org/3/trending/all/week?api_key=$_apiKey';
try {
final response = await http.get(Uri.parse(url));
if (response.statusCode >= 400) {
print(response.statusCode);
return;
}
final extractedData = json.decode(response.body);
List moviesList = extractedData['results'] as List;
List<Movie> loadedMovies = [];
for (int i = 0; i < moviesList.length; i++) {
String movieTitle = moviesList[i]['original_title'] ?? '';
String? movieImage =
'https://image.tmdb.org/t/p/w400${moviesList[i]['poster_path']}'; //results[0].poster_path
String movieDescription =
moviesList[i]['overview'] ?? ''; //results[0].overview
String movieReleaseDate = moviesList[i]['release_date'] ?? '';
String? movieRate = moviesList[i]['vote_average'].toString();
String? movieId = moviesList[i]['id'].toString();
movieTitles.add(movieTitle);
movieImageUrls.add(movieImage);
movieDescriptions.add(movieDescription);
movieReleaseDates.add(movieReleaseDate);
movieRates.add(movieRate);
movieIds.add(movieId);
loadedMovies.add(
Movie(
id: movieIds[i],
title: movieTitles[i],
imageUrl: movieImageUrls[i],
description: movieDescriptions[i],
rate: double.parse(movieRates[i]),
releaseDate: movieReleaseDates[i],
),
);
}
_movies = loadedMovies;
notifyListeners();
//print(_movies.last.title); //This prints the name of the last movie perfectly....This gets called unlimited times whenever I set the listen of the **moviesData** to true
} catch (error) {
print(error);
}
}
There's a couple of things to unpack here.
Instead of a ChangeNotifierProvider, I believe you should use a Consumer widget that listens to your Movies provided service when you call the notifyListeners call, so make it Consumer<Movie>.
You can still call it using the Provider.of above for the sake of making the async call via the FutureBuilder, but I believe because you're not returning anything out of the getTrendingMovies and is just a Future<void> and you're querying the snapshot.hasData, well there is no data coming through the snapshot. Maybe instead you should call snapshot.connectionState == ConnectionState.done as opposed to querying for whether it has data.
Make sure that the response.body is truly returning a JSON value, but I believe your issue is in one of the points above.
I am trying to get the string value of a future, and saving state in flutter. user chooses the endTime and it should display on the UI untill it ends. however, I am getting the following error:
type 'String' is not a subtype of type 'Future<String>' in type cast
the method:
final Future<SharedPreferences> _prefs =
SharedPreferences.getInstance();
Future<String> _textLine = '' as Future<String>;
Future<String> fastTrue() async {
final SharedPreferences prefs = await _prefs;
String formattedDate = DateFormat('yyyy-MM-dd,
hh:mma').format(endTime);
final textLine = (prefs.getString('formattedDate') ??
Languages.of(context)!.setYourFastTime) as Future<String>;
setState(() {
_textLine = prefs.setString('formattedDate',
Languages.of(context)!.endTimeIs
+'\n$formattedDate').then((bool success) {
return textLine;
});
});
return textLine;
}
in initState():
#override
void initState() {
super.initState();
_textLine = _prefs.then((SharedPreferences prefs) {
return prefs.getString('formattedDate') ??
Languages.of(context)!.setEndTime +'\n'+DateFormat('yyyy-MM-dd,
hh:mma').format(DateTime.now());
});
then in my widget build():
Padding(padding: const EdgeInsets.only(top: 170),
child: FutureBuilder<String>(
future: _textLine,
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const CircularProgressIndicator();
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text(
Languages.of(context)!.endTimeIs +
"\n${snapshot.data}"
);
}
}
})),
help me, pls, tried using hive, but was not able to get to save the state of the widget. Thanks!
This code throws the error because you try to cast a String to a Future<String>>, although it is a String.
Future<String> _textLine = '' as Future<String>;
If you want to declare a Future with a value, you can use the value method.
Future<String> _textLine = Future.value('');
Sorry if it's a stupid question I am beginner in Flutter and MongoDB Here is my code to return collection data btw this is the only time I use Mongo_Dart all other operations done using JS on heroku
class Azkar {
getAzkar() async {
var db = await Db.create(
'mongodb+srv://Adham:<password>#cluster0.nm0lg.mongodb.net/<db>retryWrites=true&w=majority');
await db.open();
print('Connected to database');
DbCollection coll = db.collection('zekrs');
return await coll.find().toList();
}
}
It is working and I am able to print returned data from another class it is List<Map<String, dynamic>> I want to know how should I use it to generate ListTile with all data.
This package is not worth it. I solved this issue by moving out this part of code on the backend side (NodeJS) in the cloud and just getting what I need with an HTTP request.
Instead of returning data in List<Map<String, dynamic>>, create a class for your data. Suppose your data gives us a list of users. Then
class User {
User({
this.id,
this.name,
});
int id;
String name;
}
This would be your Azkar class
class Azkar {
getAzkar() async {
final db = await Db.create(
'mongodb+srv://Adham:<password>#cluster0.nm0lg.mongodb.net/<db>retryWrites=true&w=majority');
await db.open();
print('Connected to database');
final coll = db.collection('zekrs');
final zekrsList = await coll.find().toList();
List<User> users = [];
for (var item in zekrsList) {
final user = User(
id: item['id'],
name: item['name'],
);
users.add(user);
}
return users;
}
}
You should do something like this.
FutureBuilder(
future: getAzkar(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.all(8),
child: Column(
children: [
Text("Name = ${snapshot.data[index].name}"),
Text("Id = ${snapshot.data[index].id}"),
],
),
);
});
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
if anyone still have this issue,
I solved it by setting this:
final zekrsList = await coll.find().toList();
to
final zekrsList = await coll.find(where.sortBy('_id')).toList();
I'm trying to display a pdf using this button in my flutter app but I keep getting the error in the title
AppButton.buildAppButton(
context,
AppButtonType.TEXT_OUTLINE,
'Generate PDF',
Dimens.BUTTON_BOTTOM_DIMENS, onPressed: () {
Sheets.showAppHeightEightSheet(
context: context,
widget: work(),
);
})
This is my work widget
Widget work() {
dynamic pdf = generateInvoice(PdfPageFormat.a4);
return pdf;
}
which calls this function. However I keep getting the title error type 'Future' is not a subtype of type 'Widget'. Any help is appreciated. end goal is to view the pdf but I'm not sure how ti get there. Thanks!
Future<Uint8List> generateInvoice(PdfPageFormat pageFormat) async {
final lorem = pw.LoremText();
final products = <Product>[
Product('19874', lorem.sentence(4), 3.99, 2),
Product('98452', lorem.sentence(6), 15, 2),
Product('28375', lorem.sentence(4), 6.95, 3),
Product('95673', lorem.sentence(3), 49.99, 4),
Product('23763', lorem.sentence(2), 560.03, 1),
Product('55209', lorem.sentence(5), 26, 1),
Product('09853', lorem.sentence(5), 26, 1),
];
final invoice = Invoice(
invoiceNumber: '982347',
products: products,
customerName: 'Abraham Swearegin',
customerAddress: '54 rue de Rivoli\n75001 Paris, France',
paymentInfo:
'4509 Wiseman Street\nKnoxville, Tennessee(TN), 37929\n865-372-0425',
tax: .15,
baseColor: PdfColors.teal,
accentColor: PdfColors.blueGrey900,
);
return await invoice.buildPdf(pageFormat);
}
class Invoice {
Invoice({
this.products,
this.customerName,
this.customerAddress,
this.invoiceNumber,
this.tax,
this.paymentInfo,
this.baseColor,
this.accentColor,
});
final List<Product> products;
final String customerName;
final String customerAddress;
final String invoiceNumber;
static const _darkColor = PdfColors.blueGrey800;
static const _lightColor = PdfColors.white;
PdfColor get _baseTextColor =>
baseColor.luminance < 0.5 ? _lightColor : _darkColor;
PdfColor get _accentTextColor =>
baseColor.luminance < 0.5 ? _lightColor : _darkColor;
double get _total =>
products.map<double>((p) => p.total).reduce((a, b) => a + b);
double get _grandTotal => _total * (1 + tax);
PdfImage _logo;
Future<Uint8List> buildPdf(PdfPageFormat pageFormat) async {
// Create a PDF document.
final doc = pw.Document();
final font1 = await rootBundle.load('assets/roboto1.ttf');
final font2 = await rootBundle.load('assets/roboto2.ttf');
final font3 = await rootBundle.load('assets/roboto3.ttf');
_logo = PdfImage.file(
doc.document,
bytes: (await rootBundle.load('assets/logo.png')).buffer.asUint8List(),
);
// Add page to the PDF
doc.addPage(
pw.MultiPage(
pageTheme: _buildTheme(
pageFormat,
font1 != null ? pw.Font.ttf(font1) : null,
font2 != null ? pw.Font.ttf(font2) : null,
font3 != null ? pw.Font.ttf(font3) : null,
),
header: _buildHeader,
footer: _buildFooter,
build: (context) => [
_contentHeader(context),
_contentTable(context),
pw.SizedBox(height: 20),
_contentFooter(context),
pw.SizedBox(height: 20),
_termsAndConditions(context),
],
),
);
// Return the PDF file content
return doc.save();
}
EDIT:: I'm trying to do this now but i get a red underline under the commented line
class MyWidget extends StatelessWidget {
#override
Widget build(context) {
return FutureBuilder<Uint8List>(
future: generateInvoice(PdfPageFormat.a4),
builder: (context, AsyncSnapshot<Uint8List> snapshot) {
if (snapshot.hasData) {
return snapshot.data; //get a red underline here
} else {
return CircularProgressIndicator();
}
}
);
}
}
Your work function should look like this. Here two extra package I have used. For showing pdf flutter_pdfview and to save the pdf temporary path_provider.
Future<Widget> work() async{
Uint8List pdf = await generateInvoice(PdfPageFormat.a4);
File file = await getPdf(pdf);
return PDFView(
filePath: file.path,
autoSpacing: false,
pageFling: false,
);
}
EDITED:
Future<File> getPdf(Uint8List pdf) async{
Directory output = await getTemporaryDirectory();
file = File(output.path+"/name_of_the_pdf.pdf");
await file.writeAsBytes(pdf);
return file;
}
Now update your build method as
#override
Widget build(context) {
return FutureBuilder<Widget>(
future: work(),
builder: (BuildContext context, AsyncSnapshot<Widget> snapshot) {
if (snapshot.hasData) {
return snapshot.data; //get a red underline here
} else {
return CircularProgressIndicator();
}
}
);
}