list view builder with hive database - flutter

I was using a list view builder which got its item count from the hive database. I managed to get it to work but its text appeared to be in brackets for example (Apollo, Jesus) any ideas on how to fix it. as in the formatting so it would appear as apollo,jesus. FYI I opened and initiated the box on the main.dart page
here is my code, I'm still learning sorry for bad code.
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void main() {
runApp(nextpage());
}
class nextpage extends StatefulWidget {
const nextpage({Key? key}) : super(key: key);
#override
State<nextpage> createState() => _nextpageState();
}
class _nextpageState extends State<nextpage> {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(
Icons.chevron_left,
color: Colors.black,
),
onPressed: () => Navigator.pop(context),
),
backgroundColor: Colors.yellow,
centerTitle: true,
title: Text(
'Database',
style: TextStyle(color: Colors.black),
),
),
backgroundColor: Colors.yellow[200],
body: ListView.builder(
itemCount: Hive.box('db').length,
itemBuilder: (BuildContext context, int index) {
return Container(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
Hive.box('db').values.toString(),
style: TextStyle(fontSize: 20),
),
),
],
),
);
},
),
),
),
);
}
}
I tried changing the text to Hive.box('db').values.toString but it didn't provide results

You need to open the box to receive data. You can do
void main() async {
await Hive.openBox('db');
runApp(nextpage());
}
or use FutureBuilder [.open() is a future method] before ListView.
More about using hivedb

Related

Flutter Navigation is not smooth, taking time to open next screen

I've a Quiz app which load text from a List of String class using ListViewBuilder. When i click on a category the question list is taking time to open 3-4 seconds. Here question in QuestionCategory is one for demo purpose. In real app it has 200+ question and the Navigation problem comes where question list is around more than 100+. The related question is already asked but the there is no proper solution for this.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:himachal_gk/Model/question_model.dart';
import 'package:himachal_gk/Widget/style_widgets.dart';
import '../../../Ads/GoogleAds.dart';
import 'category_question.dart';
class CategoryWiseScreen extends StatelessWidget {
const CategoryWiseScreen({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
var category = [
'River',
// 'Books',
];
return Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
title: const Text("Category Wise GK"),
actions: [
IconButton(
onPressed: () {
Navigator.of(context).pushNamed('/Favorite');
},
icon: const Icon(Icons.favorite_border_rounded))
],
),
bottomNavigationBar: GoogleAds.getBottomBannerAd(context),
body: AnimationLimiter(
child: ListView.builder(
cacheExtent: 9999999,
itemCount: category.length,
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 375),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: Column(
children: <Widget>[
SubCategoryTiles(
categoryIcon: Icons.school,
titleText: Center(
child: Text(
category[index],
style: headingTextStyle,
textAlign: TextAlign.center,
),
),
onTapHandler: () {
if (index == 0) {
List<QuestionCategory> questionCategory = [
QuestionCategory(
question:
'How many rivers are there in Himachal Pradesh',
correctAnswer: 'Five'),
];
Navigator.push(
context,
CupertinoPageRoute(
builder: ((context) => CategoryQuestion(
title: category[index],
questionCategory: questionCategory,
)),
),
);
}
},
),
const Divider(),
],
),
),
),
);
},
),
),
);
}
}
Here is SubCategoryTiles code we have used in above code.
import 'package:flutter/material.dart';
class SubCategoryTiles extends StatelessWidget {
const SubCategoryTiles({
Key? key,
required this.titleText,
required this.onTapHandler,
required this.categoryIcon,
}) : super(key: key);
final Widget titleText;
final VoidCallback onTapHandler;
final IconData categoryIcon;
#override
Widget build(BuildContext context) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Colors.white,
child: Icon(
categoryIcon,
size: 30,
),
),
title: titleText,
trailing: const Icon(Icons.arrow_right),
onTap: onTapHandler,
);
}
}
This is a performance issue. This is caused by two things in your case. First, you are loading heavy data while on a Navigation call. I will advise using initState or an async functionenter code here to call data before pushing to any screen.
List<QuestionCategory> questionCategory = [
QuestionCategory(
question: 'How many rivers are there in Himachal Pradesh',
correctAnswer: 'Five',
),
];
The above shows, you are calling within onTapHandler the same function that pushes to a new screen. In the live app, the Navigation will take time as it has to wait for data to fill in the questionCategory .

Datime value showing null

I have a field in my cloud firestore and there is posted_date it's showing perfectly there but when i try to put it in Text(' ${word.date_posted}') it's showing null. Help me out:
Here is an image of my database:
words_list.dart(This one calls the wordstile):
import 'package:flutter/material.dart';
import 'package:kopala_dictionary/models/words.dart';
import 'package:kopala_dictionary/screens/home/words_tile.dart';
import 'package:provider/provider.dart';
class WordsList extends StatefulWidget {
#override
_WordsListState createState() => _WordsListState();
}
class _WordsListState extends State<WordsList> {
#override
Widget build(BuildContext context) {
final words = Provider.of<List<Words>>(context) ?? [];
return ListView.builder(
itemCount: words.length,
itemBuilder: (context, index) {
return WordsTile(
word: words[index],
);
},
);
}
}
logged_home.dart(It displays all from words_tile and words_list):
import 'package:flutter/material.dart';
import 'package:kopala_dictionary/main/about.dart';
import 'package:kopala_dictionary/models/words.dart';
import 'package:kopala_dictionary/screens/home/words_list.dart';
import 'package:kopala_dictionary/screens/wrapper.dart';
import 'package:kopala_dictionary/services/auth.dart';
import 'package:kopala_dictionary/services/database.dart';
import 'package:kopala_dictionary/shared/app_bar.dart';
import 'package:provider/provider.dart';
class LoggedInUserHome extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return StreamProvider<List<Words>>.value(
value: DatabaseService().words,
child: Scaffold(
backgroundColor: Colors.green[10],
appBar: LoggedBar(),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text(
'Kopalationary Menu',
style: TextStyle(color: Colors.white),
),
decoration: BoxDecoration(
color: Colors.green[800],
),
),
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => Wrapper()));
},
),
ListTile(
title: Text(
'My profile',
),
onTap: () {},
),
ListTile(
title: Text('Logout'),
onTap: () async {
dynamic result = await _auth.logoutUser();
},
),
ListTile(
title: Text(
'About',
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => About()),
);
},
),
],
),
),
body: WordsList(),
),
);
}
}
words_tile.dart:
import 'package:flutter/material.dart';
import 'package:kopala_dictionary/models/words.dart';
class WordsTile extends StatelessWidget {
final Words word;
WordsTile({this.word});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(5.0, 8.0, 5.0, 0.0),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green[800],
radius: 25.0,
),
title: Text(word.word),
subtitle: Text(' ${word.date_posted}'),
),
),
);
}
}
It's showing null:

How to give a height to the PopUpMenuButton in Flutter?

I am trying to create aPopupMenuButton.I have used the PopupMenuButton class.
PopupMenuButton(
padding: EdgeInsets.only(right: 8.0),
offset: Offset(-16, 0),
child: Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.all(
Radius.circular(16.0),
)),
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0),
child: Text(
"Category",
style: TextStyle(color: Colors.white),
),
),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
//I want this context to be scrollable with some fixed height on the screen
child: Row(
children: <Widget>[
Icon(Icons.arrow_right),
Text("Dairy & Bakery")
],
),
value: '1'),
],
)
I have tried implementing the PreferredSizeWidget but is not working on PopupMenuButton.
Edit: i meant fixed height :S
PopUpMenuButton does not support a fixed height. But what u can do is adjust the PopUpMenu Package.
Something similar is done
here
with the DropdownButton. For the PopUpMenu the implemenatition should work analogously, as both have the same strucktur. (Route, RouteLayout and PopUpMenu)
Edit:
You take a look at the the original code of the DropdownButton and then look at the changes the person did to it in the custom edition.
Then you take the code of the PopUpMenuButton and copy them into your own project and adjust them like it was done with the DropDownButton.
Then you use ure custom version of the PopUpMenuButton with the argument height.
Edit 2:
As you had some problems doing what I meant, I did it for you:
Just copy this file into your directory and import it into your code.
Then use CustomPopupMenuButton with a height instead of the original one.
Usage:
import 'package:flutter/material.dart';
import 'custom_popup_menu_button.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
enum WhyFarther { harder, smarter, selfStarter, tradingCharter }
class _HomeState extends State<Home> {
WhyFarther _selection;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'it does work here',
style: TextStyle(fontSize: 20),
),
),
body: Center(
child: CustomPopupMenuButton<WhyFarther>(
onSelected: (WhyFarther result) {
setState(() {
_selection = result;
});
},
height: 100,
itemBuilder: (BuildContext context) => <PopupMenuEntry<WhyFarther>>[
const PopupMenuItem<WhyFarther>(
value: WhyFarther.harder,
child: Text('Working a lot harder'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.smarter,
child: Text('Being a lot smarter'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.selfStarter,
child: Text('Being a self-starter'),
),
const PopupMenuItem<WhyFarther>(
value: WhyFarther.tradingCharter,
child: Text('Placed in charge of trading charter'),
),
],
)),
);
}
}
If anything is not working feel free to ask, perhaps I will look into it later.

Flutter - Checkbox animation doesn't show

The value is effectively changing when clicking but the animation doesn't show :
Here's my code :
var editGender = Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Column(
children: <Widget>[
CheckboxListTile(
value: _male,
onChanged: _maleChanged,
title: Text("Male"),
activeColor: Theme.of(context).primaryColor,
),
CheckboxListTile(
value: _female,
onChanged: _femaleChanged,
title: Text("Female"),
activeColor: Theme.of(context).primaryColor,
)
],
),
);
When tapping the edit button :
FlatButton(
onPressed: (){
buildShowRoundedModalBottomSheet(context, title, editGender, option);
},
child: Text('Edit'),
it shows the bottom sheet :
Future buildShowRoundedModalBottomSheet(BuildContext context, String title, Widget content,[String date]) {
return showRoundedModalBottomSheet(
context: context,
radius: 20.0,
builder: (context){
return Padding(
padding: const EdgeInsets.only(top: 20.0, bottom: 20.0, left: 20.0, right: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
title,
style: TextStyle(
fontFamily: 'SamsungSans',
fontSize: 20.0,
),
),
content,
...
I am passing the same context to the widget :/
setState would change the value but it wouldn't rebuild your bottom sheet as it is being called on a onPressed of a FlatButton. You are certainly not invoking that onPressed again but you wouldn't want to do it either.
As I mentioned in the comments a StatefulBuilder would do the job.
A working example
import 'package:flutter/material.dart';
import 'package:rounded_modal/rounded_modal.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
bool value = false;
void _incrementCounter() {
showRoundedModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, setState) {
return Container(
height: 200.0,
child: Checkbox(value: value, onChanged: (val) {
setState(() {
value = val;
});
}),
);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
As commented by #10101010, you'll have to use a Stateful widget. And In _femaleChanged and _maleChanged, you'll have to use setState(). Example :
void _femaleChanged(bool value) => setState(() => _female = value);

Trouble sending selected information to next screen

I am trying to build a pokedex application in flutter. Currently I have created the first screen, with all 151 pokemon, their image, name, and # from a json api call. I am trying to make functionality where when you tap on a specific pokemon from the first screen, a new screen will appear with more details about the pokemon you tapped on. Currently having difficulties setting up my navigation to carry that information over.
Here is my project
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
Map _data;
List _pokemon = [];
void main() async {
_data = await fetchData();
_pokemon = _data['pokemon'];
runApp(
MaterialApp(
title: 'Poke App',
home: new HomePage(),
debugShowCheckedModeBanner: false,
),
);
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
fetchData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Poke App'),
centerTitle: true,
backgroundColor: Colors.cyan,
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.cyan,
child: Icon(Icons.search),
),
body: GridView.count(
crossAxisCount: 2,
children: List.generate(_pokemon.length, (index) {
return Padding(
padding: const EdgeInsets.fromLTRB(1.0, 5.0, 1.0, 5.0),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => new PokeDetails(_pokemon[index]
),
),
);
},
child: Card(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('${_pokemon[index]['img']}'),
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 2.0),
child: Text(
'${_pokemon[index]['name']}',
style: TextStyle(
fontSize: 16.0,
fontFamily: 'Chivo',
fontStyle: FontStyle.italic),
),
),
Text(
'${_pokemon[index]['num']}',
style: TextStyle(
fontFamily: 'Indie Flower',
fontWeight: FontWeight.w400,
fontSize: 20.0),
)
],
),
),
),
);
}),
));
}
}
Future<Map> fetchData() async {
String url =
"https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json";
http.Response response = await http.get(url);
return json.decode(response.body);
}
class PokeDetails extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.cyan,
appBar: AppBar(
title: Text('${_pokemon[index]['name']}'),
centerTitle: true,
backgroundColor: Colors.cyan,
),
);
}
}
I am expecting the correct pokemon to appear on screen 2 (PokeDetails) but i have yet to be able to achieve this
I think you may benefit from reading through some more of the documentation on flutter. Though, to get you moving forward, your PokeDetails class has no way of knowing what to look for when you're sending over the pokemon data... You should create a pokemon class so you can map the api results over to something a little easier to work with. Then you can do something like:
class PokeDetails extends StatelessWidget{
final Pokemon pokemon;
PokeDetails({
#required this.pokemon
});
//now display the pokemon details
}
Side-note, you'll want to avoid using those global variables and functions (such as fetchData, _data, and _pokemon). Those should be in their own classes. Maybe a class containing your fetch function along with a map of the data that you received. This is all kind of the bare minimum to get your feet wet. Happy coding!