How to pass API data value into the sfslider in Flutter? - android

How to pass the API data value into the sfslider if I pass the static value to the slider it can be draggable. But if I give the API data value directly it can drag but not update the new value and return to the API response value position.
I saw some of the solutions they said declare a static value outside of a widget, it works fine.
But I need to use API values, How to do it? Somebody can help me!
double _value = 40.0;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
FutureBuilder(
future: propertycall(),
// ignore: missing_return
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return SfSlider(
shouldAlwaysShowTooltip: true,
activeColor: secondarycolor,
min: snapshot.data["set-parameters"]["mortgage_interest_rate"]["min_value"],
max: snapshot.data["set-parameters"]["mortgage_interest_rate"]["max_value"],
value: _value, //issue occur here
// value:snapshot.data["set-parameters"]["mortgage_interest_rate"]
//["default_value"]
interval: snapshot.data["set-parameters"]["mortgage_interest_rate"]
["steps_value"],
showTicks: false,
showLabels: false,
enableTooltip: true,
numberFormat: NumberFormat(),
onChanged: (new_value) {
setState(() {
_value = new_value; // issues!!
//API value working but not able to drag slider,
//if I give static value from outside of a widget it works
// _value=snapshot.data["set-parameters"]["mortgage_interest_rate"]
//["default_value"]
},
);
},
),
},
},
);
),
),
);
}

Related

How do I build a searched list of users inside of an alert dialog?

I am currently attempting to make a user search list within an alert dialog, which will query users from the project's database based on the user's search input. I am doing this in Android Studio, using Flutter's native language (Dart) and Firebase Cloud Firestore. I have the search bar itself working, but for some reason, whenever I try to actually get the results from the database, my code will access the stream for the Streambuilder being used, but will never touch the actual builder, skipping it entirely. What exactly am I doing wrong here?
The function responsible for creating the alert dialog:
Future createAlertDialog(BuildContext context){
String userToSearch = '';
bool showUsers = false;
return showDialog(context: context, builder: (context){
return AlertDialog(
title: const Text("Search for a user:"),
content: StatefulBuilder(
builder: (context, setState) => Container(
child: CupertinoSearchTextField(
onChanged: (value) => {
setState(() {
showUsers = true;
}),
showUsers
? Expanded(
child: StreamBuilder(
stream: FireStoreMethods().searchUsers(value),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.connectionState ==
ConnectionState.none) {
return const Center(child: Text("Internet error"));
}
if (snapshot.hasError) {
return const Center(
child: Text("Something went wrong."),
);
}
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
return ListTile(
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ProfileScreen(
uid: snapshot.data!.docs[index]['uid'],
),
),
),
leading: CircleAvatar(
backgroundImage: NetworkImage(
snapshot.data!.docs[index]['photoUrl'],
),
radius: 16,
),
title: Text(
snapshot.data!.docs[index]['username'],
),
);
},
);
},
),
)
: const Expanded(child: Text("error"))
}
),
),
)
);
});
}
Function responsible for querying the database:
Stream searchUsers(String userInput){
String? currentUserID = FirebaseAuth.instance.currentUser?.uid;
//String? valueFromFirebase = '';
Stream s = FirebaseFirestore.instance.collection('users').where('username', isGreaterThanOrEqualTo: userInput).orderBy('username', descending: false).snapshots();
return s;
}
To be clear, I expected this code to create a list of users from the database, under the search bar in the alert dialog, containing the users that match the current input. I tried debugging, changing the positioning of certain lines of code, and comparing and contrasting my code to code I found all over the internet. The actual result that I received was the ability to use the search bar and have the input saved properly, but literally nothing happens after pressing enter. No list is rendered, no error is thrown, and the program continues like nothing happened.
You need to place StreamBuilder inside widget tree to make it visible. Currently having inside onChanged which is just callback method for textFiled.
Future createAlertDialog(BuildContext context) {
String userToSearch = '';
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text("Search for a user:"),
content: StatefulBuilder(
builder: (context, setState) => Column(
children: [
CupertinoSearchTextField(
onChanged: (value) {
setState(() {
userToSearch = value;
});
},
),
userToSearch.isNotEmpty
? Expanded(
child: StreamBuilder(
stream: FireStoreMethods().searchUsers(userToSearch),
...........
),
)
: Text("Empty")
],
),
),
);
});

Flutter - FutureBuilder sometimes gives me null distance on list of items

I get a list of items in home of my app.
In each one of this items I show the distance from the user and the item.
But in some item I have the distance and in others get null
This is my partial code:
class ProductHorizontalListItem extends StatelessWidget {
const ProductHorizontalListItem({
Key? key,
required this.product,
required this.coreTagKey,
this.onTap,
}) : super(key: key);
final Product product;
final Function? onTap;
final String coreTagKey;
#override
Widget build(BuildContext context) {
// print('***Tag*** $coreTagKey${PsConst.HERO_TAG__IMAGE}');
final PsValueHolder valueHolder =
Provider.of<PsValueHolder>(context, listen: false);
Future<double> getCurrentLocation() async {
Position position = await Geolocator.getCurrentPosition();
double lat = position.latitude;
double long = position.longitude;
final double distanceInMeters = Geolocator.distanceBetween(
double.parse(position.latitude.toString()),
double.parse(position.longitude.toString()),
double.parse(product.itemLocation!.lat.toString()),
double.parse(product.itemLocation!.lng.toString()),
);
return Future.value(distanceInMeters);
}
return FutureBuilder<double>(
future: getCurrentLocation(),
builder: (BuildContext context, AsyncSnapshot<double> snapshot) {
return InkWell(
onTap: onTap as void Function()?,
child: Container(
margin: const EdgeInsets.only(
left: PsDimens.space4, right: PsDimens.space4,
bottom: PsDimens.space12),
child: Text(
'${snapshot.data}',
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.caption!.copyWith(
color: PsColors.textColor3
)))
);});
}
}
Somebody can tell me why?
Thank you.
In the FutureBuilder you need to handle the different statuses of the future. With your current code you are building the widget on the very first snapshot. The reason of the null values is likely this, in most of the cases (if not every time) the first snapshot will not contain valid value.
Look at the following code about how to handle the different cases in a FutureBuilder:
return FutureBuilder<double>(
future: getCurrentLocation(),
builder: (BuildContext context, AsyncSnapshot<double> snapshot) {
// the future is not completed yet, so show a progress indicator
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
// the future is completed, but with an error, you have to handle it
if (snapshot.hasError) {
return...;
}
// the future is completed without error, but still you need
// to check whether it contains data, this is basically a check
// against null
if (snapshot.hasData) {
return...;
}
// if your code arrives here, it means the future is already
// completed, there was no error but the data returned is null
return...;
});

How to pass API data value into the sfslider range in Flutter?

How to pass the API data value into the sfslider if I pass the static value to the slider it can be draggable. But if I give the API data value directly it can drag but not update the new value and return to the API response value position.
I saw some of the solutions they said declare a static value outside of a widget, it works fine. But I need to use API values, How to do it? Somebody can help me!
double _value = 40.0;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
FutureBuilder(
future: propertycall(),
// ignore: missing_return
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return SfSlider(
shouldAlwaysShowTooltip: true,
activeColor: secondarycolor,
min: snapshot.data["set-parameters"]["mortgage_interest_rate"]["min_value"],
max: snapshot.data["set-parameters"]["mortgage_interest_rate"]["max_value"],
value: _value, //issue occur here
// value:snapshot.data["set-parameters"]["mortgage_interest_rate"]
//["default_value"]
interval: snapshot.data["set-parameters"]["mortgage_interest_rate"]
["steps_value"],
showTicks: false,
showLabels: false,
enableTooltip: true,
numberFormat: NumberFormat(),
onChanged: (new_value) {
setState(() {
_value = new_value; // issues!!
//API value working but not able to drag slider,
//if I give static value from outside of a widget it works
// _value=snapshot.data["set-parameters"]["mortgage_interest_rate"]
//["default_value"]
},
);
},
),
},
},
);
),
),
);
}
Make _value nullable and use it when not null.
double? _value = null;
...
value: _value ?? snapshot.data["set-parameters"]["mortgage_interest_rate"]
We have analyzed the code snippet and found that in the sample you set the static value from the API, and it does not get changed. It is always a static one, this is the reason for the point not getting dragged. For this, you just need to update the pointer value in API which is got from the onChanged callback and rebuild the slider control. Then only the point gets moved otherwise it will stay at the initial position and did not get dragged.

Flutter : How to store 'Favorited List' using shared_preference

This problem is about how to keep the favorited item in the List, even after I re-open the app.
I want to keep the favorited item in doaList into favDoa, even after I close my app and re-open it. I've seen about the shared_preference package in flutter to store data, but i confused how can i implement it into my app. Here is my code :
import 'package:flutter/material.dart';
import 'package:json_test/class/doa.dart';
import 'package:json_test/page/DoaPage.dart';
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
List<Doa> doaList;
List<Doa> favDoa;
bool _isInit = true;
Future<void> fetchDoa(BuildContext context) async {
final jsonstring =
await DefaultAssetBundle.of(context).loadString('assets/doa.json');
doaList = doaFromJson(jsonstring);
_isInit = false;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JSON Data test"),
),
body: Container(
child: FutureBuilder(
future: _isInit ? fetchDoa(context) : Future(null),
builder: (context, _) {
if (doaList.isNotEmpty) {
return ListView.builder(
itemCount: doaList.length,
itemBuilder: (BuildContext context, int index) {
Doa doa = doaList[index];
return Card(
margin: EdgeInsets.all(8),
child: ListTile(
title: Text(doa.judul),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) =>
DoaPage(
doa: doa,
)));
},
trailing: IconButton(
icon: Icon(
doa.fav
? Icons.favorite
: Icons.favorite_border,
color: doa.fav ? Colors.red : null,
),
onPressed: () => setState(() {
doa.fav = !doa.fav;
}),
)));
},
);
}
return CircularProgressIndicator();
})));
}
}
when I click the favorite icon in the list, it will be marked true in the "doa.fav". How can I implement the shared_preference package in my code to keep the doa.fav's data? Thank you so much for your answer :)
Try this:
Create a list of integer to store the Doa Ids, say you name it favoriteList
Each time you click the favorite button, add the Doa's id to favoriteList. Also save it to shared_preferences. It only support list of string, so you need to convert it first, something like:
List<String> stringFavoriteIds =
favoriteList.map((e) => e.toString()).toList();
SharedPrefs().favoriteIds = stringFavoriteIds ;
Next, each time you open the app, load SharedPrefs().favoriteIds to favoriteList
Compare the Doa Ids in favoriteList to your list of doa to mark Doa.fav to true for matching Ids.

App crashing if already one 'await' is active

I have an app for showing world times. I have a page for changing different locations around the world. It's a ListView.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: colorOne,
appBar: AppBar(
backgroundColor: Colors.black,
title: Text("Change location"),
centerTitle: true,
elevation: 0.0,
),
body: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.fromLTRB(5, 10, 5, 0),
itemCount: locations.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
onTap: () {
updateTime(index);
... rest code
As you can see, when I tap on ListTIle, it calls updateTime function
updateTime function:
void updateTime(index) async {
WorldTime instance = locations[index];
await instance.getTime();
Navigator.pop(context, {
"location": instance.location,
"flag": instance.flag,
"time": instance.time,
"date": instance.date,
"isDayTime": instance.isDayTime,
});
// obtain shared preferences
final savingLastLocation = await SharedPreferences.getInstance();
// set value
savingLastLocation.setString("location", instance.location);
savingLastLocation.setString("url", instance.url);
savingLastLocation.setString("flag", instance.flag);
}
If user starts spamming on tiles while awaiting for that function, app will either show full blank grey screen or drop red screen of death saying "boolean expression must be null".
How can I add some kind of loading screen/widget or prevent calling function again if it's already called once?
You can wrap your screen with IgnorePointer, which ignores any click.
Create bool variable.
bool ignore = false;
bool methodcalled = false; // new added line variable
Now wrap your scaffold with IgnorePointer.
return IgnorePointer(
ignoring: ignore,
child: Scaffold(
now, set ignore variable to true when user tap on any item.
onTap: () {
setState(() {
ignore = true;
});
updateTime(index).then((_){
setState(() {
ignore = false;
});
});
.... rest code
Add return in your method.
return 1
void updateTime(index) async {
if(!methodcalled){
methodcalled = !methodcalled;
}else{
return 0;
}
WorldTime instance = locations[index];
await instance.getTime();
Navigator.pop(context, {
"location": instance.location,
"flag": instance.flag,
"time": instance.time,
"date": instance.date,
"isDayTime": instance.isDayTime,
});
// obtain shared preferences
final savingLastLocation = await SharedPreferences.getInstance();
// set value
savingLastLocation.setString("location", instance.location);
savingLastLocation.setString("url", instance.url);
savingLastLocation.setString("flag", instance.flag);
methodcalled = !methodcalled; // added line
return 1; // added line
}
onPressed set like this
onPressed: () async {
dynamic result =
await Navigator.pushNamed(context, '/location');
if (result != null) {
setState(() {
data = {
'location': result['location'],
'flag': result['flag'],
'time': result['time'],
'isDateTime': result['isDateTime']
};
});
}
},

Categories

Resources