How to save API data locally in Flutter so that app can work without internet connection? - flutter

I'm developing a small Flutter application using https://newsapi.org/ API and Riverpod. I want to make my app work offline (when there is no internet connection). I'm confused in when/where to save the API response and where to retrieve it.
main.dart (EDITED)
import 'package:flutter/material.dart';
import 'package:flutter_pace_stock_internship_task/model/article_model.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'providers/providers.dart';
import 'screens/home_screen.dart';
import 'utility/size_config.dart';
import 'package:hive_flutter/hive_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(ArticleAdapter());
Hive.registerAdapter(SourceAdapter());
await Hive.openBox('myarticles');
runApp(
ProviderScope(
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
themeMode: ThemeMode.dark,
darkTheme: ThemeData.dark(),
theme: ThemeData(
fontFamily: 'Roboto',
// scaffoldBackgroundColor: scaffoldBgColor,
),
home: const HomeScreen())),
);
}
article_model.dart
import 'package:hive/hive.dart';
part 'article_model.g.dart';
#HiveType(typeId: 0)
class Article {
Article({
this.source,
this.author,
this.title,
this.description,
this.url,
this.urlToImage,
this.publishedAt,
this.content,
});
#HiveField(0)
Source? source;
#HiveField(1)
String? author;
#HiveField(2)
String? title;
#HiveField(3)
String? description;
#HiveField(4)
String? url;
#HiveField(5)
String? urlToImage;
#HiveField(6)
String? publishedAt;
#HiveField(7)
String? content;
factory Article.fromJson(Map<String, dynamic> json) => Article(
source: Source.fromJson(json["source"]),
author: json["author"] ?? '',
title: json["title"] ?? '',
description: json["description"] ?? '',
url: json["url"] ?? '',
urlToImage: json["urlToImage"] ?? '',
publishedAt: json["publishedAt"] ?? '',
content: json["content"] ?? '',
);
Map<String, dynamic> toJson() => {
"source": source!.toJson(),
"author": author ?? '',
"title": title ?? '',
"description": description ?? '',
"url": url ?? '',
"urlToImage": urlToImage ?? '',
"publishedAt": publishedAt ?? '',
"content": content ?? '',
};
}
#HiveType(typeId: 1)
class Source {
Source({
this.id,
this.name,
});
#HiveField(0)
String? id;
#HiveField(1)
String? name;
factory Source.fromJson(Map<String, dynamic> json) => Source(
id: json["id"] ?? '',
name: json["name"] ?? '',
);
Map<String, dynamic> toJson() => {
"id": id ?? '',
"name": name ?? '',
};
}
api_service.dart
import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import '../model/article_model.dart';
class ApiService {
final String _endPoint =
'https://newsapi.org/v2/top-headlines?country=in&apiKey=YOUR_API_KEY';
Future<List<Article>> getArticles() async {
http.Response response = await http.get(Uri.parse(_endPoint));
if (response.statusCode == 200) {
final List result = jsonDecode(response.body)["articles"];
return result.map<Article>((e) => Article.fromJson(e)).toList();
} else {
throw Exception(response.reasonPhrase);
}
}
}
final apiProvider = Provider<ApiService>((ref) => ApiService());
I've written the logic for checking whether there is internet connection or not inside providers.dart.
providers.dart
import 'dart:convert';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../model/article_model.dart';
import '../services/api_service.dart';
enum NetworkStatus {
on,
off,
}
class NetworkDetectorNotifier extends StateNotifier<NetworkStatus> {
late NetworkStatus newState;
NetworkDetectorNotifier() : super(NetworkStatus.off) {
Connectivity().onConnectivityChanged.listen((ConnectivityResult result) {
switch (result) {
case ConnectivityResult.wifi:
newState = NetworkStatus.on;
break;
case ConnectivityResult.mobile:
newState = NetworkStatus.on;
break;
case ConnectivityResult.none:
newState = NetworkStatus.off;
break;
case ConnectivityResult.bluetooth:
case ConnectivityResult.ethernet:
case ConnectivityResult.vpn:
}
if (newState != state) {
state = newState;
}
});
}
}
final networkCheckProvider =
StateNotifierProvider<NetworkDetectorNotifier, NetworkStatus>(
(_) => NetworkDetectorNotifier());
final articleProvider = FutureProvider<List<Article>>(
(ref) async => await ref.watch(apiProvider).getArticles());
home_screen.dart
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
import '../constant/constants.dart';
import '../providers/providers.dart';
import '../utility/size_config.dart';
import 'details_screen.dart';
class HomeScreen extends ConsumerWidget {
const HomeScreen({super.key});
#override
Widget build(BuildContext context, WidgetRef ref) {
//SizeConfig().init(context);
final articles = ref.watch(articlesProviderNew);
return Scaffold(
backgroundColor: scaffoldBgColor,
appBar: AppBar(
backgroundColor: appBarColor,
centerTitle: true,
title: const Text('HEADLINES',
style: TextStyle(
fontSize: appBarTitleSize,
color: appBarTitleColor,
fontWeight: FontWeight.w700,
)),
),
body: articles.when(
data: ((articles) => ListView.builder(
// padding: const EdgeInsets.fromLTRB(16, 0.0, 16, 24),
itemCount: articles.length,
itemBuilder: (context, index) {
final article = articles[index];
final date = DateFormat('yy-mm-dd').parse(article.publishedAt!);
return Padding(
padding: const EdgeInsets.only(
top: 16.0, left: 16.0, right: 16.0, bottom: 24.0),
child: SizedBox(
height: SizeConfig.screenHeight * .35,
width: SizeConfig.screenWidth * .75,
child: InkWell(
onTap: (() =>
Navigator.of(context).push(MaterialPageRoute(
builder: ((context) => DetailsScreen(
article: article,
))))),
child: Card(
shape: const RoundedRectangleBorder(),
child: GridTile(
footer: GridTileBar(
backgroundColor: Colors.black.withOpacity(.5),
title: Text(
article.title!,
style: const TextStyle(
fontSize: articleTitleTextSize,
color: articleTitleTextColor,
),
),
subtitle: Text(
'${article.author!}\t\t\t\t$date',
style: const TextStyle(
fontSize: authorTextSize,
color: authorTextColor,
),
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: CachedNetworkImage(
fit: BoxFit.cover,
errorWidget: (context, url, error) =>
Image.asset('assets/images/no_image.png'),
placeholder: (context, url) => const Center(
child: CircularProgressIndicator()),
imageUrl:
articles.elementAt(index).urlToImage!),
),
),
),
),
),
);
},
)),
error: ((error, stackTrace) {
print('Error : $error\n$stackTrace');
return Text('Error : $error\n$stackTrace');
}),
loading: () => const Center(
child: CircularProgressIndicator(),
),
),
);
}
}
details_screen.dart
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import '../constant/constants.dart';
import '../model/article_model.dart';
import '../utility/size_config.dart';
class DetailsScreen extends StatelessWidget {
const DetailsScreen({Key? key, required this.article}) : super(key: key);
final Article article;
#override
Widget build(BuildContext context) {
return Stack(
children: [
CachedNetworkImage(
height: SizeConfig.screenHeight,
width: SizeConfig.screenWidth,
fit: BoxFit.cover,
errorWidget: (context, url, error) =>
Image.asset('assets/images/no_image.png'),
placeholder: (context, url) =>
const Center(child: CircularProgressIndicator()),
imageUrl: article.urlToImage!),
Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
elevation: 0.0,
backgroundColor: Colors.transparent,
leading: Container(
height: 42.0,
width: 42.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color.fromRGBO(0, 0, 0, 1).withOpacity(.3)),
child: IconButton(
icon: const Icon(
Icons.arrow_back,
size: 42.0,
),
onPressed: () => Navigator.of(context).pop(),
),
)),
body: Padding(
padding: const EdgeInsets.all(leftPadding2),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
article.title!,
style: const TextStyle(
fontSize: appBarTitleSize, color: articleTitleTextColor),
),
const SizedBox(
height: vertPadding,
),
Row(
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(article.author!,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: articleTitleTextSize,
color: articleTitleTextColor)),
),
const SizedBox(
width: 10.0,
),
Expanded(
child: Text(article.publishedAt!,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: articleTitleTextSize,
color: articleTitleTextColor)),
),
],
),
const SizedBox(
height: vertPadding2,
),
Text(article.content!,
style: const TextStyle(
fontSize: articleContentSize, color: authorTextColor))
],
),
),
),
],
);
}
}
Can anyone tell me how to make my app work offline ?
Edit-: Following code I'm using for saving and retrieving API data, but I'm getting error while retrieving, that is type 'List' is not a subtype of type 'FutureOr<List>' .
final articlesProviderNew = FutureProvider<List<Article>>((ref) async {
var articleBox = Hive.box('myarticles');
var network = ref.watch(networkCheckProvider);
switch (network) {
case NetworkStatus.on:
{
List<Article> articles = await ref.watch(apiProvider).getArticles();
var articleLS = articleBox.get('articleLS');
if (articleLS == null || articleLS.isEmpty) {
await articleBox.put('articleLS', articles);
}
return articles;
}
case NetworkStatus.off:
{
var articleLS = articleBox.get('articleLS');
return articleLS;
}
}
});

first of all you need to check :
the first time ever you need to force user to have internet.
all data they will be stored in local memory for the first time then if the user will not have internet then you can get data from local memory.
class NetoworkCheck extends ConsumerWidget {
const NetoworkCheck({super.key});
#override
Widget build(BuildContext context, WidgetRef ref) {
SizeConfig().init(context);
var network = ref.watch(networkCheckProvider);
if (network == NetworkStatus.off) {
return const NoNetworkScreen();
}
return const HomeScreen();
}
}
you can check here
and put your code here for storing data
if (network == NetworkStatus.off) {
store all data
return const NoNetworkScreen();
}
don't forget to use async/await mostly it will tike some time to store data

Related

Is not a subtype of type Flutter

im trying to fetch a news api and display the data in my widget, but im getting this error: _TypeError (type '(dynamic) => Article' is not a subtype of type '(String, dynamic) => MapEntry<dynamic, dynamic>' of 'transform')
this is the function where i fetch the data
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/article_model.dart';
const url =
"https://newsapi.org/v2/top-headlines?country=br&apiKey=399c0c22d7c845608909937a974ab209";
Future<List<Article>> getArticle() async {
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
List<Article> articles =
data.map((json) => Article.fromJson(json)).toList();
print(articles);
return articles;
} else {
throw Exception("Failed to get articles");
}
}
this is the model i create to receive an article:
class Article {
final String title;
final String author;
final String description;
final String url;
final String urlToImage;
final String content;
const Article({
required this.title,
required this.author,
required this.description,
required this.url,
required this.urlToImage,
required this.content,
});
factory Article.fromJson(Map<String, dynamic> json) {
return Article(
title: json['title'],
author: json['author'],
description: json['description'],
url: json['url'],
urlToImage: json['urlToImage'],
content: json['content'],
);
}
get article => null;
}
that`s my widget:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import '../models/article_model.dart';
class ChamadaSuite extends StatelessWidget {
final Article article;
final String title;
final String author;
final String description;
final String url;
final String urlToImage;
final String content;
const ChamadaSuite(
{super.key,
required this.title,
required this.author,
required this.description,
required this.url,
required this.urlToImage,
required this.content,
required this.article});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(20),
child: Row(
children: [
Container(
width: 110,
height: 90,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: const DecorationImage(
fit: BoxFit.cover, image: AssetImage("assets/vasco.png")),
),
),
Flexible(
child: Container(
padding: EdgeInsets.only(left: 15),
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"ESPORTE",
style: TextStyle(
color: Colors.green,
fontSize: 12,
fontWeight: FontWeight.w500,
height: 1.2,
letterSpacing: 0.13,
),
),
Text(
article.title,
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold,
height: 1.4,
letterSpacing: 0.16,
),
)
],
),
),
)
],
),
);
}
}
and this is my homepage.dart, where i call the function to populate the widget:
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import '../api/get_article.dart';
import '../models/article_model.dart';
import '../widgets/manchete_suite_destaque.dart';
import '../widgets/chamada_suite.dart';
class HomePage extends StatefulWidget {
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Tab> tabs = [
const Tab(child: Text('últimas notícias')),
const Tab(child: Text('bahia')),
const Tab(child: Text('política')),
const Tab(child: Text('esportes')),
const Tab(child: Text('últimas notícias')),
const Tab(child: Text('agenda cultural')),
];
#override
void initState() {
super.initState();
}
Future<List<Article>> fetchArticles() async {
return await getArticle();
}
final article = const Article(
author: '',
content: '',
description: '',
title: '',
url: '',
urlToImage: '',
);
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: tabs.length,
child: Scaffold(
appBar: AppBar(
leadingWidth: 100,
leading: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: SvgPicture.asset('assets/ibahia.svg'),
),
actions: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.search),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.menu),
),
],
bottom: PreferredSize(
preferredSize: const Size.fromHeight(30),
child: TabBar(
indicatorColor: Colors.white,
isScrollable: true,
tabs: tabs,
)),
),
body: FutureBuilder<List<Article>>(
future: fetchArticles(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
Article article = snapshot.data![index];
return SingleChildScrollView(
child: Column(
children: [
const MancheteSuiteDestaque(),
ChamadaSuite(
title: article.title,
author: article.author,
content: article.content,
description: article.description,
url: article.url,
urlToImage: article.urlToImage,
article: article.article,
),
],
),
);
});
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else {
return const CircularProgressIndicator();
}
},
),
),
);
}
}
How can i solve this error? i dont even know where its the error
Specify a type when calling map method, for example: map<Article>.
In your code, change:
List<Article> articles =
data.map((json) => Article.fromJson(json)).toList();
To:
List<Article> articles =
data.map<Article>((json) => Article.fromJson(json)).toList();
By the way, depending on your Dart version, you may be able to write this instead:
List<Article> articles =
data.map<Article>(Article.fromJson).toList();

Flutter List of dynamic checkboxex from API

I am a learner and new to Flutter.
I want help with the followings
I need to get a list of items with checkboxes from and API
I should be able to select a single or multiple checkboxes
If I select a checkbox its should display the total amount selected
if I select two checkboxes, its should sum the total of the two for me and display it.
Below is what I have done so far.
I will greatly appreciate your solutions
here is my code
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:liquid_pull_to_refresh/liquid_pull_to_refresh.dart';
import 'dart:convert';
import 'dart:ffi';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stachup/models/TeamModel.dart';
import 'package:stachup/models/newStaches.dart';
import 'package:stachup/models/TeamModel.dart';
class Stash extends StatefulWidget {
String first_name;
String token;
String referalcode;
String last_name;
Stash(
{Key? key,
required this.first_name,
required this.token,
required this.last_name,
required this.referalcode})
: super(key: key);
#override
State<Stash> createState() => _StashState();
}
class _StashState extends State<Stash> {
bool isChecked = false;
String? first_name;
String? token;
String? last_name;
String? referalcode;
bool setup = false;
String? setupError;
bool _isChecked = false;
late SharedPreferences logindata;
userData() async {
logindata = await SharedPreferences.getInstance();
first_name = logindata.getString('first_name')!;
last_name = logindata.getString('last_name')!;
referalcode = logindata.getString('referalcode')!;
token = logindata.getString('token')!;
setState(() {});
}
List<Team> teams = [];
Future getData() async {
var response = await http.get(Uri.https(
'incoming.isplitpay.com', 'api/durationlist', {'token': token}));
var jsonData = jsonDecode(response.body);
print(token);
for (var eachTeam in jsonData) {
var datetime = DateTime.parse(eachTeam["paid_date"]);
final team = Team(
id_pes: eachTeam['id_pes'],
amount: eachTeam['amount'],
paid_date: datetime,
);
teams.add(team);
}
// print(teams.length);
}
#override
void initState() {
super.initState();
userData();
}
#override
Widget build(BuildContext context) {
//getData();
return Scaffold(
backgroundColor: Colors.blue.shade50,
body: FutureBuilder(
future: getData(),
builder: ((context, snapshot) {
//if done loading show data
if (snapshot.connectionState == ConnectionState.done) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
),
child: ListView.builder(
itemCount: teams.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 80,
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
),
color: Colors.grey[50],
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Checkbox(
checkColor: Colors.white,
value: _isChecked,
onChanged: (bool? value) {
setState(() {
_isChecked = value!;
});
print(value);
},
),
Text(
'GHS ' + teams[index].amount,
style: GoogleFonts.lato(
fontSize: 16,
),
),
Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
'Savings for',
style: GoogleFonts.lato(
fontSize: 16,
),
),
),
Text(
"${teams[index].paid_date.day.toString().padLeft(2, '0')}-${teams[index].paid_date.month.toString().padLeft(2, '0')}-${teams[index].paid_date.year}",
style: GoogleFonts.lato(
fontSize: 16,
),
),
],
)
],
),
),
);
}),
);
//else show circule progress bar
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
),
);
}
}
My Model
import 'package:flutter/material.dart';
class Team {
final String id_pes;
final String amount;
final DateTime paid_date;
Team({
required this.id_pes,
required this.amount,
required this.paid_date,
});
}
class UserProgress {
final int goaldays;
final double progress;
UserProgress({
required this.goaldays,
required this.progress,
});
}
You can add a variable inside the Class Team to control the CheckBox.
The checked list can be filtered out through the List.where() function.
I added the Tooltip() Widget to show the expected effect.
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<Team> dataList = [
Team(id_pes: '1', amount: '10', paid_date: DateTime.now()),
Team(id_pes: '2', amount: '20', paid_date: DateTime.now()),
Team(id_pes: '3', amount: '30', paid_date: DateTime.now()),
Team(id_pes: '4', amount: '40', paid_date: DateTime.now()),
Team(id_pes: '5', amount: '50', paid_date: DateTime.now()),
Team(id_pes: '6', amount: '60', paid_date: DateTime.now()),
];
Widget _buildListItem(int index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 80,
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
),
color: Colors.grey[50],
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Checkbox(
checkColor: Colors.white,
value: dataList[index].isChecked ?? false,
onChanged: (bool? value) {
setState(() {
dataList[index].isChecked = value;
});
print(value);
},
),
Text(
'GHS ' + dataList[index].amount,
),
],
),
),
);
}
#override
Widget build(BuildContext context) {
var checkedList = dataList.where((data) => data.isChecked ?? false);
var totalAmount = checkedList.isNotEmpty
? 'TotalAmount:${checkedList.reduce((before, after) => Team(amount: '${double.parse(before.amount) + double.parse(after.amount)}', id_pes: '_', paid_date: DateTime.now())).amount} '
: '';
return Scaffold(
body: ListView.builder(
shrinkWrap: true,
itemCount: dataList.length,
itemBuilder: (context, index) {
return Tooltip(
message: totalAmount, child: _buildListItem(index));
}));
}
}
class Team {
final String id_pes;
final String amount;
final DateTime paid_date;
bool? isChecked;
Team({
required this.id_pes,
required this.amount,
required this.paid_date,
this.isChecked,
});
}

Error: Too many positional arguments: 1 allowed, but 2 found

I'm working on a flutter app that is getting a JSON from an API. Then I'm parsing the JSON and building a List Tile. When I try to run the code, I'm getting this error:
lib/screens/screen4.dart:112:23: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
return _tile(data[index].ssid,data[index].auth,icon: Icons.wifi);
This is my code:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(
JobsListView(),
);
}
class Job {
final String ssid;
final String auth;
final String encry;
Job({required this.ssid, required this.auth, required this.encry});
factory Job.fromJson(Map<String, dynamic> json) {
return Job(
ssid: json['ssid'],
auth: json['auth'],
encry: json['encry'],
);
}
}
class JobsListView extends StatelessWidget {
const JobsListView({Key? key}) : super(key: key);
Future<List<Job>> _fetchJobs() async {
final response = await http.get(
Uri.parse('http://10.10.10.254/httpapi.asp?command=wlanGetApListEx'));
if (response.statusCode == 200) {
final List jsonResponse = json.decode(response.body)['aplist'] as List;
return jsonResponse.map((job) => new Job.fromJson(job)).toList();
} else {
throw Exception('Failed to load jobs from API');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Finding your available networks',
style: TextStyle(color: Colors.black87)),
titleSpacing: 00.0,
centerTitle: true,
toolbarHeight: 60.2,
toolbarOpacity: 0.6,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(25),
bottomLeft: Radius.circular(25)),
),
elevation: 0.00,
backgroundColor: Colors.transparent,
),
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: FutureBuilder<List<Job>>(
future: _fetchJobs(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Job> data = snapshot.data ?? [];
return _jobsListView(data);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Container(
alignment: Alignment.topCenter,
margin: EdgeInsets.only(top: 400),
child: CircularProgressIndicator(
backgroundColor: Colors.grey,
color: Colors.black,
),
);
},
),
),
],
),
),
);
}
ListView _jobsListView(data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return _tile(data[index].ssid, data[index].auth, icon: Icons.wifi);
});
}
ListTile _tile(BuildContext context,
{required String title,
required String subtitle,
required IconData icon}) =>
ListTile(
title: Text(title,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.grey[500],
),
trailing: Icon(
Icons.arrow_forward_ios,
),
onTap: () {
Navigator.pushNamed(context, '/fifth');
},
//Navigator.pushNamed(context, '/fifth'),
// => print('on tap'),
//TO DO: Pass the arguments selected to the next screen, and insert it into the URI
//TO DO:Hex to ASCII.
);
}
My intention is to construct the ListTile and then navigate from each Tile to another screen. Why am I getting this error?
You are passing too many positional parameters. If an argument is declared in curly braces, like title and subtitle are, then you have to use its name when calling the method. You are also not passing the BuildContext, which is the only argument not declared in curly braces.
Change it to:
return _tile(
context,
title: data[index].ssid,
subtitle: data[index].auth,
icon: Icons.wifi
);
You are using one positional parameter, and 4 required name parameter.
tTile _tile(BuildContext context,
{required String title,
required String subtitle,
required IconData icon}) =>
You need to pass data like
return _tile(
context,
subtitle:data[index].ssid,
title: data[index].auth,
icon: Icons.wifi,
);
More about using using-constructors
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(
const JobsListView(),
);
}
class Job {
final String ssid;
final String auth;
final String encry;
Job({required this.ssid, required this.auth,required this.encry});
factory Job.fromJson(Map<String, dynamic> json) {
return Job(
ssid: json['ssid'],
auth: json['auth'],
encry: json['encry'],
);
}
}
class JobsListView extends StatelessWidget {
const JobsListView({Key? key}) : super(key: key);
Future<List<Job>> _fetchJobs() async {
final response = await http
.get(
Uri.parse('http://10.10.10.254/httpapi.asp?command=wlanGetApListEx'));
if (response.statusCode == 200) {
final List jsonResponse = json.decode(response.body)['aplist'] as List;
return jsonResponse.map((job) => Job.fromJson(job)).toList();
} else {
throw Exception('Failed to load jobs from API');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home:
Scaffold(
appBar: AppBar(
title: const Text('Finding your available networks',
style: TextStyle(color: Colors.black87)),
titleSpacing: 00.0,
centerTitle: true,
toolbarHeight: 60.2,
toolbarOpacity: 0.6,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(25),
bottomLeft: Radius.circular(25)),
),
elevation: 0.00,
backgroundColor: Colors.transparent,
),
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: FutureBuilder<List<Job>>(
future: _fetchJobs(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Job> data = snapshot.data ?? [];
return _jobsListView(data);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Container(
alignment: Alignment.topCenter,
margin: const EdgeInsets.only(top: 400),
child: const CircularProgressIndicator(
backgroundColor: Colors.grey,
color: Colors.black,
),
);
},
),
),
],
),
),
),
);
}
ListView _jobsListView(data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return _tile(context, data[index].ssid, data[index].auth ,Icons.wifi);
});
}
ListTile _tile(BuildContext context, String title, String subtitle, IconData icon) =>
ListTile(
title: Text(title,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.grey[500],
),
trailing: const Icon(
Icons.arrow_forward_ios,
),
onTap: ()
{
Navigator.pushNamed(context, '/fifth');
},
//Navigator.pushNamed(context, '/fifth'),
// => print('on tap'),
//TO DO: Pass the arguments selected to the next screen, and insert it into the URI
//TO DO:Hex to ASCII.
);
}
It should work right now

Provider not rebuilding on flutter

suddently from nowhere i came up with provider not re rendering my home page when it's updated. I've inspected it and it IS UPDATED. It has newer data when i change it in firebase but the UI won't re-render showing the new data. That's my code:
Main function
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:my_event_app/pages/HomePage/home_page.dart';
import 'package:my_event_app/pages/Login/login_page.dart';
import 'package:my_event_app/providers/User/user.dart';
import 'package:provider/provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserModel()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
// is not restarted.
primarySwatch: Colors.blue,
),
home: const Wrapper(),
),
);
}
}
class Wrapper extends StatelessWidget {
const Wrapper({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.userChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
User? user = snapshot.data;
if (user == null) {
return const LoginPage();
}
return StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.snapshots(),
builder: (context, userSnapshot) {
if (userSnapshot.hasData) {
Provider.of<UserModel>(context, listen: true)
.fromJson(userSnapshot.data!.data());
return const HomePage();
}
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
});
} else {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
},
);
}
}
And this is the home page:
import 'package:flutter/material.dart';
import 'package:my_event_app/http/auth/user/sign_out.dart';
import 'package:my_event_app/pages/Create_Event/create_event_page.dart';
import 'package:my_event_app/pages/Onboarding/onboarding_page.dart';
import 'package:my_event_app/providers/User/user.dart';
import 'package:my_event_app/widgets/event_card_widget.dart';
import 'package:provider/provider.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Consumer<UserModel>(builder: (context, user, child) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.help_outline, color: Colors.black, size: 30),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return const OnboardingPage();
}));
},
),
actions: [
IconButton(
icon: const Icon(
Icons.arrow_forward_ios_sharp,
color: Colors.black,
),
onPressed: () {
signOut();
},
),
],
elevation: 0,
backgroundColor: Colors.white,
),
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Container(
color: Colors.white,
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const CircleAvatar(
radius: 25,
backgroundImage: NetworkImage(
"https://cdnnmundo1.img.sputniknews.com/img/07e5/09/13/1116212032_100:0:1273:1173_1920x0_80_0_0_efb734331af13dfe11ff6d43293c60e2.png"),
),
Container(
height: 50,
width: 50,
decoration: BoxDecoration(
color: Colors.orange[400],
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(0, 3),
),
],
),
child: Center(
child: IconButton(
color: Colors.white,
onPressed: () {
// Navigate to add event widget
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return const CreateEventPage();
}));
},
icon: const Icon(Icons.add),
),
),
),
],
),
const SizedBox(height: 32),
SizedBox(
width: double.infinity,
child: Text('Welcome, ${user.name}',
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
fontFamily: "Roboto")),
),
const SizedBox(height: 32),
Container(
padding: const EdgeInsets.all(16),
height: 100,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(0, 3),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(alignment: Alignment.center, children: [
SizedBox(
height: 45,
width: 45,
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation(Colors.orange[400]),
value: 14 / 20,
semanticsValue: "14/20",
color: Colors.black,
),
),
const Text("78%",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
fontFamily: "Roboto")),
]),
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text("Weekly progress",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
)),
Text("14/20 tasks completed"),
],
),
const Icon(Icons.bar_chart),
],
),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: const [
Text("You have 5 tasks for today",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
)),
Icon(Icons.calendar_today_outlined)
],
),
),
_renderEvents(user),
],
),
),
),
);
});
}
}
Column _renderEvents(UserModel user) {
return Column(
children: [
for (var event in user.events)
EventCard(
eventId: event,
),
],
);
}
And here's the provider:
import 'package:flutter/material.dart';
class UserModel extends ChangeNotifier {
String _name = '';
String _surnames = '';
String _uid = '';
String _email = '';
List<dynamic> _events = [];
String get name => _name;
String get surnames => _surnames;
String get uid => _uid;
String get email => _email;
List<dynamic> get events => _events;
UserModel();
set name(String value) {
_name = value;
notifyListeners();
}
set surnames(String value) {
_surnames = value;
notifyListeners();
}
set uid(String value) {
_uid = value;
notifyListeners();
}
set email(String value) {
_email = value;
notifyListeners();
}
set events(List<dynamic> value) {
_events = value;
notifyListeners();
}
void addEvent(String event) {
_events.add(event);
notifyListeners();
}
void removeEvent(String event) {
_events.remove(event);
notifyListeners();
}
void updateUser(String name, String uid) {
name = name;
uid = uid;
notifyListeners();
}
void clearUser() {
_name = '';
_uid = '';
notifyListeners();
}
Map<String, dynamic> toJson() {
return {
'name': _name,
'surnames': _surnames,
'uid': _uid,
'email': _email,
'events': _events
};
}
fromJson(Object? json) {
try {
Map<dynamic, dynamic> map = json as Map<dynamic, dynamic>;
_name = map['name'];
_surnames = map['surnames'];
_uid = map['uid'];
_email = map['email'];
_events = map['events'];
} catch (e) {
print(e);
}
}
}
```
As you can see i use Consumer in order to read data and i have a change notifier in the begginig, but it won't re render and show for example new name if i change it in fireabase.
Thank you so much!
You are using fromJson method to update values in UserModel, but it does not call notifyListeners. Add notifyListeners(); to the end of this method:
fromJson(Object? json) {
try {
Map<dynamic, dynamic> map = json as Map<dynamic, dynamic>;
_name = map['name'];
_surnames = map['surnames'];
_uid = map['uid'];
_email = map['email'];
_events = map['events'];
notifyListeners(); // add this
} catch (e) {
print(e);
}
}
Also some other things:
Consider declaring class UserModel with ChangeNotifier instead of class UserModel extends ChangeNotifier.
fromJson methods usually are acting as factory methods, meaning these return a new instance, and don't set members in an existing instance.
Instead of Provider.of<UserModel>(context, listen: true).fromJson(userSnapshot.data!.data()); you can try: context.read<UserModel>().fromJson(userSnapshot.data!.data());. Here you don't really need listening, you just want to find the provider and call fromJson. Your Consumer is the one which is listening to the changes accordingly.

how to display data in flutter firestore provider

I want to display data from firestore using provider in flutter. i got stuck please help. below are my codes
//product display page
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/product_details.dart';
import 'package:shopping/provider/app_provider.dart';
class Product extends StatefulWidget {
#override
_ProductState createState() => _ProductState();
}
class _ProductState extends State<Product> {
#override
Widget build(BuildContext context) {
final product = Provider.of<AppProvider>(context);
return GridView.builder(
itemCount: productList.length,
gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
itemBuilder: (BuildContext context, int index){
return Padding(
padding:const EdgeInsets.all(4.0),
child:SingleProd(
//where i want to get the product details
prodName: product.featuredProducts[index].name.toString(),
),
);
}
);
}
}
class SingleProd extends StatelessWidget {
final prodName;
final prodPicture;
final prodOldPrice;
final prodPrice;
SingleProd({this.prodName, this.prodPicture,this.prodOldPrice,this.prodPrice});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(tag: new Text("hero 1"),
child:
Material( child: InkWell(
onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
//here we are passing the value of the products to Product detail page
productDetailName:prodName,
)
)
),
child:GridTile(
footer: Container(
color: Colors.white,
child: new Row(
children: <Widget>[
new Expanded(
child: new Text(prodName, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
),
new Text(
"\$$prodPrice", style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
],
)
),
child: Image.asset(prodPicture,
fit: BoxFit.cover,),
),
),
),
),
);
}
}
//product class
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';
class Product{
static const ID = "id";
static const CATEGORY = "category";
static const NAME = "name";
static const PRICE = "price";
static const BRAND = "brand";
static const COLORS = "colors";
static const QUANTITY = "quantity";
static const SIZES = "sizes";
static const SALE = "sale";
static const FEATURED = "featured";
static const PICTURE = "picture";
String _id;
String _name;
String _brand;
String _category;
String _picture;
double _price;
int _quantity;
List _colors;
List _sizes;
bool _onSale;
bool _featured;
// getters
String get name => _name;
String get id => _id;
String get category => _category;
String get brand => _brand;
String get picture => _picture;
double get price => _price;
int get quantity => _quantity;
List get colors => _colors;
List get sizes => _sizes;
bool get onSale => _onSale;
bool get featured => _featured;
// named constructure
Product.fromSnapshot(DocumentSnapshot snapshot){
Map data = snapshot.data;
_name = data[NAME];
_id = data[ID];
_category = data[CATEGORY];
_brand = data[BRAND];
_price = data[PRICE];
_quantity = data[QUANTITY];
_colors = data[COLORS];
_onSale = data[SALE];
_featured = data[FEATURED];
_picture = data[PICTURE];
}
}
//provider page for the product
import 'package:flutter/material.dart';
import 'package:shopping/db/product.dart';
import 'package:shopping/models/product.dart';
class AppProvider with ChangeNotifier {
List<Product>_fearturedProducts=[];
//method
void _getFeaturedProducts()async{
_fearturedProducts=await _productService.getFeaturedProducts();
notifyListeners();
}
}
//connection to Firestore to collect data
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shopping/models/product.dart';
class ProductService{
Firestore _firestore=Firestore.instance;
String collection="Products";
Future<List<Product>>getFeaturedProducts(){
_firestore.collection(collection).where('featured', isEqualTo:true).getDocuments()
.then((snap){
List<Product>featuredProducts=[];
snap.documents.map((snapshot)=> featuredProducts.add(Product.fromSnapshot(snapshot)));
return featuredProducts;
});
}
}
guys, I have managed to solve the question. The answer is as follow //product page
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/product_details.dart';
import 'package:shopping/provider/app_provider.dart';
import 'package:shopping/models/product.dart';
class Products extends StatefulWidget {
#override
ProductsState createState() => ProductsState();
}
class ProductsState extends State<Products> {
List<Product> products;
#override
Widget build(BuildContext context) {
final productProvider = Provider.of<CRUDModel>(context);
return StreamBuilder<QuerySnapshot>(
stream: productProvider.fetchProductsAsStream(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
products = snapshot.data.documents
.map((doc) => Product.fromMap(doc.data, doc.documentID))
.toList();
return GridView.builder(
itemCount: products.length,
gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
itemBuilder: (BuildContext context, index){
return Padding(
padding:const EdgeInsets.all(4.0),
child:SingleProd(
product:products[index]
// prodPicture: productList[index]['picture'],
//prodOldPrice: productList[index]['oldPrice'],
//prodPrice: productList[index]['price'],
),
);
}
);
}
else {
return Text('fetching');
}
}
);
}
}
class SingleProd extends StatelessWidget {
//final prodName;
//final prodPicture;
//final prodOldPrice;
//final prodPrice;
final Product product;
SingleProd({ #required this.product});
//SingleProd({product.picture});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(tag: product.id,
child:
Material( child: InkWell(
onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
//here we are passing the value of the products to Product detail page
productDetailName:product.name,
productDetailNewPrice:product.price,
productDetailPicture:product.picture,
//productDetailOldPrice:prodOldPrice,
//productDetailNewPrice:prodPrice,
//productDetailPicture: prodPicture,
)
)
),
child:GridTile(
footer: Container(
color: Colors.white,
child: new Row(
children: <Widget>[
new Expanded(
child: new Text(product.name, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
),
new Text(
'${product.price} \$', style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
],
)
),
child: Image.asset('assets/${product.picture}.jpg',
fit: BoxFit.cover,),
),
),
),
),
);
}
}
//product class
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:ui';
class Product {
String id;
String name;
String brand;
String category;
String picture;
double price;
int quantity;
List colors;
List sizes;
bool sale;
bool featured;
Product(
{this.id, this.name, this.brand,
this.category, this.picture,this.price,
this.quantity,this.colors,this.sizes,this.sale,this.featured}
);
Product.fromMap(Map snapshot,String id) :
id = id ?? '',
name= snapshot['name'] ?? '',
brand = snapshot['brand'] ?? '',
category = snapshot['category'] ?? '',
picture= snapshot['picture'] ?? '',
price= snapshot['price'] ?? '',
quantity= snapshot['quantity'] ?? '',
colors= snapshot['colors'] ?? '',
sizes= snapshot['sizes'] ?? '',
sale= snapshot['sale'] ?? '',
featured= snapshot['featured'] ?? '';
toJson() {
return {
"name": name,
"brand": brand,
"category": category,
"picture": picture,
"price": price,
"quantity": quantity,
"colors": colors,
"sizes": sizes,
"sale": sale,
"featured": brand,
};
}
}
//provider class for the product
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shopping/db/Api.dart';
import 'package:shopping/models/product.dart';
class CRUDModel extends ChangeNotifier {
//Api _api = locator<Api>();
String path="Products";
Api _api= Api();
List<Product> products;
Future<List<Product>> fetchProducts() async {
var result = await _api.getDataCollection();
products = result.documents
.map((doc) => Product.fromMap(doc.data, doc.documentID))
.toList();
notifyListeners();
return products;
}
Stream<QuerySnapshot> fetchProductsAsStream() {
notifyListeners();
return _api.streamDataCollection();
}
Future<Product> getProductById(String id) async {
var doc = await _api.getDocumentById(id);
notifyListeners();
return Product.fromMap(doc.data, doc.documentID) ;
}
}
//connection to firestore
import 'package:cloud_firestore/cloud_firestore.dart';
class Api{
final Firestore _db = Firestore.instance;
String ref="Products";
//CollectionReference ref;
/*Api({this.path } ) {
ref = _db.collection(path);
}*/
Future<QuerySnapshot> getDataCollection() {
//return ref.getDocuments() ;
return _db.collection(ref).where('featured', isEqualTo:true).getDocuments();
}
Stream<QuerySnapshot> streamDataCollection() {
// return ref.snapshots() ;
//return _db.snapshots(ref).getDocuments();
return _db.collection(ref).snapshots();
}
Future<DocumentSnapshot> getDocumentById(String id) {
// return ref.document(id).get();
return _db.document(id).get();
}
Future<void> removeDocument(String id){
//return ref.document(id).delete();
return _db.document(id).delete();
}
Future<DocumentReference> addDocument(Map data) {
// return ref.add(data);
return _db.collection(ref).add(data);
}
Future<void> updateDocument(Map data , String id) {
//return ref.document(id).updateData(data) ;
return _db.document(ref).updateData(data);
}
}
//homepage where i displayed the products
import 'package:flutter/material.dart';
import 'package:carousel_pro/carousel_pro.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:shopping/commons/common.dart';
import 'package:provider/provider.dart';
import 'package:shopping/provider/app_provider.dart';
import '../provider/user_provider.dart';
//My packages imports
import 'package:shopping/componets/horizontal_listview.dart';
import 'package:shopping/componets/product.dart';
import 'package:shopping/pages/cart.dart';
import 'package:shopping/pages/login.dart';
class HomePage extends StatefulWidget {
// List<Product> products;
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController _searchController = new TextEditingController();
//final FirebaseAuth _firebaseAuth=FirebaseAuth.instance;
#override
Widget build(BuildContext context) {
final user = Provider.of<UserProvider>(context);
final productProvider=Provider.of<CRUDModel>(context);
Widget image_carousel = new Container(
height: 200.0,
child: new Carousel(
boxFit: BoxFit.cover,
images: [
AssetImage('images/c1.jpg'),
AssetImage('images/m1.jpeg'),
AssetImage('images/m2.jpg'),
AssetImage('images/w1.jpeg'),
AssetImage('images/w3.jpeg'),
AssetImage('images/w4.jpeg'),
],
autoplay:true,
animationCurve: Curves.fastOutSlowIn,
animationDuration: Duration(milliseconds:1000 ),
dotSize: 4.0,
indicatorBgPadding: 8.0,
dotBgColor: Colors.transparent,
),
);
return Scaffold(
appBar: new AppBar(
iconTheme: IconThemeData(color: blue),
elevation: 0.1,
backgroundColor: white,
title: Material(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[50],
elevation: 0.0,
child: TextFormField(
controller: _searchController,
decoration: InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
validator: (value) {
if (value.isEmpty) {
return "The Search field cannot be empty";
}
return null;
}),
),
actions: <Widget>[
new IconButton(
icon: Icon(
Icons.search,
color: blue,
),
onPressed: () {},
),
new IconButton(
icon: Icon(
Icons.shopping_cart,
color: blue,
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => new Cart()));
}),
],
),
drawer: new Drawer(
child: new ListView(
children: <Widget>[
//drawer header
new UserAccountsDrawerHeader(
accountName: Text("Afolabi"),
accountEmail: Text("mtreal62#gmail.com"),
currentAccountPicture: GestureDetector(
child: new CircleAvatar(
backgroundColor: Colors.grey,
child: Icon(
Icons.person,
color: Colors.white,
),
),
),
decoration: BoxDecoration(
color: blue,
),
),
//body
InkWell(
onTap: () {},
child: ListTile(
title: Text("Home Page"),
leading: Icon(
Icons.home,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("My Account"),
leading: Icon(
Icons.person,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("My Orders"),
leading: Icon(
Icons.shopping_basket,
color: blue,
),
),
),
InkWell(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => new Cart()));
},
child: ListTile(
title: Text("Shopping Cart"),
leading: Icon(
Icons.shopping_cart,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("Favourites"),
leading: Icon(
Icons.favorite,
color: blue,
),
),
),
Divider(),
InkWell(
onTap: () {},
child: ListTile(
title: Text("Settings"),
leading: Icon(
Icons.settings,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("About"),
leading: Icon(
Icons.help,
),
),
),
InkWell(
onTap: () {
user.signOut();
// changeScreenReplacement(context, Login());
},
child: ListTile(
title: Text("Log Out"),
leading: Icon(
Icons.transit_enterexit,
),
),
),
],
),
),
body: new Column(
children: <Widget>[
//Image Carousel for the home Page Banner
image_carousel,
//padding widget after carousel
new Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.centerLeft,
child: new Text("Categories"),
),
),
//Horizontal layout start from here
HorizontalList(),
//End of the horizontal layout
//padding widget for Recent products categories
new Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.centerLeft,
child: new Text("Recent Products"),
),
),
// Text(appProvider.featuredProducts.length.toString(),
//style: TextStyle(color: Colors.black),),
Flexible(
child: Products(),
),
//Horizontal layout start from here
],
),
);
}
}
Future _signOut() async {
try {
await FirebaseAuth.instance.signOut();
} catch (e) {
print(e); // TODO: show dialog with error
}
}
You are never calling _getFeaturedProducts() from your AppProvider class. So _fearturedProducts will always be null
In class AppProvider you are calling method on undefined name:
_productService.getFeaturedProducts()
Every IDE should show you this error ex. In my Android Studio it looks like this: