Flutter: Favourite item in listview - flutter

I am trying to add a favourite button to list view, all it needs to be is an icon on the end of each list item that you can tap to change the colour of it.
Here is what I have so far:
import 'package:flutter/material.dart';
import './images.dart';
class LikedList extends StatefulWidget {
#override
_LikedListState createState() => _LikedListState();
}
class _LikedListState extends State<LikedList> {
List<bool> _likes = [];
Color _iconColor = Colors.grey[700];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Liked List'),
),
body: ListView.separated(
separatorBuilder: (context, index) => Divider(),
itemCount: ImagesState.likes.length,
itemBuilder: (context, index) {
final item = ImagesState.likes[index];
return ListTile(
title: Text(item),
trailing: IconButton(
icon: _likes[index]
? Icon(
Icons.favorite_border,
color: Colors.grey,
)
: Icon(
Icons.favorite,
color: Colors.red,
),
onPressed: () {
setState(() {
_likes[index] = !_likes[index];
});
},
),
onLongPress: () {
setState(() {
print(ImagesState.likes[index]);
ImagesState.likes.removeAt(index);
});
},
);
},
),
);
}
}
However, this is resulting in:
RangeError (index): Invalid value: Valid value range is empty: 0
Does anyone know why this isn't working?

Your _likes list is Empty.
Initialize your _likes list with boolean values as per ypur total items of list you are showing.

Related

Firestore populated DropdownButton Item is not showing as selected, but snackbar shows otherwise

I am looking to keep the selected item from a DropdownButton list as the text in that button. Right now, I can click on the item in the dropdown list and I am showing a snackbar notification with the item selected, but it is not updating the actual dropdownbutton's text. What am I missing?
Here is my code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class InfoScreen extends StatefulWidget {
const InfoScreen({Key? key}) : super(key: key);
#override
State<InfoScreen> createState() => _InfoScreenState();
}
class _InfoScreenState extends State<InfoScreen> {
String selectedFaction = '';
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () {},
icon: const Icon(Icons.person_sharp),
),
elevation: 5,
centerTitle: true,
titleSpacing: 0,
title: const Text('Info Screen'),
actions: <Widget>[
IconButton(
onPressed: () {},
icon: const Icon(Icons.settings),
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Center(
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("factions")
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
final factionDatabaseSnapshot = snapshot.data!.docs;
factionDatabaseSnapshot.sort(
((a, b) {
return a['name']
.toLowerCase()
.compareTo(b['name'].toLowerCase());
}),
);
return DropdownButton(
onChanged: (snap) {
setState(() {
selectedFaction = snap.toString();
});
final snackbarFaction = SnackBar(
content: Text('Faction Selected: $selectedFaction'),
);
ScaffoldMessenger.of(context)
.showSnackBar(snackbarFaction);
},
items: factionDatabaseSnapshot
.map((DocumentSnapshot document) {
return DropdownMenuItem<String>(
value: document['name'],
child: Text(document['name']),
);
}).toList(),
isExpanded: false,
isDense: false,
hint: const Text('Select a faction'),
);
} else {
return const CircularProgressIndicator();
}
},
),
],
),
),
),
);
}
}
Screenshot of what I am seeing
I'd also like to save this item into Firestore on a 'submit' button, but I haven't gotten that far yet.
Any help would be greatly appreciated!
Update: Error I am receiving after adding the code from the answer selected below
your code is fine you just need to add value property inside dropdown -
return DropdownButton(
value: selectedFaction,
onChanged: (snap) {
setState(() {
selectedFaction = snap.toString();
});
final snackbarFaction = SnackBar(
content: Text('Faction Selected: $selectedFaction'),
);
ScaffoldMessenger.of(context)
.showSnackBar(snackbarFaction);
},

type 'String' is not a subtype of type 'Description'

Hello everyone i am new in flutter. I am trying to take data from API. When i try to take, i can get the body but i cannot get the datas from into it. I get an error like "I/flutter ( 8981): type 'String' is not a subtype of type 'Description'". Here is a screenshot for from my console when i run the code: Console output
and here is my code:
import 'dart:convert';
import 'dart:ffi';
import 'package:feedme_start/main.dart';
import 'package:feedme_start/model/AnaEkran_modeli.dart';
import 'package:feedme_start/model/branch_list.dart';
import 'package:feedme_start/model/restourantList.dart';
import 'package:feedme_start/widgets/Navigation_Drawer_Widget.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
class restaurantPage extends StatefulWidget {
const restaurantPage({Key? key}) : super(key: key);
#override
_restaurantPageState createState() => _restaurantPageState();
}
final datas = [];
final datas_oneri = [];
class _restaurantPageState extends State<restaurantPage> {
int counter = 0;
var personalResult;
Future getapidata() async {
//orjinal api denemesi
String url =
"https://www.mobilonsoft.com/fpsapi/default.aspx?op=branch_list&firmuid=feedmekktc&device_id=web_20210813180900001&device_platform=4&lang=en";
try {
Response responsee = await get(Uri.parse(url)); //yanıtı alır
if (responsee.statusCode == 200) {
// yanıt onaylanırsa
Map sonuc = jsonDecode(responsee.body); //içeriği alır
print("apideki veriler ;");
print(sonuc);
**Branchlist liste = Branchlist.fromJson(sonuc);**
print(liste.result.branchList.toString());
} else {}
} catch (e) {
print(e.toString());
print("verileri çekerken hata oluştu");
}
}
#override
void initState() {
getapidata();
}
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
elevation: 0,
leading: IconButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => MyApp()));
},
icon: Icon(Icons.arrow_back)),
backgroundColor: Colors.red,
actions: <Widget>[
IconButton(
onPressed: () {
showSearch(context: context, delegate: dataSearch());
},
icon: Icon(Icons.search)),
],
),
backgroundColor: Colors.white,
body: Center(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView.builder(
itemCount: counter,
itemBuilder: (context, index) {
return ListTile(
title: Text(personalResult.data[index].firstName +
" " +
personalResult.data[index].lastName),
subtitle: Text(personalResult.data[index].email),
leading: CircleAvatar(
backgroundImage:
NetworkImage(personalResult.data[index].avatar),
),
);
}),
),
),
),
);
}
}
class dataSearch extends SearchDelegate<String> {
#override
List<Widget> buildActions(BuildContext context) {
// actions for appbar
return [
IconButton(
onPressed: () {
query = "";
},
icon: Icon(Icons.clear))
];
}
#override
Widget buildLeading(BuildContext context) {
// leading icon on the left of the app bar
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
onPressed: () {
close(context, query);
},
);
}
#override
Widget buildResults(BuildContext context) {
// show some result based on the selection
return Container(
color: Colors.red,
child: Card(),
);
throw UnimplementedError();
}
#override
Widget buildSuggestions(BuildContext context) {
// show when someone searches for something
final datasOnerisi = query.isEmpty
? datas_oneri
: datas.where((p) => p.startsWith(query)).toList();
return ListView.builder(
itemBuilder: (context, index) => ListTile(
onTap: () {
showResults(context);
},
leading: Icon(Icons.search),
title: RichText(
text: TextSpan(
text: datasOnerisi[index].substring(0, query.length),
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
children: [
TextSpan(
text: datasOnerisi[index].substring(query.length),
style: TextStyle(color: Colors.grey))
]),
),
),
itemCount: datasOnerisi.length,
);
throw UnimplementedError();
}
}
I have solved the issue by changing my Model class... There were some mistakes about that. A 'string' was saved as'description' thats why it was giving this error. So i changed it with string and it solved. It was an little easy but sneaky mistake

How to fix RangeError (index): Invalid value: Only valid value is 0: 1 in Flutter

I have a screen which represent a PhotoAlbum with multiple photos. The user can click any photo to view it on fullscreen and after the option to delete it. But when I delete the photo on the last position from array I'm getting the next error:
The following RangeError was thrown building PhotoFullscreenPage(dirty, dependencies: [MediaQuery], state: _PhotoFullscreenPageState#4ce05):
RangeError (index): Invalid value: Only valid value is 0: 1
The relevant error-causing widget was:
PhotoFullscreenPage file:/.../lib/views/photos/photosAlbumPage.dart:78:33
If I delete all photos from array then I'm getting this error:
The following RangeError was thrown building PhotoFullscreenPage(dirty, dependencies: [MediaQuery], state: _PhotoFullscreenPageState#48547):
RangeError (index): Invalid value: Valid value range is empty: 0
The relevant error-causing widget was:
PhotoFullscreenPage file:/.../lib/views/photos/photosAlbumPage.dart:78:33
Here is my code for both classes:
PhotosAlbumPage.dart
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:my_app/models/photoField.dart';
import 'package:my_app/views/photos/photoFullscreenPage.dart';
class PhotosAlbumPage extends StatefulWidget {
final PhotoField photoField;
PhotosAlbumPage({Key key, this.photoField}) : super(key: key);
#override
_PhotosAlbumPageState createState() => _PhotosAlbumPageState();
}
class _PhotosAlbumPageState extends State<PhotosAlbumPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(),
body: _body(),
);
}
Widget _appBar() {
return AppBar(
title: Text('${widget.photoField.titleDescription} - Photos Album'),
centerTitle: true,
leading: _backButton(),
);
}
Widget _backButton() {
return IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () {
_sendDataBackToPhotosPage(context);
},
);
}
Widget _body() {
return CustomScrollView(slivers: <Widget>[
SliverStaggeredGrid.countBuilder(
crossAxisCount: 2,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
itemCount: widget.photoField.photoAlbum.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.all(10),
child: GestureDetector(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(20)),
child:
Image.asset(widget.photoField.photoAlbum[index].photoPath),
),
onTap: () async {
print('Click on photo: $index');
_awaitReturnValueFromPhotoFullscreenPage(
context: context,
photoField: widget.photoField,
photoIndex: index);
},
),
);
},
),
]);
}
void _awaitReturnValueFromPhotoFullscreenPage(
{BuildContext context, PhotoField photoField, int photoIndex}) async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoFullscreenPage(
photoField: photoField, photoIndex: photoIndex), // here the error is thrown
));
setState(() {
widget.photoField.photoAlbum = result;
if (widget.photoField.photoAlbum.isEmpty) {
Navigator.of(context).pop();
}
});
}
void _sendDataBackToPhotosPage(BuildContext context) {
PhotoField photoField = widget.photoField;
Navigator.pop(context, photoField);
}
}
PhotoFullscreenPage.dart
import 'package:flutter/material.dart';
import 'package:my_app/models/photo.dart';
import 'package:my_app/models/photoField.dart';
class PhotoFullscreenPage extends StatefulWidget {
final PhotoField photoField;
final int photoIndex;
const PhotoFullscreenPage({Key key, this.photoField, this.photoIndex})
: super(key: key);
#override
_PhotoFullscreenPageState createState() => _PhotoFullscreenPageState();
}
class _PhotoFullscreenPageState extends State<PhotoFullscreenPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(),
body: _body(),
);
}
Widget _appBar() {
return AppBar(
title: Text(
'${widget.photoField.titleDescription} - Photo ${widget.photoIndex}'),
centerTitle: true,
leading: _backButton(),
);
}
Widget _backButton() {
return IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () {
_sendDataBackToPhotosAlbumPage(context);
},
);
}
Widget _body() {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'${widget.photoField.photoAlbum[widget.photoIndex].photoPath}'),
IconButton(
icon: Image.asset('assets/images/delete_icon.png'),
iconSize: 70,
onPressed: () {
print("Photo will be deleted...");
setState(() {
widget.photoField.photoAlbum.removeAt(widget.photoIndex);
});
_sendDataBackToPhotosAlbumPage(context);
},
),
],
),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
);
}
void _sendDataBackToPhotosAlbumPage(BuildContext context) {
List<Photo> photoAlbum = widget.photoField.photoAlbum;
Navigator.pop(context, photoAlbum);
}
}
Please help me to identify the mistake. Thanks.
You have to check the bounds of the widget.photoField.photoAlbum before accessing it:
return Scaffold(
appBar: _appBar(),
body: widget.photoField.photoAlbum.length <= widget.photoIndex ? SizedBox() : _body(),
);
Render your empty state instead of the sample SizedBox()

Search Listview In Flutter

I have searched the web on how to add search functionality to my Flutter application. I have a list view that gets data from a mysql database and pass it as a json string. I want to add a search box on top of the list, when the user enters a string, it will take the string and search the name field of the list and re-populate the list. Here is my code please.
Thank you.
class Home extends StatefulWidget {
Home({Key key}) : super(key: key);
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
Future<List<Attendants>> students;
final studentListKey = GlobalKey<HomeState>();
#override
void initState() {
super.initState();
students = getStudentList();
}
Future<List<Attendants>> getStudentList() async {
final response = await http.get("${Env.URL_PREFIX}/list.php");
final items = json.decode(response.body).cast<Map<String, dynamic>>();
List<Attendants> students = items.map<Attendants>((json) {
return Attendants.fromJson(json);
}).toList();
return students;
}
void refreshStudentList() {
setState(() {
students = getStudentList();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: studentListKey,
appBar: AppBar(
title: Text('Members List'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search,
color: Colors.white,),
onPressed: null),
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
refreshStudentList();
},
)
],
),
body: Center(
child: FutureBuilder<List<Attendants>>(
future: students,
builder: (BuildContext context, AsyncSnapshot snapshot) {
// By default, show a loading spinner.
if (!snapshot.hasData) return CircularProgressIndicator();
// Render student lists
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
var data = snapshot.data[index];
return Card(
child: ListTile(
leading: Icon(Icons.person),
trailing: Icon(Icons.view_list),
title: Text(
data.name,
style: TextStyle(fontSize: 20),
),
onTap: () {
Navigator.push(
context,
EnterExitRoute(
exitPage: Home(),
enterPage: Details(attendants: data),
),
);
},
),
);
},
);
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return Create();
}));
},
),
);
}
}
Let me know if my question is not clear so I can explain it further
If you get all objects about your search in the future function
add your code :
// By default, show a loading spinner.
if (!snapshot.hasData) return CircularProgressIndicator();
var list = snapshot.data.where((student){
// Or some other query..
return student[“some”].contains(searchTerm);
}).toList();
return ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
var data = list[index];
..............
Else if not, this is a different subject in Flutter.

Flutter: Maintain state when navigating to different page

I have the following code which creates a Listview and adds an icon to the end of each item. This icon can be tapped in order to highlight it.
The problem is, when I navigate away from the page the items are deselected. I am using Navigator.of to load the Listview:
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return new LikedList();
}));
Full code:
import 'package:flutter/material.dart';
import './images.dart';
class LikedList extends StatefulWidget {
#override
_LikedListState createState() => _LikedListState();
}
class _LikedListState extends State<LikedList> {
List<bool> _likes = List.filled(ImagesState.likes.length,true);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Liked List'),
),
body: ListView.separated(
separatorBuilder: (context, index) => Divider(),
itemCount: ImagesState.likes.length,
itemBuilder: (context, index) {
final item = ImagesState.likes[index];
return ListTile(
title: Text(item),
trailing: IconButton(
icon: _likes[index]
? Icon(
Icons.favorite_border,
color: Colors.grey,
)
: Icon(
Icons.favorite,
color: Colors.red,
),
onPressed: () {
setState(() {
print(_likes);
_likes[index] = !_likes[index];
print(_likes);
});
},
),
onLongPress: () {
setState(() {
print(ImagesState.likes[index]);
ImagesState.likes.removeAt(index);
});
},
);
},
),
);
}
}