Please help me, I really need help. I am trying to design a TODO List application and I use SqFlite database to store the data entered by the user via the BottomSheet and I am trying for two days to display the data entered by the user by using the ReorderableListVie .builder But I have a big problem in displaying the data, which is the Key value in the ReorderableListView, and I tried to give it different values several times. But still the same error.. Does anyone have an idea to solve the error??.. Please help me!!
This is the Home code that contains all screens and user data is entered from it
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:todoapp/module/archive_tasks.dart';
import '../module/done_tasks.dart';
import '../module/new_tasks.dart';
import '../sqflite.dart';
import 'package:intl/intl.dart';
class HomeLayout extends StatefulWidget {
@override
State<HomeLayout> createState() => _HomeLayoutState();
}
//---------------------------------
List<Widget> screen=[
NewTask(),
DoneTask(),
ArchiveTasks(),
];
//tass =[{'id':1 , task ='text' ,date :'text'},{{'id':2 , task ='text' ,date :'text'}}];
List<String> title=[
'New Tasks',
'Done Tasks',
'Archive Tasks'
];
//---------------------------------------
class _HomeLayoutState extends State<HomeLayout> {
//----------------------------------------------
int CurrentIndex=0;
Color color=Colors.black;
var Scaffoldkkey=GlobalKey<ScaffoldState>();
bool showBottomshet=true;
IconData floaticon=Icons.edit;
var titlecontroller=TextEditingController();
var date=TextEditingController();
var time=TextEditingController();
var formkeyy =GlobalKey<FormState>();
//---------------------------------------------
SqlDb DataBase=SqlDb();
//Before build function call initstate.
@override
void initState() {
// TODO: implement initState
super.initState();
// Future<Database?> DB = SqlDb.db;
}
Widget build(BuildContext context) {
return Scaffold(
key: Scaffoldkkey,
appBar: AppBar(
title: Text(title[CurrentIndex]),
),
body: tasks.length !=0 ? screen[CurrentIndex] :Center(child: CircularProgressIndicator()),
//----------------------------------------------
floatingActionButton: FloatingActionButton(
onPressed: () {
//**************************************
if(!showBottomshet) {
if (formkeyy.currentState!.validate()) {
DataBase.insertData(
title: titlecontroller.text,
time: time.text,
date: date.text,
).then((value) {
DataBase.readData('SELECT * FROM Tasks').
then((value) {
Navigator.pop(context);
setState(() {
tasks=value;
showBottomshet = true;
floaticon = Icons.edit;
});
}); });
}
}
else{
titlecontroller.clear();
date.clear();
time.clear();
Scaffoldkkey.currentState!.showBottomSheet((context) =>
Container(
color: Colors.white,
padding: const EdgeInsets.all(20.0),
child: Form(
key: formkeyy,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: titlecontroller,
keyboardType: TextInputType.text,
validator: (String? value){
if(value!.isEmpty){
return 'Title must not be empty';
}
return null;
},
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 3, color: Colors.grey),),
label: Text('Task Title'),
prefixIcon:Icon( Icons.title),
),
),
SizedBox(height: 10,),
TextFormField(
controller: time,
keyboardType: TextInputType.datetime,
validator: (String? value){
if(value!.isEmpty){
return 'time must not be empty';
}
return null;
},
onTap: (){
showTimePicker(
context: context,
initialTime: TimeOfDay.now()
).then((value) {
time.text=value!.format(context).toString();
}
);
},
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 3, color: Colors.grey),),
label: Text('Task Time'),
prefixIcon:Icon( Icons.timer_sharp),
),
),
SizedBox(height: 10,),
TextFormField(
controller: date,
keyboardType: TextInputType.datetime,
validator: (String? value){
if(value!.isEmpty){
return 'date must not be empty';
}
return null;
},
onTap: (){
print('-----ontap-----');
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime.parse('2025-12-31'),
).then((value)
{
date.text = DateFormat.yMMMd().format(value!);
}
);
},
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 3, color: Colors.grey),),
label: Text('Task Date'),
prefixIcon:Icon( Icons.calendar_today),
),
),
],
),
),
),
elevation: 20.0).closed.then((value) {
});
//----------------------------------------------------------------
setState(() {
showBottomshet=false;
floaticon=Icons.close;
});
}
},
child:Icon(floaticon),
),
//----------------------------------------------
bottomNavigationBar: BottomNavigationBar(
showUnselectedLabels: false,
backgroundColor: Colors.purpleAccent,
currentIndex:CurrentIndex,
onTap: (index){
setState(() {
CurrentIndex=index;
});
},
selectedItemColor: Colors.white,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.menu,color:color ,),
label: 'Tasks',
activeIcon: Icon(Icons.menu,color:Colors.white ,),
),
BottomNavigationBarItem(
icon: Icon(Icons.check_box_outlined,color:color ),
label: 'Done',
activeIcon: Icon(Icons.check_box_outlined,color:Colors.white ),
),
BottomNavigationBarItem(
icon: Icon(Icons.archive_outlined,color:color ,),
label: 'Archive',
activeIcon: Icon(Icons.archive_outlined,color:Colors.white ,)
)
]),
);
}
}
This is the database code that contains all the CRUDE operations
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
//-----------------------------------
List<Map> tasks=[];
class SqlDb{
static Database? _db;
//-------------------------------
Future<Database?> get db async{
if(_db == null){
_db = await intialDb();
return _db;
}
else{
return _db;
}
}
//##################################
intialDb()async{
String databasepath=await getDatabasesPath();
String path=join(databasepath,'asma.db');
Database mydb=await openDatabase(path,onCreate:_onCreate,version: 1,onUpgrade:_onUpgrade,onOpen: _onOpen );
print('open DB');
return mydb;
}
//----------------------------------
_onOpen(database){
}
//----------------------------------
_onCreate(Database db ,int version){
db.execute('CREATE TABLE Tasks(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Text TEXT NOT NULL, date TEXT NOT NULL, time TEXT NOT NULL, status TEXT NOT NULL)').then((value)=>print('') )
.catchError((onError)=>print("---------||||||-------------${onError.toString}-----------||||||-----------"));
//[{id:1,titiele:"nef",date:"},{}]
}
//---------------value-------------------
_onUpgrade(Database db ,int oldversion , int newversion){
print(" onUpgrade =====================================") ;
}
//----------------------------------
Future<int> insertData({ required String title,required String time,required String date } )async{
Database? mydb =await db;
int response = await mydb!.rawInsert(
"INSERT INTO Tasks (Text ,date,time,status) VALUES('$title' ,'$date','$time','new')"
);
print("\n\n\n###################Insert#################\n\n\n");
return response;
}
//-------------------------------
Future<List<Map>> readData(String sql)async{
Database? mydb= await db;
List<Map> response =await mydb!.rawQuery(sql);
return response;
}
//-------------------------------
updateData(String sql)async{
Database? mydb =await db;
int response =await mydb!.rawUpdate(sql);
return response;
}
//-------------------------------
deleteData(String sql)async{
Database? mydb= await db;
int response =await mydb!.rawDelete(sql);
return response;
}
}
This is the New_task.dart code in which the new tasks are displayed and contains the ReorderableListView.builder
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../sqflite.dart';
//--------------------------------------
class NewTask extends StatefulWidget {
@override
State<NewTask> createState() => _NewTaskState();
}
//--------------------------------------
class _NewTaskState extends State<NewTask> {
@override
Widget build(BuildContext context) {
return ReorderableListView.builder(
itemCount: tasks.length,
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex = newIndex - 1;
}
final element = tasks.removeAt(oldIndex);
tasks.insert(newIndex, element);
});
}
, itemBuilder: (BuildContext context, int index) =>ListTasks( context ,index),);
}
Widget ListTasks(BuildContext context , int index){
return Padding(
padding: const EdgeInsets.all(8.0),
child:
Card(
key:ValueKey(tasks[index]),
elevation: 30,
shadowColor: Colors.purpleAccent.withOpacity(0.3),
child: ListTile(
leading:Container(
decoration: BoxDecoration(
color: Colors.pink.withOpacity(0.2),
border: Border.all(
color: Colors.deepPurple,
width: 3
)
),
child: Text(tasks[index]['time']) ,
) ,
title: Text(tasks[index]['Text'],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.purple
),),
subtitle: Text(tasks[index]['date']),
),
),
);
}
Widget Divdor(){
return Padding(
padding: const EdgeInsetsDirectional.only(
start: 10
),
child: Container(
height: 1,
color: Colors.grey));
}
}
this code of Archive_tasks.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class ArchiveTasks extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('ArchiveTasks',style: GoogleFonts.pacifico(
color: Colors.blue,
fontSize: 20.0,
),),
);
}
}
this code of Done_tasks.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class DoneTask extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('DoneTask',style: GoogleFonts.pacifico(
color: Colors.blue,
fontSize: 20.0,
),),
);
}
}
CodePudding user response:
In order to use ReorderableListView
you need to provide unique on each item. It can be like
Widget ListTasks(BuildContext context, int index) {
return Padding(
key: Key(tasks[index]), //there the unique data
padding: const EdgeInsets.all(8.0),
child: Card(
You need to provide key on level on itemBuilder.
More about ReorderableListView