The getter 'length' was called on null, Error in Flutter - android

I need to list a table in a .db database. When I run the application in the emulator, the error "The getter 'length' was called on null" pops up for a second, but then the list I need is displayed immediately.
And when you start Debug on a connected smartphone, everything stops with the error "The getter 'length' was called on null".
What could be the problem? It seems that somewhere there is not enough method of waiting for data from the database.
I/flutter (10923): /data/user/0/com.example.test_project/databases/database.db
I/flutter (10923): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
╞═══════════════════════════════════════════════════════════
I/flutter (10923): The following NoSuchMethodError was thrown building
FutureBuilder<List<Authors>>(dirty, state:
I/flutter (10923): _FutureBuilderState<List<Authors>>#3ecfd):
I/flutter (10923): The getter 'length' was called on null.
I/flutter (10923): Receiver: null
I/flutter (10923): Tried calling: length
Database.dart
class DBProvider {
DBProvider._();
static final DBProvider db = DBProvider._();
Database _database;
Future<Database> get database async {
_database = await initDB();
return _database;
}
initDB() async {
String path = join(await getDatabasesPath(), "database.db");
var exists = await databaseExists(path);
print(path);
return await openDatabase(path);
}
Future<List<Authors>> getAllClients() async {
final db = await database;
var res = await db.query('category');
print(res);
List<Authors> list = [];
list = res.map((c) => Authors.fromMap(c)).toList();
return list;
}
}
This is the class where the UI of the sheet of elements from the database is drawn.
class MainTab extends StatefulWidget {
#override
_MainTabState createState() => _MainTabState();
}
class _MainTabState extends State<MainTab> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
child: Container(
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
color: Theme.of(context).accentColor,
borderRadius: BorderRadius.all(Radius.circular(30))
),
child: FutureBuilder<List<Authors>>(
future: DBProvider.db.getAllClients(),
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Authors item = snapshot.data[index];
return ListTile(
title: Text(item.name),
leading: Icon(Icons.folder),
trailing: Text(item.count.toString()),
onTap: () {
},
);
},
);
},
)
),
);
}
}

Use ConnectionState
https://pub.dev/documentation/flutter_for_web/latest/widgets/FutureBuilder-class.html
You have to write something like this:
FutureBuilder<List<Authors>>(
future: DBProvider.db.getAllClients(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
case ConnectionState.done:
{
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
} else if (snapshot.hasData) {
return ListView.builder(
itemCount:snapshot.data==null?0: snapshot.data.length,
itemBuilder: (context, index) {
Authors item = snapshot.data[index];
return ListTile(
title: Text(item.name),
leading: Icon(Icons.folder),
trailing: Text(item.count.toString()),
onTap: () {
},
);
}
return Center(child: Text('No Data'));
}
default:
return Container();
}
}),

Related

Flutter error: The property 'docs' can't be unconditionally accessed because the receiver can be 'null'

I am struggling to resolve these two errors.
error: The property 'docs' can't be unconditionally accessed because the receiver can be 'null'. (unchecked_use_of_nullable_value at [church_app] lib\Screens\DevotionalList.dart:23)
error: The parameter 'devotional' can't have a value of 'null' because of its type, but the implicit default value is 'null'. (missing_default_value_for_parameter at [church_app] lib\Screens\DevotionalList.dart:39)
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class DevotionalList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('devotionals').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text('Error: ${snapshot.error}'),
);
}
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
// Use the .docs property to access the list of documents.
List<DocumentSnapshot> documents = snapshot.data.docs;
return ListView.builder(
itemCount: documents.length,
itemBuilder: (context, index) {
DocumentSnapshot devotional = documents[index];
return DevotionalTile(devotional: devotional);
},
);
},
);
}
}
class DevotionalTile extends StatelessWidget {
final DocumentSnapshot devotional;
DevotionalTile({this.devotional});
#override
Widget build(BuildContext context) {
if (devotional == null) {
return Container();
}
return ExpansionTile(
title: Text(devotional['title']),
subtitle: Text('By ${devotional['author']}'),
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(devotional['body']),
),
],
);
}
}
Any assistance would be appreciated.
Tried adding null exceptions but I still run into the same error.
at the point when your call snapshot.data.docs, it can't be null since you checked first with the hasError, so you can tell this to Dart by explicitly adding a !, instead of this:
List<DocumentSnapshot> documents = snapshot.data.docs;
add !, so it will be this:
List<DocumentSnapshot> documents = snapshot.data.docs!;
this will fix both the error you're facing.

Check if key exists in Firebase Firestore

I want to make a to-do list with task due date as an optional field, so I need to check if some tasks have dueDate and add it as a subtitle based on that. How can I check if a field exists inside a doc in a StreamBuilder?
class _TaskListState extends State<TaskList> {
var myStream;
#override
void initState() {
myStream = FirebaseFirestore.instance
.collection('tasks')
.doc(widget.uid)
.collection('mytasks')
.snapshots();
super.initState();
}
...
void _updateTaskDesc(
dynamic currTask, String newDesc, DateTime newDate, TimeOfDay newTime) {
FirebaseFirestore.instance
.collection('tasks')
.doc(widget.uid)
.collection('mytasks')
.doc(currTask['id'])
.update({
'desc': newDesc,
'dueDate': newDate.toString(),
'dueTime': newTime.toString(),
});
}
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: myStream,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: SizedBox(
height: 100, width: 100, child: CircularProgressIndicator()),
);
} else {
final docs = snapshot.data.docs;
bool hasDateTime = ????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return ListView.builder(
itemCount: docs.length,
itemBuilder: (ctx, index) {
final currTask = docs[index];
return InkWell(
highlightColor: Theme.of(context).secondaryHeaderColor,
splashColor: Theme.of(context).secondaryHeaderColor,
onLongPress: () {
showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (bCtx) {
FocusManager.instance.primaryFocus?.unfocus();
return TaskOptions(_updateTaskDesc,
() => _updateHasImage(docs[index]), currTask);
},
);
},
child: Dismissible(
direction: DismissDirection.startToEnd,
key: UniqueKey(),
onDismissed: (_) async {
FirebaseFirestore.instance
.collection('tasks')
.doc(widget.uid)
.collection('mytasks')
.doc(currTask['id'])
.delete();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("${currTask['desc']} dismissed"),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
FirebaseFirestore.instance
.collection("tasks")
.doc(widget.uid)
.collection("mytasks")
.doc(currTask['id'])
.set({
"desc": currTask['desc'],
"id": currTask['id'],
"isDone": currTask['isDone'],
"hasImage": currTask['hasImage'],
});
try {
FirebaseFirestore.instance
.collection("tasks")
.doc(widget.uid)
.collection("mytasks")
.doc(currTask['id'])
.update({
"dueDate": currTask['dueDate'],
"dueTime": currTask['dueTime'],
});
} catch (e) {}
},
),
),
);
},
child: ListTile(
...
subtitle: Text(hasDateTime
? DateFormat('dd/MM')
.format(DateTime.parse(currTask['dueDate']))
: ''),
...
I saw that a containsKey('key') method works for some people but I get NoSuchMethod when I try that. What can I do?
The single document is just a normal Dart Map, so you can check if a key exists or not using containsKey method.
So you condition becomes the following:
bool hasDateTime = currTask.containsKey('dueDate`);
NOTE: In the question I can see that you are defining the condition in the wrong place which is outside the itemBuilder method in the ListView so that it is not item based and well not work because it does not make sense.
You can have it in this place:
...
itemBuilder: (ctx, index) {
final currTask = docs[index];
bool hasDateTime = currTask.containsKey('dueDate`);
return InkWell(
...

I'm facing a error The method '[]' was called on null. Receiver: null Tried calling: []("postId")

#override
Widget build(BuildContext context) {
return FutureBuilder(
future: postsRef
.document(userId)
.collection("usersPosts")
.document(postId)
.get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
Post post = Post.fromDocument(snapshot.data);
return Center(
child: Scaffold(
appBar: header(context, titleText: post.description),
body: ListView(
children: [
Container(
child: post,
)
],
),
),
);
},
);
}
also this my error
The following NoSuchMethodError was thrown building FutureBuilder<DocumentSnapshot>(dirty, state: _FutureBuilderState<DocumentSnapshot>#37f30):
The method '[]' was called on null.
Receiver: null
Tried calling: []("postId")
The relevant error-causing widget was:
FutureBuilder<DocumentSnapshot> file:///D:/Flutter/KadShare/kadshare/lib/pages/post_screen.dart:18:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 DocumentSnapshot.[] (package:cloud_firestore/src/document_snapshot.dart:29:42)
#2 new Post.fromDocument (package:kadshare/widgets/post.dart:34:18)
#3 PostScreen.build.<anonymous closure> (package:kadshare/pages/post_screen.dart:28:26)
#4 _FutureBuilderState.build (package:flutter/src/widgets/async.dart:773:55)
My Post Class
final String postId;
final String ownerId;
final String username;
final String location;
final String description;
final String mediaUrl;
final dynamic likes;
Post({
this.postId,
this.ownerId,
this.username,
this.location,
this.description,
this.mediaUrl,
this.likes,
});
factory Post.fromDocument(DocumentSnapshot doc) {
return Post(
postId: doc["postId"],
ownerId: doc["ownerId"],
username: doc["username"],
location: doc["location"],
description: doc["description"],
mediaUrl: doc["mediaUrl"],
likes: doc["likes"],
);
}
Your snapshot is a Flutter AsyncSnapshot, specifically a AsyncSnapshot<DocumentSnapshot>. When snapshot.hasData is true, that means the DocumentSnapshot exists.
But a DocumentSnapshot exists even when the underlying document doesn't exist in the database, so you also need to check if the DocumentSnapshot has data, which you do with DocumentSnapshot.exists.
So your check then becomes:
if (!snapshot.hasData && snapshot.data.exists) {
So this change means the spinner will keep being rendered if the document doesn't exist.
Alternatively, you may want to render a different UI if the document doesn't exist:
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
if (!snapshot.data.exists) {
return Text("Document does not exist");
}
Post post = Post.fromDocument(snapshot.data);
return Center(
child: Scaffold(
appBar: header(context, titleText: post.description),
body: ListView(
children: [
Container(
child: post,
)
],
),
),
);
},
Also see What is the difference between existing types of snapshots in Firebase?
Your snapshot.data is null;
Maybe change:
if (!snapshot.hasData || snapshot.data == null) {
i assume you are working on fluttershare course app, in your activity feed page when you press show post function make sure you give userId your currentUser.id passing in a non-null value for the 'postId' parameter as shown here:
showPost(context) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PostScreen(
userId: currentUser.id,
postId: postId,
),
),
);
}

Flutter asset database error: The getter 'length' was called on null. Receiver: null Tried calling: length

I added my existing database.db file to my project with sqflite. No errors encountered, everything works fine, but... Flutter debug console says:
Restarted application in 772ms.
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building FutureBuilder<List<Countries>>(dirty, state: _FutureBuilderState<List<Countries>>#d0317):
The getter 'length' was called on null.
Receiver: null
Tried calling: length
The relevant error-causing widget was
FutureBuilder<List<Countries>>
When the exception was thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 _HomeScreen.buildBody.<anonymous closure>
#2 _FutureBuilderState.build
#3 StatefulElement.build
#4 ComponentElement.performRebuild
...
════════════════════════════════════════════════════════════════════════════════
I/flutter (14052): Opening existing database
Here is my model Country.dart :
class Countries {
int countryId;
String countryName;
String countryImageURL;
//Constructor
Countries({this.countryId, this.countryName, this.countryImageURL});
// Extract a Product Object from a Map Oject
Countries.fromMap(Map<String, dynamic> map) {
countryId = map['country_id'];
countryName = map['country_name'];
countryImageURL = map['image'];
}
Map<String, dynamic> toMap() {
var map = <String, dynamic>{
'country_name': countryName,
'image': countryImageURL
};
return map;
}
}
Here is my database_helper.dart file:
import 'dart:async';
import 'dart:io';
import 'package:city_travel_guide/model/Country.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'dart:typed_data';
import 'package:flutter/services.dart';
class DbHelper {
static Database _db;
Future<Database> get db async {
if (_db != null) {
return _db;
} else {
_db = await initDb();
return _db;
}
}
initDb() async {
var dbFolder = await getDatabasesPath();
String path = join(dbFolder, 'app.db');
var exists = await databaseExists(path);
if (!exists) {
// Should happen only the first time you launch your application
print("Creating new copy from asset");
// Make sure the parent directory exists
try {
await Directory(dirname(path)).create(recursive: true);
} catch (_) {}
// Copy from asset
ByteData data = await rootBundle.load(join("assets", "example.db"));
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
// Write and flush the bytes written
await File(path).writeAsBytes(bytes, flush: true);
} else {
print("Opening existing database");
}
// open the database
return await openDatabase(path);
}
Future<List<Countries>> getCountries() async {
var dbClient = await db;
var result = await dbClient.query('Country', orderBy: 'countryId');
return result.map((data) => Countries.fromMap(data)).toList();
}
Here is my main.dart file:
import 'package:city_travel_guide/data/database_helper.dart';
import 'package:city_travel_guide/model/Country.dart';
import 'package:flutter/material.dart';
import 'widgets/maindrawer.dart';
import 'pages/search.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'City Travel Guide',
theme: ThemeData.dark(),
debugShowCheckedModeBanner: false,
home: MyHome());
}
}
class MyHome extends StatefulWidget {
#override
_HomeScreen createState() => _HomeScreen();
}
class _HomeScreen extends State<MyHome> {
List<Countries> countries;
final dbHelper = DbHelper();
#override
void initState() {
dbHelper.initDb();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'City Travel Guide',
style: Theme.of(context).primaryTextTheme.headline6,
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SearchScreen()),
);
}),
IconButton(icon: const Icon(Icons.more_vert), onPressed: () {}),
],
),
drawer: Drawer(child: MainDrawer()),
body: buildBody(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {},
));
}
buildBody() {
return FutureBuilder<List<Countries>>(
future: dbHelper.getCountries(),
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(title: Text(snapshot.data[index].countryName));
},
);
});
}
}
How can I list items on my asset database and view it in application?
FutureBuilder is an asynchronous request. Always check that snapshot has data before building your list.
do:
buildBody() {
return FutureBuilder<List<Countries>>(
future: dbHelper.getCountries(),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data.length > 0) // This ensures that you have at least one or more countries available.
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(title: Text(snapshot.data[index].countryName));
},
);
else if (snapshot.hasData && snapshot.data.length == 0)
return Center(child:Text("There are no countries available"));
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).primaryColor),
)); // This would display a loading animation before your data is ready
});
}
Its to easy you must check if there is a data comming from the future or not before using the snapshot.data.lenght because if the snapshot.data is null(the opperation not finished yet) then lenght was calling on null so you must do it
The correct code
buildBody() {
return FutureBuilder<List<Countries>>(
future: dbHelper.getCountries(),
builder: (context, snapshot) {
if(snapshot.hasdata&&snapshot.data.runtimetype==List){
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(title: Text(snapshot.data[index].countryName));
},
);
}else{
return Proggresindicator()//or any loading widgets
}
});
}
}
and you can add check for any execption happens during the future

Flutter Bloc with news api

I am stacked!! and i know i will find help here . I create a flutter application which fetches data from news.org API . Everything was working fine until i started implementing BLOC in the app . I have successfully implemented the first part with BLOC with fetches all the data from the API . the next thing to do is to fetch another data using the categories provided by the API in another page using BLOC .
For instance , there are categories like business , technology , finance etc . So main thing is when the user taps on any of the category the data show be fetched from the API using BLOC .
the following are the codes for the bloc ...
THIS IS THE ERROR I GET
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building BlocListener<ArticleBloc, ArticleState>(dirty, state: _BlocListenerBaseState<ArticleBloc, ArticleState>#aae07):
A build function returned null.
The offending widget is: BlocListener<ArticleBloc, ArticleState>
Build functions must never return null.
To return an empty space that causes the building widget to fill available room, return "Container()". To return an empty space that takes as little room as possible, return "Container(width: 0.0, height: 0.0)".
The relevant error-causing widget was:
BlocListener<ArticleBloc, ArticleState> file:///C:/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_bloc-6.1.1/lib/src/bloc_builder.dart:149:12
When the exception was thrown, this was the stack:
#0 debugWidgetBuilderValue. (package:flutter/src/widgets/debug.dart:302:7)
#1 debugWidgetBuilderValue (package:flutter/src/widgets/debug.dart:323:4)
#2 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4632:7)
#3 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
RepositoRy
abstract class CategoryRepository {
Future<List<Article>> getCategory(String category);
}
class CatService implements CategoryRepository {
#override
Future<List<Article>> getCategory(String category) async {
// List<Article> categoryNewsList = [];
String url =
"http://newsapi.org/v2/top-headlines?country=us&category=$category&apiKey=df74fc47f0dd401bb5e56c34893a7795";
return getData(url);
/*var response = await http.get(url);
//decode the response into a json object
var jsonData = jsonDecode(response.body);
//check if the status of the response is OK
if (jsonData["status"] == "ok") {
jsonData["articles"].forEach((item) {
//check if the imageUrl and description are not null
if (item["urlToImage"] != null && item["description"] != null) {
//create an object of type NewsArticles
Article newsArticleModel = new Article(
author: item["author"],
title: item["title"],
description: item["description"],
url: item["url"],
urlToImage: item["urlToImage"],
content: item["content"]);
//add data to news list
categoryNewsList.add(newsArticleModel);
}
});
}
return categoryNewsList;*/
}
}
Future<List<Article>> getData(String url) async {
List<Article> items = [];
var response = await http.get(url);
//decode the response into a json object
var jsonData = jsonDecode(response.body);
//check if the status of the response is OK
if (jsonData["status"] == "ok") {
jsonData["articles"].forEach((item) {
//check if the imageUrl and description are not null
if (item["urlToImage"] != null && item["description"] != null) {
//create an object of type NewsArticles
Article article = new Article(
author: item["author"],
title: item["title"],
description: item["description"],
url: item["url"],
urlToImage: item["urlToImage"],
content: item["content"]);
//add data to news list
items.add(article);
}
});
}
return items;
}
Bloc
class ArticleBloc extends Bloc<ArticleEvent, ArticleState> {
CategoryRepository categoryRepository;
ArticleBloc({this.categoryRepository}) : super(ArticleInitial());
#override
Stream<ArticleState> mapEventToState(
ArticleEvent event,
) async* {
if (event is GetArticle) {
try {
yield ArticleLoading();
final articleList =
await categoryRepository.getCategory(event.category);
yield ArticleLoaded(articleList);
} catch (e) {
print(e.message);
}
}
}
}
Event
class GetArticle extends ArticleEvent{
final String category;
GetArticle(this.category);
}
States
#immutable
abstract class ArticleState {
const ArticleState();
}
class ArticleInitial extends ArticleState {
const ArticleInitial();
}
class ArticleLoading extends ArticleState {
const ArticleLoading();
}
class ArticleLoaded extends ArticleState {
final List<Article> articleList;
ArticleLoaded(this.articleList);
}
class ArticleError extends ArticleState {
final String error;
ArticleError(this.error);
#override
bool operator ==(Object object) {
if (identical(this, object)) return true;
return object is ArticleError && object.error == error;
}
#override
int get hashCode => error.hashCode;
}
UI
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'News app',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: BlocProvider(
child: TestCat(),
create: (context) => ArticleBloc(categoryRepository : CatService()),
),
);
}
}
tEST category page
class TestCat extends StatefulWidget {
#override
_TestCatState createState() => _TestCatState();
}
class _TestCatState extends State<TestCat> {
bool isLoading = true;
List<String> categoryItems;
#override
void initState() {
super.initState();
categoryItems = getAllCategories();
// getCategory(categoryItems[0]);
// getCategoryNews();
}
getCategory(cat) async {
context.bloc<ArticleBloc>().add(GetArticle(cat));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: header(context, isAppTitle: false, title: "App"),
body: _newsBody(context),
);
}
_newsBody(context) {
return ListView(
children: [
//category list
Container(
padding:
EdgeInsets.symmetric(horizontal: NewsAppConstants().margin16),
height: NewsAppConstants().columnHeight70,
child: ListView.builder(
itemCount: categoryItems.length,
itemBuilder: (context, index) {
return TitleCategory(
title: categoryItems[index],
onTap: ()=> callCat(context, categoryItems[index]),
);
},
shrinkWrap: true,
scrollDirection: Axis.horizontal,
),
),
Divider(),
Container(
child: BlocBuilder<ArticleBloc, ArticleState>(
builder: (context, ArticleState articleState) {
//check states and update UI
if (articleState is ArticleInitial) {
return buildInput(context);
} else if (articleState is ArticleLoading) {
return Loading();
} else if (articleState is ArticleLoaded) {
List<Article> articles = articleState.articleList;
updateUI(articles);
} else if (articleState is ArticleError) {
// shows an error widget when something goes wrong
final error = articleState.error;
final errorMsg = "${error.toString()}\nTap to retry";
ShowErrorMessage(
errorMessage: errorMsg,
onTap: getCategory,
);
}
return buildInput(context);
}),
),
],
);
}
getAllCategories() {
List<String> categoryList = [
"Business",
"Entertainment",
"General",
"Sports",
"Technology",
"Health",
"Science"
];
return categoryList;
}
Widget updateUI(List<Article> newsList) {
return SingleChildScrollView(
child: Column(
children: [
Container(
child: ListView.builder(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: newsList.length,
itemBuilder: (context, index) {
return NewsBlogTile(
urlToImage: newsList[index].urlToImage,
title: newsList[index].title,
description: newsList[index].description,
url: newsList[index].url,
);
}),
),
Divider(),
],
));
}
buildInput(context) {
ListView.builder(
itemCount: categoryItems.length,
itemBuilder: (context, index) {
return TitleCategory(
title: categoryItems[index],
onTap: () {
print("tapped");
// callCat(context, categoryItems[index]);
},
);
},
shrinkWrap: true,
scrollDirection: Axis.horizontal,
);
}
callCat(BuildContext context, String cat) {
print(cat);
context.bloc<ArticleBloc>().add(GetArticle(cat));
}
}
//this displays the data fetched from the API
class NewsBlogTile extends StatelessWidget {
final urlToImage, title, description, url;
NewsBlogTile(
{#required this.urlToImage,
#required this.title,
#required this.description,
#required this.url});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {},
child: Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(NewsAppConstants().margin8),
child: Column(
children: <Widget>[
ClipRRect(
borderRadius:
BorderRadius.circular(NewsAppConstants().margin8),
child: Image.network(urlToImage)),
Text(
title,
style: TextStyle(
fontWeight: FontWeight.w600,
color: Colors.black,
fontSize: NewsAppConstants().margin16),
),
SizedBox(
height: NewsAppConstants().margin8,
),
Text(
description,
style: TextStyle(color: Colors.black54),
)
],
),
),
Divider(),
],
),
),
);
}
}
//news title category
class TitleCategory extends StatelessWidget {
final title;
final Function onTap;
TitleCategory({this.title, this.onTap});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => onTap,
child: Container(
margin: EdgeInsets.all(NewsAppConstants().margin8),
child: Stack(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(NewsAppConstants().margin8),
child: Container(
child: Text(
title,
style: TextStyle(
color: Colors.white,
fontSize: NewsAppConstants().font16,
fontWeight: FontWeight.w500),
),
alignment: Alignment.center,
width: NewsAppConstants().imageWidth120,
height: NewsAppConstants().imageHeight60,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(NewsAppConstants().margin8),
color: Colors.black,
),
),
)
],
),
),
);
}
}
from what I see
you might try one of the below solutions :
try in bloc builder to return Container and inside it handle you states like this :
builder: (context, state) {
return Container(
child: Column(
children: [
if (state is Loading)
CircularProgressIndicator(),
if (state is Loaded)
CatsListView(data: state.data),
try to cover all your kind of states in if/else in your Bloc builder
so let's assume that you have 2 states (state1, state2) so your Bloc builder
would be something like this
builder: (context, state) {
if (state is state1) return Container();
else if (state is state2) return Container();
else return Container();
note that if you covered all states you don't have to do the last else

Categories

Resources