Related
I'm trying to write a shopping app. But unfortunately I stuck with loading and displaying the products from firebase with the help of the package provider.
In the app you can get from the searchPage to the ResultPage. In the ResultPage a GridView.builder should display the products whose category matches your entered searchtext from the SearchPage.
From the ResultPage you can also get to a FilterScreen where you can set filters. After you have left this screen you should only see the products on the result screen which matches your filters.
But this isn't working at all. Instead of seeing the filtered products there are no products displayed. But I get no error message. So I really stuck at this problem.
I don't even know where it's coming from.
I would be very thankful if anyone could help me!
This is my result page code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shs/providers/filters_provider.dart';
import 'package:shs/providers/products_provider.dart';
import 'package:shs/screens/filters_screen.dart';
import 'package:shs/widgets/bottom_navigation_bar.dart';
import 'package:shs/widgets/filter_overlay.dart';
import 'package:shs/widgets/my_scaffold.dart';
import 'package:shs/widgets/product_grid.dart';
import '../widgets/size_grid.dart';
import '../widgets/size_grid_buchstaben.dart';
class ResultPage extends StatefulWidget {
String searchtext;
String? gender;
ResultPage(
this.searchtext,
this.gender,
);
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
final searchController = TextEditingController();
#override
void initState() {
searchController.addListener(() => setState(() {}));
super.initState();
}
#override
Widget build(BuildContext context) {
return MyScaffold(
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 30,
),
Container(
height: 47,
margin: EdgeInsets.only(top: 30, left: 30, right: 30),
child: TextField(
onSubmitted: ((value) {
setState(() {
widget.searchtext = value;
});
}),
controller: searchController,
textInputAction: TextInputAction.search,
style: Theme.of(context).textTheme.bodyMedium,
decoration: InputDecoration(
fillColor: Colors.white,
suffixIcon: searchController.text.isEmpty
? Container(
width: 0,
)
: IconButton(
onPressed: () {
searchController.clear();
},
icon: Icon(
Icons.close_rounded,
color: Colors.black,
)),
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(15)),
prefixIcon: Container(
padding: const EdgeInsets.only(top: 5, left: 8),
child: Image.asset(
'lib/asset/icons/Search.png',
),
),
hintText: 'Search',
hintStyle: Theme.of(context).textTheme.bodyMedium,
),
),
),
SizedBox(
height: 30,
),
Padding(
padding: const EdgeInsets.only(right: 230),
child: Container(
width: 109,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Theme.of(context).colorScheme.primary,
),
child: GestureDetector(
onTap: () {
Navigator.of(context).pushNamed(FiltersScreen.routeName);
},
child: Row(
children: [
SizedBox(
width: 10,
),
Icon(Icons.filter_list_alt),
SizedBox(
width: 10,
),
Text(
'Filter',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(fontSize: 15),
)
],
),
)),
),
SizedBox(
height: 30,
),
Consumer<FilterProvider>(
builder: (context, filters, _) => ProductGrid(
filterColor: filters.filterMap['color']!,
filterZustand: filters.filterMap['state']!,
filtersize: filters.filterMap['size']!,
filterProdCat: widget.searchtext,
filterprice: filters.filteredPrice,
)), //Marke noch überall hnzufügen, wenn Filter eingefügt + searchtext zur filters.filterList hinzufügen und wie die anderen darauf referenzieeren, Suchfeld für alle Attribute verwendbar machen
SizedBox(
height: 30,
),
MyBottomNavigationBar(),
],
)),
);
}
}
This is my FilterProviderCode
import 'package:flutter/material.dart';
class FilterProvider with ChangeNotifier {
Map<String, List<String>> _filterMap = {'size': [], 'state': [], 'color': []};
double? filteredPrice;
var _expandedSize = false;
var _expandedPrice = false;
var _expandedState = false;
var _expandedColor = false;
var _expandedBrand = false;
bool _selected = false;
bool get selected {
return _selected;
}
bool _selectedSize = false;
bool _selectedState1 = false;
bool _selectedState2 = false;
bool _selectedState3 = false;
bool _selectedState4 = false;
bool _selectedState5 = false;
bool _selectedColor1 = false;
bool _selectedColor2 = false;
bool _selectedColor3 = false;
bool _selectedColor4 = false;
bool _selectedColor5 = false;
bool _selectedColor6 = false;
bool _selectedColor7 = false;
bool _selectedColor8 = false;
bool get selectedSize {
return _selectedSize;
}
Map<String, List<String>> get filterMap {
return _filterMap;
}
void setSelectedSize(bool variable) {
_selectedSize = variable;
}
void setSelectedState1(bool variable) {
_selectedState1 = variable;
}
void setSelectedState2(bool variable) {
_selectedState2 = variable;
}
void setSelectedState3(bool variable) {
_selectedState3 = variable;
}
void setSelectedState4(bool variable) {
_selectedState4 = variable;
}
void setSelectedState5(bool variable) {
_selectedState5 = variable;
}
void setSelectedColor1(bool variable) {
_selectedColor1 = variable;
}
void setSelectedColor2(bool variable) {
_selectedColor2 = variable;
}
void setSelectedColor3(bool variable) {
_selectedColor3 = variable;
}
void setSelectedColor4(bool variable) {
_selectedColor4 = variable;
}
void setSelectedColor5(bool variable) {
_selectedColor5 = variable;
}
void setSelectedColor6(bool variable) {
_selectedColor6 = variable;
}
void setSelectedColor7(bool variable) {
_selectedColor7 = variable;
}
void setSelectedColor8(bool variable) {
_selectedColor8 = variable;
}
bool get selectedState1 {
return _selectedState1;
}
bool get selectedState2 {
return _selectedState2;
}
bool get selectedState3 {
return _selectedState3;
}
bool get selectedState4 {
return _selectedState4;
}
bool get selectedState5 {
return _selectedState5;
}
bool get selectedColor1 {
return _selectedColor1;
}
bool get selectedColor2 {
return _selectedColor2;
}
bool get selectedColor3 {
return _selectedColor3;
}
bool get selectedColor4 {
return _selectedColor4;
}
bool get selectedColor5 {
return _selectedColor5;
}
bool get selectedColor6 {
return _selectedColor6;
}
bool get selectedColor7 {
return _selectedColor7;
}
bool get selectedColor8 {
return _selectedColor8;
}
bool get expandedSize {
return _expandedSize;
}
bool get expandedPrice {
return _expandedPrice;
}
bool get expandedState {
return _expandedState;
}
bool get expandedColor {
return _expandedColor;
}
bool get expandedBrand {
return _expandedBrand;
}
void expandSize() {
_expandedSize = !_expandedSize;
notifyListeners();
}
void expandPrice() {
_expandedPrice = !_expandedPrice;
notifyListeners();
}
void expandState() {
_expandedState = !_expandedState;
notifyListeners();
}
void expandColor() {
_expandedColor = !_expandedColor;
notifyListeners();
}
void expandBrand() {
_expandedBrand = !_expandedBrand;
notifyListeners();
}
void applyFilter(String key, String entry) {
_selected = !_selected;
if (_selected) {
_filterMap[key]!.add(entry);
}
if (_selected == false) {
_filterMap[key]!.removeWhere((element) => element == entry);
}
print(_filterMap);
notifyListeners();
}
void applyFilterUpdate(double entry) {
filteredPrice = entry;
notifyListeners();
print(filteredPrice);
}
}
This is my ProductProvider Code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:shs/models/product.dart';
class ProductProvider with ChangeNotifier {
final db = FirebaseFirestore.instance;
List<Product> _items = [];
List<Product> get items {
return [..._items];
}
/*Stream<QuerySnapshot> get stream {
return db
.collection('products')
.withConverter(
fromFirestore: Product.fromFirestore,
toFirestore: (Product product, _) => product.toFirestore(),
)
.snapshots();
}*/
Future<void> fetchProducts(
{required bool showAll,
List<dynamic>?
filtersize, //List ist halt manchmal leer wie bei allen anderen
double? filterprice,
List<dynamic>? filterZustand,
//required List<String>? filterMarke,
List<dynamic>? filterColor,
String? filterProdCat}) async {
List<Product> filteredProducts = [];
List<Product> allProducts = [];
List<String> allIDs = [];
final ref = db.collection('products').withConverter(
fromFirestore: Product.fromFirestore,
toFirestore: (Product product, _) => product.toFirestore(),
);
ref.snapshots().listen((event) {
List<String> products = [];
for (var doc in event.docs) {
products.add(doc.id);
allIDs = products;
}
});
allIDs.forEach((id) async {
final docSnap = await ref.doc(id).get();
final product = docSnap.data();
if (product != null) {
allProducts.add(product);
} else {
print('No such document.');
}
});
filteredProducts = allProducts.where((product) {
return filtersize!.contains(product
.size) || //Liste ist halt manchmal leer, also nur wahr wenn auch wirklich Filter gesetzt sind
product.price == filterprice ||
filterZustand!.contains(product.zustand) ||
//filterMarke.contains(product.marke) ||
filterColor!.contains(product.color) ||
product.prodCat == filterProdCat;
}).toList(); // nur wenn filtern erwünscht alle Filter Lists angeben, auch wenn sie leer sind sonst null
if (showAll) {
_items = allProducts;
} else {
_items = filteredProducts;
}
//notifyListeners();
}
}
This is my FiltersScreen Code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shs/providers/filters_provider.dart';
import 'package:shs/widgets/filter_color.dart';
import 'package:shs/widgets/filter_state.dart';
import 'package:shs/widgets/marked_text.dart';
import 'package:shs/widgets/size_grid.dart';
import 'package:shs/widgets/size_grid_buchstaben.dart';
import 'package:shs/widgets/size_grid_hosen.dart';
import 'package:shs/widgets/size_grid_shoes.dart';
class FiltersScreen extends StatefulWidget {
static const routeName = '/filters';
#override
State<FiltersScreen> createState() => _FiltersScreenState();
}
class _FiltersScreenState extends State<FiltersScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
leading: IconButton(
icon: Icon(
Icons.close,
size: 50,
),
onPressed: () {
Navigator.of(context).pop();
},
),
backgroundColor: Theme.of(context).colorScheme.primary,
actions: [
GestureDetector(
onTap: () {}, // Navigate to AccountPage
child: Container(
child: Image.asset('lib/asset/icons/Account.png'),
),
),
SizedBox(
width: 7,
),
GestureDetector(
onTap: () {}, // Navigate to ShoppingBag
child: Container(
child: Image.asset('lib/asset/icons/ShoppingBag.png'),
),
),
GestureDetector(
onTap: () {}, // Navigate to Favorite
child: Container(
child: Image.asset('lib/asset/icons/Favorite.png'),
),
),
SizedBox(
width: 7,
),
],
),
body: Consumer<FilterProvider>(
builder: (context, filters, _) => SingleChildScrollView(
child: Column(children: [
SizedBox(
height: 30,
),
Center(
child: MarkedText(
'Filters',
() {},
Theme.of(context).colorScheme.primary,
fontsize: 80,
),
),
SizedBox(
height: 30,
),
ListTile(
title: Text(
'Size',
style: Theme.of(context)
.textTheme
.displayMedium!
.copyWith(fontSize: 50),
),
trailing: IconButton(
onPressed: () {
filters.expandSize();
},
icon: Icon(
filters.expandedSize
? Icons.expand_less
: Icons.expand_more,
size: 50,
color: Colors.black)),
),
if (filters.expandedSize)
Container(
height: 1800,
child: Column(
children: [
SizedBox(
height: 30,
),
SizedBox(
height: 300,
child: Container(
width: 300, height: 500, child: SizeGrid())),
SizedBox(
height: 30,
),
SizedBox(
height: 230,
child:
Container(width: 300, child: SizeGridBuchstaben())),
SizedBox(
height: 30,
),
SizedBox(
height: 450,
child: Container(width: 300, child: SizeGridHosen())),
SizedBox(
height: 30,
),
Text(
'Size Shoes',
style: Theme.of(context)
.textTheme
.displayMedium!
.copyWith(fontSize: 50),
),
SizedBox(
height: 30,
),
SizedBox(
height: 530,
child: Container(width: 300, child: SizeGridShoes())),
SizedBox(
height: 30,
),
],
),
),
ListTile(
title: Text(
'Price',
style: Theme.of(context)
.textTheme
.displayMedium!
.copyWith(fontSize: 50),
),
trailing: IconButton(
onPressed: () {
filters.expandPrice();
},
icon: Icon(
filters.expandedPrice
? Icons.expand_less
: Icons.expand_more,
size: 50,
color: Colors.black)),
),
if (filters.expandedPrice)
Container(
child: Row(children: [
SizedBox(
width: 20,
),
Text(
'bis',
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(fontSize: 32),
),
SizedBox(
width: 30,
),
Container(
width: 150,
height: 40,
child: TextField(
keyboardType: TextInputType.number,
onSubmitted: ((value) {
final doubleValue = double.parse(value);
filters.applyFilterUpdate(doubleValue);
}),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15)),
hintText: '\$',
hintStyle: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(fontSize: 24)),
)),
]),
),
ListTile(
title: Text(
'State',
style: Theme.of(context)
.textTheme
.displayMedium!
.copyWith(fontSize: 50),
),
trailing: IconButton(
onPressed: () {
filters.expandState();
},
icon: Icon(
filters.expandedState
? Icons.expand_less
: Icons.expand_more,
size: 50,
color: Colors.black)),
),
if (filters.expandedState) FiltersState(),
ListTile(
title: Text(
'Color',
style: Theme.of(context)
.textTheme
.displayMedium!
.copyWith(fontSize: 50),
),
trailing: IconButton(
onPressed: () {
filters.expandColor();
},
icon: Icon(
filters.expandedColor
? Icons.expand_less
: Icons.expand_more,
size: 50,
color: Colors.black)),
),
if (filters.expandedColor) FilterColor(),
ListTile(
title: Text(
'Brand',
style: Theme.of(context)
.textTheme
.displayMedium!
.copyWith(fontSize: 50),
),
trailing: IconButton(
onPressed: () {
filters.expandBrand();
},
icon: Icon(
filters.expandedBrand
? Icons.expand_less
: Icons.expand_more,
size: 50,
color: Colors.black)),
), //Marken aufzählen List Tile von Zustand verwenden
SizedBox(
height: 30,
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop(); //Filter anwenden
},
child: Text('Apply Filters!')),
]),
),
),
);
}
}
This is my Product Grid Code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shs/providers/products_provider.dart';
import 'product_card.dart';
class ProductGrid extends StatelessWidget {
ScrollController scrollController = ScrollController();
List<String> filtersize;
List<String> filterColor;
String? filterProdCat;
List<String> filterZustand;
double? filterprice;
ProductGrid(
{required this.filterColor,
this.filterProdCat,
required this.filterZustand,
this.filterprice,
required this.filtersize});
Future<void> updateProducts(
{required BuildContext context,
required List<String> filtersize,
required List<String> filterColor,
//required List<String> filterMarke,
String? filterProdCat,
required List<String> filterZustand,
double? filterprice}) async {
await Provider.of<ProductProvider>(
context,
listen: false,
).fetchProducts(
showAll: false,
filtersize: filtersize,
filterColor: filterColor,
//filterMarke: filterMarke,
filterProdCat: filterProdCat,
filterZustand: filterZustand,
filterprice: filterprice);
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: updateProducts(
context: context,
filtersize: filtersize,
filterColor: filterColor,
filterZustand: filterZustand),
builder: ((context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
return Consumer<ProductProvider>(
builder: (ctx, products, _) => GridView.builder(
controller: scrollController,
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: products.items.length,
itemBuilder: ((context, index) => ProductCard(
state: products.items[index].zustand!,
imageUrl: products.items[index].imageUrl,
price: products.items[index].price,
size: products.items[index].size!,
id: products.items[index].id,
prodCat: products.items[index].prodCat,
marke: products.items[index].marke)),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10,
mainAxisExtent: 400)));
}));
}
}
And here is my dummy product data from firestore
enter image description here
If you need more code or anything else, no problem I will post it!
I'm new to Flutter so my code is a bit messy, I have to admit...
THANK YOU FOR YOUR HELP!
I have been trying to fix this bug without success. I am trying to make a Gridview.builder widget that will hold the buttons for a calculator. I want the widget to fit on the lower part of the screen without overflowing. I tried to fix it by wrapping a Gridview into a Contianer or a ConstrainedBox with a certain height and width. However, the Gridview still keeps overflowing.
Here is my code for the Gridview:
Expanded(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: ScreenHeight(context) * .3,
maxHeight: ScreenHeight(context) * .4,
),
child: Container(
margin: EdgeInsets.only(
right: ScreenHeight(context) * .02,
left: ScreenHeight(context) * .02),
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: buttons.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: getCrossAxisCount(context)),
itemBuilder: (BuildContext context, int index) {
// Clear Button
if (index == 0) {
return CalcButton(
onTap: () {
setState(() {
userInput = '';
calcAnswer = '';
});
},
buttonText: buttons[index],
color: Colors.blue[50],
textColor: Colors.black,
);
}
// +/- button
else if (index == 1) {
return CalcButton(
buttonText: buttons[index],
color: Colors.blue[50],
textColor: Colors.black,
);
}
// % Button
else if (index == 2) {
return CalcButton(
onTap: () {
setState(() {
userInput += buttons[index];
});
},
buttonText: buttons[index],
color: Colors.blue[50],
textColor: Colors.black,
);
}
// Delete Button
else if (index == 3) {
return CalcButton(
onTap: () {
setState(() {
userInput = userInput.substring(
0, userInput.length - 1);
});
},
buttonText: buttons[index],
color: Colors.blue[50],
textColor: Colors.black,
);
}
// Equal_to Button
else if (index == 18) {
return CalcButton(
onTap: () {
setState(() {
equalPressed();
});
},
buttonText: buttons[index],
color: Colors.orange[700],
textColor: Colors.white,
);
}
// other buttons
else {
return CalcButton(
onTap: () {
setState(() {
userInput += buttons[index];
});
},
buttonText: buttons[index],
color: isOperator(buttons[index])
? Colors.blueAccent
: Colors.white,
textColor: isOperator(buttons[index])
? Colors.white
: Colors.black,
);
}
},
),
),
),
),
Here is my code for CalcButton:
class CalcButton extends StatelessWidget {
final color;
final textColor;
final String buttonText;
final onTap;
CalcButton({
this.color,
this.textColor,
this.buttonText = "",
this.onTap,
});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Padding(
padding: EdgeInsets.all(.3),
child: ClipRRect(
child: Container(
color: getCalcButtonColor(calcTheme,
buttonText), //gets calc button color from created method
child: Center(
child: Text(
buttonText,
style: TextStyle(
color: getButtonTxtColor(calcTheme,
buttonText), //gets button txt color from created method
fontSize: ScreenWidth(context) * .05,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
);
}
}
Here is how it looks:
Image 1
Image 2
Note that the ScreenHeight() and ScreenWidth() functions are functions that return the value of MediaQuery.of(context).size.width and MediaQuery.of(context).size.height
I have also tried to remove Expanded() and only use a ConstrainedBox, but the same thing still happens.
Any help will be much appreciated.
I have a screen which shows list of customers using listview. Next when I click on a customer I want to show the notes(records) only of that particular customer(customerId) in next screen in listview. I know how to display all the records of table. but how to display only certain records?? Neither there is any error nor the listview is being displayed. I dont know where am I going wrong.
List<CustomerNote> cnoteList;
int count = 0;
if (cnoteList == null) {
cnoteList = List<CustomerNote>();
updateCustomerNotes();
}
db_service.dart
Future<List<CustomerNote>> getCustomerNotes(int customer) async {
await DB.init();
var res = await DB.rawQuery("noteDetails WHERE custId = '$customer'");
int count = res.length;
List<CustomerNote> cnotelist = List<CustomerNote>();
for (int i = 0; i < count; i++) {
cnotelist.add(CustomerNote.fromMap(res[i]));
}
return cnotelist;
}
People_List.dart //this is the file which displays list of customers
import 'package:customer/models/Note.dart';
import 'package:customer/models/addCustomer.dart';
import 'package:customer/screens/New_Note.dart';
import 'package:customer/screens/Note_info.dart';
import 'package:customer/screens/User_Settings.dart';
import 'package:customer/screens/add_person.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/database_helper.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
class People_List extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return People_ListState();
}
}
class People_ListState extends State<People_List> with SingleTickerProviderStateMixin{
DBService dbService = DBService();
List<AddCustomer> customerList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
var _isSelectedItemIndex;
TextEditingController _searchQuery;
bool _isSearching = false;
String searchQuery = "Search query";
#override
void initState() {
super.initState();
_searchQuery = new TextEditingController();
}
void _startSearch() {
print("open search box");
ModalRoute
.of(context)
.addLocalHistoryEntry(new LocalHistoryEntry(onRemove: _stopSearching));
setState(() {
_isSearching = true;
});
}
void _stopSearching() {
_clearSearchQuery();
setState(() {
_isSearching = false;
});
}
void _clearSearchQuery() {
print("close search box");
setState(() {
_searchQuery.clear();
updateSearchQuery("Search query");
});
}
Widget _buildTitle(BuildContext context) {
var horizontalTitleAlignment =
Platform.isIOS ? CrossAxisAlignment.center : CrossAxisAlignment.start;
return new InkWell(
onTap: () => scaffoldKey.currentState.openDrawer(),
child: new Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: horizontalTitleAlignment,
children: <Widget>[
const Text(''),
],
),
),
);
}
Widget _buildSearchField() {
return new TextField(
controller: _searchQuery,
autofocus: true,
decoration: const InputDecoration(
hintText: 'Search...',
border: InputBorder.none,
hintStyle: const TextStyle(color: Colors.white30),
),
style: const TextStyle(color: Colors.white, fontSize: 16.0),
onChanged: updateSearchQuery,
);
}
void updateSearchQuery(String newQuery) {
setState(() {
searchQuery = newQuery;
});
print("search query " + newQuery);
}
List<Widget> _buildActions() {
if (_isSearching) {
return <Widget>[
new IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (_searchQuery == null || _searchQuery.text.isEmpty) {
Navigator.pop(context);
return;
}
_clearSearchQuery();
},
),
];
}
return <Widget>[
new IconButton(
icon: const Icon(Icons.search),
onPressed: _startSearch,
),
];
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
if (customerList == null) {
customerList = List<AddCustomer>();
updateListView();
}
return Scaffold(
appBar: new AppBar(
leading: _isSearching ? const BackButton() : null,
title: _isSearching ? _buildSearchField() : _buildTitle(context),
actions: _buildActions(),
),
body:getCustomerListView(),
floatingActionButton: FloatingActionButton(
onPressed: () {
navigateToCustomer(AddCustomer(), 'Add Person');
},
child: const Icon(Icons.add),
),
bottomNavigationBar:Row (
children: <Widget>[
buildNavBarItem(Icons.home,0,"Home"),
buildNavBarItem(Icons.fiber_new_rounded,1,"Upcoming"),
buildNavBarItem(Icons.history,2,"History"),
buildNavBarItem(Icons.account_circle,3,"Account"),
],
),
);
}
ListView getCustomerListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
/*trailing: CircleAvatar(
backgroundColor: getPriorityColor(this.noteList[position].priority),
child: getPriorityIcon(this.noteList[position].priority),
),*/
title: Text(this.customerList[position].custName, style: titleStyle,),
//subtitle: Text(this.customerList[position].date),
onTap: () {
},
),
);
},
);
}
void navigateToCustomer(AddCustomer customer, String title) async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return AddPerson(customer, title);
}));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
Future<List<AddCustomer>> customerListFuture = dbService.getCustomerList();
customerListFuture.then((customerList) {
setState(() {
this.customerList = customerList;
this.count = customerList.length;
});
});
});
}
Widget buildNavBarItem(IconData icon,int index,title) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return GestureDetector(
onTap: () {
setState(() {
_isSelectedItemIndex=index;
if(_isSelectedItemIndex==3) {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => User_Settings()));
}
});
},
child: Container(
height: height * 0.09,
width: width / 4,
decoration: index==_isSelectedItemIndex?BoxDecoration(
border: Border(
bottom: BorderSide(width: 4,color: Theme.of(context).primaryColor),
),
gradient: LinearGradient(colors: [
Theme.of(context).primaryColor.withOpacity(0.3),
Theme.of(context).primaryColor.withOpacity(0.015),
],begin: Alignment.bottomCenter,end: Alignment.topCenter)
):BoxDecoration(),
child: Column(
children: <Widget>[
InkWell(
child: Icon(icon,
color: index==_isSelectedItemIndex? Theme.of(context).primaryColor:Colors.black54,
),
),
Text(title)
],)),
);
}
}
Note_Info.dart
class Note_Info extends StatefulWidget{
final String appBarTitle;
final AddCustomer customer;
Note_Info(this. customer, this.appBarTitle);
#override
State<StatefulWidget> createState() {
return Note_InfoState(this.customer,this.appBarTitle);
}
}
class Note_InfoState extends State<Note_Info> {
CustomerNote note=CustomerNote();
DBService dbService = DBService();
List<CustomerNote> cnoteList;
int count = 0;
String appBarTitle;
AddCustomer customer;
Note_InfoState(this.customer, this.appBarTitle);
PickedFile _imageFile;
final ImagePicker _picker = ImagePicker();
bool rememberMe = false;
DateTime _date = DateTime.now();
TextEditingController custNameController = TextEditingController();
void getImage(ImageSource source) async {
final pickedFile = await _picker.getImage(
source: source);
setState(() {
_imageFile = pickedFile;
});
}
#override
Widget build(BuildContext context) {
if (noteList == null) {
noteList = List<CustomerNote>();
updateCustomerNotes();
}
var height = MediaQuery.of(context).size.height;
custNameController.text = customer.custName;
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(
Icons.add,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => NewNote()));
},
)
],
),
body: Container(
child: Column(
children: <Widget>[
TextField(controller: custNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(children: [
ImageProfile(),
Padding(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
icon: Icon(
Icons.call,
color: Colors.green,
size: 45,
),
onPressed: () {
},
),
),
],),
),
SizedBox(
height: 50,
child: AppBar(
bottom: TabBar(
tabs: [
Tab(
text: "All",
),
Tab(
text: "Pending",
),
Tab(
text: "Cancelled",
),
Tab(
text: "Completed",
),
],
),
),
),
// create widgets for each tab bar here
Expanded(
child: TabBarView(
children: [
// first tab bar view widget
Container(
child: getNoteListView(),
),
// second tab bar view widget
Container(
child: Center(
child: Text(
'Pending Items',
),
),
),
Container(
child: Center(
child: Text(
'Cancelled',
),
),
),
Container(
child: Center(
child: Text(
'Completed',
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme
.of(context)
.primaryColorDark,
textColor: Colors.white,
child: Text('Save', textScaleFactor: 1.5,),
onPressed: () {
setState(() {
//_reset();
});
},
),
),
),
]
),
)
));
}
void updateCustomerNotes() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
int customerId=customer.custId;
Future<List<CustomerNote>> noteListFuture = dbService.getCustomerNotes(customerId);
noteListFuture.then((cnoteList) {
setState(() {
this.cnoteList = cnoteList;
//this.count = cnoteList.length;
});
});
});
}
ListView getNoteListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
title: Text(this.cnoteList[position].note, style: titleStyle,),
subtitle: Text(this.cnoteList[position].date),
trailing: GestureDetector(
child: Icon(Icons.delete, color: Colors.grey,),
onTap: () {
},
),
onTap: () {
},
),
);
},
);
}
void _showSnackBar(BuildContext context, String message) {
final snackBar = SnackBar(content: Text(message));
Scaffold.of(context).showSnackBar(snackBar);
}
Widget ImageProfile() {
return Center(
child: CircleAvatar(
radius: 80.0,
backgroundImage: AssetImage('images/person_icon.jpg')
),
);
}
}
If u want to get some specific data from the server then you need to provide (where: ) in your query such as
List<Map> result = await db.query(
DatabaseHelper.table,
columns: columnsToSelect,
where: whereString,
whereArgs: whereArguments);
// print the results
result.forEach((row) => print(row));
// {_id: 1, name: Bob, age: 23}
}
Note your query can be different from the above one.
and if you want to get the same specific data from already fetched data then also you need to use the where clause such as
final outData = responseData.where((i) => i.userId == customerId).toList();
and then pass the outData to next page through params.
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'dart:ui' as ui;
class EditImage extends StatefulWidget {
final String filePath;
EditImage({this.filePath});
#override
_EditImageState createState() => _EditImageState();
}
class _EditImageState extends State<EditImage> {
ui.Image decodedImage;
String newFilePath;
GlobalKey myCanvasKey = GlobalKey();
ImageEditor editor;
Color color = Colors.blue;
#override
void initState() {
loadImage(File(widget.filePath));
super.initState();
}
void loadImage(File image) async {
final data = await image.readAsBytes();
decodedImage = await decodeImageFromList(data);
editor = ImageEditor(image: decodedImage, strokeColor: color);
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: InkWell(
onTap: () {
Navigator.pop(context, newFilePath ?? widget.filePath);
},
child: Icon(Icons.close),
),
//centerTitle: true,
title: Text('Edit'),
actions: [
InkWell(
onTap: () {
editor.undo();
myCanvasKey.currentContext.findRenderObject().markNeedsPaint();
},
child: Icon(Icons.undo),
),
SizedBox(
width: 10.0,
),
InkWell(
onTap: () async {
Color pickedColor;
bool isSelected = false;
await showDialog(
context: context,
child: AlertDialog(
contentPadding: const EdgeInsets.all(8.0),
title: const Text('Stroke Color'),
content: SingleChildScrollView(
child: ColorPicker(
pickerColor: color,
onColorChanged: (color) {
pickedColor = color;
},
enableAlpha: false,
showLabel: false,
pickerAreaHeightPercent: 0.6,
),
),
actions: <Widget>[
FlatButton(
child: const Text('Cancel'),
onPressed: () => Navigator.pop(context),
),
FlatButton(
child: const Text('Select'),
onPressed: () {
isSelected = true;
Navigator.of(context).pop();
},
),
],
),
);
if (isSelected) {
editor.updateStrokeColor(pickedColor);
setState(() {
color = pickedColor;
});
}
},
child: Container(
decoration: BoxDecoration(
//borderRadius: BorderRadius.circular(15.0),
border: Border.all(color: Colors.grey),
shape: BoxShape.circle,
color: color,
),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
decoration: BoxDecoration(
color: Colors.black26, shape: BoxShape.circle),
child: Padding(
padding: const EdgeInsets.all(3.0),
child: Icon(
Icons.edit_outlined,
color: Colors.white,
semanticLabel: 'Stroke',
),
),
),
),
),
),
SizedBox(
width: 10.0,
),
InkWell(
onTap: () {
Navigator.pop(context, newFilePath ?? widget.filePath);
},
child: Icon(Icons.done),
),
SizedBox(
width: 10.0,
),
],
),
body: decodedImage == null
? Center(child: CircularProgressIndicator())
: Center(
child: FittedBox(
child: SizedBox(
height: decodedImage.height.toDouble(),
width: decodedImage.width.toDouble(),
child: GestureDetector(
onPanDown: (detailData) {
editor.update(detailData.localPosition);
myCanvasKey.currentContext
.findRenderObject()
.markNeedsPaint();
},
onPanUpdate: (detailData) {
editor.update(detailData.localPosition);
myCanvasKey.currentContext
.findRenderObject()
.markNeedsPaint();
},
onPanEnd: (detailData) {
editor.addNewPointsList();
},
child: CustomPaint(
key: myCanvasKey,
painter: editor,
),
),
),
),
),
);
}
}
class ImageEditor extends CustomPainter {
ImageEditor({
this.image,
this.strokeColor = Colors.black,
}) {
_strokes.add(_StrokeData());
}
final ui.Image image;
Color strokeColor;
List<_StrokeData> _strokes = [];
void updateStrokeColor(Color color) {
strokeColor = color;
}
void update(Offset offset) {
if (_strokes.last.color == null) _strokes.last.color = strokeColor;
_strokes.last.points.add(offset);
}
void addNewPointsList() {
print('pan end');
_strokes.add(_StrokeData());
}
void undo() {
if (_strokes.length > 1) _strokes.removeAt(_strokes.length - 2);
}
#override
void paint(Canvas canvas, Size size) {
canvas.drawImage(image, Offset.zero, Paint());
for (int i = 0; i < _strokes.length; i++) {
Paint _painter = Paint();
_painter.color = _strokes[i].color ?? Colors.transparent;
_painter.style = PaintingStyle.stroke;
_painter.strokeWidth = 15;
_painter.isAntiAlias = true;
for (int j = 0; j < _strokes[i].points.length; j++) {
if (j > 0)
canvas.drawLine(
_strokes[i].points[j - 1], _strokes[i].points[j], _painter);
}
}
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
class _StrokeData {
Color color;
List<Offset> points;
_StrokeData() {
points = List<Offset>();
}
}
How to restrict drawing within the image area ?
Use ClipRRect() as parent of FittedBox. This solves the problem
ClipRRect(child: FittedBox(child: SizedBox(...Painter widget goes here...) ))
I have 2 screens and I am trying to achieve understand how to achieve page state. For example, in the below screen, I have 4 options, and all of them take the user to the same screen the only difference is API getting called for each of them is different to build a list. I am trying to handle back arrow action, and that's where I am having issues.
Use Case -
When user is on screen 2 he is playing the song, now on back press song continues to play. Now when the user again chooses the same option from screen 1 I want to show the same list without reload and selection. If user selects any other option it should behave normal, which is working.
Solution -
I can hardcode loaded songs list and send back to screen 1 and then again get that back with the selection but this will take lot of resources.
AutomaticKeepAliveClientMixin i tried this tutorial but that didn't help or kept state active.
PageStorage is 3rd option i saw but i found majority of the time this is being used on app where we have a tab.
Screen 1 -
class Dashboard extends StatefulWidget {
int playingId;
Dashboard({this.playingId});
#override
_DashboardState createState() => _DashboardState(playingId);
}
class _DashboardState extends State<Dashboard> {
String appname;
int playingId = 0;
_DashboardState(this.playingId);
// print('${playingId}');
#override
void initState() {
appname="";
// playingId=0;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: AppColors.darkBlue,
centerTitle: true,
title: Text("Tirthankar",
style: TextStyle(color: Colors.white),),
),
backgroundColor: AppColors.styleColor,
body: Column(
children: <Widget>[
// SizedBox(height: 5),
Padding(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomGridWidget(
child: Icon(
Icons.file_download,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/bhaktambar.png',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Bhakti",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Kids",playingId: playingId,),
),
);
},
),
CustomGridWidget(
child: Icon(
Icons.file_download,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/bhaktambar.png',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Kids",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Kids",playingId: playingId,),
),
);
},
),
],
),
),
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomGridWidget(
child: Icon(
Icons.favorite,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/kids.jpg',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Favorite",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Songs"),
),
);
},
),
Align(
alignment: Alignment.center,
child: CustomGridWidget(
child: Icon(
Icons.book,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/vidyasagar.jpg',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Bhajan"),
),
);
},
),
),
],
),
),
]
),
);
}
Material boxTiles(IconData icon, String name){
return Material(
color: AppColors.mainColor,
elevation: 14.0,
shadowColor: AppColors.styleColor,
borderRadius: BorderRadius.circular(24.0),
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: (){print("tapped"); /* or any action you want */ },
child: Container(
width: 130.0,
height: 10.0,
color : Colors.transparent,
), // container
), //
//Text
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(name,
style:TextStyle(
color: AppColors.styleColor,
fontSize: 20.0,
)
),
),
//Icon
Material(
color: AppColors.styleColor,
borderRadius: BorderRadius.circular(50.0),
child: Padding(padding: const EdgeInsets.all(10.0),
child: Icon(icon, color: AppColors.lightBlue,size: 30,),
),
),
],
)
],
)
),
)
);
}
}
Screen 2 -
// import 'dart:js';
class ListPage extends StatefulWidget {
String appname;
int playingId;
ListPage({this.appname,this.playingId});
#override
_ListPageState createState() => _ListPageState(appname,playingId);
}
class _ListPageState extends State<ListPage>
with SingleTickerProviderStateMixin,AutomaticKeepAliveClientMixin<ListPage> {
String appname;
int playingId;
bool isPlaying = false;
_ListPageState(this.appname,playingId);
// List<MusicModel> _list1;
List<MusicData> _list;
var _value;
int _playId;
int _songId;
String _playURL;
bool _isRepeat;
bool _isShuffle;
bool _isFavorite;
String _startTime;
String _endTime;
AnimationController _controller;
Duration _duration = new Duration();
Duration _position = new Duration();
final _random = new Random();
AudioPlayer _audioPlayer = AudioPlayer();
#override
void initState() {
_playId = 0;
// _list1 = MusicModel.list;
this._fileUpdate();
// _list = _list1;
_controller =
AnimationController(vsync: this, duration: Duration(microseconds: 250));
_value = 0.0;
_startTime = "0.0";
_endTime = "0.0";
_isRepeat = false;
_isShuffle = false;
_isFavorite = false;
_audioPlayer.onAudioPositionChanged.listen((Duration duration) {
setState(() {
// _startTime = duration.toString().split(".")[0];
_startTime = duration.toString().split(".")[0];
_duration = duration;
// _position = duration.toString().split(".")[0];
});
});
_audioPlayer.onDurationChanged.listen((Duration duration) {
setState(() {
_endTime = duration.toString().split(".")[0];
_position = duration;
});
});
_audioPlayer.onPlayerCompletion.listen((event) {
setState(() {
isPlaying = false;
_position = _duration;
if (_isRepeat) {
_songId = _songId;
} else {
if (_isShuffle) {
var element = _list[_random.nextInt(_list.length)];
_songId = element.id;
} else {
_songId = _songId + 1;
}
}
_player(_songId);
});
});
super.initState();
}
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: AppColors.mainColor,
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Dashboard(playingId: _songId),
),
);
},
),
title: Text(
appname,
style: TextStyle(color: AppColors.styleColor),
),
),
backgroundColor: AppColors.mainColor,
body: Stack(
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(24.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomButtonWidget(
child: Icon(
Icons.favorite,
color: AppColors.styleColor,
),
size: 50,
onTap: () {},
),
CustomButtonWidget(
image: 'assets/logo.jpg',
size: 100,
borderWidth: 5,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => DetailPage(),
),
);
},
),
CustomButtonWidget(
child: Icon(
Icons.menu,
color: AppColors.styleColor,
),
size: 50,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => HomePage(),
),
);
},
)
],
),
),
slider(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(
_isRepeat ? Icons.repeat_one : Icons.repeat,
color: _isRepeat ? Colors.brown : AppColors.styleColor,
),
onPressed: () {
if (_isRepeat) {
_isRepeat = false;
} else {
_isRepeat = true;
}
},
),
IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
color: AppColors.styleColor,
),
onPressed: () {
if (isPlaying) {
_audioPlayer.pause();
setState(() {
isPlaying = false;
});
} else {
if (!isPlaying){
_audioPlayer.resume();
setState(() {
isPlaying = true;
});
}
}
}),
IconButton(
icon: Icon(
Icons.stop,
color: AppColors.styleColor,
),
onPressed: () {
if (isPlaying){
_audioPlayer.stop();
setState(() {
isPlaying = false;
_duration = new Duration();
});
}
// isPlaying = false;
}),
IconButton(
icon: Icon(
Icons.shuffle,
color:
_isShuffle ? Colors.brown : AppColors.styleColor,
),
onPressed: () {
if (_isShuffle) {
_isShuffle = false;
} else {
_isShuffle = true;
}
}),
],
),
),
Expanded(
//This is added so we can see overlay else this will be over button
child: ListView.builder(
physics:
BouncingScrollPhysics(), //This line removes the dark flash when you are at the begining or end of list menu. Just uncomment for
// itemCount: _list.length,
itemCount: _list == null ? 0 : _list.length,
padding: EdgeInsets.all(12),
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
_songId = index;
_player(index);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
//This below code will change the color of sected area or song being played.
decoration: BoxDecoration(
color: _list[index].id == _playId
? AppColors.activeColor
: AppColors.mainColor,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
//End of row color change
child: Padding(
padding: const EdgeInsets.all(
16), //This will all padding around all size
child: Row(
mainAxisAlignment: MainAxisAlignment
.spaceBetween, //This will allign button to left, else button will be infront of name
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_list[index].title,
style: TextStyle(
color: AppColors.styleColor,
fontSize: 16,
),
),
Text(
_list[index].album,
style: TextStyle(
color: AppColors.styleColor.withAlpha(90),
fontSize: 16,
),
),
],
),
IconButton(
icon: Icon(_isFavorite
? Icons.favorite
: Icons.favorite_border),
onPressed: () {
if (_isFavorite) {
_isFavorite = false;
} else {
_isFavorite = true;
}
})
//Diabled Play button and added fav button.
// CustomButtonWidget(
// //This is Play button functionality on list page.
// child: Icon(
// _list[index].id == _playId
// ? Icons.pause
// : Icons.play_arrow,
// color: _list[index].id == _playId
// ? Colors.white
// : AppColors.styleColor,
// ),
// size: 50,
// isActive: _list[index].id == _playId,
// onTap: () async {
// _songId = index;
// _player(index);
// },
// )
],
),
),
),
);
},
),
)
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 50,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.mainColor.withAlpha(0),
AppColors.mainColor,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)),
),
)
],
),
// floatingActionButton: FloatingActionButton(
// child: Icon(Icons.music_note),
// onPressed: () async { // String filePath = await FilePicker.getFilePath();
// int status = await _audioPlayer.play("https://traffic.libsyn.com/voicebot/Jan_Konig_on_the_Jovo_Open_Source_Framework_for_Voice_App_Development_-_Voicebot_Podcast_Ep_56.mp3");
// if (status == 1){
// setState(() {
// isPlaying = true;
// });
// }
// },
// )
);
}
Widget slider() {
return Slider(
activeColor: AppColors.styleColor,
inactiveColor: Colors.lightBlue,
value: _duration.inSeconds.toDouble(),
min: 0.0,
max: _position.inSeconds.toDouble(),
divisions: 10,
onChangeStart: (double value) {
print('Start value is ' + value.toString());
},
onChangeEnd: (double value) {
print('Finish value is ' + value.toString());
},
onChanged: (double value) {
setState(() {
seekToSecond(value.toInt());
value = value;
});
});
}
Future<Void> _fileUpdate() async {
String url =
"azonaws.com/input.json";
String arrayObjsText = "";
try {
eos.Response response;
Dio dio = new Dio();
response = await dio.get(url,options: Options(
responseType: ResponseType.plain,
),);
arrayObjsText = response.data;
print(response.data.toString());
} catch (e) {
print(e);
}
var tagObjsJson = jsonDecode(arrayObjsText)['tags'] as List;
this.setState(() {
_list = tagObjsJson.map((tagJson) => MusicData.fromJson(tagJson)).toList();
});
// return _list;
// print(_list);
}
Future<void> _player(int index) async {
if (isPlaying) {
if (_playId == _list[index].id) {
int status = await _audioPlayer.pause();
if (status == 1) {
setState(() {
isPlaying = false;
});
}
} else {
_playId = _list[index].id;
_playURL = _list[index].songURL;
_audioPlayer.stop();
int status = await _audioPlayer.play(_playURL);
if (status == 1) {
setState(() {
isPlaying = true;
});
}
}
} else {
_playId = _list[index].id;
_playURL = _list[index].songURL;
int status = await _audioPlayer.play(_playURL);
if (status == 1) {
setState(() {
isPlaying = true;
});
}
}
}
String _printDuration(Duration duration) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
void seekToSecond(int second) {
Duration newDuration = Duration(seconds: second);
_audioPlayer.seek(newDuration);
}
}
PageStorage is 3rd option i saw but i found majority of the time this is being used on app where we have a tab.
You still can use this approach with what you want, with or without Tab/ bottom navigation bar.
PageViewClass
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with SingleTickerProviderStateMixin{
PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
void dispose() {
super.dispose();
_pageController?.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(), // so the user cannot scroll, only animating when they select an option
children: <Widget>[
Dashboard(playingId: 1, key: PageStorageKey<String>('MyPlayList'), pageController: _pageController), //or the name you want, but you need to give them a key to all the child so it can save the Scroll Position
ListPage(appname: "FirstButton",playingId: 1, key: PageStorageKey<String>('FirstButton'), pageController: _pageController),
ListPage(appname: "SecondButton",playingId: 1, key: PageStorageKey<String>('SecondButton'), pageController: _pageController),
ListPage(appname: "ThirdButton",playingId: 1, key: PageStorageKey<String>('ThirdButton'), pageController: _pageController),
ListPage(appname: "FourthButton",playingId: 1, key: PageStorageKey<String>('FourthButton'), pageController: _pageController)
],
),
)
);
}
}
Now you pass the PageController to all children (add a key and PageController attribute to Screen 1 and 2) and in DashBoard (Screen 1) you can change the onTap of the buttons from the MaterialRoute to this
onTap: () => widget.pageController.jumpToPage(x), //where x is the index of the children of the PageView you want to see (between 0 and 4 in this case)
In Screen 2 you wrap all your Scaffold with a WillPopScope so when the user tap back instead of closing the route it goes back to the Dashboard Widget at index 0
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
widget.pageController.jumpToPage(0); // Move back to dashboard (index 0)
return false;
}
child: Scaffold(...)
);
}
You can use other methods of PageController if you want some effects like animations (animateTo, nextPage, previousPage, etc.)