Related
Hi guys I'm new in flutter and need your help. In this case, i'm able to add the budget and retrieve it to list view. but now I'm trying show only 1 list for each category but count for the amount? so if the user add the new budget, the amount will be count and updated to the list view (with the same currency). Anyone can help me how to list the the same category but with updated amount if the user add the budget in the budget code? Please help. Thank you. For the database, I'm using Firestore in the firebase
choose budget category
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/detail.dart';
import 'package:monger_app/theme/colors.dart';
class BudgetSettings extends StatefulWidget {
#override
_BudgetSettingsState createState() => _BudgetSettingsState();
}
class _BudgetSettingsState extends State<BudgetSettings> {
List<Container> categorylist = new List();
var character=[
{"name":"Food", "image":"food.png"},
{"name":"Social-Life", "image":"travel.png"},
{"name":"Transportation", "image":"transportation.png"},
{"name":"Beauty", "image":"makeup.png"},
{"name":"Household", "image":"household.png"},
{"name":"Education", "image":"education.png"},
{"name":"Health", "image":"health.png"},
{"name":"Gift", "image":"gift.png"},
{"name":"Other", "image":"other.png"},
];
_makelist() async {
for (var i = 0; i < character.length; i++) {
final newcharacter = character[i];
final String image = newcharacter["image"];
categorylist.add(
new Container(
padding: new EdgeInsets.all(20.0),
child: new Card( child:
SingleChildScrollView(
child: new Column(
children: <Widget>[
new Hero(
tag: newcharacter['name'],
child: new Material(
child: new InkWell(
onTap: ()=> Navigator.of(context).push(new MaterialPageRoute(
builder: (BuildContext context)=> new Detail(name: newcharacter['name'], image: image,),
)),
child:
new Image.asset("assets/$image", fit: BoxFit.contain,),
)
),
),
//new Image.asset('assets/$image', fit: BoxFit.cover,),
new Padding(padding: new EdgeInsets.all(5.0),),
new Text(newcharacter['name'], style: new TextStyle(fontSize: 18.0),),
],
),
),
),
),
);
}
}
#override
void initState() {
_makelist();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: primary,
title: Text(getTranslated((context), "budget_settings"),
),),
body: new GridView.count(
crossAxisCount: 2,
children: categorylist,
),
);
}
}
Add budget code
import 'package:dropdownfield/dropdownfield.dart';
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/account.dart';
import 'package:monger_app/page/budgetsettings.dart';
import 'package:monger_app/theme/colors.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Detail extends StatefulWidget {
Detail({this.name, this.image});
final String name;
final String image;
#override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text(getTranslated((context), "budget_settings"),),
elevation: 0,
brightness: Brightness.light,
backgroundColor: primary,
leading: IconButton(
onPressed: (){
Navigator.pop(context, MaterialPageRoute(builder: (context) => Account()));
},
icon: Icon(Icons.arrow_back_ios,
size: 20,
color: Colors.black,),
),
),
body: new ListView(
children: <Widget>[
new Container(
height: 250.0,
child:
new Hero(tag: widget.name,
child: new Material(
child: new InkWell(
child: new Image.asset("assets/${widget.image}", fit: BoxFit.contain,),
)
))
),
new Name(name: widget.name,),
],
),
);
}
}
class Name extends StatefulWidget {
Name({this.name});
final String name;
#override
_NameState createState() => _NameState();
}
class _NameState extends State<Name> {
#override
String selectCurrency;
final currencySelected = TextEditingController();
var _formKey = GlobalKey<FormState>();
List <String> currencycategories = [
"IDR",
"MYR",
"USD",
"CNY"
];
Widget build(BuildContext context) {
final amount = TextEditingController();
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference collect= firestore.collection("Budget");
final FirebaseAuth _auth = FirebaseAuth.instance;
final User user =_auth.currentUser;
final uid = user.uid;
return Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Container(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: Text(
widget.name,
textAlign: TextAlign.center,
style: new TextStyle(
fontSize: 25.0,
color: primary,
fontWeight: FontWeight.bold,
),
),
),
Row(
children: <Widget> [
new Expanded(child: new DropDownField(
controller: currencySelected,
labelText: getTranslated((context), "currency_hint"),
enabled: true,
itemsVisibleInDropdown: 4,
items: currencycategories,
onValueChanged: (dynamic value) {
selectCurrency = value;
},
value: selectCurrency,
required: false,
),
flex: 2,
),
new SizedBox(
width: 10.0,
),
new Expanded(child: TextFormField(
validator: (input) {
if (input.isEmpty) return 'Please fill up the text fields';
},
controller: amount,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: getTranslated((context), "budget_enter"),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondary),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondary),
),
),
),
flex: 2,
)],
),
Padding(
padding: EdgeInsets.all(20.0),
child: ElevatedButton(
onPressed: () async {
final FirebaseAuth _auth = FirebaseAuth
.instance;
final User user = _auth.currentUser;
final uid = user.uid;
if(!_formKey.currentState.validate()){
return;
}
_formKey.currentState.save();
collect.add({
'name': this.widget.name,
'currency': selectCurrency,
'amount': amount.text,
});
amount.text = "";
Navigator.pop(context);
},
child: Text(getTranslated((context), "save_button").toUpperCase(), style: TextStyle (
fontSize: 14,
)),
style: ButtonStyle(
padding: MaterialStateProperty.all<EdgeInsets>(EdgeInsets.all(20.0)),
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
backgroundColor: MaterialStateProperty.all<Color>(Colors.pink),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
side: BorderSide(color: secondary)
),
),
),
),
)
],
),
)
)
],
),
)
);
}
}
Retrieve it to list view code
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/transaction.dart';
import 'package:monger_app/theme/colors.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import './transaction.dart' as expense;
import './transaction.dart' as income;
class TransactionMonthly extends StatefulWidget {
#override
_TransactionMonthlyState createState() => _TransactionMonthlyState();
}
class _TransactionMonthlyState extends State<TransactionMonthly> with SingleTickerProviderStateMixin {
TabController controller;
#override
void initState() {
controller = new TabController(vsync: this, length: 2);
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(getTranslated(context, 'budget_title'),),
elevation: 0,
brightness: Brightness.light,
backgroundColor: primary,
leading: IconButton(
onPressed: (){
Navigator.pop(context, MaterialPageRoute(builder: (context) => Transactions()));
},
icon: Icon(Icons.arrow_back_ios,
size: 20,
color: Colors.black,),
),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('Budget').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
return ListView(
children: snapshot.data.docs.map((document) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
SizedBox(width: 10,),
Text(document.get('name'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
],
),
SizedBox(height: 10,),
Row(children: [
SizedBox(width: 10,),
Text(document.get('currency'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
SizedBox(width: 10,),
Text(document.get('amount'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
],
),
SizedBox(height: 8,),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: (){
Widget cancelButton = FlatButton(child: Text("Cancel"),
onPressed: (){
Navigator.pop(context);
},
);
Widget deleteButton = FlatButton(child: Text("Delete"),
onPressed: (){
FirebaseFirestore.instance.collection('Budget').doc(document.id).delete();
Navigator.pop(context);
},
);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Delete Budget'),
content: Text('Are you sure want to delete it?'),
actions: [
cancelButton,
deleteButton,
],
),
);
//_showDeleteDialog();
//_showDeleteDialog(document: document);
},
child: Row(
children: [
Icon(Icons.delete_forever_outlined,
color: Colors.red,
),
SizedBox(width: 6,),
Text('Delete', style: TextStyle(fontSize: 16,
color: Colors.red,
fontWeight: FontWeight.w600
), ),
],
),
)
],
)
],)
);
}).toList(),
);
}
return Center(
child: CircularProgressIndicator(),
);
}
),
);
}
}
I think what you want is a sort of group by name so that you show the food category with 160 in your example instead of two times the same category (Correct me if i am wrong). What i suggest is to first create a class named Budget with your three attributes name, currency and amount. When you receive your data in TransactionMonthly Streambuilder you need to group your snapshot data by name. Once you done that you create a list of budgets List<Budget> budgets so that you add the sum of amount per name of budgets.
Here is a sample code that you can use, you can simply copy paste it and try on DartPad by yourself:
import 'package:collection/collection.dart';
//DATA coming from your Firebase collection
Map<String, dynamic> data1 = {
'name':"Food",
'currency': "IDR",
'amount': 100,
};
Map<String, dynamic> data2 = {
'name':"Food",
'currency': "IDR",
'amount': 60,
};
Map<String, dynamic> data3 = {
'name':"Beauty",
'currency': "USD",
'amount': 120,
};
//Your Budget class
class Budget{
String currency;
String name;
int amount;
#override
String toString(){
return "Budget: {currency: $currency, name: $name, amount: $amount}";
}
Budget({required this.currency, required this.name, required this.amount});
}
void main(){
List<Map<String, dynamic>> snapshot = [data1, data2, data3];
List<Budget> budgets = [];
//you group your budgets by name so you will have: {'Food': [data1, data2], 'Beauty':[data3]}
final groupByName = groupBy(snapshot, (Map<String, dynamic> doc)=>doc['name']);
print(groupByName);
int totalAmount = 0;
String currency = "";
groupByName.forEach((name, value){
//because we grouped by name every value will have same currency
currency = value[0]['currency'];
//Here we calculate the sum of all Food
totalAmount = value.map((e)=>e['amount']).reduce((v, e)=> v+e);
budgets.add(Budget(currency: currency, amount: totalAmount, name: name));
});
//budgets is your final list to use in your listView
print(budgets);
}
I am fetching the list from my http server .The list is fetching the data whenever the scroll controller reaches to the bottom of the screen. Loading data from http service and showing in the screen is working fine. The problem comes when loading more data the scroll controller goes to the top of the screen instead of staying on the last location its going to top and doing scrolling again to the previous scrolled data.
I just want to avoid the scrollbar to go to top so the user will only scroll the latest data.
//Here is my viewModel
import 'package:testingApp/models/property_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:testingApp/helpers/debouncer.dart';
import 'package:testingApp/helpers/toastr.dart';
import 'package:testingApp/services/property_service.dart';
class PropertyViewModel extends BaseViewModel {
List _properties = [];
int _offsetVal = 0;
//String _keyword;
bool _isResults = true;
bool _isFiltering = false;
String _filterCheck = 'date_up';
String _filterPriceCheck = 'price_up';
String _filterAreaCheck = 'area_up';
bool loadingShimmer = true;
bool searchFilterStatus = false;
ScrollController scrollController = ScrollController();
TextEditingController searchCtrl = new TextEditingController();
Debouncer _debouncer = Debouncer(milliseconds: 1000);
Property property = Property();
void initialise() {
scrollController.addListener(() {
if (scrollController.position.pixels ==
scrollController.position.maxScrollExtent) {
this.incrementOffset();
this._isFiltering = false;
notifyListeners();
}
});
}
#override
void dispose() {
searchCtrl.dispose();
scrollController.dispose();
super.dispose();
}
//FETCHING THE properties FROM HTTP SERVICE
getTheProperty(priceSliderMin, priceSliderMax, areaSliderMin, areaSliderMax,
beds, baths, chosenCity, searchKeywords, searchStatus, searchType) async {
if (!_isFiltering) {
if (_isResults) {
this.loadingShimmer = true;
await PropertyService.getProperties(
_offsetVal,
priceSliderMin,
priceSliderMax,
areaSliderMin,
areaSliderMax,
beds,
baths,
chosenCity,
searchKeywords,
searchStatus,
searchType,
).then((propertyJSON) {
//MAP JSON TO property LIST
final List properties = propertyFromJson(propertyJSON);
if (properties.length != 0) {
_properties.addAll(properties);
} else {
showToastrMessage('No more properties found.');
_isResults = false;
//NO MORE RESULTS
}
});
} else {
showToastrMessage('No more properties found.');
}
}
this.loadingShimmer = false;
return _properties;
}
//INCREATING TO LOAD MORE DATA USING INFINITE SCROLLING
incrementOffset() {
_offsetVal = property.incrementOffset(_offsetVal);
}
//USE TO PRINT ERRRO IN SCREEN
Widget showError(String msg) {
return Center(
child: Text(msg),
);
}
}
//HERE IS MY VIEW
import 'package:flutter/material.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import 'package:stacked/stacked.dart';
import 'package:testingApp/helpers/error_handling.dart';
import 'package:testingApp/widgets/property_detail.dart';
import 'property_viewmodel.dart';
import 'package:shimmer/shimmer.dart';
import 'package:testingApp/constant.dart';
import 'package:testingApp/nav_drawer.dart';
import 'package:testingApp/ui/views/search/search_view.dart';
class PropertyView extends StatelessWidget {
final double priceSliderMin;
final double priceSliderMax;
final double areaSliderMin;
final double areaSliderMax;
final String beds;
final String baths;
final String chosenCity;
final String searchKeywords;
final String searchStatus;
final String searchType;
const PropertyView(
{Key key,
this.priceSliderMin,
this.priceSliderMax,
this.areaSliderMin,
this.areaSliderMax,
this.beds,
this.baths,
this.chosenCity,
this.searchKeywords,
this.searchStatus,
this.searchType})
: super(key: key);
#override
Widget build(BuildContext context) {
return ViewModelBuilder<PropertyViewModel>.reactive(
builder: (context, model, child) => Scaffold(
drawer: Theme(
data: Theme.of(context).copyWith(canvasColor: plpGredientOne),
child: NavDrawer(),
),
appBar: PreferredSize(
preferredSize: Size.fromHeight(55.0),
child: AppBar(
title: Text('Properties'),
backgroundColor: plpGredientOne,
elevation: 0.0,
),
),
body: Container(
color: Colors.white,
child: new Builder(builder: (BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
SizedBox(
height: 1,
),
Row(
children: <Widget>[
Expanded(
child: ElevatedButton(
onPressed: () {
model.setFilteringCheck = true;
model.filterByDate();
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.all(12.0),
primary: plpGredientOne,
onPrimary: plpGredientTwo,
onSurface: Colors.grey[400],
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(0),
),
),
child: Row(
children: [
Icon(
model.filterStatus == 'date_down'
? LineAwesomeIcons.sort_amount_down
: LineAwesomeIcons.sort_amount_up,
color: Colors.white,
size: 25.0),
Text(
'Date',
style: TextStyle(
color: Colors.white,
fontSize: 14.0,
),
),
],
),
),
),
Expanded(
child: ElevatedButton(
onPressed: () {
model.setFilteringCheck = true;
model.filterByArea();
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.all(12.0),
primary: plpGredientOne,
onPrimary: plpGredientTwo,
onSurface: Colors.grey[400],
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(0),
),
),
child: Row(
children: [
Icon(
model.filterAreaCheck == 'area_up'
? LineAwesomeIcons.sort_amount_up
: LineAwesomeIcons.sort_amount_down,
color: Colors.white,
size: 25.0),
Text(
'Area',
style: TextStyle(
color: Colors.white,
fontSize: 14.0,
),
),
],
),
),
),
Expanded(
child: ElevatedButton(
onPressed: () {
model.setFilteringCheck = true;
model.filterByPrice();
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.all(12.0),
primary: plpGredientOne,
onPrimary: plpGredientTwo,
onSurface: Colors.grey[400],
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(0),
),
),
child: Row(
children: [
Icon(
model.filterPriceCheck == 'price_down'
? LineAwesomeIcons.sort_amount_down
: LineAwesomeIcons.sort_amount_up,
color: Colors.white,
size: 25.0),
Text(
'Price',
style: TextStyle(
color: Colors.white,
fontSize: 14.0,
),
),
],
),
),
),
model.searchFilterStatus
? Expanded(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchView()));
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.all(12.0),
primary: plpGredientOne,
onPrimary: plpGredientTwo,
onSurface: Colors.grey[400],
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(0),
),
),
child: Row(
children: [
Icon(LineAwesomeIcons.times,
color: Colors.white, size: 25.0),
Text(
' Clear',
style: TextStyle(
color: Colors.white,
fontSize: 14.0,
),
),
],
),
),
)
: Expanded(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchView()));
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.all(12.0),
primary: plpGredientOne,
onPrimary: plpGredientTwo,
onSurface: Colors.grey[400],
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(0),
),
),
child: Row(
children: [
Icon(LineAwesomeIcons.search,
color: Colors.white, size: 25.0),
Text(
' Search',
style: TextStyle(
color: Colors.white,
fontSize: 14.0,
),
),
],
),
),
),
],
),
SizedBox(
height: 10,
),
Expanded(
child: new FutureBuilder(
future: model.getTheProperty(
priceSliderMin,
priceSliderMax,
areaSliderMin,
areaSliderMax,
beds,
baths,
chosenCity,
searchKeywords,
searchStatus,
searchType),
builder: (context, snapshot) {
if (snapshot.hasData && model.loadingShimmer == false) {
List myList = snapshot.data;
return ListView.builder(
controller: model.scrollController,
itemCount: myList.isEmpty ? 0 : myList.length,
itemBuilder: (context, index) {
return MyPropertyDetail(
propertyId: myList[index].propertyId,
propertyName: myList[index].title,
propertyImgUrl:
myList[index].propertyThumbnailUrl,
propertyCity: myList[index].propertyCity,
propertyAddress:
myList[index].propertyAddress,
propertyBed: myList[index].propertyBeds,
propertyBath: myList[index].propertyBaths,
propertyArea: myList[index].propertyArea +
' ' +
myList[index].propertyAreaPostfix,
propertyRate:
myList[index].propertyPricePrefix +
' ' +
myList[index].propertyRate +
' ' +
myList[index].propertyPricePostfix,
propertyType: myList[index].propertyType,
propertyStatus: myList[index].propertyStatus,
propertyFeatured: myList[index].propertyLabel,
propertyDate: myList[index].propertyDate);
},
);
} else {
if (snapshot.hasError) {
if (snapshot.error is NoInternetException) {
NoInternetException noInternetException =
snapshot.error as NoInternetException;
return model
.showError(noInternetException.message);
}
if (snapshot.error is NoServiceFoundException) {
NoServiceFoundException noServiceFoundException =
snapshot.error as NoServiceFoundException;
return model
.showError(noServiceFoundException.message);
}
if (snapshot.error is InvalidFormatException) {
InvalidFormatException invalidFormatException =
snapshot.error as InvalidFormatException;
return model
.showError(invalidFormatException.message);
}
UnknownException unknownException =
snapshot.error as UnknownException;
return model.showError(unknownException.message);
} else {
return LoadingPost();
}
}
}),
),
],
);
}),
),
),
fireOnModelReadyOnce: true,
disposeViewModel: true,
onModelReady: (model) => model.initialise(),
viewModelBuilder: () => PropertyViewModel(),
);
}
}
enter image description here
Trying already for a couple of days to get document id of a document in Firestore from my Flutter app.
what I want is to update or delete document, but have to identify it first by his id.
I have that ID with other values like name, address, etc.., when I open Firestore.
Now I am trying to understand how to get document id into a variable, which I then use in my function to delete or update the document.
getDocIndex() {
var documentID = Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(documentID);
}
I understand that widget in a function is not usable. Maybe something with snapshot.data.... but its also marked as red.
This is my function which then should work:
deleteDocument(){
Firestore.instance.collection('Requests').document(documentID).delete();
}
enter image description here
enter image description here
If you know the values inside the document, you can use a where query to find all documents that have those parameters.
Firestore.instance.collection('requests').where('Document ID', isEqualTo: "ID")
.snapshots().listen(
(data) => print('grower ${data.documents[0]['name']}')
);
However, if you already have access to the document's data locally, you can pull the reference path from the document snapshot if you have stored it locally. It is only an issue of recovering that data from within your app at that point.
Thank you all! I've got it!
return ListTile(
title: Text(
'${snapshot.data[index].data['Name']}',
style: GoogleFonts.lexendDeca(),
),
subtitle: Text(
'${snapshot.data[index].data['Anfrage vom']}',
style: GoogleFonts.lexendDeca(),
),
onTap: () {
navigateToDetail(snapshot.data[index]);
keyID = snapshot.data[index].data['Document ID'];
print(keyID.toString());
Below I get in keyID the Document ID from field in a document. After that I can use the delete function with ID reference.
Firestore.instance.collection('Requests').document(keyID).delete();
getDocIndex() {
var document = Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(document.id);
}
getDocIndex() async {
var document = await Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(document.id);
}
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:kuechenrechner/card_widget.dart';
import 'package:kuechenrechner/gmaps.dart';
import 'package:geocoder/geocoder.dart';
import 'adminslogin.dart';
//final documentsRef = Firestore.instance.collection('Requests');
class Admins extends StatefulWidget {
#override
_AdminsState createState() => _AdminsState();
}
class _AdminsState extends State<Admins> {
/*geoConvert() async {
// Geocoding for Address
// final query = "1600 Amphiteatre Parkway, Mountain View";
var addresses = await Geocoder.local.findAddressesFromQuery(query);
var first = addresses.first;
print("${first.featureName} : ${first.coordinates}");
}
*/
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return AdminsLogin();
}));
}),
title: Text(
'Anfragen',
style: GoogleFonts.lexendDeca(),
),
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
setState(() {});
})
],
),
body: AdminsList(),
);
}
}
Future getPosts() async {
var firestore = Firestore.instance;
QuerySnapshot qn = await firestore
.collection("Requests")
.orderBy('Anfrage vom')
.getDocuments();
return qn.documents;
}
//Abfrage DocumentID
getDocIndex() async {
/* var documentID = Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(documentID);
*/
var document = await Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(document.id);
}
class AdminsList extends StatefulWidget {
#override
_AdminsListState createState() => _AdminsListState();
}
class _AdminsListState extends State<AdminsList> {
navigateToDetail(DocumentSnapshot post) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => AdminsDetails(post: post)));
}
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: getPosts(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: Text('Loading...'),
);
} else {
return ListView.separated(
reverse: true,
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return ListTile(
title: Text(
'${snapshot.data[index].data['Name']}',
style: GoogleFonts.lexendDeca(),
),
subtitle: Text(
'${snapshot.data[index].data['Anfrage vom']}',
style: GoogleFonts.lexendDeca(),
),
onTap: () => navigateToDetail(snapshot.data[index]),
leading: Icon(
Icons.business_center,
color: Colors.blue,
),
trailing: IconButton(
icon: Icon(Icons.sort),
onPressed: () {
getDocIndex();
}),
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider();
},
);
}
}),
);
}
}
class AdminsDetails extends StatefulWidget {
final DocumentSnapshot post;
AdminsDetails({this.post});
#override
_AdminsDetailsState createState() => _AdminsDetailsState();
}
String keyID;
class _AdminsDetailsState extends State<AdminsDetails> {
//Anfragen löschen intern
deleteDocument() async {
/* CollectionReference collectionReference =
Firestore.instance.collection("Requests");
QuerySnapshot querySnapshot = await collectionReference.getDocuments();
querySnapshot.documents[0].reference.delete();
*/
Firestore.instance.collection('Requests').document(keyID).delete();
}
//Anfragen intern ändern, anpassen! Button in der Appbar!
TextEditingController adminComment = TextEditingController();
updateData() async {
CollectionReference collectionReference =
Firestore.instance.collection("Requests");
QuerySnapshot querySnapshot = await collectionReference.getDocuments();
querySnapshot.documents[0].reference
.updateData({'Administrator Anmerkung': adminComment.text});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Anfrage von ${widget.post.data["Name"]}',
style: GoogleFonts.lexendDeca(),
),
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
setState(() {
updateData();
});
})
],
),
body: SingleChildScrollView(
child: Container(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Kontaktdaten des Kunden: ',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w200),
),
TextButton(
onPressed: () => customLaunch(
'mailto:${widget.post.data["Email"]}?subject=Feed%20back&body=Write your%20feedback'),
child: Text('Email: ${widget.post.data["Email"]}',
style: TextStyle(fontSize: 18)),
),
SizedBox(
child: Container(color: Colors.amber),
),
TextButton(
onPressed: () =>
customLaunch('tel: ${widget.post.data["Telefon"]}'),
child: Text('Telefon: ${widget.post.data["Telefon"]}',
style: TextStyle(fontSize: 18)),
),
Divider(),
Text(
'Kundenanschrift: ',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w200),
),
SizedBox(
height: 8.0,
),
TextButton(
child: Text('${widget.post.data["Anschrift"]}'),
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return MapsDemo();
})),
),
SizedBox(
height: 8.0,
),
Divider(),
Text(
'Kommentar:',
style: TextStyle(fontWeight: FontWeight.w200, fontSize: 18.0),
),
SizedBox(
height: 16.0,
),
Text('${widget.post.data["Kommentar"]}',
style: GoogleFonts.lexendDeca()),
Divider(),
Text(
'Details der Anfrage: ',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w200),
),
SizedBox(
height: 16.0,
),
Text('Anfrage vom: ${widget.post.data["Anfrage vom"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text('Küchenlänge: ${widget.post.data["Küchenlaenge"]} Meter',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text('Hängeschränke: ${widget.post.data["Hängeschränke"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Gebrauchte Küche: ${widget.post.data["Gebrauchte Küche"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Arbeitsplatte schneiden: ${widget.post.data["Arbeitsplatte bearbeiten"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Anschluss Waschmaschine: ${widget.post.data["Anschluss WaMa"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Anschluss Spülmaschine: ${widget.post.data["Anschluss Spuel"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Anschluss Herd: ${widget.post.data["Anschluss Herd"]}',
style: GoogleFonts.lexendDeca(),
),
SizedBox(
height: 16.0,
),
Text(
'Wunschdatum Montage: ${widget.post.data["Wunschdatum"]}',
style: GoogleFonts.lexendDeca(),
),
SizedBox(
height: 16.0,
),
Text(
'Gesamt geschätzt: ${widget.post.data["Gesamt geschätzt"]} Euro',
style: GoogleFonts.lexendDeca(
fontSize: 18,
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline),
),
TextField(
controller: adminComment,
decoration: InputDecoration(
hintText: 'Anmerkung Administrator:',
)),
//Kommentare von Administratoren:
Container(
child: Text(
'${widget.post.data['Administrator Anmerkung']}',
style: GoogleFonts.lexendDeca(),
)),
Column(
children: [
Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red,
),
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return AlertDialog(
title: Text('Diese Anfrage wirklich löschen?',
style: GoogleFonts.lexendDeca()),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Abbrechen')),
TextButton(
onPressed: () async {
setState(() {
deleteDocument();
Navigator.push(context,
MaterialPageRoute(builder:
(BuildContext context) {
return Admins();
}));
});
},
child: Text('Löschen')),
],
);
}));
},
child: Text('Anfrage löschen')),
),
],
),
],
),
),
),
),
);
}
}
recently I have followed a Youtube tutorial where it shows how to add product item to cart. But in the video, it didn't show how to delete an item from cart. Video link: https://www.youtube.com/watch?v=K8d3qqbP3qk
ProductModel.dart
class ProductModel{
String name;
int price;
String image;
ProductModel(String name, int price, String image){
this.name = name;
this.price = price;
this.image = image;
}
}
ProductScreen.dart
import 'package:flutter/material.dart';
import '../ProductModel.dart';
import 'package:ecommerce_int2/models/product.dart';
class ProductScreen2 extends StatelessWidget {
final ValueSetter<ProductModel> _valueSetter;
ProductScreen2(this._valueSetter);
List<ProductModel> products = [
ProductModel("Grey Jacket", 100, 'assets/jacket_1.png'),
ProductModel("Brown Pants", 60, 'assets/jeans_9.png'),
ProductModel("Grey Pants", 50, 'assets/jeans_6.png'),
ProductModel("Orange Pants", 70, 'assets/jeans_8.png'),
ProductModel("Long Jeans", 80, 'assets/jeans_2.png'),
ProductModel("Black and Blue Cap", 40, 'assets/cap_2.png'),
ProductModel("Black Cap", 30, 'assets/cap_6.png'),
ProductModel("Red Cap", 35, 'assets/cap_4.png'),
];
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.separated(
itemBuilder: (context, index){
return ListTile(
leading: Image.asset(
products[index].image,
width: 100,
height: 100,
fit: BoxFit.fitWidth,
),
title: Text(products[index].name),
trailing: Text("\RM${products[index].price}", style: TextStyle(color: Colors.redAccent, fontSize: 20, fontWeight: FontWeight.w500),),
onTap: (){
_valueSetter(products[index]);
},
);
},
separatorBuilder: (context, index){
return Divider();
},
itemCount: products.length
),
);
}
}
CheckoutScreen.dart
import 'package:flutter/material.dart';
import 'package:ecommerce_int2/screens/address/add_address_page.dart';
import 'package:device_apps/device_apps.dart';
class CheckoutScreen extends StatelessWidget {
final cart;
final sum;
CheckoutScreen(this.cart, this.sum);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ListView.separated(
itemBuilder: (context, index){
return ListTile(
title: Text(cart[index].name),
trailing: Text("\RM${cart[index].price}", style: TextStyle(color: Colors.redAccent, fontSize: 20, fontWeight: FontWeight.w500),),
onTap: (){
},
);
},
separatorBuilder: (context, index){
return Divider();
},
itemCount: cart.length,
shrinkWrap: true,
),
Divider(),
Text("Total : \RM$sum", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500), textAlign: TextAlign.right,),
SizedBox(
height: 20,
),
Text("Remarks", style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),),
TextFormField(
decoration: InputDecoration(
hintText: ('Example: Red Cap: Free Size, Grey Jacket: UK, M Size'),
),
maxLines: 5,
),
SizedBox(
height: 50,
),
RaisedButton(
color: Theme.of(context).accentColor,
child: Text('Buy Now',style: TextStyle(color: Colors.white, fontSize: 20)),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (_) => AddAddressPage()));
},
),
RaisedButton(
color: Theme.of(context).accentColor,
child: Text('Try Out',style: TextStyle(color: Colors.white, fontSize: 20)),
onPressed: () => DeviceApps.openApp('com.DefaultCompany.clothestryingfunction2'),
),
],
),
);
}
}
add_to_cart.dart
import 'package:ecommerce_int2/ProductModel.dart';
import 'package:ecommerce_int2/screens/CheckoutScreen.dart';
import 'package:ecommerce_int2/screens/ProductScreen.dart';
import 'package:flutter/material.dart';
class CartApp extends StatefulWidget {
#override
_CartAppState createState() => _CartAppState();
}
class _CartAppState extends State<CartApp> {
List<ProductModel> cart = [];
int sum = 0;
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text("Add To Cart"),
bottom: TabBar(
tabs: <Widget>[
Tab(text: "Products",),
Tab(text: "Cart",),
],
),
),
body: TabBarView(
children: <Widget>[
ProductScreen2((selectedProduct){
setState(() {
cart.add(selectedProduct);//update
sum = 0;
cart.forEach((item){
sum = sum + item.price;
});
});
}),
CheckoutScreen(cart, sum),
],
),
),
);
}
}
The goal is to remove the selected item from cart and minus the selected item's price from the sum. Can anyone tell me how to do that?
First, you need to add a callback in the CheckoutScreen:
class CheckoutScreen extends StatelessWidget {
final cart;
final sum;
final ValueSetter<ProductModel> _valueDeleter;
CheckoutScreen(this.cart, this.sum, this._valueDeleter);
...
After that, add the callback function when using it in the TabBarView in CartApp:
CheckoutScreen(cart, sum, (deleteProduct) {
setState(() {
// Use this loop instead of cart.removeWhere() to delete 1 item at a time
for (var i = 0; i < cart.length; i++) {
if (cart[i].name == deleteProduct.name) {
cart.removeAt(i);
break;
}
}
sum = 0;
cart.forEach((item) {
sum = sum + item.price;
});
});
}),
Finally, add a button in the ListTile within CheckoutScreen to initiate the delete action (I'm using a Row in title here for simplicity):
ListTile(
...
title: Row(
children: [
IconButton(
icon: Icon(Icons.delete),
color: Colors.red,
onPressed: () => _valueDeleter(cart[index]),
),
Text(cart[index].name),
],
),
trailing: Text(
...
Good Morning,
I'm trying to put a Carousel on the home page looking for Firebase data, but for some reason, the first time I load the application it appears the message below:
════════ Exception caught by widgets library ═════════════════════════════════════ ══════════════════
The following _CastError was thrown building DotsIndicator (animation: PageController # 734f9 (one client, offset 0.0), dirty, state: _AnimatedState # 636ca):
Null check operator used on a null value
and the screen looks like this:
After giving a hot reload the error continues to appear, but the image is loaded successfully, any tips of what I can do?
HomeManager:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provantagens_app/models/section.dart';
class HomeManager extends ChangeNotifier{
HomeManager({this.images}){
_loadSections();
images = images ?? [];
}
void addSection(Section section){
_editingSections.add(section);
notifyListeners();
}
final List<dynamic> _sections = [];
List<String> images;
List<dynamic> newImages;
List<dynamic> _editingSections = [];
bool editing = false;
bool loading = false;
int index, totalItems;
final Firestore firestore = Firestore.instance;
Future<void> _loadSections() async{
loading = true;
firestore.collection('home').snapshots().listen((snapshot){
_sections.clear();
for(final DocumentSnapshot document in snapshot.documents){
_sections.add( Section.fromDocument(document));
images = List<String>.from(document.data['images'] as List<dynamic>);
}
});
loading = false;
notifyListeners();
}
List<dynamic> get sections {
if(editing)
return _editingSections;
else
return _sections;
}
void enterEditing({Section section}){
editing = true;
_editingSections = _sections.map((s) => s.clone()).toList();
defineIndex(section: section);
notifyListeners();
}
void saveEditing() async{
bool valid = true;
for(final section in _editingSections){
if(!section.valid()) valid = false;
}
if(!valid) return;
loading = true;
notifyListeners();
for(final section in _editingSections){
await section.save();
}
for(final section in List.from(_sections)){
if(!_editingSections.any((s) => s.id == section.id)){
await section.delete();
}
}
loading = false;
editing = false;
notifyListeners();
}
void discardEditing(){
editing = false;
notifyListeners();
}
void removeSection(Section section){
_editingSections.remove(section);
notifyListeners();
}
void onMoveUp(Section section){
int index = _editingSections.indexOf(section);
if(index != 0) {
_editingSections.remove(section);
_editingSections.insert(index - 1, section);
index = _editingSections.indexOf(section);
}
notifyListeners();
}
HomeManager clone(){
return HomeManager(
images: List.from(images),
);
}
void onMoveDown(Section section){
index = _editingSections.indexOf(section);
totalItems = _editingSections.length;
if(index < totalItems - 1){
_editingSections.remove(section);
_editingSections.insert(index + 1, section);
index = _editingSections.indexOf(section);
}else{
}
notifyListeners();
}
void defineIndex({Section section}){
index = _editingSections.indexOf(section);
totalItems = _editingSections.length;
notifyListeners();
}
}
HomeScreen:
import 'package:carousel_pro/carousel_pro.dart';
import 'package:flutter/material.dart';
import 'package:provantagens_app/commom/custom_drawer.dart';
import 'package:provantagens_app/commom/custom_icons_icons.dart';
import 'package:provantagens_app/models/home_manager.dart';
import 'package:provantagens_app/models/section.dart';
import 'package:provantagens_app/screens/home/components/home_carousel.dart';
import 'package:provantagens_app/screens/home/components/menu_icon_tile.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
// ignore: must_be_immutable
class HomeScreen extends StatelessWidget {
HomeManager homeManager;
Section section;
List<Widget> get children => null;
String videoUrl = 'https://www.youtube.com/watch?v=VFnDo3JUzjs';
int index;
var _tapPosition;
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(colors: const [
Colors.white,
Colors.white,
], begin: Alignment.topCenter, end: Alignment.bottomCenter)),
child: Scaffold(
backgroundColor: Colors.transparent,
drawer: CustomDrawer(),
appBar: AppBar(
backgroundColor: Colors.transparent,
iconTheme: IconThemeData(color: Colors.black),
title: Text('Página inicial', style: TextStyle(color: Color.fromARGB(255, 30, 158, 8))),
centerTitle: true,
actions: <Widget>[
Divider(),
],
),
body: Consumer<HomeManager>(
builder: (_, homeManager, __){
return ListView(children: <Widget>[
AspectRatio(
aspectRatio: 1,
child:HomeCarousel(homeManager),
),
Column(
children: <Widget>[
Container(
height: 50,
),
Divider(
color: Colors.black,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Padding(
padding: const EdgeInsets.only(left:12.0),
child: MenuIconTile(title: 'Parceiros', iconData: Icons.apartment, page: 1,),
),
Padding(
padding: const EdgeInsets.only(left:7.0),
child: MenuIconTile(title: 'Beneficios', iconData: Icons.card_giftcard, page: 2,),
),
Padding(
padding: const EdgeInsets.only(right:3.0),
child: MenuIconTile(title: 'Suporte', iconData: Icons.help_outline, page: 6,),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
MenuIconTile(iconData: Icons.assignment,
title: 'Dados pessoais',
page: 3)
,
MenuIconTile(iconData: Icons.credit_card_outlined,
title: 'Meu cartão',
page: 4)
,
MenuIconTile(iconData: Icons.account_balance_wallet_outlined,
title: 'Pagamento',
page: 5,)
,
],
),
Divider(
color: Colors.black,
),
Container(
height: 50,
),
Consumer<HomeManager>(
builder: (_, sec, __){
return RaisedButton(
child: Text('Teste'),
onPressed: (){
Navigator.of(context)
.pushReplacementNamed('/teste',
arguments: sec);
},
);
},
),
Text('Saiba onde usar o seu', style: TextStyle(color: Colors.black, fontSize: 20),),
Text('Cartão Pró Vantagens', style: TextStyle(color: Color.fromARGB(255, 30, 158, 8), fontSize: 30),),
AspectRatio(
aspectRatio: 1,
child: Image.network(
'https://static.wixstatic.com/media/d170e1_80b5f6510f5841c19046f1ed5bca71e4~mv2.png/v1/fill/w_745,h_595,al_c,q_90,usm_0.66_1.00_0.01/Arte_Cart%C3%83%C2%B5es.webp',
fit: BoxFit.fill,
),
),
Divider(),
Container(
height: 150,
child: Row(
children: [
AspectRatio(
aspectRatio: 1,
child: Image.network(
'https://static.wixstatic.com/media/d170e1_486dd638987b4ef48d12a4bafee20e80~mv2.png/v1/fill/w_684,h_547,al_c,q_90,usm_0.66_1.00_0.01/Arte_Cart%C3%83%C2%B5es_2.webp',
fit: BoxFit.fill,
),
),
Padding(
padding: const EdgeInsets.only(left:20.0),
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: 'Adquira já o seu',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
TextSpan(
text: '\n\CARTÃO PRÓ VANTAGENS',
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 30, 158, 8)),
),
]),
),
),
],
),
),
Divider(),
tableBeneficios(),
Divider(),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(
'O cartão Pró-Vantagens é sediado na cidade de Hortolândia/SP e já está no mercado há mais de 3 anos. Somos um time de profissionais apaixonados por gestão de benefícios e empenhados em gerar o máximo de valor para os conveniados.'),
FlatButton(
onPressed: () {
launch(
'https://www.youtube.com/watch?v=VFnDo3JUzjs');
},
child: Text('SAIBA MAIS')),
],
),
),
Container(
color: Color.fromARGB(255, 105, 190, 90),
child: Column(
children: <Widget>[
Row(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
'© 2020 todos os direitos reservados a Cartão Pró Vantagens.',
style: TextStyle(fontSize: 10),
),
)
],
),
Divider(),
Row(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
'Rua Luís Camilo de Camargo, 175 -\n\Centro, Hortolândia (piso superior)',
style: TextStyle(fontSize: 10),
),
),
Padding(
padding: const EdgeInsets.only(left: 16),
child: IconButton(
icon: Icon(CustomIcons.facebook),
color: Colors.black,
onPressed: () {
launch(
'https://www.facebook.com/provantagens/');
},
),
),
Padding(
padding: const EdgeInsets.only(left: 16),
child: IconButton(
icon: Icon(CustomIcons.instagram),
color: Colors.black,
onPressed: () {
launch(
'https://www.instagram.com/cartaoprovantagens/');
},
),
),
],
),
],
),
)
],
),
]);
},
)
),
);
}
tableBeneficios() {
return Table(
defaultColumnWidth: FlexColumnWidth(120.0),
border: TableBorder(
horizontalInside: BorderSide(
color: Colors.black,
style: BorderStyle.solid,
width: 1.0,
),
verticalInside: BorderSide(
color: Colors.black,
style: BorderStyle.solid,
width: 1.0,
),
),
children: [
_criarTituloTable(",Plus, Premium"),
_criarLinhaTable("Seguro de vida\n\(Morte Acidental),X,X"),
_criarLinhaTable("Seguro de Vida\n\(Qualquer natureza),,X"),
_criarLinhaTable("Invalidez Total e Parcial,X,X"),
_criarLinhaTable("Assistência Residencial,X,X"),
_criarLinhaTable("Assistência Funeral,X,X"),
_criarLinhaTable("Assistência Pet,X,X"),
_criarLinhaTable("Assistência Natalidade,X,X"),
_criarLinhaTable("Assistência Eletroassist,X,X"),
_criarLinhaTable("Assistência Alimentação,X,X"),
_criarLinhaTable("Descontos em Parceiros,X,X"),
],
);
}
_criarLinhaTable(String listaNomes) {
return TableRow(
children: listaNomes.split(',').map((name) {
return Container(
alignment: Alignment.center,
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: name != "X" ? '' : 'X',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
TextSpan(
text: name != 'X' ? name : '',
style: TextStyle(
fontSize: 10.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 30, 158, 8)),
),
]),
),
padding: EdgeInsets.all(8.0),
);
}).toList(),
);
}
_criarTituloTable(String listaNomes) {
return TableRow(
children: listaNomes.split(',').map((name) {
return Container(
alignment: Alignment.center,
child: RichText(
text: TextSpan(children: <TextSpan>[
TextSpan(
text: name == "" ? '' : 'Plano ',
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
TextSpan(
text: name,
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 30, 158, 8)),
),
]),
),
padding: EdgeInsets.all(8.0),
);
}).toList(),
);
}
void _storePosition(TapDownDetails details) {
_tapPosition = details.globalPosition;
}
}
I forked the library to create a custom carousel for my company's project, and since we updated flutter to 2.x we had the same problem.
To fix this just update boolean expressions like
if(carouselState.pageController.position.minScrollExtent == null ||
carouselState.pageController.position.maxScrollExtent == null){ ... }
to
if(!carouselState.pageController.position.hasContentDimensions){ ... }
Here is flutter's github reference.
This worked for me
So I edited scrollposition.dart package
from line 133
#override
//double get minScrollExtent => _minScrollExtent!;
// double? _minScrollExtent;
double get minScrollExtent {
if (_minScrollExtent == null) {
_minScrollExtent = 0.0;
}
return double.parse(_minScrollExtent.toString());
}
double? _minScrollExtent;
#override
// double get maxScrollExtent => _maxScrollExtent!;
// double? _maxScrollExtent;
double get maxScrollExtent {
if (_maxScrollExtent == null) {
_maxScrollExtent = 0.0;
}
return double.parse(_maxScrollExtent.toString());
}
double? _maxScrollExtent;
Just upgrade to ^3.0.0 Check here https://pub.dev/packages/carousel_slider
I faced the same issue.
This is how I solved it
class PlansPage extends StatefulWidget {
const PlansPage({Key? key}) : super(key: key);
#override
State<PlansPage> createState() => _PlansPageState();
}
class _PlansPageState extends State<PlansPage> {
int _currentPage = 1;
late CarouselController carouselController;
#override
void initState() {
super.initState();
carouselController = CarouselController();
}
}
Then put initialization the carouselController inside the initState method I was able to use the methods jumpToPage(_currentPage ) and animateToPage(_currentPage) etc.
I use animateToPage inside GestureDetector in onTap.
onTap: () {
setState(() {
_currentPage = pageIndex;
});
carouselController.animateToPage(_currentPage);
},
I apologize in advance if this is inappropriate.
I solved the similar problem as follows. You can take advantage of the Boolean variable. I hope, help you.
child: !loading ? HomeCarousel(homeManager) : Center(child:ProgressIndicator()),
or
child: isLoading ? HomeCarousel(homeManager) : SplashScreen(),
class SplashScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Loading...')
),
);
}
}