From 03cb6b81c41d548530d0d621b3529da7ff276868 Mon Sep 17 00:00:00 2001 From: Sewmina Date: Tue, 15 Mar 2022 02:49:27 +0530 Subject: [PATCH] Multi step list and editor UI done --- lib/Data.dart | 3 +- lib/DateTimeRangeCustom.dart | 2 +- lib/NewProject.dart | 777 ++++++++++++++++++++--------------- 3 files changed, 450 insertions(+), 332 deletions(-) diff --git a/lib/Data.dart b/lib/Data.dart index 58f4d8e..ac363e7 100644 --- a/lib/Data.dart +++ b/lib/Data.dart @@ -90,10 +90,11 @@ class Queries{ } class ProjectStep{ - ProjectStep(this.stepName,this.eta); + ProjectStep(this.stepName,this.eta,this.progress); String stepName; int eta; + int progress; } diff --git a/lib/DateTimeRangeCustom.dart b/lib/DateTimeRangeCustom.dart index ba75b66..f43e700 100644 --- a/lib/DateTimeRangeCustom.dart +++ b/lib/DateTimeRangeCustom.dart @@ -17,7 +17,7 @@ Future showDurationSelector(BuildContext context, {required Function(Durat return AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30)), - backgroundColor: Colors.white10, + backgroundColor: Color(0xFF1F1F1F), title: Align(alignment: Alignment.center, child: const Text('Select Time Range')), content: Row( diff --git a/lib/NewProject.dart b/lib/NewProject.dart index 3b3dd86..d36e19d 100644 --- a/lib/NewProject.dart +++ b/lib/NewProject.dart @@ -39,155 +39,119 @@ class _NewProjectState extends State { appBar: AppBar(title: Text('New Project')), body: Container( height: MediaQuery.of(context).size.height, - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SingleChildScrollView( - child: Padding( - padding: EdgeInsets.fromLTRB(20, 50, 20, 50), - child: Column( - children: [ - Container( - padding: EdgeInsets.all(0), - child: Text('Project Name')), - Container( - padding: EdgeInsets.all(10), - child: TextField( - controller: nameController, - decoration: InputDecoration( - hintText: - 'ex: Cool science project, Build a new game etc...', - border: OutlineInputBorder()), - ), - ), - Divider(), - Column(children: [ - Container( - padding: EdgeInsets.all(0), - child: Text('Related Category')), - Container( - margin: EdgeInsets.all(10), - padding: EdgeInsets.symmetric( - horizontal: 12, vertical: 1), - decoration: BoxDecoration( - color: Colors.white10, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: Colors.grey, width: 2)), - child: DropdownButton( - dropdownColor: Colors.black, - iconSize: 30, - elevation: 10, - borderRadius: BorderRadius.circular(10), - value: selectedCat, - isExpanded: true, - items: getCategoryNames() - .map>( - (String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), - onChanged: (String? _value) { - setState(() { - selectedCat = _value!; - }); - })), - Divider(), - Container( - padding: EdgeInsets.all(10), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text('This project is', - style: TextStyle(fontSize: 18)), - FlutterSwitch( - width: 130, - height: 35.0, - valueFontSize: 15.0, - toggleSize: 25.0, - toggleColor: Colors.white70, - activeTextColor: Colors.white, - inactiveTextColor: Colors.white, - value: multiLine, - borderRadius: 30.0, - showOnOff: true, - activeText: 'Multi step', - inactiveText: 'Single step', - activeColor: Colors.deepOrange, - activeIcon: Icon(Icons.linear_scale, - color: Colors.orange), - inactiveIcon: Icon(Icons.check, - color: Colors.green), - inactiveColor: Colors.green, - onToggle: (val) { - setState(() { - multiLine = val; - print( - "Multi=Step : $multiLine"); - }); - }, - ) - ])), - ]), - ], - ))), - Container( - padding: - EdgeInsets.symmetric(vertical: 10, horizontal: 20), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + child: Column(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + SingleChildScrollView( + child: Padding( + padding: EdgeInsets.fromLTRB(20, 50, 20, 50), + child: Column( children: [ - Expanded( - flex: 5, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 0), - child: ElevatedButton( - style: ElevatedButton.styleFrom( - primary: Colors.red, - shape: StadiumBorder()), - onPressed: () { - setState(() { - Navigator.pop(context); - }); - }, - child: Text('Cancel', - style: TextStyle(fontSize: 20))))), - Expanded( - flex: 6, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 0), - child: ElevatedButton( - style: ElevatedButton.styleFrom( - primary: Colors.green, - shape: StadiumBorder()), - onPressed: () { - // add_action(); - if (nameController.text.length > 3) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => - NewProject2( - projectName: - nameController.text, - ))); - } else { - showAlertDialog(context, 'Really?', - 'Enter a valid name for this project!'); - } - }, - child: Text('Next', - style: TextStyle(fontSize: 20))))), + Container(padding: EdgeInsets.all(0), child: Text('Project Name')), + Container( + padding: EdgeInsets.all(10), + child: TextField( + controller: nameController, + decoration: + InputDecoration(hintText: 'ex: Cool science project, Build a new game etc...', border: OutlineInputBorder()), + ), + ), + Divider(), + Column(children: [ + Container(padding: EdgeInsets.all(0), child: Text('Related Category')), + Container( + margin: EdgeInsets.all(10), + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 1), + decoration: BoxDecoration( + color: Colors.white10, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey, width: 2)), + child: DropdownButton( + dropdownColor: Colors.black, + iconSize: 30, + elevation: 10, + borderRadius: BorderRadius.circular(10), + value: selectedCat, + isExpanded: true, + items: getCategoryNames().map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + onChanged: (String? _value) { + setState(() { + selectedCat = _value!; + }); + })), + Divider(), + Container( + padding: EdgeInsets.all(10), + child: Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text('This project is', style: TextStyle(fontSize: 18)), + FlutterSwitch( + width: 130, + height: 35.0, + valueFontSize: 15.0, + toggleSize: 25.0, + toggleColor: Colors.white70, + activeTextColor: Colors.white, + inactiveTextColor: Colors.white, + value: multiLine, + borderRadius: 30.0, + showOnOff: true, + activeText: 'Multi step', + inactiveText: 'Single step', + activeColor: Colors.deepOrange, + activeIcon: Icon(Icons.linear_scale, color: Colors.orange), + inactiveIcon: Icon(Icons.check, color: Colors.green), + inactiveColor: Colors.green, + onToggle: (val) { + setState(() { + multiLine = val; + print("Multi=Step : $multiLine"); + }); + }, + ) + ])), + ]), ], - )) - ]))); + ))), + Container( + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + flex: 5, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0), + child: ElevatedButton( + style: ElevatedButton.styleFrom(primary: Colors.red, shape: StadiumBorder()), + onPressed: () { + setState(() { + Navigator.pop(context); + }); + }, + child: Text('Cancel', style: TextStyle(fontSize: 20))))), + Expanded( + flex: 6, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0), + child: ElevatedButton( + style: ElevatedButton.styleFrom(primary: Colors.green, shape: StadiumBorder()), + onPressed: () { + // add_action(); + if (nameController.text.length > 3) { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => NewProject2( + projectName: nameController.text, + ))); + } else { + showAlertDialog(context, 'Really?', 'Enter a valid name for this project!'); + } + }, + child: Text('Next', style: TextStyle(fontSize: 20))))), + ], + )) + ]))); } void pickColor(BuildContext context) => showDialog( @@ -216,8 +180,7 @@ class _NewProjectState extends State { String catName = nameController.value.text; if (catName.length < 2) { - showAlertDialog(context, 'Category needs a name', - 'Please enter a name for this category'); + showAlertDialog(context, 'Category needs a name', 'Please enter a name for this category'); return; } var hex = '#${pickerColor.value.toRadixString(16)}'; @@ -272,14 +235,8 @@ class NewProject2 extends StatefulWidget { class _NewProject2State extends State { bool knowEta = false; int etaHours = 1; - List steps = [ - ProjectStep('Step 1', 3), - ProjectStep('Step 2', 2), - ProjectStep('Ez Step', 1), - ProjectStep('Very hard', 10), - ProjectStep('Finishing', 5) - ]; - DateTime deadline = DateTime.now().add(Duration(days:7)); + List steps = []; + DateTime deadline = DateTime.now().add(Duration(days: 7)); late String? projectName; _NewProject2State({String? pName}) { projectName = pName; @@ -291,192 +248,352 @@ class _NewProject2State extends State { appBar: AppBar(title: Text(projectName ?? 'Error')), body: Container( height: MediaQuery.of(context).size.height, - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SingleChildScrollView( - child: Container( - padding: EdgeInsets.fromLTRB(20, 50, 20, 50), - child: (multiLine) - ? Column( - children: [ - Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.all(10), - child: Text('List your steps down') - ), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: Colors.white10, - ), - padding: EdgeInsets.all(10), - - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child:Column( - children: printSteps(), - ) - ), - ), - ], - ) - ], - ) - : Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.all(10), - child: Text( - "Estimated Time to reach target")), - Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - InkWell( - onTap: () { - showDurationSelector(context,selectedHour: etaHours, onChange: (newVal){ - etaHours = newVal.inHours; - knowEta=true; - setState(() { - - }); - print("Selected $newVal"); - }); - }, + child: Column(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Container( + padding: EdgeInsets.fromLTRB(20, 50, 20, 50), + child: (multiLine) + ? Column( + children: [ + Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container(padding: EdgeInsets.all(10), child: Text('List your steps down')), + LimitedBox( + maxHeight: 300, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Colors.white10, + ), + padding: EdgeInsets.all(10), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, child: Container( - decoration: BoxDecoration( - color: (knowEta) ? Colors.green:Colors.white10, - borderRadius: - BorderRadius.circular(30), + child: Column( + children: printSteps(), ), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 50, vertical: 10), - child: Text("${(knowEta)?etaHours:'?'} Hours"), - ), - ), - ),InkWell( - onTap: (){ - knowEta=false; + )), + ), + ), + SizedBox( + height: 5, + ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Colors.white10, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + children: [ + InkWell( + onTap: () { + int maxProgress = 100; + steps.forEach((element) { + maxProgress -= element.progress; + }); + if (maxProgress > 0) { + showStepEditor(context, maxProgress: maxProgress, onChange: (step) { + steps.add(step); + setState(() {}); + }); + } else { + showAlertDialog(context, 'Progress full', + 'Progress has already reached 100%, Cannot add more steps since the work is done'); + } + }, + child: Container(margin: EdgeInsets.all(10), child: Icon(Icons.add))), + InkWell( + enableFeedback: (steps.length > 0), + onTap: () { + int maxProgress = 100; + steps.forEach((element) { + maxProgress -= element.progress; + }); + int stepProgress = steps[selectedStep].progress; + showStepEditor(context, + editStep: steps[selectedStep], + maxProgress: (maxProgress > stepProgress) ? maxProgress : stepProgress, onChange: (step) { + steps[selectedStep] = step; + setState(() {}); + }); + }, + child: Container( + margin: EdgeInsets.all(10), + child: Icon(Icons.edit, color: (steps.length > 0) ? Colors.white : Colors.grey))), + InkWell(onTap: () { + if(steps.length <= 0){return;} + steps.remove(steps[selectedStep]); setState(() { }); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30), - color: (knowEta) ? Colors.white10 :Colors.redAccent - ), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20,vertical: 10), - child: Text("I have no idea"), - ) - ), - ) - ], - ), - SizedBox( - height: 20, - ), - Container( - padding: EdgeInsets.all(8), - child: Text("Deadline")), - InkWell( - onTap: () { - DatePicker.showDatePicker( - context, - showTitleActions: true, - minTime: DateTime.now(), - theme: DatePickerTheme(backgroundColor: Colors.white), - onChanged: (date) { - // print('change $date'); - }, onConfirm: (date) { - setState(() { - if(deadline.isAfter(DateTime.now())){ - deadline=date; - }else{ - showAlertDialog(context, 'Come on!', 'Deadline was passed?'); - } - }); - }, - currentTime: deadline, - locale: LocaleType.en); - setState(() { - - }); - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white10, - borderRadius: - BorderRadius.circular(30), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 100, vertical: 10), - child: Text(DateFormat("MMMM dd yyyy").format(deadline)), - ), - ), - ), - ], - ))), - - Container( - padding: - EdgeInsets.symmetric(vertical: 10, horizontal: 20), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Expanded( - flex: 5, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 0), - child: ElevatedButton( - style: ElevatedButton.styleFrom( - primary: Colors.red, - shape: StadiumBorder()), - onPressed: () { - setState(() { - Navigator.pop(context); + }, child: Container(margin: EdgeInsets.all(10), child: Icon(Icons.remove, color: (steps.length > 0) ? Colors.white : Colors.grey))), + ], + )) + ], + ) + ], + ) + : Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container(padding: EdgeInsets.all(10), child: Text("Estimated Time to reach target")), + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + InkWell( + onTap: () { + showDurationSelector(context, selectedHour: etaHours, onChange: (newVal) { + etaHours = newVal.inHours; + knowEta = true; + setState(() {}); + print("Selected $newVal"); }); }, - child: Text('Back', - style: TextStyle(fontSize: 20))))), - Expanded( - flex: 6, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 10, vertical: 0), - child: ElevatedButton( - style: ElevatedButton.styleFrom( - primary: Colors.green, - shape: StadiumBorder()), - onPressed: () {}, - child: Text('Next', - style: TextStyle(fontSize: 20))))), - ], - )) - ]))); + child: Container( + decoration: BoxDecoration( + color: (knowEta) ? Colors.green : Colors.white10, + borderRadius: BorderRadius.circular(30), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 10), + child: Text("${(knowEta) ? etaHours : '?'} Hours"), + ), + ), + ), + InkWell( + onTap: () { + knowEta = false; + setState(() {}); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), color: (knowEta) ? Colors.white10 : Colors.redAccent), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + child: Text("I have no idea"), + )), + ) + ], + ), + SizedBox( + height: 20, + ), + Container(padding: EdgeInsets.all(8), child: Text("Deadline")), + InkWell( + onTap: () { + DatePicker.showDatePicker(context, + showTitleActions: true, + minTime: DateTime.now(), + theme: DatePickerTheme(backgroundColor: Colors.white), onChanged: (date) { + // print('change $date'); + }, onConfirm: (date) { + setState(() { + if (deadline.isAfter(DateTime.now())) { + deadline = date; + } else { + showAlertDialog(context, 'Come on!', 'Deadline was passed?'); + } + }); + }, currentTime: deadline, locale: LocaleType.en); + setState(() {}); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white10, + borderRadius: BorderRadius.circular(30), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 100, vertical: 10), + child: Text(DateFormat("MMMM dd yyyy").format(deadline)), + ), + ), + ), + ], + ))), + Container( + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + flex: 5, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0), + child: ElevatedButton( + style: ElevatedButton.styleFrom(primary: Colors.red, shape: StadiumBorder()), + onPressed: () { + setState(() { + Navigator.pop(context); + }); + }, + child: Text('Back', style: TextStyle(fontSize: 20))))), + Expanded( + flex: 6, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0), + child: ElevatedButton( + style: ElevatedButton.styleFrom(primary: Colors.green, shape: StadiumBorder()), + onPressed: () {}, + child: Text('Next', style: TextStyle(fontSize: 20))))), + ], + )) + ]))); } + int selectedStep = 0; - List printSteps(){ + List printSteps() { List _steps = []; - for(int i=0; i < steps.) - _steps.add( - InkWell(onTap:(){se},child: Container(padding:EdgeInsets.symmetric(horizontal: 10,vertical: 2),child: Row(mainAxisSize:MainAxisSize.max,mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [Text(value.stepName), Icon(Icons.timelapse), Text(value.eta.toString() + " Hours")],)))); + for (int i = 0; i < steps.length; i++) { + ProjectStep value = steps[i]; + _steps.add(InkWell( + onTap: () { + selectedStep = i; + setState(() {}); + }, + child: Container( + height: 30, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), color: (selectedStep == i) ? Colors.black26 : null), + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(flex: 4, child: Text(value.stepName)), + // Expanded(flex:1,child: Icon(Icons.timelapse)), + Expanded(flex: 1, child: Text("${value.progress}%")), + Expanded( + flex: 3, + child: Text( + value.eta.toString() + " Hours", + textAlign: TextAlign.end, + )) + ], + )))); } return _steps; } + + Future showStepEditor(BuildContext context, {required Function(ProjectStep) onChange, ProjectStep? editStep, int? maxProgress}) async { + TextEditingController nameController = TextEditingController(); + int progress = 1; + int eta = 1; + bool editing = false; + int _maxP = maxProgress ?? 100; + + if (editStep != null) { + editing = true; + nameController.text = editStep.stepName; + eta = editStep.eta; + progress = editStep.progress; + } + + return showDialog( + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return StatefulBuilder(builder: (context, setState) { + setState(() {}); + return AlertDialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), + backgroundColor: Color(0xFF1F1F1F), + title: Align(alignment: Alignment.center, child: Text((editing) ? 'Edit step' : 'Add new step')), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Step name'), + TextField( + controller: nameController, + decoration: InputDecoration( + filled: true, hintText: 'Collect resources', border: OutlineInputBorder(borderRadius: BorderRadius.circular(20))), + style: TextStyle(fontSize: 15), + ) + ], + ), + SizedBox( + height: 20, + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Progress : $progress%'), + Slider( + min: 1, + max: _maxP.toDouble(), + value: progress.toDouble(), + onChanged: (val) { + progress = val.toInt(); + setState(() {}); + }, + label: 'Progress', + ), + ], + ), + SizedBox( + height: 20, + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(4.0), + child: Text('Estimated Time'), + ), + InkWell( + onTap: () { + showDurationSelector(context, selectedHour: eta, onChange: (newVal) { + eta = newVal.inHours; + setState(() {}); + print("Selected $newVal"); + }); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white10, + borderRadius: BorderRadius.circular(30), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 10), + child: Text("${eta} Hours"), + ), + ), + ) + ], + ), + ], + ), + actions: [ + TextButton( + child: const Text('Cancel'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + MaterialButton( + color: Colors.green, + child: Text((editing) ? 'Apply' : 'Add'), + onPressed: () { + ProjectStep step = ProjectStep(nameController.text, eta, progress); + onChange(step); + Navigator.of(context).pop(); + }, + ), + ], + ); + }); + }, + ); + } }