Related
I'm making a food ordering app in which I want to provide a discount feature. I've implemented most of the part but I'm getting stuck at a point where I basically want to update the totalAmount with the discountRate.
class CartScreen extends StatefulWidget
{
final String? sellerUID;
const CartScreen({super.key, this.sellerUID});
#override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen>
{
List<int>? separateItemQuantityList;
num totalAmount = 0;
final _couponText = TextEditingController();
#override
void initState() {
super.initState();
totalAmount = 0;
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(0);
separateItemQuantityList = separateItemQuantities();
}
#override
Widget build(BuildContext context) {
var _coupon = Provider.of<CouponProvider>(context);
double discountRate = _coupon.discount/100;
return Scaffold(
appBar: AppBar(
title: const Text("Cart"),
flexibleSpace: Container(decoration: BoxDecoration(color: myColor),),
automaticallyImplyLeading: true,
),
body: CustomScrollView(
slivers: [
//display cart items with quantity number
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("items")
.where("itemID", whereIn: separateItemIDs())
.orderBy("publishedDate", descending: true)
.snapshots(),
builder: (context, snapshot)
{
return !snapshot.hasData
? SliverToBoxAdapter(child: Center(child: circularProgress(),),)
: snapshot.data!.docs.isEmpty
? const SliverToBoxAdapter(child: Center(child: Padding(
padding: EdgeInsets.only(top: 300),
child: Text("The cart is empty",style: TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),),
)))
: SliverList(
delegate: SliverChildBuilderDelegate((context, index)
{
Items model = Items.fromJson(
snapshot.data!.docs[index].data()! as Map<String, dynamic>,
);
if(index == 0)
{
totalAmount = 0;
totalAmount = totalAmount + (model.price! * separateItemQuantityList![index]);
}
else
{
totalAmount = totalAmount + (model.price! * separateItemQuantityList![index]);
}
if(snapshot.data!.docs.length - 1 == index)
{
WidgetsBinding.instance.addPostFrameCallback((timeStamp)
{
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(totalAmount.toDouble());
});
}
return CartItemDesign(
model: model,
context: context,
quanNumber: separateItemQuantityList![index],
);
},
childCount: snapshot.hasData ? snapshot.data!.docs.length : 0,
),
);
},
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: const Color(0xfffb9e5a).withOpacity(0.6),
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
),
width: double.infinity,
height: 160,
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 12, 8, 6),
child: Column(
children: [
Consumer2<TotalAmount, CartItemCounter>(builder: (context, amountProvider, cartProvider, c){
return Center(
child: cartProvider.count == 0
? const Text("Please add something in the cart", style: TextStyle(fontSize: 18),)
: Column(
children: [
Text("The total amount is ₹${amountProvider.tAmount.toString()}", style: const TextStyle(fontSize: 18)),
const SizedBox(height: 10,),
Container(
height: 50,
width: MediaQuery.of(context).size.width * 8,
decoration: BoxDecoration(
border: Border.all(color: myColor, width: 1,),
borderRadius: const BorderRadius.all(Radius.circular(20)),
color: Colors.white54
//color: Colors.white54
),
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 15),
child: TextField(
controller: _couponText,
maxLines: 1,
decoration: const InputDecoration.collapsed(
hintText: 'Apply coupon here ...'
),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: ElevatedButton(
onPressed: (){
_coupon.getcouponDetails(_couponText.text).then((value) {
if(value.data() == null){
setState(() {
_coupon.discount = 0;
});
showCodeDialog(_couponText.text, 'not valid');
return;
}
if(_coupon.expired==false){
// Code to be done here.
Fluttertoast.showToast(msg: 'Coupon is valid');
// I want to update the totalAmount value with the discountRate here...
}
if(_coupon.expired==true){
setState(() {
_coupon.discount = 0;
});
showCodeDialog(_couponText.text, 'expired');
return;
}
});
},
style: ElevatedButton.styleFrom(
textStyle: const TextStyle(
fontSize: 15,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
)
),
child: const Text('Apply'),
),
),
],
),
),
const SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
onPressed: (){
clearCartNow(context);
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (c) => const HomeScreen()));
Fluttertoast.showToast(msg: "Cart cleared");
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black, backgroundColor: myColor
),
icon: const Icon(Icons.clear_all),
label: const Text("Clear")),
ElevatedButton.icon(
onPressed: (){
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (c)=> AddressScreen(
totalAmount: totalAmount.toDouble(),
sellerUID: widget.sellerUID,
),
),
);
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black,
backgroundColor: myColor,
),
icon: const Icon(Icons.navigate_next),
label: const Text("Proceed")),
],
)
],
),
);
}),
],
),
)
),
),
)
],
),
);
}
showCodeDialog(code, validity){
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return CupertinoAlertDialog(
title: const Text('Apply Coupon'),
content: Text('This discount coupon $code you have entered is $validity'),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: (){Navigator.pop(context);},
child: Text('Ok', style: TextStyle(color: Colors.white),),
),
)
],
);
});
}
}
I tried changing the totalAmount, amountProvider.tAmount and their types, but nothing is working for me.
In this image, the total amount is without discount. If I apply a coupon of 10%, the total amount should be subtracted by 10%.
I can add more information if required.
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
I ran into problem attempting to refresh the ListView inside a FutureBuilder, I can't get it to refresh, not by using setState, not anything else, could someone more experienced with flutter suggest what is wrong with the way I utilize FutureBuilder or setState?
Here is the code that I am running into the problem with:
class ChatScreen extends StatefulWidget {
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
String contact_name;
int contact_id;
String str_id;
List<Align> messagesList = [];
Align messageUnit;
int ownID;
String ownName;
double height;
double width;
final TextEditingController messageGetter = TextEditingController();
#override
void initState() {
super.initState();
final res = Variables.getContactName();
contact_name = res;
final res_2 = Variables.getContactID();
contact_id = res_2;
str_id = res_2.toString();
final res_3 = Variables.getOwnID();
ownID = res_3;
final res_4 = Variables.getOwnName();
ownName = res_4;
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future:getMessages(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
final data = snapshot.data;
width = MediaQuery
.of(context)
.size
.width;
height = MediaQuery
.of(context)
.size
.height;
print(data);
return Scaffold(
appBar:
AppBar(
title: Text(contact_name),
backgroundColor: Color(0xD3232323),
),
body:
Column(
children: [
Expanded(
child: ListView(
children: messagesList,
reverse: true,
),
),
Container(
child: Row(
children: [
Expanded(
child: Padding(
child: TextField(
controller: messageGetter,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: BorderSide(),
),
),
),
padding: EdgeInsets.fromLTRB(8, 8, 8, 8),
),
),
Container(
child: Padding(
child: OutlinedButton(
onPressed: () {
sendMessage();
setState(() {
getMessages();
});
},
child: Text("+"),
style: ButtonStyle(
),
),
padding: EdgeInsets.fromLTRB(8, 8, 8, 8),
),
),
],
),
),
],
)
);
}
if (snapshot.hasError) {
return Scaffold(
appBar: AppBar(
title: Text(contact_name),
backgroundColor: Color(0xD3232323),
),
body:
Container(
child:
Align(alignment: Alignment.center,
child:
Text("Error"),
),
),
);
}
if (snapshot.connectionState != ConnectionState.done) {
return Scaffold(
appBar: AppBar(
title: Text(contact_name),
backgroundColor: Color(0xD3232323),
),
body:
Container(
child:
Align(alignment: Alignment.center,
child:
CircularProgressIndicator(
),
),
),
);
}
else
return Text("Meow");
}
);
}
Future<String> getMessages() async{
final result = await context.read<TelegramService>().send(
TdApi.GetChatHistory(chatId: contact_id, limit: 1, )
);
print(result);
final res = await context.read<TelegramService>().send(
TdApi.GetChatHistory(chatId: contact_id, limit: 999)
);
TdApi.Messages messages = res;
messagesList.clear();
for(var i = 0; i < messages.totalCount; i++) {
TdApi.Message message = messages.messages[i];
TdApi.MessageContent text = message.content;
TdApi.MessageText textContent = text;
TdApi.FormattedText textFinal = textContent.text;
TdApi.MessageSenderUser messageSender = message.sender;
if (messageSender.userId == ownID) {
messageUnit = Align (
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.fromLTRB(0, 8, 0, 8),
child: OutlinedButton(
child: Text(textFinal.text,
style: TextStyle(
color: Color(0xD3232323),
),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Color(0xD300FFEA)),
),
),
),
);
}
else {
messageUnit = Align (
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.fromLTRB(0, 8, 0, 8),
child: OutlinedButton(
child: Text(textFinal.text),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Color(0xD3383838)),
),
),
),
);
}
messagesList.add(messageUnit);
}
return "Messages Retrieved";
}
sendMessage() async {
TdApi.FormattedText messageText = TdApi.FormattedText(text: messageGetter.text, entities: []);
TdApi.MessageSendOptions messageSendOptions = TdApi.MessageSendOptions(disableNotification: false) ;
TdApi.InputMessageText message = TdApi.InputMessageText(text: messageText);
final result = await context.read<TelegramService>().send(
TdApi.SendMessage(chatId: contact_id, inputMessageContent: message, options: messageSendOptions),
);
print(result);
messageGetter.clear();
}
}
Wrap your listview with a stateful builder, like this:
StatefulBuilder(builder: (context, setState) {
return ListView(
children: messagesList,
reverse: true,);
}),
I resolved my current issue regarding locking and unlocking buttons. I am basing my levels on the marks the user got. If they got a score of 25 and above, they will proceed to the next level.
Now the problem here is since my quiz is sharing one code with a different JSON file, when the user perfects the score on the first stage, the whole level will unlock which is a no-no. The idea is even they scored perfect, the next stage will be unlocked not the whole level. I tried thinking of ways on how to do it but nothing comes to my mind.
Here is my Quiz Page:
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:baybay_app/Quiz/NextLevel class.dart';
import 'package:baybay_app/Quiz/QuizHome.dart';
import 'package:baybay_app/Quiz/ResultPage.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Quizjson extends StatelessWidget {
String roundName;
bool isComplete = false;
Quizjson(this.roundName, mark);
String assettoload;
int question;
// a function
// sets the asset to a particular JSON file
// and opens the JSON
setasset() {
if (roundName == 'Easy Round') {
assettoload ='assets/Sample.json';
} else if (roundName == 'Average Round') {
assettoload = 'assets/Medium.json';
} else if (roundName == 'Hard Round') {
assettoload = 'assets/Hard.json';
}else {
assettoload = 'assets/Intermediate.json';
}
}
#override
Widget build(BuildContext context) {
setasset();
return FutureBuilder(
future: DefaultAssetBundle.of(context).loadString(assettoload, cache: false),
builder: (context, snapshot){
List mydata = json.decode(snapshot.data.toString());
if(mydata == null){
return Scaffold(
body: Center(
child: Text(
"Loading",
),
),
);
}else{
return quizpage(mydata: mydata);
}
}
);
}
}
class quizpage extends StatefulWidget {
String langname;
var mydata;
quizpage({Key key, #required this.mydata}): super(key: key);
#override
_quizpageState createState() => _quizpageState(mydata);
}
class _quizpageState extends State<quizpage> {
var mydata;
_quizpageState(this.mydata);
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitDown, DeviceOrientation.portraitUp]);
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 3,
child: Container(
padding: EdgeInsets.all(20.0),
alignment: Alignment.bottomLeft,
child: Text(mydata[0][question.toString()])
),
),
Expanded(
flex: 6,
child: Container(
child: Column(
children: [
Row(
children:[
ChoiceButton("a"),
ChoiceButton("b")
]
),
Row(
children: [
ChoiceButton("c"),
ChoiceButton("d"),
]
)
]
),
),
),
Expanded(
flex: 1,
child: Container(
alignment: Alignment.topCenter,
child: Center(
child: Text(
showtimer,
style: TextStyle(
fontSize: 20.0
),
),
),
),
),
],
)
);
}
Widget ChoiceButton(String k) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0),
child: MaterialButton(
onPressed: ()=>CheckAnswer(k),
child: Text(
mydata[1][question.toString()][k],
style: TextStyle(
color: Colors.white
)),
color: btncolor[k],
),
);
}
Color colorsToShow = Colors.brown[700];
Color right = Colors.greenAccent[700];
Color wrong = Colors.redAccent[700];
int mark = 0;
int question = 1;
int timer = 30;
String showtimer = "30";
bool canceltimer = false;
bool isComplete = false;
Map<String,Color> btncolor = {
"a" : Colors.brown[700],
"b" : Colors.brown[700],
"c" : Colors.brown[700],
"d" : Colors.brown[700],
};
#override
void initState(){
starttimer();
super.initState();
}
#override
void setState(fn){
if(mounted){
super.setState(fn);
}
}
void starttimer() async {
const onesec = Duration(seconds: 1);
Timer.periodic(onesec, (Timer t){
setState(() {
if(timer < 1){
t.cancel();
NextQuestion();
}
else if(canceltimer==true){
t.cancel();
}
else{
timer = timer - 1;
}
showtimer = timer.toString();
});
});
}
void NextQuestion(){
canceltimer = false;
timer = 30;
setState(() {
if(question< 10){
question++;
}
else{
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => ResultPage(mark: mark),
));}
btncolor["a"] = Colors.brown[700];
btncolor["b"] = Colors.brown[700];
btncolor["c"] = Colors.brown[700];
btncolor["d"] = Colors.brown[700];
isComplete = true;
});
starttimer();
}
void CheckAnswer(String k) {
if(mydata[2][question.toString()] == mydata[1][question.toString()][k]){
mark = mark+5;
colorsToShow = right;
}
else{
colorsToShow = wrong;
}
setState(() {
btncolor[k] = colorsToShow;
});
Timer(Duration(seconds: 2), NextQuestion);
}
}
Here is my Quiz Home:
import 'package:baybay_app/Quiz/QuizTracingSound.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:baybay_app/Quiz/QuizTracingSound.dart';
class QuizHome extends StatefulWidget {
int mark = 0;
QuizHome({ #required this.mark });
#override
_QuizHomeState createState() => _QuizHomeState(mark);
}
class _QuizHomeState extends State<QuizHome> {
createAlertDialouge(BuildContext context){
return showDialog(context: context, builder: (context){
return AlertDialog(
title: Text('Not Complete'),
content: Text('Please score 25 above mark'),
actions: [
Center(
child: RaisedButton(
onPressed: (){Navigator.of(context).pop();},
color: Colors.grey[100],
),
),
],
shape: RoundedRectangleBorder(side: BorderSide(width: 16.0, color: Colors.red.shade100)),
backgroundColor: Colors.lightBlue.shade100,
);
});
}
createAlertDialougeOne(BuildContext context){
return showDialog(context: context, builder: (context){
return AlertDialog(
title: Text('Not Complete'),
content: Text('Please score 35 and above mark'),
actions: [
Center(
child: RaisedButton(
onPressed: (){Navigator.of(context).pop();},
color: Colors.grey[100],
),
),
],
shape: RoundedRectangleBorder(side: BorderSide(width: 16.0, color: Colors.red.shade100)),
backgroundColor: Colors.lightBlue.shade100,
);
});
}
createAlertDialougeTwo(BuildContext context){
return showDialog(context: context, builder: (context){
return AlertDialog(
title: Text('Not Complete'),
content: Text('Please score 35 and above mark'),
actions: [
Center(
child: RaisedButton(
onPressed: (){Navigator.of(context).pop();},
color: Colors.grey[100],
),
),
],
shape: RoundedRectangleBorder(side: BorderSide(width: 16.0, color: Colors.red.shade100)),
backgroundColor: Colors.lightBlue.shade100,
);
});
}
int mark = 0 ;
_QuizHomeState(this.mark);
String langname;
bool isComplete = false;
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitDown, DeviceOrientation.portraitUp]);
List <String> images = [
'assets/Ba.gif',
'assets/GA.PNG',
'assets/HA.PNG',
'assets/SA.PNG'
];
return Scaffold(
appBar: AppBar(
title: Text('Quiz Home '),
),
body:ListView(
children: <Widget>[
FlatButton(
child: CustomCard('Easy Round', images[0], des[1], isComplete, Colors.green, mark),
onPressed: () {
{ Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context)=> Quizjson("Easy Round", mark = 5),
));}
}
),
SizedBox(
height: 20.0,
),
FlatButton(
child: CustomCard('Average Round', images[1], des[1], isComplete, lockOrNot, mark),
onPressed: _onPressedOne,
),
SizedBox(
height: 20.0,
),
FlatButton(
onPressed: _onPressedTwo,
child: CustomCard('Hard Round', images[2],des[2], isComplete, btncolor, mark)
),
SizedBox(
height: 20.0,
),
FlatButton(
onPressed: _onPressedThree,
child: CustomCard('Intermediate Round', images[3],des[3], isComplete, btncolor, mark )
),
],
)
);
}
List <String> des = [
"The easy round lets you test your knowledge in determining letters. Are you up for the challenge? Click here!!!",
"Do you want to step up your baybayin game? Let's see if you can distinguish words! Click here!!!",
"Do you know how to construct sentences with the use of Baybayin? Click here!!!",
"Masters of baybayin can only enter this quiz! Are you one of them? Click Here!!!",
];
Color btncolor;
Widget CustomCard(String roundName,images,String des, bool isComplete, Color btncolor, int mark ) {
return Material(
color: btncolor,
elevation: 10.0,
borderRadius: BorderRadius.circular(20.0),
child: Container(
child: Column(
children: <Widget>[
Text(
'$mark'
),
Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
),
child: Material(
elevation: 5.0,
borderRadius: BorderRadius.circular(100.0),
child: Container(
height: 200.0,
width: 200.0,
child:ClipOval(
child: Image(
image: AssetImage(images),
),
)
),
),
),
Center(
child: Text( roundName,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
letterSpacing: 10.0,
fontFamily: 'S'
),),
),
Container(
padding:EdgeInsets.all(8.0),
child: Text(
des,
style: TextStyle(
color: Colors.white,
letterSpacing: 1.0
),
),
),
],
),
),
);
}
Color unlockColor = Colors.green;
Color lockColor = Colors.grey;
Color lockOrNot = Colors.grey;
void _onPressedOne() {
int marks1 = 24;
if(marks1< mark){
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context)=> Quizjson( "Average Round", 7 ),
));
}
else{
createAlertDialouge(context);
}
}
void _onPressedTwo() {
int marks2 = 34;
int marc = mark;
if( marks2 < marc ){
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context)=> Quizjson("Hard Round", 7 ),
));
}
else{
createAlertDialougeOne(context);
}
}
void _onPressedThree() {
int marks3 = 49;
int marc = mark;
if( marks3 < marc ){
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context)=> Quizjson("Average Round", 8),
));
}
else{
createAlertDialougeTwo(context);
}
}
}
If you need the Result page:
import 'package:baybay_app/Quiz/QuizHome.dart';
import 'package:flutter/material.dart';
class ResultPage extends StatefulWidget {
int mark;
ResultPage({Key key, #required this.mark}) : super(key: key);
#override
_ResultPageState createState() => _ResultPageState(mark);
}
class _ResultPageState extends State<ResultPage> {
List<String> images = [
'assets/excellent.jpg',
'assets/good.png',
'assets/Sorry.png'
];
String message;
String image;
#override
void initState(){
if(mark<5){
image = images[2];
message = 'Try Again..\n' + 'You scored $mark';
}
else if(mark==5){
image = images[1];
message = 'Good.. \n' + 'You scored $mark';
}
else{
image = images[0];
message = 'Excellent!!!...\n' + 'You scored $mark';
}
}
int mark;
_ResultPageState(this.mark);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Result"
)
),
body: Column(
children:[
Expanded(
flex: 6,
child: Material(
elevation: 5.0,
child: Container(
child:Column(
children: [
Material(
child: Container(
width: 300.0,
height: 300.0,
child: ClipRect(
child: Image(
image: AssetImage(
image,
)
)
),
),
),
Center(
child: Text(
message,
style: TextStyle(
fontSize: 20.0,
fontFamily: 'Staatliches'
),
),
)
],
),
),
),
),
Expanded(
flex:4,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:<Widget>[
OutlineButton(
onPressed: () {
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context)=> QuizHome(mark:mark)));
},
child: Text(
'Continue',
style: TextStyle(
fontSize: 20.0,
fontFamily: 'Staatliches'
)
),
padding: EdgeInsets.symmetric(vertical: 10.0,horizontal: 15.0),
borderSide: BorderSide(width: 3.0,color: Colors.brown[700])
)
],
)
)
]
)
);
}
}
What can I try next?
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);
},
);
},
);
}
}