In my app there is an alert dialog witch displays the rating based on some conditions, the rating is with stars image, i have a function with the conditions witch displays the rating, on another screen, i need those rating for that level that the user plays the same image that displays on the alert dialog based on the conditions to display on the other screen. for example if the user gets as rating 3 stars, than he goes to the other screen he will see the same rating there.
db_helper.dart
class Picture {
late final int? id;
late final String title;
late final Uint8List picture;
Picture(this.id, this.title, this.picture);
Picture.fromMap(Map map, this.id, this.title, this.picture) {
id = map[id];
title = map[title];
picture = map[picture];
}
Map<String, dynamic> toMap() => {
"id": id,
"title": title,
"picture" : picture,
};
}
class DatabaseHelper {
static final _databasename = "rating.db";
static final _databaseversion = 1;
static final table = "my_table";
static final columnID = 'id';
static final columnName = "ratingWithStars";
static final DatabaseHelper _databaseHelper = DatabaseHelper._();
DatabaseHelper._();
late Database db;
factory DatabaseHelper() {
return _databaseHelper;
}
Future<Database> get databse async {
if (db != null) return db;
// krijon database nese nuk ka
db = await _initDatabase();
return db;
}
_initDatabase() async {
Directory documentdirecoty = await getApplicationDocumentsDirectory();
String path = join(documentdirecoty.path, _databasename);
return await openDatabase(path,
version: _databaseversion, onCreate: _onCreate);
}
// funksion qe krijon database nese nuk ekziston
Future _onCreate(Database db, int version) async {
// sql code
await db.execute("CREATE TABLE Picture(id INTEGER PRIMARY KEY, title TEXT, picture BLOB )");
}
void savePicture(Picture picture) async {
var dbClient = await db;
await dbClient.insert("Picture", picture.toMap());
}
Future<List<Picture>> getPictures() async {
var dbClient = await db;
List<Map> list = await dbClient.rawQuery('SELECT * FROM Picture');
List<Picture> pictures = [];
for (int i = 0; i < list.length; i++) {
pictures.add(new Picture(list[i]["id"], list[i]["text"], list[i]["picture"]));
}
return pictures;
}
}
renditdjalet_button.dart
this is the class witch contains the function to display the rating on the alert dialog
class RenditFjaletButton extends StatefulWidget {
RenditFjaletButton(
{required this.QuizList,
required this.AllQuizLists,
required this.CurrentIndex,
Key? key})
: super(key: key);
late List AllQuizLists;
late List QuizList;
late int CurrentIndex;
#override
State<RenditFjaletButton> createState() => _RenditFjaletButtonState();
}
class _RenditFjaletButtonState extends State<RenditFjaletButton> {
late DatabaseHandler handler;
late Future<List<QuizInfo>?> futureData;
List<QuizDescription> selectReportList = [];
List<String> selectedWords = [];
List<QuizDescription> quizList = [];
int _selectedChipsIndex = 0;
String starsRating = '';
late Timer timer;
int startTimer = 65;
String starsOnTimer = '';
late QuizInfo question;
void initState() {
super.initState();
futureData = fetchData1();
startTheTimer();
this.handler = DatabaseHandler();
}
onPressed: () async {
await showDialog(
barrierDismissible: false,
context: context,
builder: (_) => AlertDialog(
backgroundColor: Color(0xFF50CFFD),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(35.0),
),
),
content: Builder(
builder: (context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
String joinedWords =
selectedWords.join(" ").toString();
String setRatingInAlert(int timerForAlert) { //function for rating
double halfTimeForAlert = timerForAlert / 2;
if (joinedWords ==
data[widget.CurrentIndex].sentence &&
startTimer > halfTimeForAlert) {
starsRating = 'assets/threestars_small.png';
} else if (joinedWords ==
data[widget.CurrentIndex].sentence &&
startTimer <= 1) {
starsRating = 'assets/onestar_small.png';
} else if (joinedWords == question.sentence &&
startTimer < halfTimeForAlert) {
starsRating = 'assets/twostars_small.png';
} else {
starsRating = 'assets/zerostars_small.png';
}
return starsRating;
}
where i need to show the rating same as the one in the alert
renditfjalet_screen.dart
body: FutureBuilder<List<QuizInfo>?>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<QuizInfo>? data = snapshot.data;
data?.sort((a, b) => a.level.compareTo(b.level));
return Stack(
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/background.PNG',
),
fit: BoxFit.cover),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: GridView.count(
crossAxisCount: 4,
children: List.generate(
data!.length,
(index) {
return InkWell(
overlayColor:
MaterialStateProperty.all(Colors.green),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RenditFjaletButton(
QuizList: data[index].word,
AllQuizLists: data,
CurrentIndex: index,
),
),
);
},
child: Card(
elevation: 3.0,
margin: EdgeInsets.all(7.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0)),
child: Column(
children: <Widget>[
Align(
alignment: Alignment.center,
child: Container(
child: Text(
'${data[index].level}',
style: GoogleFonts.fredokaOne(
textStyle: TextStyle(
fontSize: 30.0.sp,
color: Color(0xFF50CFFD),
),
),
)),
),
Container(
alignment: Alignment.center,
height: 30,
width: 65,
child: Image(
image: AssetImage('assets/threestars_small.png'), // here is where i want to show the rating, for now i just hardcoded it
),
),
],
),
),
);
},
),
),
),
),
],
You can convert an image to BASE64 and store image as a string in your database . Click there for more info
Related
When the Artworks screen is first rendered, it makes an async call that fetches the first page of data and then displays it in a grid. In the initState() function, I also add a scroll listener that fetches the next available page of data when the user reaches the bottom of the screen. The fetching logic works just fine, but the GridView doesn't seem to be rebuilt with the newly enhanced list despite calling setState(). Any ideas on why that is?
Artworks screen:
class Artworks extends StatefulWidget {
const Artworks({
Key? key,
}) : super(key: key);
#override
State<StatefulWidget> createState() => _ArtworksState();
}
class _ArtworksState extends State<Artworks> {
AlbumCubit get _cubit => context.read<AlbumCubit>();
List<Photo> get artworks => _cubit.artworks;
final ArtworkRepository _artworkRepository = getIt<ArtworkRepository>();
final ScrollController _controller = ScrollController();
int _totalArtworkPages = 0;
int _currentPage = 0;
bool fetchedFirstPage = false;
#override
void initState() {
super.initState();
_controller.addListener(() async {
if (_controller.position.atEdge) {
final bool isTop = _controller.position.pixels == 0;
if (!isTop) {
// scrolled to the bottom, fetch new page if available
if (_currentPage < _totalArtworkPages - 1) {
await _artworkRepository.getSavedArtworks(page: ++_currentPage);
setState(() {});
}
}
}
});
initData();
}
Future<void> initData() async {
_totalArtworkPages =
await _artworkRepository.getSavedArtworks(page: _currentPage);
setState(() {
fetchedFirstPage = true;
});
}
#override
Widget build(BuildContext context) {
return (!fetchedFirstPage)
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
CircularProgressIndicator(color: AppColors.red),
SizedBox(
height: 10,
),
Text(
'Loading artworks',
style: montserratMedium14,
)
],
),
)
: GridView.builder(
controller: _controller,
itemCount: _artworkRepository.savedArtworks.length,
padding: const EdgeInsets.symmetric(horizontal: 16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
),
itemBuilder: (BuildContext context, int index) {
final Photo artwork = _artworkRepository.savedArtworks[index];
return ArtworkItem(artwork: artwork);
},
);
}
}
class ArtworkItem extends StatelessWidget {
const ArtworkItem({Key? key, required this.artwork}) : super(key: key);
final Photo artwork;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () =>
NavigatorUtils.goToArtworkViewScreen(context, artworkId: artwork.id),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: AppColors.grey,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: CachedNetworkImage(
placeholder: (context, url) => const Center(
child: CircularProgressIndicator(
color: AppColors.red,
),
),
errorWidget: (context, url, dynamic error) =>
const Icon(Icons.error),
imageUrl: artwork.thumbnailPhoto ?? artwork.firebasePhoto,
fit: BoxFit.cover,
),
),
),
);
}
}
ArtworksRepositoryImpl:
class ArtworkRepositoryImpl implements ArtworkRepository {
ArtworkRepositoryImpl({required DioClient dioClient}) : _client = dioClient;
final DioClient _client;
final String baseUrl = getIt<AppRepository>().env == Env.staging //
? stagingUrl
: productionUrl;
final ArtistRepository artistRepository = getIt<ArtistRepository>();
#override
String? token;
#override
List<Photo> savedArtworks = [];
#override
Future<int> getSavedArtworks(
{int page = 0, int pageSize = 20, bool ascendent = true}) async {
try {
final ApiResponse response = await _client.httpCall(
baseUrl: baseUrl,
path: '/mobile/artwork/list',
httpMethod: HttpMethod.GET,
headers: <String, dynamic>{'x-auth-token': token},
queryParameters: <String, dynamic>{
'p': page,
'size': pageSize,
'asc': ascendent
},
);
final Map<String, dynamic> data = response.data;
final List<dynamic> artworksJson = data['results'] as List<dynamic>;
savedArtworks.addAll(
artworksJson.map((dynamic json) => Photo.fromJson(json)).toList(),
);
savedArtworks = savedArtworks.toSet().toList(); // remove duplicates
return data['totalPages'] as int;
} catch (e) {
rethrow;
}
}
}
Maybe it work,if you have not try you can create a function and replace wit in your listener like :
_controller.addListener(_onScroll);
then create _onScroll
Future _onScroll() async{
if (_controller.position.atEdge) {
final bool isTop = _controller.position.pixels == 0;
if (!isTop) {
// scrolled to the bottom, fetch new page if available
if (_currentPage < _totalArtworkPages - 1) {
await _artworkRepository.getSavedArtworks(page: ++_currentPage);
setState(() {});
}
}
}
}
and check the link below
https://www.youtube.com/watch?v=eENDlIgadr4
fetchData is my function from where I call the API and put the data into an object, which is UserModel Somehow, it is working perfectly. But I want to put my data into a list because I want to make a search function where I can search by name. Look into my code, which will help you to understand.
Future<UserModel>? futureUser;
Future<UserModel>? fetchData() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
print('This is Response: $response');
if (response.statusCode == 200) {
// this is a way which I've tried already and it works
// return UserModel.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
But I want to put the data into a list and make the search available. Like if i put some name like r+a+b+b+i, it will show the matching name from the API.
I have tried this but I am not clear about the consepet. I am not familiar with how to manipulate the JSON data in a list or object or how to convert an object into a list.
List<UserModel>? userList = [];
Future<UserModel>? fetchData() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
print('This is Response: $response');
if (response.statusCode == 200) {
// var result= UserModel.fromJson(jsonDecode(response.body));
// print('this is result $userList');
return userList.add(UserModel.fromJson(jsonDecode(response.body)));
// this is an way which i tried already and its works
// return UserModel.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
This is my whole code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:learning_1ui_6228/utilities/app_colors.dart';
import 'package:learning_1ui_6228/utilities/helper.dart';
import 'package:learning_1ui_6228/utilities/widgets/app_line.dart';
import 'package:learning_1ui_6228/utilities/widgets/list_tile_widget.dart';
import 'package:learning_1ui_6228/views/nav_pages/profile_page.dart';
import 'package:http/http.dart' as http;
import '../model/UserModel.dart';
class FirstScreen extends StatefulWidget {
const FirstScreen({Key? key}) : super(key: key);
#override
State<FirstScreen> createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
Future<UserModel>? futureUser;
TextEditingController textController = TextEditingController();
// List<UserModel> userList=[];
#override
void initState() {
// searchedList = userList;
futureUser = fetchData();
super.initState();
}
List<UserModel>? userList = [];
Future<UserModel>? fetchData() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
print('This is Response: $response');
if (response.statusCode == 200) {
// var result= UserModel.fromJson(jsonDecode(response.body));
// print('this is result $userList');
return userList.add(UserModel.fromJson(jsonDecode(response.body)));
// this is an way which i tried already and its works
// return UserModel.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
List<UserModel> searchedList = [];
void searchUser(String enteredData){
print('entered word + ${enteredData}');
searchedList = [];
for(int i=0; i<userList!.length; i++){
if(userList[i].data![i].firstName!.toLowerCase().contains(enteredData.toLowerCase())){
searchedList.add(userList![i]);
}
}
}
#override
Widget build(BuildContext context) {
//print('user list data + $searchedList');
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xfff8f8fa),
body: Column(
children: [
//1st Section
Container(
height: HelperClass.h250,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: AppColors.gradientColor,
),
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(HelperClass.r10),
bottomLeft: Radius.circular(HelperClass.r10))),
child: Column(
children: <Widget>[
//Text and cross button
Container(
margin: EdgeInsets.only(
left: HelperClass.w10,
right: HelperClass.w10,
top: HelperClass.h20),
height: HelperClass.h50,
// color: Colors.red,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.clear,
color: Colors.white,
size: 30,
))),
Expanded(
child: Container(
margin: EdgeInsets.only(right: 30),
alignment: Alignment.center,
// color: Colors.lightBlueAccent,
child: Text(
'Search',
style: TextStyle(
fontSize: HelperClass.t25,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
),
],
),
),
SizedBox(
height: HelperClass.h25,
),
//Search Bar
Container(
margin: EdgeInsets.only(
left: HelperClass.w10, right: HelperClass.w10),
//color: Colors.amber,
height: HelperClass.h70,
width: double.infinity,
child: TextField(
controller: textController,
onChanged: (name) {
setState(() {
searchUser(name);
});
},
decoration: InputDecoration(
prefix: Icon(
Icons.search,
size: 26,
),
suffix: IconButton(
onPressed: () {
setState(() {
textController.clear();
searchedList = userList;
});
},
icon: Icon(
Icons.clear,
size: 26,
),
),
hintText: 'Search',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(3),
borderSide: BorderSide.none,
),
filled: true,
fillColor: Colors.white,
),
),
),
],
),
),
// List View
Expanded(
child: FutureBuilder<UserModel>(
future: futureUser,
builder: (context, snapshot){
if(snapshot.hasData){
return ListView.builder(
itemCount: snapshot.data!.data!.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(10),
child: Column(
children: [
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage(
userName:snapshot.data!.data![index].firstName??'',
followers: snapshot.data!.data![index].id.toString(),
address: snapshot.data!.data![index].email.toString(),
following: snapshot.data!.data![index].lastName.toString(),
imageUrl: snapshot.data!.data![index].avatar.toString(),
),
));
},
child: ListTileWidgets(
following: snapshot.data!.data![index].lastName.toString(),
address: snapshot.data!.data![index].email.toString(),
imageUrl:snapshot.data!.data![index].avatar.toString(),
name: snapshot.data!.data![index].firstName??'',
followersCount:
'Followers: ${snapshot.data!.data![index].id.toString()}',
iconWidget: Icon(
Icons.person_add_alt_outlined,
color: Colors.red,
size: 25,
),
),
),
AppLine(
paddingLeft: 10,
paddingRight: 10,
heightLine: 1,
lineColor: Colors.grey),
],
),
);
},
);
}
else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return Center(child: CircularProgressIndicator());
}),
),
],
),
),
);
}
}
This is my UserModel class
import 'dart:convert';
UserModel userModelFromJson(String str) => UserModel.fromJson(json.decode(str));
String userModelToJson(UserModel data) => json.encode(data.toJson());
class UserModel {
UserModel({
this.page,
this.perPage,
this.total,
this.totalPages,
this.data,
this.support,});
UserModel.fromJson(dynamic json) {
page = json['page'];
perPage = json['per_page'];
total = json['total'];
totalPages = json['total_pages'];
if (json['data'] != null) {
data = [];
json['data'].forEach((v) {
data?.add(Data.fromJson(v));
});
}
support = json['support'] != null ? Support.fromJson(json['support']) : null;
}
int? page;
int? perPage;
int? total;
int? totalPages;
List<Data>? data;
Support? support;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['page'] = page;
map['per_page'] = perPage;
map['total'] = total;
map['total_pages'] = totalPages;
if (data != null) {
map['data'] = data?.map((v) => v.toJson()).toList();
}
if (support != null) {
map['support'] = support?.toJson();
}
return map;
}
}
Support supportFromJson(String str) => Support.fromJson(json.decode(str));
String supportToJson(Support data) => json.encode(data.toJson());
class Support {
Support({
this.url,
this.text,});
Support.fromJson(dynamic json) {
url = json['url'];
text = json['text'];
}
String? url;
String? text;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['url'] = url;
map['text'] = text;
return map;
}
}
Data dataFromJson(String str) => Data.fromJson(json.decode(str));
String dataToJson(Data data) => json.encode(data.toJson());
class Data {
Data({
this.id,
this.email,
this.firstName,
this.lastName,
this.avatar,});
Data.fromJson(dynamic json) {
id = json['id'];
email = json['email'];
firstName = json['first_name'];
lastName = json['last_name'];
avatar = json['avatar'];
}
int? id;
String? email;
String? firstName;
String? lastName;
String? avatar;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['email'] = email;
map['first_name'] = firstName;
map['last_name'] = lastName;
map['avatar'] = avatar;
return map;
}
}
this is my api link
https://reqres.in/api/users?page=2
No need to add UserModel to list.
change this
class _FirstScreenState extends State<FirstScreen> {
UserModel? usermodel;
List<Data?> searchResult= [];
change your fetch data . this will return UserModel as result.
Future<UserModel?> fetchData() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
print('This is Response: $response');
if (response.statusCode == 200) {
return UserModel.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
create init function to set your initial data
void initFunction() async {
UserModel data = await fetchData(); // you have to await until get the response
//then setState to local variable so it can display to widget
// if you skip this , your usermodel is null
setState ({
usermodel = data ;
});
}
then in your initState
#override
void initState() {
initFunction();
super.initState();
}
usermodel.data consist of data user.
to then you can apply logic to search user from the list.
void searchUser(String enteredData){
List<Data?> temp = [];
for(int i=0; i<usermodel.data.length; i++){
if(enteredData.toLowerCase() == usermodel.data[i].firstName.toLowerCase()){
temp.add(usermodel.data[i];
}
}
// you need to setState again
setState({
searchResult = temp;
});
}
last in you can acces the data in userModel
#override
Widget build(BuildContext context) {
//print('user list data + $searchedList');
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xfff8f8fa),
body: Column(
children: [
Text('${usermodel.data.length}'), /// number all list user
Text('${searchResult.length}'), /// number search user
// now you have list all user
// and all searched list user
// additional, you need to add logic when query is empty
.................
maybe there error in null-safety, please debug first.
You can simply do this
var myList= []; // declare an empty list
if (response.statusCode == 200) {
var result= UserModel.fromJson(jsonDecode(response.body));
if(result != null){
myList.clear();
myList.addAll(result);
}
}
This project is a shopping app and the function I am trying to achieve with the following code is the add to cart function. I got an "Undefined Name" error for integer "index" despite defining it in the void(saveData). I'm very new to coding so I'm thinking there might be something I've overlooked.
The error is the highlighted line in this image here:
[highlighted line of undefined name error][1]
The line of code where I defined "index" is in the following image:
[defining "index" in void][2]
The full code for this dart file is as follows:
import 'package:provider/provider.dart';
import 'package:MyShoppingApp/provider/CartProvider.dart';
import 'package:MyShoppingApp/db/cart_database.dart';
import 'package:MyShoppingApp/model/cart.dart';
import 'model/products_repository.dart';
class ProductDetailsPage extends StatelessWidget {
static const routeName = '/user-products';
ProductDetailsPage({Key? key}) : super(key: key); //const
DBHelper dbHelper = DBHelper();
#override
Widget build(BuildContext context) {
//get particular productId using the ModalRoute class
final productId = ModalRoute.of(context)!.settings.arguments as String;
print(productId);
//use Provider package to find out ID by accessing method declared in Product()
final loadedProduct = ProductsRepository().findById(productId);
//List<bool> clicked = List.generate(10, (index) => false, growable: true);
final cart = Provider.of<CartProvider>(context);
void saveData(int index) {
dbHelper
.insert(
CartItem(
id: index,
title: loadedProduct.name,
price: loadedProduct.price.toDouble(),
quantity: ValueNotifier(1),
image: loadedProduct.image,
),
)
.then((value) {
cart.addTotalPrice(loadedProduct.price.toDouble());
cart.addCounter();
print('Product Added to cart');
}).onError((error, stackTrace) {
print(error.toString());
});
}
return Scaffold(
backgroundColor: Colors.orange[50],
appBar: AppBar(
backgroundColor: Colors.deepOrange[900],
title: const Text("Product details "),
leading: IconButton(
icon: const Icon(
Icons.arrow_back_ios_outlined,
color: Colors.black,
semanticLabel: 'back to home',
),
onPressed: () {
Navigator.pop(context);
},
),
),
body:
SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(
height: 300,
width: double.infinity,
child: Image.network(
loadedProduct.image,
fit: BoxFit.cover,
),
),
const SizedBox(height: 10),
Text(
'\$${loadedProduct.price}',
style: const TextStyle(
color: Colors.grey,
fontSize: 20,
),
),
const SizedBox(
height: 10,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.blueGrey.shade900),
onPressed: () {
saveData(index);
},
child: const Text('Add to Cart')),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10),
width: double.infinity,
child: Text(
loadedProduct.description,
textAlign: TextAlign.center,
softWrap: true,
),
),
],
),
),
);
}
}
Any form of help would be so greatly appreciated, I have been struggling with this error for very long. Thank you!
Edit:
CartProvider dart file code:
import 'package:flutter/cupertino.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';
import '../model/cart.dart';
import 'package:MyShoppingApp/db/cart_database.dart';
class CartProvider with ChangeNotifier {
DBHelper dbHelper = DBHelper();
int _counter = 0;
int _quantity = 1;
int get counter => _counter;
int get quantity => _quantity;
double _totalPrice = 0.0;
double get totalPrice => _totalPrice;
List<CartItem> cart = [];
Future<List<CartItem>> getData() async {
cart = await dbHelper.getCartList();
notifyListeners();
return cart;
}
void _setPrefsItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setInt('cart_items', _counter);
prefs.setInt('item_quantity', _quantity);
prefs.setDouble('total_price', _totalPrice);
notifyListeners();
}
void _getPrefsItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
_counter = prefs.getInt('cart_items') ?? 0;
_quantity = prefs.getInt('item_quantity') ?? 1;
_totalPrice = prefs.getDouble('total_price') ?? 0;
}
void addCounter() {
_counter++;
_setPrefsItems();
notifyListeners();
}
void removeCounter() {
_counter--;
_setPrefsItems();
notifyListeners();
}
int getCounter() {
_getPrefsItems();
return _counter;
}
void addQuantity(int id) {
final index = cart.indexWhere((element) => element.id == id);
cart[index].quantity!.value = cart[index].quantity!.value + 1;
_setPrefsItems();
notifyListeners();
}
void deleteQuantity(int id) {
final index = cart.indexWhere((element) => element.id == id);
final currentQuantity = cart[index].quantity!.value;
if (currentQuantity <= 1) {
currentQuantity == 1;
} else {
cart[index].quantity!.value = currentQuantity - 1;
}
_setPrefsItems();
notifyListeners();
}
void removeItem(int id) {
final index = cart.indexWhere((element) => element.id == id);
cart.removeAt(index);
_setPrefsItems();
notifyListeners();
}
int getQuantity(int quantity) {
_getPrefsItems();
return _quantity;
}
void addTotalPrice(double productPrice) {
_totalPrice = _totalPrice + productPrice;
_setPrefsItems();
notifyListeners();
}
void removeTotalPrice(double productPrice) {
_totalPrice = _totalPrice - productPrice;
_setPrefsItems();
notifyListeners();
}
double getTotalPrice() {
_getPrefsItems();
return _totalPrice;
}
}```
[1]: https://i.stack.imgur.com/V8OGs.png
[2]: https://i.stack.imgur.com/JYE10.png
The body is returning a ListView.builder, and index can be get from there,
body: ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 8.0),
shrinkWrap: true,
itemCount: products.length,
itemBuilder: (context, index) {
return Card(
The original code can be found here
You don't have any list to represent that index so, in your ElevatedButton instead of using index could use an other number. so there is a workaround for that and that is use random number for that.
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.blueGrey.shade900),
onPressed: () {
saveData(Random().nextInt(1000));
},
child: const Text('Add to Cart')),
my console shows no error but still i cant generate a data base with my app i dont know where's the problem at first when i run the app and add a transaction and then i enter the transaction page it shows 'no transactions' and then when i left the app and get back it shows 'loading' and when i try add another transaction the button add doesnt respond i have to say that when i delete the part of the code about db the app works perfectly but without a database
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'transaction.dart';
class TransactionsDatabase {
static final TransactionsDatabase instance = TransactionsDatabase._init();
static Database? _database;
TransactionsDatabase._init();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB();
return _database!;
}
Future<Database> _initDB() async {
Directory documentsDirectory = await getApplicationSupportDirectory();
String path = join(documentsDirectory.path, 'TransactionsDatabase.db');
return await openDatabase(path, version: 1, onCreate: _createDB);
}
Future _createDB(Database db, int version) async {
final idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
final textType = 'TEXT NOT NULL';
final boolType = 'BOOLEAN NOT NULL';
final doubleType = 'DOUBLE NOT NULL';
await db.execute('''
CREATE TABLE $tableTransactions (
${TransactionFields.id} $idType,
${TransactionFields.isIncome} $boolType,
${TransactionFields.Tname} $textType,
${TransactionFields.Tamount} $doubleType,
${TransactionFields.time} $textType
)
''');
}
Future<int> create(Transactionn transactionn) async {
Database db = await instance.database;
return await db.insert(tableTransactions, transactionn.toJson());
}
Future<List<Transactionn>> readAllNotes() async {
Database db = await instance.database;
var transactions =
await db.query(tableTransactions, orderBy: TransactionFields.Tname);
List<Transactionn> transactionList = transactions.isNotEmpty
? transactions.map((json) => Transactionn.fromJson(json)).toList()
: [];
return transactionList;
}
Future close() async {
final db = await instance.database;
db.close();
}
}
my class exemple look like this : Transaction.dart
final String tableTransactions = 'transactions';
class TransactionFields {
static final List<String> values = [
/// Add all fields
id, isIncome, Tname, Tamount, time
];
static final String id = '_id';
static final String isIncome = 'isIncome';
static final String Tname = 'tname';
static final String Tamount = 'tamount';
static final String time = 'time';
}
class Transactionn {
final int? id;
final bool isIncome;
final String Tname;
final double Tamount;
final DateTime createdTime;
const Transactionn(
{this.id,
required this.isIncome,
required this.Tname,
required this.Tamount,
required this.createdTime});
Map<String, Object?> toJson() => {
TransactionFields.id: id,
TransactionFields.isIncome: isIncome ? 1 : 0,
TransactionFields.Tname: Tname,
TransactionFields.Tamount: Tamount,
TransactionFields.time: createdTime.toIso8601String(),
};
Transactionn copy({
int? id,
bool? isIncome,
String? Tname,
double? Tamount,
DateTime? createdTime,
}) =>
Transactionn(
id: id ?? this.id,
isIncome: isIncome ?? this.isIncome,
Tname: Tname ?? this.Tname,
Tamount: Tamount ?? this.Tamount,
createdTime: createdTime ?? this.createdTime,
);
static Transactionn fromJson(Map<String, Object?> json) => Transactionn(
id: json[TransactionFields.id] as int?,
isIncome: json[TransactionFields.isIncome] == 1,
Tname: json[TransactionFields.Tname] as String,
Tamount: json[TransactionFields.Tamount] as double,
createdTime: DateTime.parse(json[TransactionFields.time] as String),
);
}
in my Homepage class i use a dialogbox to add a transaction to my db :
onPressed: () async {
if (_IncomeName.text.isNotEmpty &
_IncomeAmountName.text.isNotEmpty) {
IncomeName = _IncomeName.text;
IncomeAmountName = _IncomeAmountName.text;
IncomeAmount = double.parse(IncomeAmountName);
IncomeAmount = IncomeAmount.toDouble();
await TransactionsDatabase.instance.create(Transactionn(
isIncome: true,
Tname: IncomeName,
Tamount: IncomeAmount,
createdTime: DateTime.now()));
tt = preferences.getDouble('total');
if (tt == null) {
ttt = IncomeAmount;
} else {
ttt = IncomeAmount + tt!;
}
preferences.setDouble('total', ttt);
setState(() {
capital = preferences.getDouble('total') as double;
});
_IncomeName.clear();
_IncomeAmountName.clear();
Navigator.pop(context);
} else {}
},
and then i have a transactions page where im supposed to see all my db contents transactions.dart
import 'package:flutter/material.dart';
import 'package:mywallet/Database_Helper.dart';
import 'package:mywallet/transaction.dart';
class TransactionsPage extends StatefulWidget {
const TransactionsPage({Key? key}) : super(key: key);
#override
State<TransactionsPage> createState() => _TransactionsPageState();
}
class _TransactionsPageState extends State<TransactionsPage> {
List<Transactionn> transactions = [];
bool isLoading = false;
#override
void initState() {
refreshTransactions();
super.initState();
}
#override
void dispose() {
TransactionsDatabase.instance.close();
super.dispose();
}
Future refreshTransactions() async {
setState(() {
isLoading = true;
});
this.transactions = await TransactionsDatabase.instance.readAllNotes();
setState(() {
isLoading = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black26,
body: Container(
padding:
const EdgeInsets.only(top: 40, left: 15, right: 15, bottom: 40),
child: Column(
children: [
Row(
children: [
const SizedBox(
width: 20,
),
IconButton(
icon: Image.asset(
'images/Images/back.png',
width: 24,
height: 24,
),
onPressed: () {
Navigator.pop(context);
},
)
],
),
const SizedBox(
height: 70,
),
Container(
width: MediaQuery.of(context).size.width,
height: 350,
decoration: BoxDecoration(
color: const Color.fromARGB(255, 25, 28, 31),
borderRadius: BorderRadius.circular(30)),
child: Container(
padding: const EdgeInsets.only(
top: 30, left: 20, right: 10, bottom: 10),
child: Column(
children: [
Row(
children: const [
Text('Transactions : ',
style: TextStyle(
fontSize: 14,
color: Color.fromARGB(249, 95, 190, 188),
fontWeight: FontWeight.bold))
],
),
const SizedBox(height: 20),
Center(
child: FutureBuilder<List<Transactionn>>(
future: TransactionsDatabase.instance.readAllNotes(),
builder: (BuildContext context,
AsyncSnapshot<List<Transactionn>> snapshot) {
if (!snapshot.hasData) {
return Center(
child: Text(
'Loading..',
style: TextStyle(
color: Colors.white, fontSize: 20),
));
}
return snapshot.data!.isEmpty
? const Center(
child: Text(
'no traansactiions',
style: TextStyle(
color: Colors.white, fontSize: 20),
))
: ListView(
children:
snapshot.data!.map((Transactionn) {
return Center(
child: ListTile(
title: Text(Transactionn.Tname),
),
);
}).toList(),
);
},
),
)
],
),
))
],
),
),
);
}
}
In my flutter project, i have a method that returns a String from the firebase:
Future<String> getNomeById(bool retirada, String userId) async {
QuerySnapshot snapshot = await firestore
.collection('users')
.where(FieldPath.documentId, isEqualTo: userId)
.getDocuments();
users = snapshot.documents.map((d) => User.fromDocument(d)).toList();
if (retirada) {
name = users[0].name;
} else {
name = 'Other';
}
return name;
}
Here I get the method return
u.getNomeById(retirada, userId).then((value) {
returnFutureString = value;
print(returnFutureString);//It's OK here
});
I need to use the return Future String in the title of my alertDialog,
I can't because my variable is null there, I know I'm doing it wrong, but I couldn't make it work by searching for similar examples.
class ExportAddressDialog extends StatelessWidget {
ExportAddressDialog(this.address, this.retirada, this.userId);
final Firestore firestore = Firestore.instance;
final Address address;
final bool retirada;
final String userId;
final ScreenshotController screenshotController = ScreenshotController();
#override
Widget build(BuildContext context) {
String returnFutureString;
Util u = new Util();
u.getNomeById(retirada, userId).then((value) {
returnFutureString = value;
print(returnFutureString);//It's OK here
});
return AlertDialog(
title: Text(returnFutureString),//I need to use my returnFutureString as the alert title, but is null here
content: Screenshot(
controller: screenshotController,
child: Container(
padding: const EdgeInsets.all(8),
color: Colors.white,
child: Text(
'${address.street}, ${address.number} ${address.complement}\n'
'${address.district}\n'
'${address.city}/${address.state}\n'
'${address.zipCode}',
),
),
),
contentPadding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
actions: <Widget>[
FlatButton(
onPressed: () async {
Navigator.of(context).pop();
final file = await screenshotController.capture();
await GallerySaver.saveImage(file.path);
},
textColor: Theme.of(context).primaryColor,
child: const Text('Exportar'),
)
],
);
}
Future<String> _getTitle() async {
String returnFutureString = await u.getNomeById(retirada, userId)
return returnFutureString;
}
Use FutureBuilder to fetch async values:
FutureBuilder<String>(
future: _getTitle(),
builder: (ctx, snapshot) {
if (snapshot.hasData) {
return AlertDialog(
title: Text(snapshot.data)
);
}
return Center(child: CircularProgressIndicator());
}
),);