Flutter Hive: deleteAt is making the value null instead of deleting it - flutter

So let's say I have a list of books.
Deleting book at nth index using deleteAt is not actually deleting it and shifting (n+1)th element to it's place, rather it is making it null. i.e. the element at nth is now null.
How to perform deleteAt perfectly?
BTW I have used delete outside of the ValueListenableBuilder.
ValueListenableBuilder(
valueListenable: Hive.box('books').listenable(),
builder: (context, box, _) {
if (box.values.length == 0)
return Center(
child: Text("No books"),
);
return ListView.builder(
primary: true,
padding: EdgeInsets.only(bottom: 95),
itemCount: box.values.length,
itemBuilder: (context, int index) {
Book book = box.get(index);
return Padding(
padding:
const EdgeInsets.only(bottom: kMasterPadding),
child: BookItem(
title: book.title,
author: book.authorName,
),
);
},
);
},
),
deleting code
() async {
await Hive.box("books").deleteAt(Hive.box("books").length - 2);
//deleted at last 2nd coz deleting at the end was working perfectly
},

You can try Book book = box.getAt(index); instead of Book book = box.get(index);
https://github.com/hivedb/hive/issues/376

You can remove an element from a List<E> by running .removeAt(index) on your list. This also shifts your last elements one index to the left.

Related

How do I setup a scoreboard in flutter? (using firebase)

Hi I'm having trouble setting up my scoreboard in flutter, everything is working as intended except one part. I want to create a scoreboard which displays a username, image and some data. All the data is stored in a collection in firebase and I have set it up as following.
date "2022-05-12"
time 20220512
träning "data"
userID "x"
I would like to get the username and the image from another collection where I've saved the user info. The user documents looks like this and they are named after the userID.
name "x"
imagePath "x"
My original idea was to get the data and the userID and then use the userID to get the name and image. This is my current code. Im getting the correct userID but I cant figure out how to get the name and the image from the user documents. Does anyone know how I could solve this? I'll add an example screenshot at the end. Thanks for reading.
StreamBuilder<QuerySnapshot<Object?>> buildStreamBuilderTop() {
return StreamBuilder<QuerySnapshot>(
stream: trViewTop,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Nått gick snett');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text('Datan hämtas');
}
final data = snapshot.requireData;
return AnimationLimiter(
child: ListView.builder(
itemCount: data.size,
itemBuilder: (context, index) {
QueryDocumentSnapshot user = snapshot.data!.docs[index];
String userID = user['userID'];
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(seconds: 1),
child: SlideAnimation(
verticalOffset: 44,
child: FadeInAnimation(
child: Card(
child: ListTile(
leading: CircleAvatar(radius: 30, backgroundImage: NetworkImage(*this is where i want the image*)),
title: Text(*this is where i want the name*),
subtitle: Text('Träningar ${data.docs[index]['totalTr']}'),
trailing: Text(' + ${data.docs[index]['totalTr'] * 20 } Kr',
style: TextStyle(color: Colors.green),),
),
),
),
),
);
}
),
);
},
);
}

Flutter - The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type

I'm trying to show a list of search results. The error is with the ListView Builder.
ListView.builder(
itemCount: searchResults.length,
itemBuilder: (context, index) {
final searchResultAccount = searchResults[index];
for (var element in searchResults[index].profile!) {
final searchResultProfile = element;
return ListTile(
leading: CircleAvatar(
backgroundImage: searchResultProfile.profileImage.isNotEmpty
? NetworkImage(
searchResultProfile.profileImage,
)
: null,
child: searchResultProfile.profileImage.isNotEmpty
? null
: const Icon(
Icons.person,
),
),
title: Text(
searchResultProfile.profileName,
),
onTap: () {
//navigate to profile
},
);
}
if (searchResults.isEmpty) {
return Text('no results');
}
},
),
I tried putting the code inside a try-catch block and even with the conditional statement above that I added in the end to return Text widget I'm still getting the same error.
How to clear this error?
It is possible that we will get null value from searchResults[index].profile. Therefore, loop may not return any ListTile widget.
Also, while using loop, it will return a list of widget. But you are returning single ListTile. You can wrap with Column.
searchResults.isEmpty may not meet the criteria and won't return Text(..). You can include an else statement and return a widget.
itemBuilder: (context, index) {
final searchResultAccount =....;
List<Widget> xWidgets = [];
for (var element in searchResults[index].profile!) {
xWidgets.add( ListTile(..));
}
if (xWidgets.isNotEmpty) {
return Column(
mainAxisSize: MainAxisSize.min,
children: xWidgets,
);
}
return Text('no results');
},
I would say that one of the parameters are being sent as null, try dugguing to find out where it is sending the error.
Also the for seem a bit inappropriate as it will only iterate once and return the first element of the profile at that index. You can achieve the same getting the first element.

Animating stateful list item on the basis of api changes Flutter

Is there any way I can animate a single list item (say glowing border of a container) on the basis of changes on api? I have a listview which has price of items and when price changes in real time, I want to animate that particular item container. I have been searching for a solution for months now and I haven't found any yet.
StreamBuilder<MyProducts>(
stream: myProductsBloc.subject.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.error != null &&
snapshot.data.error.length > 0) {
return ShowError(
error: snapshot.data.error,
onTap: () => myProductsBloc.getMyProducts(),
);
} else if (snapshot.data.data.length == 0) {
return EmptyWidget();
}
return ListView.separated(
separatorBuilder: (context, i) =>
const SizedBox(height: 10),
padding: EdgeInsets.all(10),
itemCount: snapshot.data.data.length,
itemBuilder: (context, i) {
ProductData productData = snapshot.data.data[i];
return GestureDetector(
onTap: () =>
_buildBottomSheet(argument: productData),
child: ProductCard(product: productData));
},
);
} else if (snapshot.hasError) {
return Center(
child: Text('${snapshot.data.error}'),
);
} else {
return Center(
child: LoadingWidget(text: "Fetching products.."));
}
}),
Here I want to animate border of product card if price on the api changes.
in pseudo code,
Border(borderWidth: (myListItemId == 'special' ? controller_value*2 : 1)
...should do. With colors it is a bit more tricky, but you could use an index of a list with colors

Changing property of children don't trigger UI change on Flutter Getx

I'm trying to render a reactive widget, based on a object list.
I needed that when the children of this object, has his boolean property changes, the UI should be updated.
In this scenario, my controller has a list os Sections and each section has a list of Lessons.
To better understanding, i rewriter my code making a simple example, based on what i need.
I already try using .map, .forEach, and others approaches, but the children property never trigger the UI update.
GetX<LessonController>(
initState: (state) => controller.getLessonsByCourse(course.id),
builder: (_) {
return Expanded(
child: ListView.separated(
scrollDirection: Axis.vertical,
itemCount: _.sectionList.length,
itemBuilder: (BuildContext context, int index) {
return ExpansionTile(
title: Text(_.sectionList[index].title),
children: <Widget>[
for(var i = 0; i < _.sectionList[index].lessons.length; i++)
Padding(
padding: const EdgeInsets.all(8.0),
child:
Obx(() =>
GestureDetector(
child: Text((_.sectionList[index].lessons[i] as Lesson).isCompleted.toString()),
onTap: () {
(_.sectionList[index].lessons[i] as Lesson).isCompleted = !(_.sectionList[index].lessons[i]as Lesson).isCompleted;
print((_.sectionList[index].lessons[i]as Lesson).isCompleted.toString());
})
),
)
]);
},
separatorBuilder: (context, ind) => Divider(
height: 2,
color: Colors.grey[300],
),
),
);
})
Solution:
The GetX container monitores changes on the list items, so when you change a property from one of this items, the list itself doesn't change. To solved that, i change the item property, and after that i overrited it on the list.
onTap: (value) {
Section tappedSection = _.sectionList[index];
tappedSection.lessons[lessonIndex].isCompleted = value;
// This is the secret
// Making GetX detect a change on the list and rebuild UI
_.sectionList[index] = tappedSection;
}));
As far as I could tell, an observable list in Flutter GetX is not concerned with internal changes to objects in itself.
To force the UI update, I had to return the updated object to the same position in the list, in order to pretend that there was a change in the objects in the main list.
Something like that:
Section tappedSection = _.sectionList[index];
tappedSection.lessons[i].isCompleted = value;
_.notifyLessonProgress(tappedSection.lessons[i].id, value);
_.sectionList[index] = tappedSection;
It looks like the problem is here:
this._sectionList.value = value;
Try this instead:
this._sectionList = value;

ListView not updating after filtering Flutter

I am trying to filter a listview. I am able to see that data is filtered but I don't get anything at the screen. Probably it is just a simple thing.
Part of the code:
final messageBubble = MessageBubble(
document: nameDocument,
name: gaName,
);
messageBubbles.add(messageBubble);
filtermessageBubbles= messageBubbles;
(...)
FloatingSearchBar.builder(
pinned: true,
itemCount: filtermessageBubbles.length,
padding: EdgeInsets.only(top: 10.0),
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: filtermessageBubbles[index],
);
},
onChanged: (String value) {
setState(() {
filtermessageBubbles = messageBubbles.where((item) => item.name.toLowerCase().contains(value.toLowerCase())).toList();
print(filtermessageBubbles.length);
print(filtermessageBubbles);
});
},
and when I run it, I am able to see that filteredmessageBubbler.length reduces its number, but I don't see any change in the virtual device.
Thanks in advance!