hope you doin' well
I'm a newbie to flutter and I'm working on a basic weather app as a starter. now, somehow everything is okay, except the city name. I don't know how to implement city search feature and get data from api based on the location. In my code, I defined city name manually.
here is my code:
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:hava_chitor/Carousel.dart';
import 'package:hava_chitor/UnderCarousel.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var temp;
var name;
var humidity;
var description;
var city = 'London';
CarouselController buttonCarouselController = CarouselController();
Future getWeather() async {
http.Response response = await http.get(
"http://api.openweathermap.org/data/2.5/weather?q=$city&units=metric&appid=apikey");
var results = jsonDecode(response.body);
setState(() {
this.temp = results['main']['temp'];
this.name = results['name'];
this.humidity = results['main']['humidity'];
this.description = results['weather'][0]['main'];
});
}
#override
void initState() {
super.initState();
this.getWeather();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hava Chitor?',
theme: ThemeData(
primaryColor: Color(0xff424242),
),
home: Scaffold(
drawer: Drawer(),
appBar: AppBar(
actions: [
Padding(
padding: const EdgeInsets.all(15),
child: GestureDetector(
onTap: () {
print('kir');
},
child: Icon(
Icons.add_circle_outline,
color: Color(0xff5d5f64),
),
),
)
],
backgroundColor: Colors.transparent,
elevation: 0,
iconTheme: IconThemeData(color: Color(0xff5d5f64)),
title: Text(
'Hava Chitor?',
style: TextStyle(
color: Color(0xff5d5f64),
fontFamily: 'Sans',
fontWeight: FontWeight.w700),
),
centerTitle: true,
),
backgroundColor: Colors.white,
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 1.0),
child: Column(
children: [
Carousel(name),
UnderCarousel(temp, description, humidity),
],
),
),
),
);
}
}
you need to add a TextField and a TextFieldController and call the function getWeather when the user finish writing the city name, something like this
String city;
TextEditingController textEditingController = TextEditingController();
TextField(
controller: textEditingController,
onSubmitted: (value){
city = textEditingController.text;
getWeather();
},
),
what you need to do is add TextField for the user to input the city name.
the way you can do that is shown before. The next thing you have to do is write a function to fetch weather data with city name.
var url =
'http://api.openweathermap.org/data/2.5/weather?q=\$city&units=metric&appid=apikey';
class CityWeatherData {
final String city, temprateure, humidity; //...
CityWeatherData({
this.city,
this.temprateure,
this.humidity,
// ...
});
factory CityWeatherData.fromJson(Map<String, dynamic> json) {
return CityWeatherData(
city: json['city'],
humidity: json['city']['humidity'],
temprateure: json['city']['temp'],
// ...
);
}
}
Future<CityWeatherData> fetchWeatherDataBycity() async {
final response = await http.get(url);
if (response.statusCode == 200) {
return CityWeatherData.fromJson(jsonDecode(response.body));
} else {
throw Exception('failed to fetch data.');
}
}
I depending on the JSON data you get you have to edit the fromjson method.
I hope this was helpful!
Related
I'm using easy Localization Package in 2 languages Application ,,And I Need To swith langauge using a Button . How could i Do That?
await EasyLocalization.ensureInitialized();
log(token);
runApp(
EasyLocalization(
supportedLocales: const [Locale('ar'), Locale('en')],
path: 'assets/translations',
startLocale: const Locale('ar'),
fallbackLocale: const Locale('en'),
saveLocale: true,
assetLoader: const CodegenLoader(),
child: ScreenUtilInit(
designSize: const Size(411.4, 683.4),
child: const MyApp(),
builder: (context, child) => child!,
),
),
);
There is lesson explain the right way to make it:
Source_code_in_github
Explain Localization with provider and shared preferences
There are some steps you should follow:
Add packages provider and shared_preferneces.
Create folder name it as l10n.
Add language json file in l10n folder as *.arb i.e app_ar.arb and app_en.arb.
Add Dart file in l10n folder name it: l10n.dart.
Write what you need in arb files like this: "youKey":"your_value first letter of key must be small letter camelCase, no _ nor -. i.e
{
"application": "application",
"setting": "settings",
"langAR": "Arabic",
"langEN": "English",
"blue": "blue",
"green": "green",
"purple": "purple"
}
add your list language to l10n.dart.
import 'package:flutter/cupertino.dart';
class L10n {
static final all = [const Locale('ar'), const Locale('en')];
}
Create l10n.yaml file in the root space of your project and write in it:
arb-dir: lib/l10n
template-arb-file: app_en.arb
out-localization-file: app_local.dart
Then in your terminal run flutter pub get that will generate the classes that contain all you properties of your languages.
Add new dart file name i.e app_local.dart with this code:
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class AppLocal {
static AppLocalizations? _loc;
static AppLocalizations get loc {
return AppLocal._loc!;
}
static void init(BuildContext context) {
_loc = AppLocalizations.of(context);
}
}
Add dart file name it i.e setting_provider.dart:
import 'package:flutter/cupertino.dart';
class SettingProvider extends ChangeNotifier {
String? local;
updateLocal(String? lang) {
local = lang;
notifyListeners();
}
}
Add dart file name it i.e shared_pref.dart:
import 'package:shared_preferences/shared_preferences.dart';
class SharedPref {
static String? lang;
static addLang(String lang) async {
SharedPreferences sp = await SharedPreferences.getInstance();
sp.setString('lang', lang);
}
static Future<String?> getLang() async {
SharedPreferences sp = await SharedPreferences.getInstance();
lang = sp.getString('lang');
return lang;
}
}
Write in your main function:
Future<void> main(List<String> args) async {
WidgetsFlutterBinding.ensureInitialized();
await SharedPref.getLang();
runApp(const MyApp());
}
and then in MyApp class return the provider like:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => SettingProvider())
],
child: Builder(
builder: (context) {
return MaterialApp(
supportedLocales: L10n.all,
locale: Locale(Provider.of<SettingProvider>(context).local ??
SharedPref.lang ??
'en'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
title: 'Localization',
home: const HomePage(),
);
},
),
);
}
}
Finally call the language in any class as in my example HomePage:
Widget build(BuildContext context) {
AppLocal.init(context);
SettingProvider prov = Provider.of(context);
return Scaffold(
appBar: AppBar(
title: Text(AppLocal.loc.application),
),
body: Column(
children: [
Wrap(
children: List.generate(L10n.all.length, (index) {
return RadioListTile(
title: Text(
L10n.all[index].languageCode == 'en'
? AppLocal.loc.langEN
: AppLocal.loc.langAR,
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.w900,
),
),
value: L10n.all[index].languageCode,
groupValue: prov.local,
onChanged: (String? value) {
SharedPref.addLang(value!);
prov.updateLocal(value);
},
);
}),
),
Center(
child: Text(
AppLocal.loc.setting,
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.w900,
),
),
),
],
),
);
}
}
you need to import easy localization package
import 'package:easy_localization/easy_localization.dart'
Then pass a parameter ('ar' or 'en')
ElevatedButton(
onPressed: () {
setState(() {context.setLocale(Locale('en')); //ar});
},
I am trying to parse a JSON after doing a HTTP GET request for my flutter app, however when it is parsed, the body shows as empty, this is the parsing code
urlHausParseBox() {
Future<_GoneSmishinState> fetchUrlResponse() async {
String url = myController.text;
final response = await http.post(
Uri.parse("https://urlhaus-api.abuse.ch/v1/url/"),
headers: <String, String>{
'Accept': 'application/json',
},
body: (<String, String>{
'url': url,
'query_status': query_status,
'url_status' : url_status,
//'status' : status,
//'urlStatus' : urlStatus,
}));
After this I have a check for the 200 status, and when recieved will return this to use after the fact, I printed the fields 'query_status' and 'url_status' but they came up empty so I printed what I was returning here
if (response.statusCode == 200) {
print (_GoneSmishinState.fromJson(jsonDecode(response.body)));
return _GoneSmishinState.fromJson(jsonDecode(response.body));
but all that is printed out is _GoneSmishinState#23f48(lifecycle state: created, no widget, not mounted)
which is not what is supposed to be returned by the HTTP GET request
The rest of my code is below
import 'dart:convert';
import 'package:validators/validators.dart';
import 'package:flutter/material.dart';
import 'package:sms/sms.dart';
import 'dart:io';
import 'dart:developer' as developer;
import 'package:http/http.dart' as http;
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
String url = "https://urlhaus-api.abuse.ch/v1/urls/recent/"; //address for URL file
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key:key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: "Gone Smishin'",
home: GoneSmishin(),
);
}
}
class GoneSmishin extends StatefulWidget {
const GoneSmishin({Key? key}) : super(key: key);
State<GoneSmishin> createState() {
return _GoneSmishinState(url_status: '', query_status: '');
}
}
class _GoneSmishinState extends State<GoneSmishin> {
String message = "";
String word = "";
bool isOn = false;
final myController = TextEditingController();
#override
void dispose() {
myController.dispose();
super.dispose();
}
_GoneSmishinState({
required this.query_status,
required this.url_status,
});
final String query_status;
final String url_status;
factory _GoneSmishinState.fromJson(Map<String, dynamic> json) {
return _GoneSmishinState(
query_status: json["query_status"],
url_status: json["url_status"],
);
}
urlHausParseBox() {
Future<_GoneSmishinState> fetchUrlResponse() async {
String url = myController.text;
final response = await http.post(
Uri.parse("https://urlhaus-api.abuse.ch/v1/url/"),
headers: <String, String>{
'Accept': 'application/json',
},
body: (<String, String>{
'url': url,
'query_status': query_status,
'url_status' : url_status,
}));
if (response.statusCode == 200) {
print (_GoneSmishinState.fromJson(jsonDecode(response.body)));
return _GoneSmishinState.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load website');
}
}
fetchUrlResponse();
if (query_status == "ok" && url_status == "online") {
const Text ('Found in URLHause Database - Probably Smishing');
print("found");
} else if (query_status == "ok" && url_status == "offline") {
const Text ('Found in URLHaus, not online');
print("found offline");
} else {
const Text ('Found Nothing');
print("not found");
print (query_status);
print (url_status);
}
_pushInput() {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) {
return Scaffold(
appBar: AppBar(
title: const Text ('Submit a Link')
),
body: (
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField (
controller: myController,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter your Link Text',
contentPadding: EdgeInsets.symmetric(
vertical: 40, horizontal: 20),
),
),
ElevatedButton(
onPressed: () {
urlHausParseBox();
},
child: const Text('Submit')
)
]
)
));
}
)
);
}
#override
var buttonText = 'OFF';
String textHolder = "App is Off";
changeTextON() {
setState(() {
textHolder = "App is ON";
});
isOn == true;
}
changeTextOFF() {
setState(() {
textHolder = "App is OFF";
});
isOn == false;
}
Widget build(BuildContext context) {
final ButtonStyle outlineButtonStyle = OutlinedButton.styleFrom(
primary: Colors.black87,
minimumSize: Size(200, 130),
padding: EdgeInsets.symmetric(horizontal: 200),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(300)),
),
).copyWith(
side: MaterialStateProperty.resolveWith<BorderSide>(
(Set<MaterialState> states) {
return BorderSide(
color: Theme.of(context).colorScheme.primary,
width: 1,
);
},
),
);
return Scaffold(
appBar: AppBar(
title: const Text("Gone Smishin'"),
actions: [
IconButton(
icon: const Icon(Icons.add_link),
onPressed: _pushInput,
tooltip: 'Submit a Link'
)
],
backgroundColor: Colors.red,
),
body: Column (
children: [
Container(
padding: EdgeInsets.fromLTRB(50, 50, 50, 50),
child: Text('$textHolder',
style: TextStyle(fontSize: 50)
),
),
Container(
//child: Text(result)
),
TextButton(
style: outlineButtonStyle,
onPressed: () {
changeTextON();
},
child: Text('ON')
),
TextButton(
style: outlineButtonStyle,
onPressed: () {
changeTextOFF();
},
child: Text("OFF"),
)
]
),
);
}
}
Change this:
_GoneSmishinState({
required this.query_status,
required this.url_status,
});
final String query_status;
final String url_status;
factory _GoneSmishinState.fromJson(Map<String, dynamic> json) {
return _GoneSmishinState(
query_status: json["query_status"],
url_status: json["url_status"],
);
}
to this:
_GoneSmishinState();
var queryStatus = '';
var urlStatus = '';
and this:
if (response.statusCode == 200) {
print (_GoneSmishinState.fromJson(jsonDecode(response.body)));
return _GoneSmishinState.fromJson(jsonDecode(response.body));
}
to:
if (response.statusCode == 200) {
setState(() {
final decoded = json.decode(response.body);
queryStatus = decoded['query_status'];
urlStatus = decoded['url_status'];
}
);
}
And, finally, patch up any unused/misnamed variables. As an aside, it's difficult to read functions declared inside other functions. Is fetchUrlResponse inside urlHausParseBox? Move it outside.
I am Working on Flutter App Both for web and mobile and stuck at the Following Error:
======== Exception caught by widgets library =======================================================
The following ProviderNotFoundException was thrown building Products(dirty):
Error: Could not find the correct Provider<List<ProductsModel>> above this Products Widget
This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- You added a new provider in your `main.dart` and performed a hot-reload.
To fix, perform a hot-restart.
- The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that Products is under your MultiProvider/Provider<List<ProductsModel>>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
```
consider using `builder` like so:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
```
The relevant error-causing widget was:
Products file:///E:/Flutter%20Projects/flutter_web_firebase_host/lib/screens/home/home.dart:37:63
When the exception was thrown, this was the stack:
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49 throw_
packages/provider/src/provider.dart 332:7 _inheritedElementOf
packages/provider/src/provider.dart 284:30 of
packages/flutter_web_firebase_host/screens/databaseScreens/products.dart 10:31 build
packages/flutter/src/widgets/framework.dart 4569:28 build
...
====================================================================================================
Main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/model/users.dart';
import 'package:flutter_web_firebase_host/provider/product_provider.dart';
import 'package:flutter_web_firebase_host/screens/wrapper.dart';
import 'package:flutter_web_firebase_host/services/auth.dart';
import 'package:flutter_web_firebase_host/services/firestore_service.dart';
import 'package:provider/provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final firestoreServise = FirestoreService();
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ProductProvider(),
),
StreamProvider(
create: (context) => firestoreServise.getProducts(),
initialData: [],
),
StreamProvider<Users>.value(
value: AuthService().user,
initialData: null,
),
],
/* child: StreamProvider<Users>.value(
value: AuthService().user,
initialData: null*/
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Wrapper(),
),
);
// );
}
Product.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/model/ProductModel.dart';
import 'package:flutter_web_firebase_host/screens/databaseScreens/edit_product.dart';
import 'package:provider/provider.dart';
class Products extends StatelessWidget {
#override
Widget build(BuildContext context) {
final products = Provider.of<List<ProductsModel>>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: Text('Products'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => EditProduct()));
}),
],
),
body: (products != null)
? ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(products[index].name),
trailing: Text(products[index].price.toString()),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditProduct(products[index])));
},
);
},
)
: Center(child: CircularProgressIndicator()));
}
}
Home.dart
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/screens/databaseScreens/products.dart';
import 'package:flutter_web_firebase_host/services/auth.dart';
import 'package:flutter_web_firebase_host/shared/drawer.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
backgroundColor: Colors.brown[100],
appBar: AppBar(
title: Text('Brew Crew'),
backgroundColor: Colors.brown[100],
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person),
label: Text('logout'),
onPressed: () async {
await _auth.signOut();
},
),
IconButton(
icon: Icon(Icons.add, color: Colors.black),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Products()));
}),
],
),
body: SingleChildScrollView(
child: Center(
child: Column(
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 50, 0, 0),
child: Container(
child: Text(
'Stock Market',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
)),
),
),
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Image.asset(
"assets/graph.jpg",
width: 500,
height: 600,
),
),
),
],
),
),
),
drawer: MyDrawer(),
),
);
}
}
product_provider.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter_web_firebase_host/model/ProductModel.dart';
import 'package:flutter_web_firebase_host/services/firestore_service.dart';
import 'package:uuid/uuid.dart';
class ProductProvider with ChangeNotifier {
final firestoreService = FirestoreService();
String _name;
double _price;
String _productId;
var uuid = Uuid();
//Geters
String get name => _name;
double get price => _price;
//Seters
changeName(String value) {
_name = value;
notifyListeners();
}
changePrice(String value) {
_price = double.parse(value);
notifyListeners();
}
loadValues(ProductsModel product) {
_name=product.name;
_price=product.price;
_productId=product.productId;
}
saveProduct() {
print(_productId);
if (_productId == null) {
var newProduct = ProductsModel(name: name, price: price, productId: uuid.v4());
firestoreService.saveProduct(newProduct);
} else {
//Update
var updatedProduct =
ProductsModel(name: name, price: _price, productId: _productId);
firestoreService.saveProduct(updatedProduct);
}
}
}
Authservise.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_web_firebase_host/model/users.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on firebase user
Users _userFromFirebaseUser(User user) {
return user != null ? Users(uid: user.uid) : null;
}
// auth change user stream
Stream<Users> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
// sign in anon
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in with email and password
Future signInWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(email: email, password: password);
User user = result.user;
return user;
} catch (error) {
print(error.toString());
return null;
}
}
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User user = result.user;
return _userFromFirebaseUser(user);
} catch (error) {
print(error.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (error) {
print(error.toString());
return null;
}
}
//sign in with google
Future<bool> loginWithGoogle() async {
try {
GoogleSignIn googleSignIn = GoogleSignIn();
GoogleSignInAccount account = await googleSignIn.signIn();
if(account == null )
return false;
UserCredential res = await _auth.signInWithCredential(GoogleAuthProvider.credential(
idToken: (await account.authentication).idToken,
accessToken: (await account.authentication).accessToken,
));
if(res.user == null)
return false;
return true;
} catch (e) {
print(e.message);
print("Error logging with google");
return false;
}
}
}
Basically my app is connect to firebase both for web app and android app. Also i send data to firestore from my app but when i click the add button to go to textfield to send data it give the error as i mention it in start. I am using multiprovider as you can see my main.dart code
Is There anything I missing. I need Help.
the way to fix this is to put MultiProvider as parent of myApp in your main like this
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ProductProvider(),
),
StreamProvider(
create: (context) => firestoreServise.getProducts(),
initialData: [],
),
StreamProvider<Users>.value(
value: AuthService().user,
initialData: null,
),
],
child:MyApp(
));
I have a problem with Future builder in Flutter. It gets the info from api successfully but doesn't show it. When I put print and print the info from api, it is ok and it shows the movies name without any problems. here is my code:
class Search extends StatefulWidget {
final String value;
Search({Key key, String this.value}) : super(key: key);
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
var title;
Future getSearch({index}) async {
http.Response response = await http.get(
'https://api.themoviedb.org/3/search/company?api_key=6d6f3a650f56fd6b3347428018a20a73&query=' +
widget.value);
var results = json.decode(response.body);
setState(() {
this.title = results['results'];
});
return title[index]['name'];
}
getName(index) {
return title[index]['name'];
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xff1d1d27),
body: Column(
children: [
Expanded(
child: FutureBuilder(
initialData: [],
future: getSearch(),
builder: (context, snapshot) {
return ListView.builder(itemBuilder: (context, index) {
Padding(
padding:
EdgeInsets.symmetric(horizontal: 30, vertical: 20),
child: Container(
color: Colors.white,
child: Text(getName(index).toString()),
),
);
});
},
))
],
)),
);
}
}
Please Use this code, It works fine to fetch the names and show them on the list,
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class Search extends StatefulWidget {
final String value;
Search({Key key, String this.value}) : super(key: key);
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
var title;
var results;
getSearch() async {
http.Response response = await http.get(
'https://api.themoviedb.org/3/search/company?api_key=6d6f3a650f56fd6b3347428018a20a73&query=' +
widget.value);
results = json.decode(
response.body); //make it global variable to fetch it everywhere we need
return results['results'][0]['name'];
}
getName(index) {
return results['results'][index]['name'];
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xff1d1d27),
body: Column(
children: [
Expanded(
child: FutureBuilder(
// initialData: [],
future: getSearch(),
builder: (context, snapshot) {
String name =
snapshot.data; // to get the data from the getSearch
print(name);
if (snapshot.hasData) {
// if there is data then show the list
return ListView.builder(
itemCount: results['results']
?.length, // to get the list length of results
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 30, vertical: 20),
child: Container(
color: Colors.white,
child: Text(getName(index)
.toString()), // pass the index in the getName to get the name
),
);
});
} else {
// if there is no data or data is not loaded then show the text loading...
return new Text("Loading...",
style: TextStyle(fontSize: 42, color: Colors.white));
}
},
))
],
)),
);
}
}
P.S
To Learn the basics of Futurebuilder You can see this article For more learning
I have commented the code to explain more to you.
So I built my first app. It's a weather app. So far everything works as intended. But there is one problem, whenever I close the app and then reopen it, everything is null (weather forecast, location name, max and min temperature). When I press the refresh button it null is updated to current condition. What I'd like t be able to do is, instead of showing null, I'd like the app to show the last refresh and update it if I press the refresh button. How can I do this.
Keep in mind I'm a newbie.
main.dart:
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'GetLocation.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() {
runApp(AuraWeather());
}
class AuraWeather extends StatefulWidget {
#override
_AuraWeatherState createState() => _AuraWeatherState();
}
class _AuraWeatherState extends State<AuraWeather> {
var apiKey = '5f10958d807d5c7e333ec2e54c4a5b16';
var description;
var city;
var maxTemp;
var minTemp;
var temp;
#override
Widget build(BuildContext context) {
setState(() {
getLocation();
});
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(displayBackground()),
),
),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaY: 2, sigmaX: 2),
child: Container(
color: Colors.black.withOpacity(0.5),
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
children: <Widget>[
Container(
child: Center(
child: Text(
'$city',
style: TextStyle(
fontSize: 35,
color: Colors.white,
),
),
),
),
Container(
child: Icon(
FontAwesomeIcons.locationArrow,
color: Colors.white,
),
),
Container(
margin: EdgeInsets.only(top: 80),
child: Text(
'$temp' + '°',
style: TextStyle(
fontSize: 50,
color: Colors.white,
fontWeight: FontWeight.w600),
),
),
],
),
Container(
margin: EdgeInsets.only(top: 30),
child: Icon(
Icons.wb_sunny,
color: Colors.white,
size: 100,
),
),
Container(
child: Center(
child: Text(
'$maxTemp ° | $minTemp °',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
),
Container(
child: Text(
'$description',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
Container(
child: FlatButton(
child: Icon(
Icons.refresh,
color: Colors.white,
size: 40,
),
color: Colors.transparent,
onPressed: () {
setState(
() {
getLocation();
},
);
},
),
),
],
),
),
),
),
),
);
}
// display background images based on current time
displayBackground() {
var now = DateTime.now();
final currentTime = DateFormat.jm().format(now);
if (currentTime.contains('AM')) {
return 'images/Blood.png';
} else if (currentTime.contains('PM')) {
return 'images/Sun.png';
}
}
//getLocation
void getLocation() async {
Getlocation getlocation = Getlocation();
await getlocation.getCurrentLocation();
print(getlocation.latitude);
print(getlocation.longitude);
print(getlocation.city);
city = getlocation.city;
getTemp(getlocation.latitude, getlocation.longitude);
}
//Get current temp
Future<void> getTemp(double lat, double lon) async {
http.Response response = await http.get(
'https://api.openweathermap.org/data/2.5/weather?lat=$lat&lon=$lon&appid=$apiKey&units=metric');
//print(response.body);
var dataDecoded = jsonDecode(response.body);
description = dataDecoded['weather'][0]['description'];
temp = dataDecoded['main']['temp'];
temp = temp.toInt();
maxTemp = dataDecoded['main']['temp_max'];
maxTemp = maxTemp.toInt();
minTemp = dataDecoded['main']['temp_min'];
minTemp = minTemp.toInt();
print(temp);
}
}
GetLocation.dart:
import 'package:geolocator/geolocator.dart';
class Getlocation {
double latitude;
double longitude;
var city;
//Get current location
Future<void> getCurrentLocation() async {
try {
Position position = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.best);
latitude = position.latitude;
longitude = position.longitude;
city = await getCityName(position.latitude, position.longitude);
} catch (e) {
print(e);
}
}
//Get city name
Future<String> getCityName(double lat, double lon) async {
List<Placemark> placemark =
await Geolocator().placemarkFromCoordinates(lat, lon);
print('city name is: ${placemark[0].locality}');
return placemark[0].locality;
}
}
Easy solution, would be to use SharedPreferences, then after you refresh weather save every variable to it, like
Future<void> _saveStringInSharedPrefs(String key, String value) async =>
SharedPreferences.getInstance().then((prefs) => prefs.setString(key, value));
for each of the values. You may also want to change vars to types, like double, String and so on.
Then you can add initState to your state, where you set each of the variables to SharedPreferences.getString(variable_key). It will be convenient to use SharedPreferences prefs = SharedPreferences.getInstance() and then call prefs.getString() You could add it in build, but you probably should not, build methods are meant to be really fast, so they could run up to 60 times/s.
Edit:
http.Response response = await http.get(
'https://api.openweathermap.org/data/2.5/weather?lat=$lat&lon=$lon&appid=$apiKey&units=metric');
//print(response.body);
await SharedPreferences.getInstance().then((prefs) {prefs.setString('weather_data', response.body}) // add this line
var dataDecoded = jsonDecode(response.body);
// (rest of the code)
This will save your json to SharedPrefs. Now you only need to extract the function that works with JSON and sets the variables. So it would look something like this:
void _setData(String jsonString) {
var dataDecoded = jsonDecode(response.body);
description = dataDecoded['weather'][0]['description'];
// here it would be safer to have temp be of type 'int' instead of 'var' and set it like this:
// temp = dataDecoded['main']['temp'].toInt();
temp = dataDecoded['main']['temp'];
temp = temp.toInt();
maxTemp = dataDecoded['main']['temp_max'];
maxTemp = maxTemp.toInt();
minTemp = dataDecoded['main']['temp_min'];
minTemp = minTemp.toInt();
}
You can then split getTemp like that:
Future<void> getTemp(double lat, double lon) async {
http.Response response = await http.get(
'https://api.openweathermap.org/data/2.5/weather?lat=$lat&lon=$lon&appid=$apiKey&units=metric');
//print(response.body);
_setData(response.body);
}
And then, when you launch the app you want it to load the values from SharedPreferences. So add this to _AuraWeatherState:
#override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
_setData(prefs.getString('weather_data'));
}
This should work but I didn't have time to check if it executes. So if you have any other questions, I'll be glad to help :)