I am following a course video from YouTube to design a shopping cart in Flutter. But according to the course video, I am supposed to see the output showing the pictures of the items, their prices, units, and other details [shown in picture 1]. But in my output I am seeing nothing but only the AppBar title [shown in picture 2].
The output in the YouTube course video:
My Output:
I have attached the entire code below, please help fix my mistake.
main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping_cart/cart_provider.dart';
import 'package:shopping_cart/cart_screen.dart';
import 'package:shopping_cart/product_list.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => CartProvider(),
child: Builder(builder: (BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(),
debugShowCheckedModeBanner: false,
home: const CartScreen(),
);
}),
);
}
}
product_list.dart
import 'package:badges/badges.dart';
import 'package:flutter/material.dart' hide Badge;
import 'package:provider/provider.dart';
import 'package:shopping_cart/cart_model.dart';
import 'package:shopping_cart/db_helper.dart';
import 'cart_provider.dart';
import 'cart_screen.dart';
class ProductListScreen extends StatefulWidget {
const ProductListScreen({super.key});
#override
State<ProductListScreen> createState() => _ProductListScreenState();
}
class _ProductListScreenState extends State<ProductListScreen> {
DBHelper? dbHelper = DBHelper();
List<String> productName = [
'Mango',
'Orange',
'Grapes',
'Banana',
'Chery',
'Peach',
'Mixed Fruit Basket'
];
List<String> productUnit = [
'KG',
'Dozen',
'KG',
'Dozen',
'KG',
'KG',
'KG',
];
List<int> productPrice = [10, 20, 30, 40, 50, 60, 70];
List<String> productImage = [
'https://image.shutterstock.com/image-photo/mango-isolated-on-white-background-600w-610892249.jpg',
'https://image.shutterstock.com/image-photo/orange-fruit-slices-leaves-isolated-600w-1386912362.jpg',
'https://image.shutterstock.com/image-photo/green-grape-leaves-isolated-on-600w-533487490.jpg',
'https://media.istockphoto.com/photos/banana-picture-id1184345169?s=612x612',
'https://media.istockphoto.com/photos/cherry-trio-with-stem-and-leaf-picture-id157428769?s=612x612',
'https://media.istockphoto.com/photos/single-whole-peach-fruit-with-leaf-and-slice-isolated-on-white-picture-id1151868959?s=612x612',
'https://media.istockphoto.com/photos/fruit-background-picture-id529664572?s=612x612',
];
#override
Widget build(BuildContext context) {
final cart = Provider.of<CartProvider>(context); // reference
return Scaffold(
appBar: AppBar(
title: const Text("Product List"),
centerTitle: true,
backgroundColor: Colors.deepPurple,
actions: [
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CartScreen(),
),
);
},
child: Center(
child: Badge(
badgeContent: Consumer<CartProvider>(
builder: (context, value, child) {
return Text(
value.getCounter().toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.bold,
),
);
},
),
badgeAnimation: const BadgeAnimation.fade(
animationDuration: Duration(milliseconds: 300),
),
child: const Icon(
Icons.shopping_cart_outlined,
size: 30,
),
),
),
),
const SizedBox(width: 20),
],
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: productName.length,
itemBuilder: ((context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Image(
height: 100,
width: 100,
image:
NetworkImage(productImage[index].toString()),
),
const SizedBox(
width: 15,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
productName[index],
style: const TextStyle(fontSize: 23),
),
const SizedBox(
height: 5,
),
Text(
productUnit[index] +
" " r"$" +
productPrice[index].toString(),
style: const TextStyle(fontSize: 23),
),
const SizedBox(
height: 10,
),
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () {
dbHelper!
.insert(Cart(
id: index,
productId: index.toString(),
productName: productName[index]
.toString(),
initialPrice:
productPrice[index],
productPrice:
productPrice[index],
quantity: 1,
unitTag: productUnit[index]
.toString(),
image: productImage[index]
.toString()))
.then((value) {
print("Product is Added to Cart");
cart.addTotalPrice(double.parse(
productPrice[index].toString()));
cart.addCounter();
}).onError((error, stackTrace) {
print(error.toString());
});
},
child: Container(
height: 35,
width: 130,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(50),
color: Colors.green,
),
child: const Center(
child: Text(
"Add to Cart",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w500),
),
),
),
),
)
],
),
)
],
)
],
),
),
);
}),
),
),
Consumer<CartProvider>(builder: (context, value, child) {
return Column(
children: [
ReusableWidget(
'subtotal',
r'$' + value.getTotalPrice().toStringAsFixed(2),
),
],
);
})
],
),
);
}
}
class ReusableWidget extends StatelessWidget {
final String title, value;
const ReusableWidget(this.title, this.value, {super.key});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
children: [
Text(
title,
style: Theme.of(context).textTheme.titleSmall,
),
Text(
value,
style: Theme.of(context).textTheme.titleSmall,
)
],
),
);
}
}
db_helper.dart
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
import 'dart:io' as io;
import 'cart_model.dart';
class DBHelper {
static Database? _db;
Future<Database?> get db async {
_db = await initDatabase();
if (_db != null) {
return _db!;
}
}
initDatabase() async {
io.Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, 'cart.db');
var db = await openDatabase(path, version: 1, onCreate: _onCreate);
return db;
}
// Method
_onCreate(Database db, int version) async {
await db.execute(
'CREATE TABLE cart (id INTEGER PRIMARY KEY, productId VARCHAR UNIQUE, productName TEXT, initialPrice INTEGER, productPrice INTEGER, quantity INTEGER, unitTag TEXT, image TEXT)',
);
}
Future<Cart> insert(Cart cart) async {
print(cart.toMap());
var dbClient = await db;
await dbClient!.insert('cart', cart.toMap());
return cart;
}
Future<List<Cart>> getCartList() async {
var dbClient = await db;
final List<Map<String, Object?>> queryResult =
await dbClient!.query("cart");
return queryResult.map((e) => Cart.fromMap(e)).toList();
}
}
cart_screen.dart
import 'package:badges/badges.dart';
import 'package:flutter/material.dart' hide Badge;
import 'package:provider/provider.dart';
import 'cart_model.dart';
import 'cart_provider.dart';
class CartScreen extends StatefulWidget {
const CartScreen({super.key});
#override
State<CartScreen> createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen> {
#override
Widget build(BuildContext context) {
final cart = Provider.of<CartProvider>(context);
return Scaffold(
appBar: AppBar(
title: const Text("My Products"),
centerTitle: true,
backgroundColor: Colors.deepPurple,
actions: [
Center(
child: Badge(
badgeContent: Consumer<CartProvider>(
builder: (context, value, child) {
return Text(
value.getCounter().toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.bold,
),
);
},
),
badgeAnimation: const BadgeAnimation.fade(
animationDuration: Duration(milliseconds: 300),
),
child: const Icon(
Icons.shopping_cart_outlined,
size: 30,
),
),
),
const SizedBox(width: 20),
],
),
body: Column(
children: [
FutureBuilder(
future: cart.getData(),
builder: (context, AsyncSnapshot<List<Cart>> snapshot) {
if (snapshot.hasData) {
return Expanded(
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: ((context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Image(
height: 100,
width: 100,
image: NetworkImage(
snapshot.data![index].image.toString(),
),
),
const SizedBox(
width: 15,
),
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
snapshot.data![index].productName
.toString(),
),
const SizedBox(
height: 5,
),
Text(
snapshot.data![index].unitTag
.toString() +
" " r"$" +
snapshot.data![index].productPrice
.toString(),
style: const TextStyle(fontSize: 23),
),
const SizedBox(
height: 10,
),
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () {},
child: Container(
height: 35,
width: 130,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(50),
color: Colors.green,
),
child: const Center(
child: Text(
"Add to Cart",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight:
FontWeight.w500),
),
),
),
),
)
],
),
)
],
)
],
),
),
);
}),
),
);
} else {
return const Text("Shahzain");
}
},
)
],
),
);
}
}
cart_provider.dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shopping_cart/cart_model.dart';
import 'package:shopping_cart/db_helper.dart';
class CartProvider with ChangeNotifier {
DBHelper db = DBHelper(); // DBHelper() is a class
int _counter = 0;
int get counter => _counter;
double _totalPrice = 0.0;
double get totalPrice => _totalPrice;
late Future<List<Cart>> _cart;
Future<List<Cart>> get cart => _cart; // => means to indicate
Future<List<Cart>> getData() async {
_cart = db.getCartList();
return _cart;
}
void _setPrefItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setInt('cart_item', _counter);
prefs.setDouble('total_price', _totalPrice);
notifyListeners();
}
void _getPrefItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
// giving initial value by ?? 0 for null safety
_counter = prefs.getInt('cart_item') ?? 0;
// giving initial value by ?? 0.0 for null safety
_totalPrice = prefs.getDouble('total_price') ?? 0.0;
notifyListeners();
}
void addTotalPrice(double productPrice) {
_totalPrice = _totalPrice + productPrice;
_setPrefItems();
notifyListeners();
}
void removeTotalPrice(double productPrice) {
_totalPrice = _totalPrice - productPrice;
_setPrefItems();
notifyListeners();
}
double getTotalPrice() {
_getPrefItems();
return _totalPrice;
}
void addCounter() {
// initial value of counter was 0, will be incremented to 1, and will be stored to sharedPreferences
_counter++;
_setPrefItems();
notifyListeners();
}
void removeCounter() {
_counter--;
_setPrefItems();
notifyListeners();
}
int getCounter() {
_getPrefItems();
return _counter;
}
}
cart_model.dart
class Cart {
late final int? id;
final String? productId;
final String? productName;
final int? initialPrice;
final int? productPrice;
final int? quantity;
final String? unitTag;
final String? image;
// Creating the constructor
Cart({
required this.id, // primary key
required this.productId,
required this.productName,
required this.initialPrice,
required this.productPrice,
required this.quantity,
required this.unitTag,
required this.image,
});
Cart.fromMap(Map<dynamic, dynamic> res) // res = resources
: id = res['id'],
productId = res['productId'],
productName = res['productName'],
initialPrice = res['initialPrice'],
productPrice = res['productPrice'],
quantity = res['quantity'],
unitTag = res['unitTag'],
image = res['image'];
Map<String, Object?> toMap(){
return {
'id' : id,
'productId' : productId,
'productName' : productName,
'initialPrice' : initialPrice,
'productPrice' : productPrice,
'quantity' : quantity,
'unitTag' : unitTag,
'image' : image
};
}
}
in your main.dart file
you set,
home: const CartScreen(),
and the video tutorial you have followed, he sets home: ProductListsScreen()
Fix this and I hope your problem will be solved,
also, be sure where to use const
Related
So I made a CRUD app with Firebase Firestore in Flutter. I have this error where it says
Exception caught by gesture
═══════════════════════
a document path must be a non-empty string
'package:cloud_firestore/src/collection_reference.dart':
package:cloud_firestore/src/collection_reference.dart:1
Failed assertion: line 116 pos 14: 'path.isNotEmpty'
I build this app with various tutorial videos in Youtube. I can make the Create, Read, and Delete features but I face this problem with Update features. Here's the code ...or check this Github https://github.com/rayhanyovi/Dapurku
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:dapurkuu/warna.dart';
import 'package:dapurkuu/widget.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
//=====================================
const Color Red = Color(0xFFDA4040);
const Color Blue = Color(0xFF5F52EE);
const Color Black = Color(0xFF3A3A3A);
const Color Grey = Color(0xFF717171);
const Color BGColor = Color(0xFFEEEFF5);
final controllerName = TextEditingController();
final controllerAge = TextEditingController();
final controllerBirthday = TextEditingController();
final updateName = TextEditingController();
final updateAge = TextEditingController();
final updateBirthday = TextEditingController();
//=====================================
class User {
String id;
final String name;
final int age;
final DateTime birthday;
User({
this.id = '',
required this.name,
required this.age,
required this.birthday,
});
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'age': age,
'birthday': birthday,
};
static User fromJson(Map<String, dynamic> json) => User(
id: json['id'],
name: json['name'],
age: json['age'],
birthday: (json['birthday'] as Timestamp).toDate(),
);
}
//=====================================
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.transparent));
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Test",
home: Home(),
);
}
}
//=====================================
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final CollectionReference _users =
FirebaseFirestore.instance.collection('users');
#override
Widget build(BuildContext context) {
Future createUser(User user) async {
final docUser = FirebaseFirestore.instance.collection('users').doc();
user.id = docUser.id;
final json = user.toJson();
await docUser.set(json);
Future updateUser(User user) async {
final docUser = FirebaseFirestore.instance.collection('users').doc();
user.id = docUser.id;
final json = user.toJson();
await docUser.update(json);
}
}
Widget buildUser(User user) {
return Container(
margin: EdgeInsets.only(
right: 20,
left: 20,
bottom: 15,
),
child: Material(
child: ListTile(
onTap: () {
print("card");
},
contentPadding:
EdgeInsets.only(top: 10, bottom: 10, left: 20, right: 15),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
tileColor: Colors.white,
title: Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Text(
user.name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jumlah: ${user.age}',
),
Text(
'Kadaluarsa: ${DateFormat('dd MMMM yyyy').format(user.birthday)}')
],
),
trailing: Wrap(spacing: 0, children: [
IconButton(
icon: Icon(Icons.edit),
iconSize: 24,
color: Colors.black,
onPressed: () async {
await Edit(context, createUser);
},
),
IconButton(
icon: Icon(Icons.delete),
iconSize: 24,
color: Colors.red,
onPressed: () {
final docUser = FirebaseFirestore.instance
.collection('users')
.doc(user.id);
docUser.delete();
},
),
]),
),
),
);
}
return Scaffold(
backgroundColor: BGColor,
appBar: _AppBar(),
body: Column(
children: [
/* JUDUL */
Column(
children: [
Container(
margin: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: SearchBox()),
Container(
margin: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: Text(
'Bahan Dapurmu',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Black,
),
),
)
],
),
/* STREAM BUILDER */
StreamBuilder(
stream: readUsers(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final users = snapshot.data!;
return Expanded(
child: ListView(
scrollDirection: Axis.vertical,
shrinkWrap: true,
children: users.map(buildUser).toList(),
),
);
} else if (snapshot.hasError) {
return Container(
child: Text("data kosong"),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Create(context, createUser);
},
child: Icon(Icons.add),
),
);
}
Edit(BuildContext context, Future<dynamic> updateUser(User user)) async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Tambahkan bahan"),
content: Column(
children: [
TextField(
decoration: const InputDecoration(
labelText: 'Nama',
),
controller: updateName,
),
TextField(
decoration: const InputDecoration(
labelText: 'Umur',
),
controller: updateAge,
keyboardType: TextInputType.number,
),
TextField(
controller: updateBirthday,
//editing controller of this TextField
decoration: InputDecoration(
labelText: "Enter Date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1950),
//DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2100));
if (pickedDate != null) {
print(
pickedDate);
//pickedDate output format => 2021-03-10 00:00:00.000
//formatted date output using intl package => 2021-03-16
setState(() {
updateBirthday.text = pickedDate
.toString(); //set output date to TextField value.
});
} else {}
},
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("Ubah Data"),
onPressed: () {
final user = User(
name: updateName.text,
age: int.parse(updateAge.text),
birthday: DateTime.parse(updateBirthday.text),
);
final docUser = FirebaseFirestore.instance
.collection('users')
.doc(user.id);
updateUser(user);
}),
],
);
});
}
Create(BuildContext context, Future<dynamic> createUser(User user)) async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Tambahkan bahan"),
content: Column(
children: [
TextField(
decoration: const InputDecoration(
labelText: 'Nama',
),
controller: controllerName,
),
TextField(
decoration: const InputDecoration(
labelText: 'Umur',
),
controller: controllerAge,
keyboardType: TextInputType.number,
),
TextField(
controller: controllerBirthday,
//editing controller of this TextField
decoration: InputDecoration(
labelText: "Enter Date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1950),
//DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2100));
if (pickedDate != null) {
print(
pickedDate);
//pickedDate output format => 2021-03-10 00:00:00.000
//formatted date output using intl package => 2021-03-16
setState(() {
controllerBirthday.text = pickedDate
.toString(); //set output date to TextField value.
});
} else {}
},
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("Tambahkan"),
onPressed: () {
final user = User(
name: controllerName.text,
age: int.parse(controllerAge.text),
birthday: DateTime.parse(controllerBirthday.text),
);
createUser(user);
}),
],
);
});
}
Stream<List<User>> readUsers() => FirebaseFirestore.instance
.collection('users')
.snapshots()
.map((snapshot) =>
snapshot.docs.map((doc) => User.fromJson(doc.data())).toList());
}
//=====================================
AppBar _AppBar() {
return AppBar(
elevation: 0,
backgroundColor: BGColor,
title: Center(
child: Text(
"Dapurku",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Black,
),
),
),
);
}
//=====================================
class UpdateButton extends StatelessWidget {
const UpdateButton({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: IconButton(
icon: Icon(Icons.edit),
iconSize: 24,
color: Colors.black,
onPressed: () {},
),
);
}
}
//=====================================
class SearchBox extends StatelessWidget {
const SearchBox({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 10),
child: const TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0),
prefixIcon: Icon(
Icons.search,
color: Black,
size: 20,
),
prefixIconConstraints: BoxConstraints(
maxHeight: 20,
minWidth: 25,
),
border: InputBorder.none,
hintText: "Cari Bahan...",
hintStyle: TextStyle(
color: Grey,
)),
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
);
}
}
Can you tell me what I did wrong or help me solve the problem? I've been looking for it anywhere and solving this problem for days. It is for my school assignment :/
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
//Run this first
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Smart Bin',
home: new HomePageWidget(),
);
}
}
class HomePageWidget extends StatefulWidget {
const HomePageWidget({Key key}) : super(key: key);
#override
_HomePageWidgetState createState() => _HomePageWidgetState();
}
class _HomePageWidgetState extends State<HomePageWidget> {
final scaffoldKey = GlobalKey<ScaffoldState>();
final currentBinRecord = FirebaseFirestore.instance.collection("current_bin");
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title: Text(
'SmartBin',
),
),
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: StreamBuilder<List<CurrentBinRecord>>(
stream: queryCurrentBinRecord(
queryBuilder: (currentBinRecord) =>
currentBinRecord.orderBy('level', descending: true),
),
builder: (context, snapshot) {
// Customize what your widget looks like when it's loading.
if (!snapshot.hasData) {
return Center(
child: SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
}
List<CurrentBinRecord> listViewCurrentBinRecordList =
snapshot.data;
return ListView.builder(
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
itemCount: listViewCurrentBinRecordList.length,
itemBuilder: (context, listViewIndex) {
final listViewCurrentBinRecord =
listViewCurrentBinRecordList[listViewIndex];
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
listViewCurrentBinRecord.area,
),
Text(
listViewCurrentBinRecord.level.toString(),
),
],
);
},
);
},
),
),
],
),
),
),
);
}
}
This is the error
First error is on:
child: StreamBuilder<List<CurrentBinRecord>>
The name 'CurrentBinRecord' isn't a type so it can't be used as a type argument.
Try correcting the name to an existing type, or defining a type named 'CurrentBinRecord'.
Second error is on:
stream: queryCurrentBinRecord
The method 'queryCurrentBinRecord' isn't defined for the type '_HomePageWidgetState'.
Try correcting the name to the name of an existing method, or defining a method named 'queryCurrentBinRecord'.
Third error is on:
List<CurrentBinRecord> listViewCurrentBinRecordList =
snapshot.data;
The name 'CurrentBinRecord' isn't a type so it can't be used as a type argument.
Try correcting the name to an existing type, or defining a type named 'CurrentBinRecord'.
These is the syntax try -
return StreamBuilder(
stream: theStreamSource, // Eg a firebase query
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, int index) {
return Text(snapshot.data.documents[index]['title']);
}
);
},
);
Hope it helps.
I think the best way to use StreamBuilder is to create separate controller class that can handle all your business logic and update UI.
// your widget class
class UIClass extends StatefulWidget {
const UIClass({Key key}) : super(key: key);
#override
_UIClassState createState() => _UIClassState();
}
class _UIClassState extends State<UIClass> {
UIClassController<List<CurrentBinRecord>> _uiController;
#override
void initState() {
_uiController = UIClassController(StreamController<List<CurrentBinRecord>>());
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Text("Hello Everyone"),
StreamBuilder<List<CurrentBinRecord>>(
stream: _uiController.uiStream,
builder: (context, snapshot) {
if(snapshot.hasError){
return ErrorWidget();
}
else if(snapshot.connectionState == ConnectionState.waiting){
return WaitingWidget();
}
else if(snapshot.hasData){
return ListView.builder(
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
itemCount: snapshot.data.length,
itemBuilder: (context, listViewIndex) {
final listViewCurrentBinRecord =
snapshot.data[listViewIndex];
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
listViewCurrentBinRecord.area,
),
Text(
listViewCurrentBinRecord.level.toString(),
),
],
);
},
);
}
else{
return SizedBox();
}
}
),
],
);
}
#override
void dispose() {
super.dispose();
_uiController.dispose();
}
}
// controller class to handle all business logic
// you can also split it into multiple sub controllers
class UIClassController<T> {
final StreamController<T> _controller;
// If you are using this on multiple widgets then use asBroadcastStream()
Stream<T> get uiStream => _controller.stream;
UIClassController(this._controller);
void updateMyUI([dynamic params]){
T t;
// your logic //
//------------//
_controller.sink.add(t);
}
void dispose(){
_controller.close();
}
}
Code I'm Using for StreamBuilder
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../door/widgets/Navbar.dart';
import '../door/widgets/sidenav.dart';
import 'package:get/get.dart';
FirebaseAuth auth = FirebaseAuth.instance;
class CartPage extends StatefulWidget {
#override
_CartPageState createState() => _CartPageState();
}
class _CartPageState extends State<CartPage> {
final FirebaseFirestore fb = FirebaseFirestore.instance;
int up = 1;
bool loading = false;
final ScrollController _scrollController = ScrollController();
#override
void initState() {
super.initState();
getCartData();
}
void addMore(qty, documentID) {
int new_qty = qty + 1;
Get.snackbar('Qty! ', new_qty.toString());
String collection_name = "cart_${auth.currentUser?.email}";
FirebaseFirestore.instance
.collection(collection_name)
.doc(documentID)
.update({
'qty': new_qty,
'updated_at': Timestamp.now(),
}) // <-- Your data
.then((_) => print('Added'))
.catchError((error) => Get.snackbar('Failed!', 'Error: $error'));
}
void minusMore(qty, documentID) {
if (qty > 1) {
int new_qty = qty - 1;
String collection_name = "cart_${auth.currentUser?.email}";
FirebaseFirestore.instance
.collection(collection_name)
.doc(documentID)
.update({
'qty': new_qty,
'updated_at': Timestamp.now(),
}) // <-- Your data
.then((_) => print('Subtracted'))
.catchError((error) => Get.snackbar('Failed!', 'Error: $error'));
}
}
Stream<QuerySnapshot> getCartData() {
String collection_name = "cart_${auth.currentUser?.email}";
return FirebaseFirestore.instance
.collection(collection_name)
.orderBy("created_at", descending: false)
.snapshots();
}
final ButtonStyle style = ElevatedButton.styleFrom(
minimumSize: Size(50, 30),
backgroundColor: Color(0xFFFFB61A),
elevation: 6,
textStyle: const TextStyle(fontSize: 11),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(20),
)));
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: Navbar.navbar(),
drawer: Sidenav.sidenav(),
body: Container(
padding: EdgeInsets.all(10.0),
child: StreamBuilder<QuerySnapshot>(
stream: getCartData(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
if (snapshot.hasError) {
return buildText('Something Went Wrong Try later');
} else {
if (!snapshot.hasData) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 100,
minHeight: 190,
maxWidth: 200,
maxHeight: 200,
),
child: Icon(Icons.shopping_cart, size: 45),
),
title: Text('No Food!'),
subtitle: const Text('Your cart is empty!'),
),
],
),
);
} else {
return ListView.builder(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
itemCount: snapshot.data?.docs.length,
itemBuilder: (BuildContext context, int index) {
return SizedBox(
height: 90.0,
child: Card(
elevation: 10,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
const SizedBox(
width: 20,
),
_buildImg('assets/logo.png', '60', '60'),
const SizedBox(
width: 14,
),
SizedBox(
width:
MediaQuery.of(context).size.width *
0.33,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(
height: 20,
),
Text(
snapshot.data?.docs[index]
["name"],
maxLines: 2,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14)),
const SizedBox(
height: 5,
),
Text(
"₹${snapshot.data?.docs[index]["price"]}",
style: const TextStyle(
fontWeight: FontWeight.w400,
fontSize: 12)),
],
),
),
const SizedBox(
width: 10,
),
Container(
margin: const EdgeInsets.only(
top: 20.0, bottom: 10.0),
decoration: BoxDecoration(
color: const Color(0xFFFFB61A),
// color: Color(0xFF0A2031),
borderRadius:
BorderRadius.circular(17)),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment.end,
children: <Widget>[
SizedBox(
height: 40,
child: IconButton(
onPressed: () {
minusMore(
snapshot.data
?.docs[index]
["qty"],
snapshot
.data
?.docs[index]
.reference
.id);
},
color: Colors.white,
icon:
const Icon(Icons.remove)),
),
const SizedBox(
width: 5,
),
Container(
margin: const EdgeInsets.only(
bottom: 10.0),
child: Text(
"${snapshot.data?.docs[index]["qty"]}",
style: const TextStyle(
fontWeight:
FontWeight.w400,
color: Colors.white,
fontSize: 16)),
),
const SizedBox(
width: 5,
),
SizedBox(
height: 40,
child: IconButton(
color: Colors.white,
onPressed: () {
addMore(
snapshot.data
?.docs[index]
["qty"],
snapshot
.data
?.docs[index]
.reference
.id);
},
icon: const Icon(Icons.add)),
),
],
),
),
const SizedBox(
width: 10,
),
],
),
),
);
});
}
}
}
},
),
),
);
}
Widget buildText(String text) => Center(
child: Text(
text,
style: TextStyle(fontSize: 24, color: Colors.black),
),
);
_buildImg(img, hei, wid) {
return Container(
alignment: Alignment.center, // use aligment
child: Image.asset(
img,
height: double.parse(hei),
width: double.parse(wid),
fit: BoxFit.cover,
),
);
}
}
so i want to print user name and user username in the profile page and in the end it shows it but for a few seconds there is a red screen that says The following _TypeError was thrown building Profile_page(dirty, state: _Profile_pageState#68414):
type 'Null' is not a subtype of type 'String'
this is the code of main.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:gp1_7_2022/screen/auth/signup/userInfo/name.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question1.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question2.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question3.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question4.dart';
import 'package:gp1_7_2022/screen/auth/signup/Questions/question5.dart';
import 'package:gp1_7_2022/screen/auth/signup/userInfo/photo.dart';
import 'package:gp1_7_2022/screen/home/Profile_Page.dart';
import 'package:firebase_core/firebase_core.dart';
/*pages */
import 'package:gp1_7_2022/screen/auth/signup_login.dart';
import 'package:gp1_7_2022/screen/auth/signup/userAuth/signup.dart';
import 'package:gp1_7_2022/screen/auth/Login/login.dart';
import 'package:gp1_7_2022/screen/auth/signup/userAuth/signupConfirmationCode.dart';
import 'package:gp1_7_2022/screen/auth/signup/userAuth/signupPassword.dart';
import 'package:gp1_7_2022/screen/auth/signup/userInfo/signupBirthday.dart';
import 'package:gp1_7_2022/screen/auth/signup/userInfo/signupUsername.dart';
import 'package:gp1_7_2022/screen/auth/Login/forget_password.dart';
import 'package:gp1_7_2022/screen/settings.dart';
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MaterialApp(
initialRoute: "/",
routes: {
"/": (context) => MainPage(),
"/signup": (context)=> Signup(),
'/login':(context)=>Login(),
'/Profile_Page':(context) => Profile_page(uid: FirebaseAuth.instance.currentUser!.uid),
// '/confirmationCode':(context) => ConfirmationCode(),
// '/signupPassword':(context) => signupPassword(),
'/signupBirthday':(context) => SignupBirthday(),
'/signupUsername':(context) => SignupUsername(),
'/forget_password':(context) => forget_password(),
'/name':(context) => name(),
'/question1':(context) => question1(),
'/question2':(context) => question2(),
'/question3':(context) => question3(),
'/question4':(context) => question4(),
'/question5':(context) => question5(),
'/photo':(context) => Photo(),
'/settings':(context) => settings(),
}
)
);
}
class MainPage extends StatelessWidget {
const MainPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot){
if(snapshot.connectionState==ConnectionState.waiting){
return const Center(child: CircularProgressIndicator());
}else if(snapshot.hasError){
return const Center(child: Text("Something went wrong!"));
}else if(snapshot.hasData){
if(FirebaseAuth.instance.currentUser!.emailVerified && FirebaseAuth.instance.currentUser!.uid != null ){
String uid = FirebaseAuth.instance.currentUser!.uid;
return Profile_page(uid: uid );
}else{
String? x = FirebaseAuth.instance.currentUser!.email;
String y= x??" ";
return ConfirmationCode(email: y);
}
} else{
return const Signup_Login();
}
},
),
);
}
}
this is the code of profile_page.dart
// import 'dart:html';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:focused_menu/focused_menu.dart';
import 'package:focused_menu/modals.dart';
/*pages */
/*colors */
import 'package:gp1_7_2022/config/palette.dart';
import 'package:gp1_7_2022/Widgets/follow_button.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'package:gp1_7_2022/screen/settings.dart';
class Profile_page extends StatefulWidget {
final uid;
const Profile_page({Key? key, required this.uid}) : super(key: key);
#override
State<Profile_page> createState() => _Profile_pageState();
}
class _Profile_pageState extends State<Profile_page> {
var padding= 0.8;
var userData = {};
#override
void initState() {
super.initState();
getData();
}
/* get data method */
getData() async {
try {
if (widget.uid != null) {
var userSnap = await FirebaseFirestore.instance.collection('users').doc(
widget.uid).get();
userData = userSnap.data()!;
setState(() {
});
}
}
catch(e){
Alert(
context: context,
title: "Something went wrong!",
desc: e.toString(),
).show();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Palette.backgroundColor,
appBar: AppBar(
//appBar style
elevation: 0,
backgroundColor: Palette.backgroundColor,
automaticallyImplyLeading: false,//no arrow
//username
title: Padding(
padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
child: Text(
userData['username'],
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 24,
),
),
),
//setting icon
actions:[
FocusedMenuHolder(
//
menuWidth: MediaQuery.of(context).size.width * 0.4,
menuOffset: 0,
menuItemExtent: 49,
//list
menuItems: [
FocusedMenuItem(
title: const Text("Log out"),
trailingIcon: const Icon(Icons.logout),
onPressed: (){
/*go to sign up page*/
Navigator.pushNamed(context, '/');
return FirebaseAuth.instance.signOut();
}
),
FocusedMenuItem(
title: const Text("Settings"),
trailingIcon: const Icon(Icons.settings),
onPressed: (){
Navigator.of(context).popAndPushNamed('/settings');
},
),
],
openWithTap: true,
onPressed: (){},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Image.asset(
"assets/menu-icon.png",
height: 25,
width: 25,
),
),
),
],
),
body: ListView(
children: [
Container(
margin: const EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
//user photo
const Padding(
padding: EdgeInsets.fromLTRB(0, 0, 40, 0),
child: CircleAvatar(
backgroundColor: Colors.white ,
child: Icon(
Icons.account_circle_sharp,
color: Colors.grey,
size: 90,
),
),
),
//end user photo
Expanded(
flex: 7,
child: Column(
children: [
SizedBox(height:40,),
//post, followers and following
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
buildStatColumn(20, "posts"),
buildStatColumn(150, "Followers"),
buildStatColumn(10, "Following"),
],
),
//end post, followers and following
],
),
),
],
),
//username
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.fromLTRB(10, 40, 0, 0),
child: Text(
userData['name'],
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
//end of username
//bio
Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.fromLTRB(10, 1, 0, 0),
child: const Text(
'bio',
style: TextStyle(
fontSize: 16,
),
),
),
//end of bio
//edit profile button
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FollowButton(
text: 'Edit profile',
backgroundColor: Palette.backgroundColor,
borderColor: Palette.grey,
textColor: Colors.black,
function: () {},
)
],
),
//end of button
],
),
),
],
),
);
}
}
// function to show following/followers/# of posts
Column buildStatColumn(int num, String label) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
num.toString(),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
Container(
margin: const EdgeInsets.only(top: 4),
child: Text(
label,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
),
),
],
);
}
enter image description here
Show some other widgets until data is not fully loaded.
class _Profile_pageState extends State<Profile_page> {
...
bool _isloaded = false; // Add this boolean
In getData function
getData() async {
try {
...
setState(() {
_isloaded = true; // when data is loaded update state
});
}
...
In build, return widget according to data(user)
#override
Widget build(BuildContext context) {
return _isloaded == false ?
Center(
child: CircularProgressIndicator(), // Show indicator
)
: Scaffold(
backgroundColor: Palette.backgroundColor,
...
); //Scaffold
You're assuring flutter that the data isn't null which will result in a momentary error. You can try either setting a load bool that sets to true when the data arrives or using the ?? operator. e.g userData['name'] ?? "loading" which will print loading incase the userData['name'] is null
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:image_picker/image_picker.dart';
import 'package:qrscan/qrscan.dart' as scanner;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Uint8List bytes = Uint8List(0);
TextEditingController _inputController;
TextEditingController _outputController;
#override
initState() {
super.initState();
this._inputController = new TextEditingController();
this._outputController = new TextEditingController();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.grey[300],
body: Builder(
builder: (BuildContext context) {
return ListView(
children: <Widget>[
_qrCodeWidget(this.bytes, context),
Container(
color: Colors.white,
child: Column(
children: <Widget>[
TextField(
controller: this._inputController,
keyboardType: TextInputType.url,
textInputAction: TextInputAction.go,
onSubmitted: (value) => _generateBarCode(value),
decoration: InputDecoration(
prefixIcon: Icon(Icons.text_fields),
helperText: 'Please input your code to generage qrcode image.',
hintText: 'Please Input Your Code',
hintStyle: TextStyle(fontSize: 15),
contentPadding: EdgeInsets.symmetric(
horizontal: 7, vertical: 15),
),
),
SizedBox(height: 20),
TextField(
controller: this._outputController,
maxLines: 2,
decoration: InputDecoration(
prefixIcon: Icon(Icons.wrap_text),
helperText: 'The barcode or qrcode you scan will be displayed in this area.',
hintText: 'The barcode or qrcode you scan will be displayed in this area.',
hintStyle: TextStyle(fontSize: 15),
contentPadding: EdgeInsets.symmetric(
horizontal: 7, vertical: 15),
),
),
SizedBox(height: 20),
this._buttonGroup(),
SizedBox(height: 70),
],
),
),
],
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _scanBytes(),
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
);
}
Widget _qrCodeWidget(Uint8List bytes, BuildContext context) {
return Padding(
padding: EdgeInsets.all(20),
child: Card(
elevation: 6,
child: Column(
children: <Widget>[
Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Icon(Icons.verified_user, size: 18, color: Colors.green),
Text(' Generate Qrcode', style: TextStyle(fontSize: 15)),
Spacer(),
Icon(Icons.more_vert, size: 18, color: Colors.black54),
],
),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 9),
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4), topRight: Radius.circular(4)),
),
),
Padding(
padding: EdgeInsets.only(
left: 40, right: 40, top: 30, bottom: 10),
child: Column(
children: <Widget>[
SizedBox(
height: 190,
child: bytes.isEmpty
? Center(
child: Text('Empty code ... ',
style: TextStyle(color: Colors.black38)),
)
: Image.memory(bytes),
),
Padding(
padding: EdgeInsets.only(top: 7, left: 25, right: 25),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
flex: 5,
child: GestureDetector(
child: Text(
'remove',
style: TextStyle(
fontSize: 15, color: Colors.blue),
textAlign: TextAlign.left,
),
onTap: () =>
this.setState(() => this.bytes = Uint8List(0)),
),
),
Text('|', style: TextStyle(fontSize: 15, color: Colors
.black26)),
Expanded(
flex: 5,
child: GestureDetector(
onTap: () async {
final success = await ImageGallerySaver.saveImage(
this.bytes);
SnackBar snackBar;
if (success) {
snackBar = new SnackBar(content: new Text(
'Successful Preservation!'));
Scaffold.of(context).showSnackBar(snackBar);
} else {
snackBar =
new SnackBar(content: new Text('Save failed!'));
}
},
child: Text(
'save',
style: TextStyle(
fontSize: 15, color: Colors.blue),
textAlign: TextAlign.right,
),
),
),
],
),
)
],
),
),
Divider(height: 2, color: Colors.black26),
],
),
),
);
}
Widget _buttonGroup() {
return Row(
children: <Widget>[
Expanded(
flex: 1,
child: SizedBox(
height: 120,
child: InkWell(
onTap: () => _generateBarCode(this._inputController.text),
child: Card(
child: Column(
children: <Widget>[
Expanded(
flex: 2,
child: Image.asset('images/generate_qrcode.png'),
),
Divider(height: 20),
Expanded(flex: 1, child: Text("Generate")),
],
),
),
),
),
),
Expanded(
flex: 1,
child: SizedBox(
height: 120,
child: InkWell(
onTap: _scan,
child: Card(
child: Column(
children: <Widget>[
Expanded(
flex: 2,
child: Image.asset('images/scanner.png'),
),
Divider(height: 20),
Expanded(flex: 1, child: Text("Scan")),
],
),
),
),
),
),
Expanded(
flex: 1,
child: SizedBox(
height: 120,
child: InkWell(
onTap: _scanPhoto,
child: Card(
child: Column(
children: <Widget>[
Expanded(
flex: 2,
child: Image.asset('images/albums.png'),
),
Divider(height: 20),
Expanded(flex: 1, child: Text("Scan Photo")),
],
),
),
),
),
),
],
);
}
Future _scan() async {
String barcode = await scanner.scan();
if (barcode == null) {
print('nothing return.');
} else {
this._outputController.text = barcode;
}
}
Future _scanPhoto() async {
String barcode = await scanner.scanPhoto();
this._outputController.text = barcode;
}
Future _scanPath(String path) async {
String barcode = await scanner.scanPath(path);
this._outputController.text = barcode;
}
Future _scanBytes() async {
File file = await ImagePicker.pickImage(source: ImageSource.camera);
Uint8List bytes = file.readAsBytesSync();
String barcode = await scanner.scanBytes(bytes);
this._outputController.text = barcode;
}
Future _generateBarCode(String inputCode) async {
Uint8List result = await scanner.generateBarCode(inputCode);
this.setState(() => this.bytes = result);
}
}
class MyAppState extends State<MyApp> {
Future<SharedPreferences> _sPrefs = SharedPreferences.getInstance();
final TextEditingController controller = TextEditingController();
List<String> listOne, listTwo;
#override
void initState() {
super.initState();
listOne = [];
listTwo = [];
}
Future<Null> addString() async {
final SharedPreferences prefs = await _sPrefs;
listOne.add(controller.text);
prefs.setStringList('list', listOne);
setState(() {
controller.text = '';
});
}
Future<Null> clearItems() async {
final SharedPreferences prefs = await _sPrefs;
prefs.clear();
setState(() {
listOne = [];
listTwo = [];
});
}
Future<Null> getStrings() async {
final SharedPreferences prefs = await _sPrefs;
listTwo = prefs.getStringList('list');
setState(() {});
}
Future<Null> updateStrings(String str) async {
final SharedPreferences prefs = await _sPrefs;
setState(() {
listOne.remove(str);
listTwo.remove(str);
});
prefs.setStringList('list', listOne);
}
#override
Widget build(BuildContext context) {
getStrings();
return Center(
child: ListView(
children: <Widget>[
TextField(
controller: controller,
decoration: InputDecoration(
hintText: 'Type in something...',
)),
RaisedButton(
child: Text("Submit"),
onPressed: () {
addString();
},
),
RaisedButton(
child: Text("Clear"),
onPressed: () {
clearItems();
},
),
Flex(
direction: Axis.vertical,
children: listTwo == null
? []
: listTwo
.map((String s) => Dismissible(
key: Key(s),
onDismissed: (direction) {
updateStrings(s);
},
child: ListTile(
title: Text(s),
)))
.toList(),
)
],
),
);
}
}
Here the first Appstate creates a Qr code reader. Second is for creating an input controller with shared preferences that can store and retrieve data locally. But when running the code the app displays only the qrscan part and 2nd is not working. I'm new to Flutter. I've just started working on Android Studio. Can anybody help please?
Try to call Another class from home property of the MyApp class.
As you can see in this image
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
//Here I have called MyWidget Class
home: MyWidget()
);
}
}
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Uint8List bytes = Uint8List(0);
TextEditingController _inputController;
TextEditingController _outputController;
#override
initState() {
super.initState();
this._inputController = new TextEditingController();
this._outputController = new TextEditingController();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
i need yur advice .
I Have code to fetch data from api to ListView .
The question is , how to create searchview in this listview .
class PM extends StatefulWidget {
#override
_PMState createState() => _PMState();
}
class _PMState extends State<PM> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text(value),
backgroundColor: Colors.blueAccent,
));
}
final GlobalKey<RefreshIndicatorState> _refresh =
GlobalKey<RefreshIndicatorState>();
ModelPM modelPM;
ModelPM _modelPM;
bool loading = false;
Future<Null> _fetchData() async {
setState(() => loading = true);
var value;
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
value = preferences.getString("id");
});
final response = await http.post(BaseURL.systemTicket, body: {
"key": BaseURL.apiKey,
"method": "get",
"resource": "tabel_pm",
"filters[adminidtabelpm]": value,
});
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final pmModelFromJson = ModelPM.fromJson(data);
setState(() {
modelPM = pmModelFromJson;
loading = false;
});
} else {
showInSnackBar("Data Gagal Load");
}
}
#override
void initState() {
super.initState();
_fetchData();
}
_listPM(i) {
final x = modelPM.results[i];
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: ListTile(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => DetilPM(x, _fetchData)));
},
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
x.name,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: x.status == "Not Yet"
? Colors.blue
: x.status == "Pending" ? Colors.red : Colors.green,
fontWeight: FontWeight.bold),
),
Text(
'Status : ' + x.status,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: x.status == "Not Yet"
? Colors.blue
: x.status == "Pending" ? Colors.red : Colors.green,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
],
),
subtitle: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("MIDTID",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("TID",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("CSI",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
],
),
Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.midtid,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.tid,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.csi,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
],
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.black, size: 30.0),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('PM CIMB List'),
),
key: _scaffoldKey,
body: RefreshIndicator(
onRefresh: _fetchData,
key: _refresh,
child: loading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: modelPM.results.length,
itemBuilder: (context, i) {
return _listPM(i);
},
),
),
);
}
}
and below this model class PM .
class ModelPM {
final int status;
final String status_message;
final List<ModelPMResult> results;
ModelPM({this.status, this.status_message, this.results});
factory ModelPM.fromJson(Map<String, dynamic> json) {
List<ModelPMResult> results = (json['result'] as List)
.map((resultTicketJson) => ModelPMResult.fromJson(resultTicketJson))
.toList();
return ModelPM(
status: json['status'],
status_message: json['status_message'],
results: results,
);
}
}
class ModelPMResult {
final String id;
final String admintabelpm;
final String namaitfs;
final String serial;
final String merchantid;
final String assetid;
final String kondisi_edc;
final String status;
final String detail_edc;
final String note;
final String foto_struk;
final String foto_mesin;
final String foto_toko;
final String kondisi_merchant;
final String request_merchant;
final String tgl_pm;
final String name;
final String batch;
final String idmerchant;
final String midtid;
final String tid;
final String csi;
final String sign;
ModelPMResult({
this.id,
this.admintabelpm,
this.namaitfs,
this.serial,
this.merchantid,
this.assetid,
this.kondisi_edc,
this.status,
this.detail_edc,
this.kondisi_merchant,
this.request_merchant,
this.tgl_pm,
this.name,
this.batch,
this.idmerchant,
this.midtid,
this.tid,
this.csi,
this.foto_mesin,
this.foto_struk,
this.foto_toko,
this.note,
this.sign,
});
factory ModelPMResult.fromJson(Map<String, dynamic> json) {
return new ModelPMResult(
id: json['id'],
admintabelpm: json['id'],
namaitfs: json['namaitfs'],
serial: json['serial'],
merchantid: json['merchantid'],
assetid: json['assetid'],
kondisi_edc: json['kondisi_edc'],
status: json['status'],
detail_edc: json['detail_edc'],
kondisi_merchant: json['kondisi_merchant'],
request_merchant: json['request_merchant'],
tgl_pm: json['tgl_pm'],
name: json['name'],
batch: json['batch'],
idmerchant: json['idmerchant'],
midtid: json['midtid'],
tid: json['tid'],
csi: json['csi'],
note: json['note'],
foto_mesin: json['foto_mesin'],
foto_toko: json['foto_toko'],
foto_struk: json['foto_struk'],
sign: json['sign'],
);
}
}
Please advice for , how to create listview menu in my Page Flutter .
Thanks for your advice .
and also how after the data is deleted in the search menu, data from the API returns to the list
Two solutions : you can copy paste run full code below
Solution 1 : Search use current ListView page, In itemBuilder return data only fit your condition, such as string contains, if not return Container()
ListView.builder(
itemCount: modelPM.results.length,
itemBuilder: (context, i) {
if (myController.text == "") return _listPM(i);
if (myController.text != "" &&
modelPM.results[i].tid.contains(myController.text)) {
return _listPM(i);
} else {
return Container();
}
},
),
demo 1
full code 1
import 'package:flutter/material.dart';
import 'dart:convert';
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(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: PM(),
);
}
}
class PM extends StatefulWidget {
#override
_PMState createState() => _PMState();
}
class _PMState extends State<PM> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void showInSnackBar(String value) {
_scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text(value),
backgroundColor: Colors.blueAccent,
));
}
final GlobalKey<RefreshIndicatorState> _refresh =
GlobalKey<RefreshIndicatorState>();
ModelPM modelPM;
ModelPM _modelPM;
bool loading = false;
Future<Null> _fetchData() async {
setState(() => loading = true);
var value;
/*SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
value = preferences.getString("id");
});
final response = await http.post(BaseURL.systemTicket, body: {
"key": BaseURL.apiKey,
"method": "get",
"resource": "tabel_pm",
"filters[adminidtabelpm]": value,
});*/
/* if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final pmModelFromJson = ModelPM.fromJson(data);
setState(() {
modelPM = pmModelFromJson;
loading = false;
});
} else {
showInSnackBar("Data Gagal Load");
}*/
String responsebody = '''
{
"status": 200,
"status_message" : "OK",
"result" : [
{
"id": "123",
"name" : "name1",
"notes" : "notes1",
"midtid" : "midtid1",
"tid" : "tid1",
"csi" : "csi1",
"status" : "abc"
}
,
{
"id": "456",
"name" : "name2",
"notes" : "notes2",
"midtid" : "midtid2",
"tid" : "tid2",
"csi" : "csi2",
"status" : "def"
}
]
}
''';
final data = jsonDecode(responsebody);
final pmModelFromJson = ModelPM.fromJson(data);
setState(() {
modelPM = pmModelFromJson;
loading = false;
});
}
#override
void initState() {
super.initState();
_fetchData();
}
_listPM(i) {
final x = modelPM.results[i];
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: ListTile(
onTap: () {
/*Navigator.of(context).push(
MaterialPageRoute(builder: (context) => DetilPM(x, _fetchData)));*/
},
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
x.name,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: x.status == "Not Yet"
? Colors.blue
: x.status == "Pending" ? Colors.red : Colors.green,
fontWeight: FontWeight.bold),
),
Text(
'Status : ' + x.status,
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 12,
color: x.status == "Not Yet"
? Colors.blue
: x.status == "Pending" ? Colors.red : Colors.green,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
],
),
subtitle: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("MIDTID",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("TID",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text("CSI",
style: TextStyle(color: Colors.black, fontSize: 10))),
),
],
),
Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.midtid,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.tid,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 0.0),
child: Text(x.csi,
style: TextStyle(color: Colors.black, fontSize: 10))),
),
],
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.black, size: 30.0),
),
);
}
final myController = TextEditingController();
#override
void dispose() {
// Clean up the controller when the widget is removed from the
// widget tree.
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
controller: myController,
decoration:
InputDecoration(border: InputBorder.none, hintText: 'Search'),
onChanged: (value) {
setState(() {});
},
),
),
key: _scaffoldKey,
body: RefreshIndicator(
onRefresh: _fetchData,
key: _refresh,
child: loading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: modelPM.results.length,
itemBuilder: (context, i) {
if (myController.text == "") return _listPM(i);
if (myController.text != "" &&
modelPM.results[i].tid.contains(myController.text)) {
return _listPM(i);
} else {
return Container();
}
},
),
),
);
}
}
class ModelPM {
final int status;
final String status_message;
final List<ModelPMResult> results;
ModelPM({this.status, this.status_message, this.results});
factory ModelPM.fromJson(Map<String, dynamic> json) {
List<ModelPMResult> results = (json['result'] as List)
.map((resultTicketJson) => ModelPMResult.fromJson(resultTicketJson))
.toList();
return ModelPM(
status: json['status'],
status_message: json['status_message'],
results: results,
);
}
}
class ModelPMResult {
final String id;
final String admintabelpm;
final String namaitfs;
final String serial;
final String merchantid;
final String assetid;
final String kondisi_edc;
final String status;
final String detail_edc;
final String note;
final String foto_struk;
final String foto_mesin;
final String foto_toko;
final String kondisi_merchant;
final String request_merchant;
final String tgl_pm;
final String name;
final String batch;
final String idmerchant;
final String midtid;
final String tid;
final String csi;
final String sign;
ModelPMResult({
this.id,
this.admintabelpm,
this.namaitfs,
this.serial,
this.merchantid,
this.assetid,
this.kondisi_edc,
this.status,
this.detail_edc,
this.kondisi_merchant,
this.request_merchant,
this.tgl_pm,
this.name,
this.batch,
this.idmerchant,
this.midtid,
this.tid,
this.csi,
this.foto_mesin,
this.foto_struk,
this.foto_toko,
this.note,
this.sign,
});
factory ModelPMResult.fromJson(Map<String, dynamic> json) {
return new ModelPMResult(
id: json['id'],
admintabelpm: json['id'],
namaitfs: json['namaitfs'],
serial: json['serial'],
merchantid: json['merchantid'],
assetid: json['assetid'],
kondisi_edc: json['kondisi_edc'],
status: json['status'],
detail_edc: json['detail_edc'],
kondisi_merchant: json['kondisi_merchant'],
request_merchant: json['request_merchant'],
tgl_pm: json['tgl_pm'],
name: json['name'],
batch: json['batch'],
idmerchant: json['idmerchant'],
midtid: json['midtid'],
tid: json['tid'],
csi: json['csi'],
note: json['note'],
foto_mesin: json['foto_mesin'],
foto_toko: json['foto_toko'],
foto_struk: json['foto_struk'],
sign: json['sign'],
);
}
}
Solution 2 : Search with SearchDelegate, data actually display in another page
When click search button, open another page
demo
full demo code
import 'package:flutter/material.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(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: SearchDemo(),
);
}
}
class SearchDemo extends StatefulWidget {
static const String routeName = '/material/search';
#override
_SearchDemoState createState() => _SearchDemoState();
}
class _SearchDemoState extends State<SearchDemo> {
final _SearchDemoSearchDelegate _delegate = _SearchDemoSearchDelegate();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
int _lastIntegerSelected;
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
leading: IconButton(
tooltip: 'Navigation menu',
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
color: Colors.white,
progress: _delegate.transitionAnimation,
),
onPressed: () {
_scaffoldKey.currentState.openDrawer();
},
),
title: const Text('Numbers'),
actions: <Widget>[
IconButton(
tooltip: 'Search',
icon: const Icon(Icons.search),
onPressed: () async {
final int selected = await showSearch<int>(
context: context,
delegate: _delegate,
);
if (selected != null && selected != _lastIntegerSelected) {
setState(() {
_lastIntegerSelected = selected;
});
}
},
),
//MaterialDemoDocumentationButton(SearchDemo.routeName),
IconButton(
tooltip: 'More (not implemented)',
icon: Icon(
Theme.of(context).platform == TargetPlatform.iOS
? Icons.more_horiz
: Icons.more_vert,
),
onPressed: () { },
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MergeSemantics(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text('Press the '),
Tooltip(
message: 'search',
child: Icon(
Icons.search,
size: 18.0,
),
),
Text(' icon in the AppBar'),
],
),
const Text('and search for an integer between 0 and 100,000.'),
],
),
),
const SizedBox(height: 64.0),
Text('Last selected integer: ${_lastIntegerSelected ?? 'NONE' }.'),
],
),
),
floatingActionButton: FloatingActionButton.extended(
tooltip: 'Back', // Tests depend on this label to exit the demo.
onPressed: () {
Navigator.of(context).pop();
},
label: const Text('Close demo'),
icon: const Icon(Icons.close),
),
drawer: Drawer(
child: Column(
children: <Widget>[
const UserAccountsDrawerHeader(
accountName: Text('Peter Widget'),
accountEmail: Text('peter.widget#example.com'),
currentAccountPicture: CircleAvatar(
backgroundImage: AssetImage(
'people/square/peter.png',
package: 'flutter_gallery_assets',
),
),
margin: EdgeInsets.zero,
),
MediaQuery.removePadding(
context: context,
// DrawerHeader consumes top MediaQuery padding.
removeTop: true,
child: const ListTile(
leading: Icon(Icons.payment),
title: Text('Placeholder'),
),
),
],
),
),
);
}
}
class _SearchDemoSearchDelegate extends SearchDelegate<int> {
final List<int> _data = List<int>.generate(100001, (int i) => i).reversed.toList();
final List<int> _history = <int>[42607, 85604, 66374, 44, 174];
#override
Widget buildLeading(BuildContext context) {
return IconButton(
tooltip: 'Back',
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
},
);
}
#override
Widget buildSuggestions(BuildContext context) {
final Iterable<int> suggestions = query.isEmpty
? _history
: _data.where((int i) => '$i'.startsWith(query));
return _SuggestionList(
query: query,
suggestions: suggestions.map<String>((int i) => '$i').toList(),
onSelected: (String suggestion) {
query = suggestion;
showResults(context);
},
);
}
#override
Widget buildResults(BuildContext context) {
final int searched = int.tryParse(query);
if (searched == null || !_data.contains(searched)) {
return Center(
child: Text(
'"$query"\n is not a valid integer between 0 and 100,000.\nTry again.',
textAlign: TextAlign.center,
),
);
}
return ListView(
children: <Widget>[
_ResultCard(
title: 'This integer',
integer: searched,
searchDelegate: this,
),
_ResultCard(
title: 'Next integer',
integer: searched + 1,
searchDelegate: this,
),
_ResultCard(
title: 'Previous integer',
integer: searched - 1,
searchDelegate: this,
),
],
);
}
#override
List<Widget> buildActions(BuildContext context) {
return <Widget>[
if (query.isEmpty)
IconButton(
tooltip: 'Voice Search',
icon: const Icon(Icons.mic),
onPressed: () {
query = 'TODO: implement voice input';
},
)
else
IconButton(
tooltip: 'Clear',
icon: const Icon(Icons.clear),
onPressed: () {
query = '';
showSuggestions(context);
},
),
];
}
}
class _ResultCard extends StatelessWidget {
const _ResultCard({this.integer, this.title, this.searchDelegate});
final int integer;
final String title;
final SearchDelegate<int> searchDelegate;
#override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
return GestureDetector(
onTap: () {
searchDelegate.close(context, integer);
},
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text(title),
Text(
'$integer',
style: theme.textTheme.headline.copyWith(fontSize: 72.0),
),
],
),
),
),
);
}
}
class _SuggestionList extends StatelessWidget {
const _SuggestionList({this.suggestions, this.query, this.onSelected});
final List<String> suggestions;
final String query;
final ValueChanged<String> onSelected;
#override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
return ListView.builder(
itemCount: suggestions.length,
itemBuilder: (BuildContext context, int i) {
final String suggestion = suggestions[i];
return ListTile(
leading: query.isEmpty ? const Icon(Icons.history) : const Icon(null),
title: RichText(
text: TextSpan(
text: suggestion.substring(0, query.length),
style: theme.textTheme.subhead.copyWith(fontWeight: FontWeight.bold),
children: <TextSpan>[
TextSpan(
text: suggestion.substring(query.length),
style: theme.textTheme.subhead,
),
],
),
),
onTap: () {
onSelected(suggestion);
},
);
},
);
}
}