I am new to riverpod and flutter(go easy on me) and I am trying make this directory kinda thing where I will store my note. So, I made a function to test if my main function would rebuild on when a folder is added to hive and to my surprise it didn’t.
here is my provider code:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/adapters.dart';
import '../models/folder.dart';
import '../models/note.dart';
final folderNotifierProvider =
StateNotifierProvider<FolderNotifier, Box<Folder>>((ref) {
return FolderNotifier();
});
class FolderNotifier extends StateNotifier<Box<Folder>> {
late List<Folder> navigationStack = [];
Folder? currentFolder;
FolderNotifier() : super(Hive.box<Folder>('folders')) {
Hive.box<Folder>('folders').listenable().addListener(() {
state = Hive.box<Folder>('folders');
print('Changes has been made');
});
}
void navigateToFolder(Folder folder) {
navigationStack.add(currentFolder!);
currentFolder = folder;
state = state;
}
void navigateBack() {
if (navigationStack.isNotEmpty) {
currentFolder = navigationStack.removeLast();
}
}
Future<void> initializeRootFolder() async {
final folderBox = Hive.box<Folder>('folders');
Folder rootFolder;
if (folderBox.isEmpty) {
rootFolder = Folder(name: 'Notes');
await folderBox.add(rootFolder);
} else {
rootFolder =
folderBox.values.firstWhere((folder) => folder.name == 'Notes');
}
currentFolder = rootFolder;
}
List<Note> filterNotes() {
return currentFolder?.notes?.cast<Note>() ?? [];
}
List<Folder> filterSubfolders() {
return currentFolder?.subfolders?.cast<Folder>() ?? [];
}
Future<void> createSubfolder(Folder parentFolder, String name) async {
final folderBox = Hive.box<Folder>('folders');
final subfolder = Folder(name: name);
await folderBox.add(subfolder);
parentFolder.subfolders ??= HiveList(folderBox);
parentFolder.subfolders!.add(subfolder);
await parentFolder.save();
}
Future<void> updateFolder(Folder folder, {String? name}) async {
folder.name = name ?? folder.name;
await folder.save();
}
}
and here is my screen:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:intl/intl.dart';
import 'package:nb_utils/nb_utils.dart';
import '../colors/AppColors.dart';
import '../providers/drawerProvider.dart';
import '../providers/provider.dart';
class Notes extends ConsumerStatefulWidget {
const Notes({super.key});
@override
_NotesState createState() => _NotesState();
}
class _NotesState extends ConsumerState<Notes> {
final TextEditingController _searchController = TextEditingController();
final TextEditingController _subfolderController = TextEditingController();
void initState() {
super.initState();
ref.read(folderNotifierProvider.notifier).initializeRootFolder();
}
Widget build(BuildContext context) {
var folders = ref.watch(folderNotifierProvider.notifier);
var subfolders = ref.watch(folderNotifierProvider.notifier).filterSubfolders();
var notes = ref.watch(folderNotifierProvider.notifier).filterNotes();
if (folders.currentFolder == null) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0,
leading: IconButton(
icon: SvgPicture.asset(
"assets/images/notes/Menu.svg",
height: 24,
width: 24,
color: AppColors.primaryTextColor,
),
onPressed: () {
ref.read(drawerManagerProvider).openDrawer();
}).paddingLeft(6),
actions: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: AppColors.secondaryColor,
),
height: 30,
width: 165,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SvgPicture.asset(
"assets/images/notes/crown.svg",
height: 16,
width: 16,
color: Colors.white,
),
SizedBox(width: 6),
Text(
'Upgrade to premium',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Colors.white,
fontSize: 12,
),
),
],
),
).paddingRight(24),
],
backgroundColor: AppColors.backgroundColor,
elevation: 0,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
4.height,
SizedBox(
height: 38,
child: TextField(
onTapOutside: (focus) {
FocusScope.of(context).unfocus();
},
enabled: false,
controller: _searchController,
textAlignVertical: TextAlignVertical.bottom,
textAlign: TextAlign.start,
maxLines: 1,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 16,
color: AppColors.primaryTextColor,
),
decoration: InputDecoration(
hintText: "Search",
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 16,
color: AppColors.borderColor,
),
prefixIcon: UnconstrainedBox(
child: SvgPicture.asset(
"assets/images/notes/search.svg",
height: 16,
width: 16,
color: AppColors.borderColor,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
strokeAlign: BorderSide.strokeAlignOutside,
color: AppColors.primaryColor,
width: 1,
),
borderRadius: BorderRadius.circular(12),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
strokeAlign: BorderSide.strokeAlignOutside,
color: Color(0xffEAEAEA),
width: 0.5,
),
borderRadius: BorderRadius.circular(12),
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xffEAEAEA),
width: 0.5,
),
borderRadius: BorderRadius.circular(12),
),
),
),
),
24.height,
if (folders.currentFolder!.name != 'Notes')
GestureDetector(
onTap: () {
folders.navigateBack();
setState(() {
});
},
child: Row(
children: [
SvgPicture.asset(
"assets/images/notes/back.svg",
height: 22,
width: 22,
color: AppColors.primaryTextColor,
),
SizedBox(width: 4),
Text(
folders.currentFolder!.name,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
fontSize: 18,
),
),
],
),
),
if (folders.currentFolder!.name == 'Notes')
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
child: Text(
folders.currentFolder!.name,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
fontSize: 18,
),
),
),
],
),
16.height,
Expanded(
child: ListView.builder(
physics: const BouncingScrollPhysics(),
reverse: false,
itemCount: subfolders.length + notes.length,
itemBuilder: (context, index) {
if (index < subfolders.length) {
final subfolder = subfolders[index];
return GestureDetector(
onTap: (){
folders.navigateToFolder(subfolder);
},
child: Container(
height: 48,
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: AppColors.borderColor,
width: 0.5,
),
),
padding: EdgeInsets.symmetric(horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SvgPicture.asset(
'assets/images/notes/folder.svg',
height: 24,
width: 24,
color: AppColors.borderColor,
),
SizedBox(width: 12),
Expanded(
child: Text(
subfolder.name,
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 15,
letterSpacing: 0.4,
color:AppColors.primaryTextColor,
),
),
),
GestureDetector(
child: SvgPicture.asset(
'assets/images/notes/moreV.svg',
height: 16,
width: 16,
color: AppColors.primaryTextColor,
),
),
],
),
),
).paddingOnly(bottom: 16);
} else {
final note = notes[index - subfolders.length];
final formattedDate =
DateFormat('yyyy-MM-dd HH:mm').format(note.createdAt);
return GestureDetector(
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: AppColors.borderColor,
width: 0.5,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
note.title,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontSize: 16,
color: AppColors.primaryTextColor,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
).paddingRight(24),
),
GestureDetector(
child: SvgPicture.asset(
'assets/images/notes/moreH.svg',
height: 16,
width: 16,
color: AppColors.primaryTextColor,
),
)
],
),
4.height,
Text(
note.content.trim(),
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 13,
height: 1.4,
color: AppColors.secondaryTextColor,
),
maxLines: 4,
overflow: TextOverflow.ellipsis,
),
],
).paddingOnly(
left: 12, right: 12, top: 12, bottom: 12),
).paddingBottom(16),
);
}
},
),
),
],
).paddingOnly(left: 24, right: 24),
floatingActionButton: FloatingActionButton(
onPressed: () {
showAddSubfolderBottomSheet();
},
child: Icon(Icons.add),
),
);
}
void showAddSubfolderBottomSheet() {
final folders = ref.read(folderNotifierProvider.notifier);
showModalBottomSheet(
backgroundColor: Colors.white,
context: context,
isScrollControlled: true,
builder: (context) {
return Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom, // Add this line
left: 24.0,
right: 24.0,
top: 24.0,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Add Folder To ${folders.currentFolder!.name}',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: 18,
)),
16.height,
SizedBox(
height: 48,
child: TextField(
onTapOutside: (focus) {},
controller: _subfolderController,
textAlignVertical: TextAlignVertical.center,
textAlign: TextAlign.start,
maxLines: 1,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 16,
color: AppColors.primaryTextColor,
),
decoration: InputDecoration(
hintText: "Name your folder",
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 14,
color: Color(0xff98A2B3),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
strokeAlign: BorderSide.strokeAlignOutside,
color: AppColors.primaryColor,
width: 1,
),
borderRadius: BorderRadius.circular(16),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
strokeAlign: BorderSide.strokeAlignOutside,
color: AppColors.primaryTextColor.withOpacity(0.6),
width: 0.5,
),
borderRadius: BorderRadius.circular(16),
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: AppColors.primaryTextColor.withOpacity(0.6),
width: 0.5,
),
borderRadius: BorderRadius.circular(16),
),
),
),
),
SizedBox(height: 24),
Row(
children: [
Expanded(
child: GestureDetector(
onTap: () {
Navigator.of(context).pop();
_subfolderController.clear();
},
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'Cancel',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontSize: 12,
),
),
],
),
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: Border.all(
strokeAlign: BorderSide.strokeAlignInside,
color: AppColors.borderColor,
width: 0.5,
),
),
height: 44,
),
),
),
8.width,
Expanded(
child: GestureDetector(
onTap: () {
if (_subfolderController.text.isNotEmpty) {
ref.watch(folderNotifierProvider.notifier).createSubfolder(
folders.currentFolder!,
_subfolderController.text,
);
Navigator.of(context).pop();
_subfolderController.clear();
} else {}
},
child: Container(
decoration: BoxDecoration(
color: AppColors.primaryColor,
borderRadius: BorderRadius.circular(12),
),
height: 44,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'Save',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontSize: 12,
color: Colors.white,
),
),
],
),
),
),
)
],
).paddingOnly(bottom: 24),
],
),
);
},
);
}
}
I think whenever there is change in the hive box the screen should rebuild but it does not and when I use set state it works. Help a brother out..
Muhammad Ali Hassan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.