I am trying to send an API post through my flutter app:
The user inserts the log_weight through a textfield which inside table inside a Form. The row of the table are iterations from a list.
In my flutter app I have created a table that iterates through a list inside a form. So I am trying to get a log submission from each iteration.
Here is my api_serice.dart:
class APIService {
static var client = http.Client();
Future<http.Response> addLog(
int logWeight) async {
var url = Uri.parse(Config.apiURL +
Config.userAddlogAPI);
final response = await http.post(url, headers: {
HttpHeaders.authorizationHeader:
'Token xxxxxxxxxxxxxxxxxx',
}, body: {
'log_weight': logWeight,
});
}
Here is the exercises.dart:
class Exercises extends StatefulWidget {
#override
_ExercisesState createState() => _ExercisesState();
}
class _ExercisesState extends State<Exercises> {
late Map<String, int> arguments;
late int logWeight;
Here is the form:
Builder(builder: (context) {
return Form(
key: key,
child: Table(
children: [
const TableRow(children: [
Text(
'',
style: TextStyle(
fontSize: 15,
fontWeight:
FontWeight.bold,
color: Colors.black,
),
),
Text(
'Weight',
style: TextStyle(
fontSize: 15,
fontWeight:
FontWeight.bold,
color: Colors.black,
),
),
Text(
'New Weight',
style: TextStyle(
fontSize: 15,
fontWeight:
FontWeight.bold,
color: Colors.black,
),
),
Text(
'Submit',
style: TextStyle(
fontSize: 15,
fontWeight:
FontWeight.bold,
color: Colors.black,
),
)
]),
// Iterate over the breakdowns list and display the sequence information
for (var breakdown in snapshot
.data![index].breakdowns)
TableRow(children: [
Text(
'${breakdown.order}',
style: const TextStyle(
fontSize: 15,
color: Colors.black,
),
),
Text(
'${breakdown.weight}',
style: const TextStyle(
fontSize: 15,
color: Colors.black,
),
),
TextFormField(
decoration:
InputDecoration(
border:
InputBorder.none,
),
style: const TextStyle(
fontSize: 15,
color: Colors.black,
),
validator: (value) {
if (value == null) {
return 'Please enter a valid number';
}
return null;
},
onSaved: (value) {
logWeight =
int.parse(value!);
},
),
OutlinedButton(
onPressed: () async {
final Map<String, int>
arguments =
ModalRoute.of(
context)!
.settings
.arguments
as Map<String,
int>;
final int id =
arguments['id'] ??
0;
try {
if (Form.of(context)
?.validate() ==
true) {
Form.of(context)
?.save();
APIService.addLog(
id,
logWeight);
}
} catch (error) {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
'Error'),
content: Text(error
.toString()),
actions: [
OutlinedButton(
child: Text(
'OK'),
onPressed:
() {
Navigator.of(
context)
.pop();
}, ),],);},);}},
child: Text('Submit'),
),]),],),);
How can I fix my code so that I can send the log_weight. I keep getting E/flutter ( 4353): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: LateInitializationError: Field 'logWeight' has not been initialized.
The error is caused by late keyword. variables that are late must be initialized. Try not to use late that much.
Solution 1. make logWeight non-nullable and initialize it. Because your addLog method only allows non-nullable logWeight value.
int logWeight = 0;
Solution 2. make logWeight nullable and before calling the api, check if it's null or not. (If logWeight is required param for your api)
int? logWeight;
---
if(logWeight != null) {
APIService.addLog(id,logWeight);
}
or use validation
Solution 3. (If logWeight is not required param for your api) just make logWeight nullable and change your method to allow nullable logWeight value
int? logWeight;
---
class APIService {
static var client = http.Client();
Future<http.Response> addLog(
int? logWeight) async {
...
}
Related
From the 'Cel' class, I want to transfer data from the 'cel_lista', but only the 'cel' items enter image description here
`
here is the 'Cel' class code
class Cel {
late String cel;
late int wartosc = 1;
Cel({required this.cel, required this.wartosc});
static List<Cel> cel_lista() {
return [
Cel(cel: 'Schudnąć', wartosc: 500),
Cel(cel: 'utrzymać wagę', wartosc: 0),
Cel(cel: 'przytyć', wartosc: 500),
];
}
}
here is the DropdownButton code:
#override
State<Cel> createState() => _CelState();
}
class _CelState extends State<Cel> {
String dropdownValue = cel_lista.cel.first;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.black),
underline: Container(
height: 2,
color: Colors.white,
),
onChanged: (String? value) {
// This is called when the user selects an item.
setState(() {
dropdownValue = value!;
});
},
items: list.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}
`
I want to assign the variable 'imie' to text enter image description here
`
here is the User class code:
class User {
String? imie;
late int wiek;
late int waga;
late int wzrost;
User(
{required this.wiek,
required this.imie,
required this.waga,
required this.wzrost});
static List<User> dane_User() {
return [User(wiek: 22, imie: 'Monika', waga: 80, wzrost: 190)];
}
}
here is the TEXT item code
Text(
User.dane_User(imie!),
textAlign: TextAlign.center,
style: GoogleFonts.lato(
textStyle: TextStyle(
fontSize: 20.0,
height: 1.2,
color: Colors.white,
fontWeight: FontWeight.w500)),
)
`
I tried to call the object but unsuccessfully I lack knowledge
Here is the answer to your first question:
I have modified your class Cel, I have converted cel_lista method to a getter.
class Cel {
late String cel;
late int wartosc = 1;
Cel({required this.cel, required this.wartosc});
// converted method to a getter
static List<Cel> get cel_lista {
return [
Cel(cel: 'Schudnąć', wartosc: 500),
Cel(cel: 'utrzymać wagę', wartosc: 0),
Cel(cel: 'przytyć', wartosc: 500),
];
}
}
So the line that was giving error will be like this:
Before
String dropdownValue = cel_lista.cel.first;
After:
String dropdownValue = cel_lista.first.cel;
Answer to your second question
Convert your dane_User method to getter
class User {
String? imie;
late int wiek;
late int waga;
late int wzrost;
User(
{required this.wiek,
required this.imie,
required this.waga,
required this.wzrost});
static List<User> get dane_User {
return [User(wiek: 22, imie: 'Monika', waga: 80, wzrost: 190)];
}
}
Then your Text widget will be:
Before:
Text(
User.dane_User(imie!),
textAlign: TextAlign.center,
style: GoogleFonts.lato(
textStyle: TextStyle(
fontSize: 20.0,
height: 1.2,
color: Colors.white,
fontWeight: FontWeight.w500)),
)
After:
Text(
User.dane_User.first.imie,
textAlign: TextAlign.center,
style: GoogleFonts.lato(
textStyle: TextStyle(
fontSize: 20.0,
height: 1.2,
color: Colors.white,
fontWeight: FontWeight.w500)),
)
Please let me know if you have any question. Hope this helps you!
I am trying to make an in app purchase function,
and I faced this error: "you already own this item".
I found out that this is because the store considers the item as non-consumable item.
Unlike in_app_purchase package, this package doesn't support buyConsumable and buyNonConsumable functions.
so how to execute purchasing consumable item using that package?
also I assume that this is because of what's said above
items that are purchased keep being refunded automatically.
anyway my code is based on their example code but there it is:
storeController.dart
late StreamSubscription purchaseUpdatedSubscription;
late StreamSubscription purchaseErrorSubscription;
late StreamSubscription connectionSubscription;
// just followed the example
final List<String> productLists = Platform.isAndroid
? [
'point1',
'point2',
'point3',
]
: [
'point1',
'point2',
'point3'
];
String platformVersion = Platform.operatingSystem;
RxList<IAPItem> itemsList = <IAPItem>[].obs;
RxList<PurchasedItem> purchasesList = <PurchasedItem>[].obs;
#override
void onInit() async {
init();
await initPlatformState();
await getProduct();
await getPurchaseHistory();
}
Future<void> initPlatformState() async {
// Platform messages may fail, so we use a try/catch PlatformException.
// prepare
var result = await FlutterInappPurchase.instance.initialize();
print('result: $result');
// refresh items for android
try {
String msg = await FlutterInappPurchase.instance.consumeAll();
print('consumeAllItems: $msg');
} catch (err) {
print('consumeAllItems error: $err');
}
connectionSubscription =
FlutterInappPurchase.connectionUpdated.listen((connected) async {
print('connected: $connected');
});
purchaseUpdatedSubscription =
FlutterInappPurchase.purchaseUpdated.listen((productItem) async {
print('purchase-updated: $productItem');
await getPurchaseHistory();
});
purchaseErrorSubscription =
FlutterInappPurchase.purchaseError.listen((purchaseError)async {
print('purchase-error: $purchaseError');
});
}
Future getProduct() async {
List<IAPItem> items =
await FlutterInappPurchase.instance.getProducts(productLists);
for (var item in items) {
print('${item.toString()}');
itemsList.add(item);
}
}
Future getPurchaseHistory() async {
List<PurchasedItem>? items =
await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items!) {
print('${item.toString()}');
purchasesList.add(item);
}
}
and the productListWidget:
Widget productList(context) {
return GridView.builder(
shrinkWrap: true,
itemCount: controller.itemsList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
mainAxisExtent: Get.width * 0.4 + 70,
),
itemBuilder: (BuildContext context, int index) {
final item = controller.itemsList[index];
return
Container(
width: Get.width * 0.5,
alignment: Alignment.center,
color: Colors.transparent,
margin: const EdgeInsets.fromLTRB(10,0,10,0),
child: Stack(
children: [
Container(
color: const Color(0xff353535),
child: Column(
children: [
const SizedBox(height: 10),
const Text('Name', style: TextStyle(color: Colors.white)),
Text(
item.title ?? '',
style: const TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.w600,
fontStyle: FontStyle.normal,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
const Text('Desc', style: TextStyle(color: Colors.white)),
Text(
item.description ?? '',
style: const TextStyle(
color: Colors.grey,
fontSize: 13,
fontStyle: FontStyle.normal,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
const Text('Price', style: TextStyle(color: Colors.white)),
Text(
'${item.currency ?? ''} ${item.originalPrice}',
style: const TextStyle(
color: Colors.white,
fontSize: 12,
fontStyle: FontStyle.normal,
overflow: TextOverflow.ellipsis
)
),
const SizedBox(height: 10),
GestureDetector(
onTap: () async {
controller.requestPurchase(item);
},
child: Container(
alignment: Alignment.center,
width: 100,
height: 30,
color: const Color(0xffE1FD2E),
child: const Text('Purchase')
)
)
]
),
),
]
)
);
}
);
}
The StateNotifier with the gender does not update as the dropdown choice changes. I have these providers at the beginning of the file:
class GenderController extends StateNotifier<String>{
GenderController(String state) : super(state);
}
final profileProvider = FutureProvider.autoDispose((ref) {
final details = ref.watch(authToken);
var data = API().staffProfile(token: details['token'], staffID: details['ID']);
return data;
});
final gender = StateNotifierProvider.autoDispose((ref) => GenderController(""));
And this is what the build method looks like in a ConsumerWidget:
Widget build(BuildContext context, WidgetRef ref) {
var dropdownValue = ref.watch(gender);
final details = ref.watch(profileProvider);
return details.when(
data: (data){
dropdownValue = data['gender'];
// show the form with the info
return Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: formKey,
child: Column(
children: [
DropdownButton2(
isExpanded: true,
underline: Container(
color: kDarkGrey,
height: 1.0,
),
buttonPadding: const EdgeInsets.symmetric(vertical: 10.0),
hint: const CustomText(
text: "Gender",
fontSize: 16.0,
color: kBlack,
),
items: genders
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 16,
color: kBlack,
),
overflow: TextOverflow.ellipsis,
),
))
.toList(),
value: dropdownValue == "" ? null : dropdownValue.toString(),
onChanged: (value) {
ref.watch(gender.notifier).state = value!;
}
),
],
)
),
);
},
error: (err, _){
debugPrint(_.toString());
return const Center(
child: CustomText(
text: "Error getting profile",
),
);
},
loading: () => Center(
child: CircularProgressIndicator(
color: kPrimary,
),
)
);
}
I have also tried making the data type of the dropdownValue to be final and then assigning the data to it as ref.watch(gender.notifier).state = data['gender']; but that resulted in a "At least listener of the StateNotifier Instance of 'GenderController' threw an exception when the notifier tried to update its state." error. Please help.
In callbacks, you must call ref.read
ref.read(gender.notifier).state = data['gender'];
I figured it out. I initialised the dropdown before calling the details.when like this:
DropdownButton2 dropdown = DropdownButton2(
isExpanded: true,
underline: Container(
color: kDarkGrey,
height: 1.0,
),
buttonPadding: const EdgeInsets.symmetric(vertical: 10.0),
hint: const CustomText(
text: "Gender",
fontSize: 16.0,
color: kBlack,
),
items: genders
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 16,
color: kBlack,
),
overflow: TextOverflow.ellipsis,
),
))
.toList(),
value: dropdownValue == "" ? null : dropdownValue.toString(),
onChanged: (value) {
ref.read(gender.notifier).state = value!;
}
);
And then I updated the StateNotifier after the data was returned in the FutureProvider like so:
final profileProvider = FutureProvider.autoDispose((ref) async {
final details = ref.watch(authToken);
var data = await API().staffProfile(token: details['token'], staffID: details['ID']);
ref.read(gender.notifier).state = data['gender'];
return data;
});
Everything works fine now, and as it should.
Am using flutter bloc library and maintaining simple process for as per library for state management. In this code I am getting the state as expected but UI is not updating, its always returning the default state ui which a circle spinner . I have checked the state using bloc observer too. So need to know that what I have done wrong and need suggestions on that.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAppBar(context),
body: Column(
children: [
BlocBuilder<UserManageCubit, UserManageState>(
builder: (context, state) {
if (state is Initial) {
return const Center(
child: CircularProgressIndicator(
color: Colors.red,
));
}
if (state is UserDetailFetched) {
Column(
children: <Widget>[
Text(
'${state.userDetails.name}'.toUpperCase(),
style: kNavyTextStyleNormal.copyWith(
fontSize: 18.sp,
),
),
Text(
'${state.userDetails.email}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
'${state.userDetails.phone}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
'Registered on ${DateTimeUtils.format(
DateTimeUtils.fromString(state.userDetails.createdAt!),
).split("-")[0]}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
color: go11ThemeGreen,
),
),
SizedBox(height: 16.h),
],
);
}
return CircularProgressIndicator(
color: Colors.amber,
);
},
),
],
),
);
}
Calling bloc
#override
void initState() {
BlocProvider.of<UserManageCubit>(context).getUserDetails(widget.userId);
super.initState();
}
#Cubit impl
UserManageCubit({required this.userManageRepo})
: super(const UserManageState.initial());
void getUserDetails(int userId) async {
final FormData formData = FormData.fromMap({
'user_id': userId,
});
final Either<Failure, UserDetailsResponse> userDetailResponseEither =
await userManageRepo.getUserDetails(formData);
emit(const UserManageState.loading());
userDetailResponseEither.fold(
(failure) => {
emit(
UserManageState.loadFailure(
errorObject:
ErrorObject.mapFailureToErrorObject(failure: failure),
),
)
},
(response) => {
emit(
UserManageState.userDetailFetched(
userDetails: response.userDetails),
),
});
}
#state class
#freezed
class UserManageState with _$UserManageState {
const factory UserManageState.initial() = Initial;
const factory UserManageState.loading() = Loading;
const factory UserManageState.loadFailure({
required ErrorObject errorObject,
}) = LoadFailure;
const factory UserManageState.userDetailFetched(
{required UserDetails userDetails,
#Default(0) int currentDocType,
#Default(0) int currentCancelType}) = UserDetailFetched;
}
You are not returning your column
if (state is UserDetailFetched) {
return Column(
children: <Widget>[
Text(
'${state.userDetails.name}'.toUpperCase(),
style: kNavyTextStyleNormal.copyWith(
fontSize: 18.sp,
),
),
Text(
'${state.userDetails.email}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
'${state.userDetails.phone}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
'Registered on ${DateTimeUtils.format(
DateTimeUtils.fromString(state.userDetails.createdAt!),
).split("-")[0]}',
style: kNavyTextStyleNormal.copyWith(
fontWeight: FontWeight.bold,
color: go11ThemeGreen,
),
),
SizedBox(height: 16.h),
],
);
}
I try to add dynamic links in my app. First I add firebase dynamic link package to my app, and did all firebase configuration.
My final goal is to give a gift to the user who share the link with a coin for each installation did with his share link
here is my current implementation who give gift for the user who clic on the link but not ( I think) for the user who share the link.
class parrainage extends StatefulWidget {
#override
_parrainageState createState() => _parrainageState();
}
class _parrainageState extends State<parrainage> {
int referral_gift=0;
String _linkMessage;
bool _isCreatingLink = false;
String _testString =
"Fais un appuis long sur le lien pour le copier";
#override
void initState() {
super.initState();
initDynamicLinks();
}
void initDynamicLinks() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
referral_gift = prefs.getInt('referral_gift')??0;
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
referral_gift=referral_gift+1;
prefs.setInt('referral_gift', referral_gift);
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
referral_gift=referral_gift+1;
prefs.setInt('referral_gift', referral_gift);
}
}
Future<void> _createDynamicLink(bool short) async {
setState(() {
_isCreatingLink = true;
});
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://XXXXX.page.link/XXXX',
link: Uri.parse('https://XXXXXXXX.page.link/'),
androidParameters: AndroidParameters(
packageName: 'XXXXXXXXXXXXX',
minimumVersion: 0,
),
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.short,
),
iosParameters: IosParameters(
bundleId: 'XXXXXXXXXXXXX',
minimumVersion: '0',
),
socialMetaTagParameters: SocialMetaTagParameters(
title: 'XXXXXXX',
description: 'Débloque une fonction premium',
),
);
Uri url;
if (short) {
final ShortDynamicLink shortLink = await parameters.buildShortLink();
url = shortLink.shortUrl;
} else {
url = await parameters.buildUrl();
}
setState(() {
_linkMessage = url.toString();
_isCreatingLink = false;
});
}
#override
Widget build(BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
title: Text(("Parrainage"),textAlign: TextAlign.center, style: TextStyle(color: Colors.black, fontWeight: FontWeight.w600, fontSize: SizeConfig.safeBlockHorizontal * 7.0)),
content:
Padding(
padding: const EdgeInsets.all(16),
child:
new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text("XXXXXX",textAlign: TextAlign.center, style: TextStyle(color: Colors.black, fontWeight: FontWeight.w400, fontSize: SizeConfig.safeBlockHorizontal * 4)),
new Text("$referral_gift",textAlign: TextAlign.center, style: TextStyle(color: Colors.black, fontWeight: FontWeight.w800, fontSize: SizeConfig.safeBlockHorizontal * 5)),
new RaisedButton(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
elevation: 5,
highlightElevation: 10,
color:Color(0xffff9a7b),
splashColor: Color(0xffff9a7b),
child : Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text("Créer un lien",textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontWeight: FontWeight.w800, fontSize: SizeConfig.safeBlockHorizontal * 5)),
new Container (
padding: const EdgeInsets.only(left:0),
child: new Icon(
Icons.arrow_forward_ios,
color: Colors.white,
size: 20.0,
),),
],
),
padding: const EdgeInsets.all (15.0),
onPressed:
!_isCreatingLink
? () => _createDynamicLink(false)
: null,
),
InkWell(
child: Text(
_linkMessage ?? '',
style: const TextStyle(color: Colors.blue),
),
onTap: () async {
if (_linkMessage != null) {
await launch(_linkMessage);
}
},
onLongPress: () {
Clipboard.setData(ClipboardData(text: _linkMessage));
Scaffold.of(context).showSnackBar(
const SnackBar(content: Text("Lien copié, plus qu'à le partager")),
);
},
),
Text(_linkMessage == null ? '' : _testString)
]
),
),
);
}
}
I will suggest you to add firebase auth in your application and you can manage your points on server not locally , as you are using shared preference it will only store data till application is installed not always . After application is unistall all points earned by user will be removed or equals to 0 .