How to make collapse paneItem in navigationpane in fluent ui in flutter - flutter

I am trying to do collapse paneItem in navigationpane after a lot of searcb and i didn't found anything about that if anyone used fluent ui with flutter and know how to do that it will be nice
That is mycode:
import 'dart:ui';
import 'package:fluent_ui/fluent_ui.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return FluentApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
brightness: Brightness.dark,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
int _selectedindex = 0;
bool _visible = true;
TextEditingController search = TextEditingController();
final autoSuggestBox = TextEditingController();
final values = ['Blue', 'Green', 'Yellow', 'Red'];
String? comboBoxValue;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
void initState() {
search.text = 'Search';
super.initState();
}
#override
Widget build(BuildContext context) {
return NavigationView(
appBar: NavigationAppBar(
title: Text(widget.title),
),
pane: NavigationPane(
displayMode: PaneDisplayMode.compact,
onChanged: (newindex) {
setState(() {
_selectedindex = newindex;
});
},
footerItems: [
PaneItemSeparator(),
PaneItem(
icon: const Icon(FluentIcons.settings),
title: const Text('Settings'),
),
],
selected: _selectedindex,
autoSuggestBox: AutoSuggestBox(
controller: TextEditingController(),
placeholder: 'Search',
trailingIcon: Icon(FluentIcons.search),
items: const ['Item 1', 'Item 2', 'Item 3', 'Item 4'],
),
autoSuggestBoxReplacement: const Icon(FluentIcons.search),
items: [
PaneItem(
icon: const Icon(FluentIcons.settings),
title: const Text('page 0')),
PaneItemHeader(header: Text('data')),
PaneItem(
icon: const Icon(FluentIcons.settings),
title: const Text('page 1')),
]),
content: NavigationBody(index: _selectedindex, children: [
ScaffoldPage(
padding: EdgeInsets.only(top: 0),
header: _visible
? InfoBar(
title: const Text('Update available'),
content:
const Text('Restart the app to apply the latest update.'),
severity: InfoBarSeverity.info,
onClose: () {
setState(() => _visible = false);
})
: null,
content: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 200,
child: AutoSuggestBox(
controller: autoSuggestBox,
items: const [
'Blue',
'Green',
'Red',
'Yellow',
'Grey',
],
onSelected: (text) {
print(text);
}),
),
SizedBox(
height: 20,
),
SizedBox(
width: 200,
child: Combobox<String>(
placeholder: Text('Selected list item'),
isExpanded: true,
items: values
.map((e) => ComboboxItem<String>(
value: e,
child: Text(e),
))
.toList(),
value: comboBoxValue,
onChanged: (value) {
// print(value);
if (value != null) setState(() => comboBoxValue = value);
},
),
),
SizedBox(
height: 20,
),
FilledButton(
style: ButtonStyle(
backgroundColor: ButtonState.all(Colors.blue)),
onPressed: () {
// showDialog(
// context: context,
// builder: (context) {
// return ContentDialog(
// title: Text('No WiFi connection'),
// content: Text('Check your connection and try again'),
// actions: [
// Button(
// child: Text('Ok'),
// onPressed: () {
// Navigator.pop(context);
// })
// ],
// );
// },
// );
},
child: const Icon(FluentIcons.add),
)
],
),
),
),
const ScaffoldPage(
header: PageHeader(
title: Text(
'Your Page 1',
textAlign: TextAlign.center,
)),
content: Center(child: Text('Page 1')),
),
const ScaffoldPage(
header: PageHeader(
title: Text(
'Your Page 2',
textAlign: TextAlign.center,
)),
content: Center(child: Text('Page 2')),
),
const ScaffoldPage(
header: PageHeader(
title: Text(
'Your Page 3',
textAlign: TextAlign.center,
)),
content: Center(child: Text('Page 3')),
),
]),
);
}
}
I am trying to do multi-level of paneItem in navigationpane in fluent ui in flutter but i don't know how to do that if anyone used fluent ui with flutter and know how to do that it will be nice

Related

How can I repurpose boost button widgets in flutter?

I have a question here, I created an increase button widget in a separate file (component)...
increase_button_widget.dart
import 'package:flutter/material.dart';
class IncreaseButtonWidget extends StatefulWidget {
const IncreaseButtonWidget({super.key});
#override
State<IncreaseButtonWidget> createState() => _IncreaseButtonWidgetState();
}
class _IncreaseButtonWidgetState extends State<IncreaseButtonWidget> {
int _counterValue = 0;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return CounterButton(
loading: false,
onChange: (int val) {
setState(() {
_counterValue = val;
});
},
count: _counterValue,
countColor: Colors.blue,
buttonColor: Colors.blue,
progressColor: Colors.blue,
);
}
}
Here I will reuse it more than once in my application...
increase.dart
import 'package:increase/widgets/increase_button_widget.dart';
import 'package:flutter/material.dart';
class MyPassagerClassPage extends StatefulWidget {
const MyPassagerClassPage({super.key});
#override
State<MyPassagerClassPage> createState() => _MyPassagerClassPageState();
}
enum SingingCharacter { economy, business, first }
class _MyPassagerClassPageState extends State<MyPassagerClassPage> {
SingingCharacter? _character = SingingCharacter.economy;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Passager & Class"),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.check_outlined),
tooltip: 'Go to the next page',
onPressed: () {
Navigator.pop(context);
},
),
],
),
body: Column(
children: [
const SizedBox(height: 20),
const Text(
'Passengers',
style: TextStyle(fontSize: 30),
),
const ListTile(
leading: Icon(Icons.accessibility_outlined),
title: Text('Adults'),
subtitle: Text('12+ years'),
trailing: IncreaseButtonWidget(),
),
const ListTile(
leading: Icon(Icons.boy_outlined),
title: Text('Children'),
subtitle: Text('2-11 years'),
trailing: IncreaseButtonWidget(),
),
const ListTile(
leading: Icon(Icons.child_care_outlined),
title: Text('Infants'),
subtitle: Text('Under 2 years'),
trailing: IncreaseButtonWidget(),
),
const DividerWidget(),
const SizedBox(height: 25),
const Text(
'Class',
style: TextStyle(fontSize: 30),
),
ListTile(
title: const Text('Economy'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.economy,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
},
),
),
ListTile(
title: const Text('Business'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.business,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
},
),
),
ListTile(
title: const Text('First'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.first,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
},
),
),
const DividerWidget(),
],
),
);
}
}
In this case i used this widget 3 times...
My question is how to get the value of each of these increase buttons separately to be able to get them in a different variable...
Hence, in this case, each of these widgets has input data that I will need later to do another calculation.

How to declare check boxes values to String values and save firestore on flutter?

In my code can select multiple checkboxes, but I want to print the selected checkboxes titles.And also then application run checkboxes are unselecting ( checkboxes values are bool = false)
Ex: Like as this Image I selected dart and java checkboxes so I want to insert those names in the firestore.I have no idea how to equal the check box value to string values.
How to insert that values?
code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class HomePageWidget extends StatefulWidget {
const HomePageWidget({Key? key}) : super(key: key);
#override
_HomePageWidgetState createState() => _HomePageWidgetState();
}
class _HomePageWidgetState extends State<HomePageWidget> {
bool? checkboxListTileValue1;
bool? checkboxListTileValue2;
bool? checkboxListTileValue3;
bool? checkboxListTileValue4;
bool? checkboxListTileValue5;
String checkboxListTileValue1 = "c++"
String checkboxListTileValue2 = "c"
String checkboxListTileValue3 = "java"
String checkboxListTileValue4 = "react"
String checkboxListTileValue5 = "dart"
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Page Title',
),
actions: [],
centerTitle: false,
elevation: 2,
),
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Theme(
data: ThemeData(
unselectedWidgetColor: Color(0xFF95A1AC),
),
child: CheckboxListTile(
value: checkboxListTileValue1 ??= false,
onChanged: (newValue) async {
setState(() => checkboxListTileValue1 = newValue!);
},
title: Text(
'c++',
),
tileColor: Color(0xFFF5F5F5),
dense: false,
controlAffinity: ListTileControlAffinity.trailing,
),
),
Theme(
data: ThemeData(
unselectedWidgetColor: Color(0xFF95A1AC),
),
child: CheckboxListTile(
value: checkboxListTileValue2 ??= false,
onChanged: (newValue) async {
setState(() => checkboxListTileValue2 = newValue!);
},
title: Text(
'c',
),
tileColor: Color(0xFFF5F5F5),
dense: false,
controlAffinity: ListTileControlAffinity.trailing,
),
),
Theme(
data: ThemeData(
unselectedWidgetColor: Color(0xFF95A1AC),
),
child: CheckboxListTile(
value: checkboxListTileValue3 ??= false,
onChanged: (newValue) async {
setState(() => checkboxListTileValue3 = newValue!);
},
title: Text(
'java',
),
tileColor: Color(0xFFF5F5F5),
dense: false,
controlAffinity: ListTileControlAffinity.trailing,
),
),
Theme(
data: ThemeData(
unselectedWidgetColor: Color(0xFF95A1AC),
),
child: CheckboxListTile(
value: checkboxListTileValue4 ??= false,
onChanged: (newValue) async {
setState(() => checkboxListTileValue4 = newValue!);
},
title: Text(
'react',
),
tileColor: Color(0xFFF5F5F5),
dense: false,
controlAffinity: ListTileControlAffinity.trailing,
),
),
Theme(
data: ThemeData(
unselectedWidgetColor: Color(0xFF95A1AC),
),
child: CheckboxListTile(
value: checkboxListTileValue5 ??= false,
onChanged: (newValue) async {
setState(() => checkboxListTileValue5 = newValue!);
},
title: Text(
'dart',
),
tileColor: Color(0xFFF5F5F5),
dense: false,
controlAffinity: ListTileControlAffinity.trailing,
),
),
ElevatedButton(onPressed: press(), child: Text('submit'))
],
),
),
),
);
}
press() {
FirebaseFirestore.instance
.collection("users")
.doc()
.set({
"checkboxes": checkboxListTileValue1 + checkboxListTileValue2 + checkboxListTileValue3 + checkboxListTileValue4 + checkboxListTileValue5,
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const HomePageWidget()),
);
}
}
errors
this
First you need to define class model for your checkbox like this:
class CheckBoxModel {
final String title;
final bool value;
CheckBoxModel({required this.title, required this.value});
}
then use it like this:
class TestingDesign2 extends StatefulWidget {
const TestingDesign2({super.key});
#override
State<TestingDesign2> createState() => _TestingDesign2State();
}
class _TestingDesign2State extends State<TestingDesign2> {
List<CheckBoxModel> checkboxes = [
CheckBoxModel(title: 'C++', value: false),
CheckBoxModel(title: 'java', value: false),
CheckBoxModel(title: 'C', value: false),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return buildCheckBox(checkboxes[index], index);
},
itemCount: checkboxes.length,
),
),
ElevatedButton(onPressed: press(), child: Text('submit'))
],
),
);
}
buildCheckBox(CheckBoxModel checkbox, int index) {
return Theme(
data: ThemeData(
unselectedWidgetColor: Color(0xFF95A1AC),
),
child: CheckboxListTile(
value: checkbox.value,
onChanged: (newValue) async {
setState(() => checkboxes[index] =
CheckBoxModel(title: checkbox.title, value: newValue!));
},
title: Text(
checkbox.title,
style: TextStyle(
fontSize: 12,
),
),
tileColor: Colors.transparent,
dense: false,
controlAffinity: ListTileControlAffinity.trailing,
),
);
}
press() {
List<CheckBoxModel> checked =
checkboxes.where((element) => element.value).toList();
String result = '';
checked.forEach((element) {
result = result + element.title;
});
FirebaseFirestore.instance.collection("users").doc().set({
"checkboxes": result,
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const HomePageWidget()),
);
}
}

How to pass a entire list to a new page

I have been trying to pass a entire List to a new page but a receiver this error " Exception has occurred. RangeError (RangeError (index): Invalid value: Valid value range is empty: 0) ". I believe the problem is on the page that is sending the list, since the error is apparently because the list is empty, right?
This is the code of my page that a sending the List:
import 'package:flutter/material.dart';
import 'package:flutter_cont`enter code here`ador/main.dart';
import 'package:flutter_contador/view/LeitorEAN_View.dart';
import 'package:sqflite/sqflite.dart';
import 'package:flutter_contador/data/produto.dart';
class ListaDeProdutos extends StatefulWidget {
final Future<Database>? database;
const ListaDeProdutos({Key? key, this.database}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _ListaDeProdutosState();
}
}
class _ListaDeProdutosState extends State<ListaDeProdutos> {
List<Produto> listaproduto = List.empty(growable: true);
#override
void initState() {
fetchProdutos();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Produto'),
bottom: AppBar(
automaticallyImplyLeading: false,
elevation: 0,
title: Container(
width: double.infinity,
height: 40,
color: Colors.white,
child: const Center(
child: TextField(
// controller: _controller,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
// hintText: (Get.put(LeitorCodigoBarrasControle()).valorCodigoBarras),
hintText: ('Buscar...'),
),
),
),
),
),
),
body: ListView.builder(
itemCount: listaproduto.length,
itemBuilder: (context, index,) {
return Card(
child: ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LeitorCodigoBarras(database: database, listaproduto: [],)),
);
}, // alterar quantidade do produto com leitor EAN
onLongPress: (){openUpdateProdutoView(index);}, // alterar quantidade do produto manualmente
// onLongPress: (){ deleteRecord(listaproduto[index]);}, // deletar o produto
leading: Text(listaproduto[index].codigo,style: const TextStyle(fontSize: 25)),
subtitle: Column(
children: [
Text(listaproduto[index].descricao,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 16)
),
Text(listaproduto[index].codigoEAN,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 16)),
],
),
trailing: Text(listaproduto[index].quantidade.toString(),style: const TextStyle(fontSize: 20)),
));
}),
);
}
void fetchProdutos() async {
final db = await widget.database;
final List<Map<String, dynamic>> maps =
await db!.query(Produto.tableName);
var list = List.generate(maps.length, (i) {
return Produto(
id: maps[i]['id'],
codigo: maps[i]['codigo'],
descricao: maps[i]['descricao'],
codigoEAN: maps[i]['codigoEAN'],
quantidade: maps[i]['quantidade'],
);
});
setState(() {
listaproduto.clear();
listaproduto.addAll(list);
});
}
// void deleteRecord(Produto produto) async {
// final db = await widget.database;
// db!.delete(Produto.tableName,
// where: 'id = ?', whereArgs: [produto.id]);
//
// fetchProdutos();
// }
void openUpdateProdutoView(int index) async {
bool doUpdate = await Navigator.pushNamed(context, "/updateProduto",
arguments: listaproduto[index]) as bool;
if (doUpdate) {
fetchProdutos();
}
}
}
This is the code of my page that a receiving the List:
import 'package:flutter/material.dart';
import 'package:flutter_contador/data/Produto.dart';
import 'package:scan/scan.dart';
import 'package:sqflite/sqflite.dart';
class LeitorCodigoBarras extends StatefulWidget {
const LeitorCodigoBarras(
{Key? key, required this.database, required this.listaproduto})
: super(key: key);
final Future<Database>? database;
final List<Produto> listaproduto;
#override
_LeitorCodigoBarrasState createState() => _LeitorCodigoBarrasState();
}
class _LeitorCodigoBarrasState extends State<LeitorCodigoBarras> {
List<Produto> listaproduto = List.empty(growable: true);
ScanController controller = ScanController();
var quantidadeEditController = TextEditingController();
var index = 0;
var quantidade = 0;
var scanResult = '';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 80,
title: const Text(
'Leitor EAN',
textAlign: TextAlign.center,
),
elevation: 0.0,
backgroundColor: const Color(0xFF333333),
leading: GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: const Center(
child: Icon(
Icons.cancel,
color: Colors.white,
)),
),
actions: [
IconButton(
icon: const Icon(Icons.save),
onPressed: () {
}),
IconButton(
icon: const Icon(Icons.flashlight_on),
onPressed: () {
controller.toggleTorchMode();
})
],
),
body: Column(
children: [
SizedBox(
height: 400,
child: ScanView(
controller: controller,
scanAreaScale: .7,
scanLineColor: const Color.fromARGB(255, 51, 255, 0),
onCapture: (data) {
setState(() {
scanResult = data;
for (var i = 0; i < listaproduto.length; i++) {
if (listaproduto[i].codigoEAN == scanResult) {
index = i;
}else{
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(const SnackBar(content: Text("Código EAN não encontrado.")));
}
}
});
controller.resume();
},
),
),
SingleChildScrollView(
child: ListTile(
title: Text(
'Produto ${widget.listaproduto[index].codigo}',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black, fontSize: 40),
),
subtitle: Text(
'0000000',
textAlign: TextAlign.center,
),
),
),
const SizedBox(
child: ListTile(
title: Text(
'10',
textAlign: TextAlign.center,
),
leading: Icon(Icons.add),
trailing: Icon(Icons.remove),
),
),
],
),
);
}
}
You pass your list as an argument to a named route, but you do not take the argument anywhere on the page where you receive the list.
Inside your build add this to receive the list:
List<Produto> list = ModalRoute.of(context)!.settings.arguments as List<Produto>;
See here: https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments

Search Bar Layout with DataTable Flutter

I've made a simple search bar for my DataTable list, but the problem is I can't return just the item I search for but instead I get empty fields and the item I search for. I've tried various things, but I get the error that I need rows as much as I have columns, so this is the only way for now that I've made it to work.
But I wanted it to make it like this:
Here is the code:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/vehicle.dart';
import 'services/vehicle_api.dart';
import 'models/vehicle_data_provider.dart';
class VehicleList extends StatefulWidget {
#override
_VehicleList createState() => _VehicleList();
}
class _VehicleList extends State<VehicleList> {
TextEditingController controller = TextEditingController();
String _searchResult = '';
_getPosts() async {
HomePageProvider provider =
Provider.of<HomePageProvider>(context, listen: false);
var postsResponse = await fetchVehicles();
if (postsResponse.isSuccessful) {
provider.setPostsList(postsResponse.data, notify: false);
} else {
provider.mergePostsList(
postsResponse.data,
);
}
provider.setIsHomePageProcessing(false);
}
#override
void initState() {
_getPosts();
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: (value) {
setState(() {
_searchResult = value;
});
}),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
setState(() {
controller.clear();
_searchResult = '';
});
},
),
),
),
Consumer<HomePageProvider>(
builder: (context, vehicleData, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.all(
Radius.circular(12.0),
),
),
child: SingleChildScrollView(
child: DataTable(
columnSpacing: 30,
columns: <DataColumn>[
DataColumn(
numeric: false,
label: Text(
'Friendly Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Licence Plate',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Delete',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: List.generate(
vehicleData.postsList.length,
(index) {
VehicleData post = vehicleData.getPostByIndex(index);
return post.licencePlate
.toLowerCase()
.contains(_searchResult) ||
'${post.model}'
.toLowerCase()
.contains(_searchResult) ||
'${post.make}'
.toLowerCase()
.contains(_searchResult) ||
post.type
.toLowerCase()
.contains(_searchResult)
? DataRow(
cells: <DataCell>[
DataCell(
Text('${post.friendlyName}'),
),
DataCell(
Text('${post.licencePlate}'),
),
DataCell(
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
vehicleData.deletePost(post);
},
),
),
],
)
: DataRow(
/// This is the part where I return empty rows with one row with the search bar results, so I assume this must me changed
cells: <DataCell>[
DataCell(Text('')),
DataCell(Text('')),
DataCell(Text('')),
],
);
},
),
),
),
),
],
);
},
),
],
);
}
}
Can't seem to figure this one out. Thanks in advance for the help!
Okay after your comment i finally made it work like i think you want. The idea is to uses two lists instead of one and not using the List.generate method because of that empty row. When you change the _searchResult value you filter the userFiltered list with the original values coming from the users lists.
I used the flutter sample for DataTable with those edits and it works:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyStatelessWidget(),
),
);
}
}
class User{
String name;
int age;
String role;
User({this.name, this.age, this.role});
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatefulWidget {
MyStatelessWidget({Key key}) : super(key: key);
#override
_MyStatelessWidgetState createState() => _MyStatelessWidgetState();
}
class _MyStatelessWidgetState extends State<MyStatelessWidget> {
List<User> users = [User(name: "Sarah", age: 19, role: "Student"), User(name: "Janine", age: 43, role: "Professor")];
List<User> usersFiltered = [];
TextEditingController controller = TextEditingController();
String _searchResult = '';
#override
void initState() {
super.initState();
usersFiltered = users;
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: (value) {
setState(() {
_searchResult = value;
usersFiltered = users.where((user) => user.name.contains(_searchResult) || user.role.contains(_searchResult)).toList();
});
}),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
setState(() {
controller.clear();
_searchResult = '';
usersFiltered = users;
});
},
),
),
),
DataTable(
columns: const <DataColumn>[
DataColumn(
label: Text(
'Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Age',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Role',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: List.generate(usersFiltered.length, (index) =>
DataRow(
cells: <DataCell>[
DataCell(Text(usersFiltered[index].name)),
DataCell(Text(usersFiltered[index].age.toString())),
DataCell(Text(usersFiltered[index].role)),
],
),
),
),
],
);
}
}
OLD POST:
I was looking for a way to filter a datatable and your problem fixed mine thanks ( i will try to help you now!). By using a PaginatedDataTable widget instead of DataTable i can achieve the result you want to. The idea is to filter the list before you pass it to the source property. This is a part of the code i used to filter my list. Inside the switch block i filter it to remove the other elements:
switch(filter){
case "Id d'expédition":
expeditionsList = expeditionsList.where((e) => e.expeditionId.toLowerCase() == stringToSearch.toLowerCase()).toList();
break;
}
return PaginatedDataTable(
showCheckboxColumn: false,
rowsPerPage: 5,
source: DataTableSourceExpedition(
expeditions: expeditionsList,
onRowClicked: (index) async {
await ExpeditionRowDialog.buildExpeditionRowDialog(
context, expeditionsList[index].expeditionsDetails)
.show();
},
header: Container(
width: 100,
child: Text("Expéditions"),
),
columns: [
DataColumn(
label: Text("Id d'expédition"), numeric: false, tooltip: "id"),
],
);
Then i need to pass the data to the table by using the source property which expects a DataTableSource object. I created a separate class which extends DataTableSource. I pass the filtered list as a parameter of this class and override the methods of the DataTableSource class:
class DataTableSourceExpedition extends DataTableSource {
List<Expedition> expeditions = List();
Function onRowClicked;
Function onDeleteIconClick;
final df = DateFormat('dd.MM.yyyy');
DataTableSourceExpedition({this.expeditions, this.onRowClicked,
this.onDeleteIconClick});
DataRow getRow(int index) {
final _expedition = expeditions[index];
return DataRow.byIndex(
index: index,
cells: <DataCell>[
DataCell(Text("${_expedition.expeditionId}")),
DataCell(IconButton(
icon: Icon(Icons.delete_forever, color: kReturnColor,),
onPressed: (){onDeleteIconClick(index);},
))
],
onSelectChanged: (b) => onRowClicked(index));
}
bool get isRowCountApproximate => false;
int get rowCount => expeditions.length;
int get selectedRowCount => 0;
}
Like this, i can get the only item filtered without the need of adding an empty row as you can see on the image below:
It works also if the list is empty.

Flutter - How can I add a circular loading indicator to my button?

I have a Flutter code. instead of showing nothing when the submit button is clicked, I want to show the circular loading indicator when the button is clicked so to keep the user busy but I'm having a challenge to convert a tutorial I have that does that to a work with my code.
Here is the tutorial:
...
children: <Widget>[
new Padding(
padding: const EdgeInsets.all(16.0),
child: new MaterialButton(
child: setUpButtonChild(),
onPressed: () {
setState(() {
if (_state == 0) {
animateButton();
}
});
},
elevation: 4.0,
minWidth: double.infinity,
height: 48.0,
color: Colors.lightGreen,
),
)
],
Widget setUpButtonChild() {
if (_state == 0) {
return new Text(
"Click Here",
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
),
);
} else if (_state == 1) {
return CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
);
} else {
return Icon(Icons.check, color: Colors.white);
}
}
void animateButton() {
setState(() {
_state = 1;
});
Timer(Duration(milliseconds: 1000), () {
setState(() {
_state = 2;
});
});
Timer(Duration(milliseconds: 3300), () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => AnchorsPage(),
),
);
});
}
Here's my code. All I want to do is to display the CircularProgressIndicator when the system is performing the HTTP request.
And here is my code where I want to use the CircularProgressIndicator:
Center(
child:
RaisedButton(
padding: EdgeInsets.fromLTRB(80, 10, 80, 10),
color: Colors.green,
child: setUpButtonChild(),
onPressed: () {
setState(()async {
_state = 1;
var toSubmit = {
"oid": EopOid,
"modifiedBy": user['UserName'].toString(),
"modifiedOn": DateTime.now().toString(),
"submitted": true,
"submittedOn": DateTime.now().toString(),
"submittedBy": user['UserName'].toString()
};
for (EopLine i in selectedEops) {
var item = {
"oid": i.oid.toString(),
"quantityCollected": i.quantityCollected,
"modifiedBy": user['UserName'].toString(),
"modifiedOn": DateTime.now().toString(),
};
await http
.put(
"http://api.ergagro.com:112/UpdateEopLine",
headers: {
'Content-Type': 'application/json'
},
body: jsonEncode(item))
.then((value) async {
if (selectedEops.indexOf(i) ==
selectedEops.length - 1) {
await http
.put(
"http://api.ergagro.com:112/SubmitEop",
headers: {
'Content-Type':
'application/json'
},
body: jsonEncode(toSubmit))
.then((value) {
print('${value.statusCode} submitted');
Navigator.pop(context);
});
}
});
}
_state = 2;
});
//Navigator.of(context).push(MaterialPageRoute(
//builder: (context) =>
//StartScanPage(widget.dc_result)));
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
),
),
If you're using a button with the icon() constructor (icon + text), you can swap the icon with the CircularProgressIndicator when the button state changes. It works because both the icon and the indicator are widgets:
return ElevatedButton.icon(
onPressed: _isLoading ? null : _onSubmit,
style: ElevatedButton.styleFrom(padding: const EdgeInsets.all(16.0)),
icon: _isLoading
? Container(
width: 24,
height: 24,
padding: const EdgeInsets.all(2.0),
child: const CircularProgressIndicator(
color: Colors.white,
strokeWidth: 3,
),
)
: const Icon(Icons.feedback),
label: const Text('SUBMIT'),
);
Live Demo
You can copy paste run full code below
You can directly use package https://pub.dev/packages/progress_indicator_button
or reference it's source code
You can pass AnimationController to http job and use controller.forward and reset
code snippet
void httpJob(AnimationController controller) async {
controller.forward();
print("delay start");
await Future.delayed(Duration(seconds: 3), () {});
print("delay stop");
controller.reset();
}
...
ProgressButton(
borderRadius: BorderRadius.all(Radius.circular(8)),
strokeWidth: 2,
child: Text(
"Sample",
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
onPressed: (AnimationController controller) async {
await httpJob(controller);
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:progress_indicator_button/progress_button.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void httpJob(AnimationController controller) async {
controller.forward();
print("delay start");
await Future.delayed(Duration(seconds: 3), () {});
print("delay stop");
controller.reset();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 200,
height: 60,
child: ProgressButton(
borderRadius: BorderRadius.all(Radius.circular(8)),
strokeWidth: 2,
child: Text(
"Sample",
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
onPressed: (AnimationController controller) async {
await httpJob(controller);
},
),
),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
You can also use ternary operator to output based on some _isLoading state variable and make use of CircularProgressIndicator(), of course this is a simple solution without using any third party libraries.
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: () {},
child: Container(
padding: const EdgeInsets.all(10),
child: _isLoading
? SizedBox(
height: 25,
width: 25,
child: CircularProgressIndicator(),
)
: Text('ORDER NOW'),
),
);
}