diff --git a/src/timemanagerapp/lib/main.dart b/src/timemanagerapp/lib/main.dart index cd4b247..d410fc6 100644 --- a/src/timemanagerapp/lib/main.dart +++ b/src/timemanagerapp/lib/main.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:timemanagerapp/setting/Setting.dart'; import 'package:timemanagerapp/widgets/HomeWidget.dart'; +import 'package:timemanagerapp/provider/TimeProvider.dart'; init() async { WidgetsFlutterBinding.ensureInitialized(); @@ -18,10 +20,15 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { Setting.deviceWidth = MediaQuery.of(context).size.width; - return MaterialApp( - home: Scaffold( - body: HomeWidget(), + return MultiProvider( //全局状态管理Timetable + providers: [ + ChangeNotifierProvider(create: (ctx) => TimeProvider()), + ], + child: MaterialApp( + home: Scaffold( + body: HomeWidget(), + ), ), - ); + ); // MaterialApp } } diff --git a/src/timemanagerapp/lib/provider/TimeProvider.dart b/src/timemanagerapp/lib/provider/TimeProvider.dart new file mode 100644 index 0000000..6c3ae50 --- /dev/null +++ b/src/timemanagerapp/lib/provider/TimeProvider.dart @@ -0,0 +1,18 @@ +import 'package:flutter/cupertino.dart'; + +class TimeProvider extends ChangeNotifier { + int _updatTimtTablecount = 0; + + int get updatTimtTablecount => _updatTimtTablecount; + + + set updatTimtTablecount(int value) { + _updatTimtTablecount = value; + notifyListeners(); + } + + void updateTimetable() { + _updatTimtTablecount = ~_updatTimtTablecount; + notifyListeners(); + } +} \ No newline at end of file diff --git a/src/timemanagerapp/lib/widgets/AddCourseFormWidget.dart b/src/timemanagerapp/lib/widgets/AddCourseFormWidget.dart index 16eb08f..1a791e4 100644 --- a/src/timemanagerapp/lib/widgets/AddCourseFormWidget.dart +++ b/src/timemanagerapp/lib/widgets/AddCourseFormWidget.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; import 'package:multi_select_flutter/dialog/multi_select_dialog_field.dart'; import 'package:multi_select_flutter/util/multi_select_item.dart'; +import 'package:provider/provider.dart'; import 'package:timemanagerapp/controller/CourseController.dart'; import 'package:timemanagerapp/entity/CourseForm.dart'; + +import '../provider/TimeProvider.dart'; class AddCourseFormWidget extends StatefulWidget { const AddCourseFormWidget({Key? key}) : super(key: key); @@ -181,27 +184,39 @@ class _AddCourseFormWidgetState extends State { }, child: Text('取消'), ), - ElevatedButton( - onPressed: () { - // 点击确定按钮后的操作 - if (_formKey.currentState!.validate()) { - _formKey.currentState!.save(); - // 在这里执行表单提交操作 - courseForm.course = course; - courseForm.credit = double.parse(credit); - courseForm.note = note; - courseForm.location = location; - courseForm.selectedDays = selectedDays.map((e) => weekdayMap[e]!).toList(); - courseForm.startWeek = int.parse(startWeek); - courseForm.endWeek = int.parse(endWeek); - courseForm.startTime = int.parse(startTime); - courseForm.endTime = int.parse(endTime); - courseForm.teacher = teacher; - courseController.addCourseForm(courseForm).then((value) => Navigator.pop(context)); // 关闭当前界面 + Selector( // time状态改变时会重新构建子树 + selector: (ctx, provider) => provider, + shouldRebuild: (pre, next) => false, + builder: (ctx, timePro, child) { + return ElevatedButton( + onPressed: () { + // 点击确定按钮后的操作 + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + // 在这里执行表单提交操作 + courseForm.course = course; + courseForm.credit = double.parse(credit); + courseForm.note = note; + courseForm.location = location; + courseForm.selectedDays = selectedDays.map((e) => weekdayMap[e]!).toList(); + courseForm.startWeek = int.parse(startWeek); + courseForm.endWeek = int.parse(endWeek); + courseForm.startTime = int.parse(startTime); + courseForm.endTime = int.parse(endTime); + courseForm.teacher = teacher; + courseController.addCourseForm(courseForm).then(((value){ + // 关闭当前界面 + timePro.updateTimetable(); + timePro.updatTimtTablecount = 100; + Navigator.pop(context); - } + })); + }; + }, + child: Text('确定'), + ); }, - child: Text('确定'), + // child: Icon(Icons.add), ), ], ), diff --git a/src/timemanagerapp/lib/widgets/AutoImportWidget.dart b/src/timemanagerapp/lib/widgets/AutoImportWidget.dart new file mode 100644 index 0000000..63222e6 --- /dev/null +++ b/src/timemanagerapp/lib/widgets/AutoImportWidget.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:timemanagerapp/controller/courseController.dart'; + +import '../entity/course.dart'; +import '../provider/TimeProvider.dart'; + +class AutoImportWidget extends StatefulWidget { + @override + _AutoImportWidgetState createState() => _AutoImportWidgetState(); +} + +class _AutoImportWidgetState extends State { + final CourseController courseController = CourseController.getInstance(); + final TextEditingController stuIdController = TextEditingController(); + final TextEditingController passwordController = TextEditingController(); + final TextEditingController yearController = TextEditingController(); + final TextEditingController termController = TextEditingController(); + + Future handleAutoImport(BuildContext context) async { + int stuId = int.parse(stuIdController.text); + String password = passwordController.text; + int year = int.parse(yearController.text); + int term = int.parse(termController.text); + int res = await courseController.autoImportCours(stuId, password,year,term); + if(res!=0) { + Provider.of(context, listen: false).updateTimetable(); // 更新操作 + Navigator.pop(context); + }else{ + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('用户名或密码错误')) + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('自动导入校园账号课程'), + ), + body: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextFormField( + controller: stuIdController, + decoration: InputDecoration( + labelText: '账号', + ), + ), + SizedBox(height: 16.0), + TextFormField( + controller: passwordController, + obscureText: true, // 密码输入框,隐藏文本 + decoration: InputDecoration( + labelText: '密码', + ), + ), + SizedBox(height: 16.0), + TextFormField( + controller: yearController, + decoration: InputDecoration( + labelText: '学年', + ), + ), + SizedBox(height: 16.0), + TextFormField( + controller: termController, + decoration: InputDecoration( + labelText: '学期', + ), + ), + SizedBox(height: 24.0), + ElevatedButton( + onPressed: () => handleAutoImport(context), // 传递context + child: Text('导入'), + ), + ], + ), + ), + ), + ); + } +} diff --git a/src/timemanagerapp/lib/widgets/TimetableWidget.dart b/src/timemanagerapp/lib/widgets/TimetableWidget.dart index d065fda..8ed815f 100644 --- a/src/timemanagerapp/lib/widgets/TimetableWidget.dart +++ b/src/timemanagerapp/lib/widgets/TimetableWidget.dart @@ -2,16 +2,19 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:timemanagerapp/controller/CourseController.dart'; import 'package:timemanagerapp/controller/CourseWidgetController.dart'; import '../entity/Course.dart'; +import '../provider/TimeProvider.dart'; import '../setting/Setting.dart'; class TimetableWidget extends StatefulWidget { - final double deviceWidth=Setting.deviceWidth; + final double deviceWidth = Setting.deviceWidth; @override - State createState() => TimetableWidgetState(deviceWidth: deviceWidth); + State createState() => + TimetableWidgetState(deviceWidth: deviceWidth); } class TimetableWidgetState extends State { @@ -71,318 +74,351 @@ class TimetableWidgetState extends State { } } - //执行初始化,将需要的数值进行加工 - @override - initState() { - super.initState(); - - courseController.getCourses().then((res) { - courseList = res; - - //数据初始化 - //获取数据库课程表 - // courseList = await courseController.getCourses(); - //获取本周星期一是几号 - var mondayTime = courseWidgetController.getmondayTime(); - currentWeek = courseWidgetController.getWeekCount(); - weekCount = currentWeek; - // courseList = CourseWidgetController.testcourseList; - weekCount = courseWidgetController.getWeekCount(); - courseWeekMap = courseWidgetController.transformCourseMap(courseList); + Future futureDo() async { + courseList = await courseController.getCourses(); + //数据初始化 + //获取数据库课程表 + // courseList = await courseController.getCourses(); + //获取本周星期一是几号 + var mondayTime = courseWidgetController.getmondayTime(); + currentWeek = courseWidgetController.getWeekCount(); + weekCount = currentWeek; + // courseList = CourseWidgetController.testcourseList; + weekCount = courseWidgetController.getWeekCount(); + courseWeekMap = courseWidgetController.transformCourseMap(courseList); - //初始化日期列表 - for (int i = 0; i < 7; i++) { - dateListstr.add((mondayTime.day + i).toString()); - if ((mondayTime.day + i) == DateTime.now().day) { - currentWeekDayIndex = i + 1; - } + //初始化日期列表 + for (int i = 0; i < 7; i++) { + dateListstr.add((mondayTime.day + i).toString()); + if ((mondayTime.day + i) == DateTime.now().day) { + currentWeekDayIndex = i + 1; } - // print('Recent monday '+DateTime.now().day.toString()); + } + // print('Recent monday '+DateTime.now().day.toString()); - //调用函数初始化时间轴的绝对坐标 - positions = - courseWidgetController.convertTimeList(timePoints, deviceWidth); + //调用函数初始化时间轴的绝对坐标 + positions = courseWidgetController.convertTimeList(timePoints, deviceWidth); + } - setState(() { - loading = false; - }); - }); + //执行初始化,将需要的数值进行加工 + @override + initState() { + super.initState(); } @override - Widget build(BuildContext context) { - if (loading == false) { - return GestureDetector( - onHorizontalDragEnd: (details) { - if (details.primaryVelocity! > 0) { - // 右滑 - setState(() { - weekCount--; - updateDateByWeekCount(); - }); - } else if (details.primaryVelocity! < 0) { - // 左滑 - setState(() { - weekCount++; - updateDateByWeekCount(); - }); - } - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, //垂直方向居中对齐 - children: [ - SizedBox( - //顶部的周数和日期 - //显示第一行的周天数和日期 - child: GridView.builder( - shrinkWrap: true, - //解决无限高度问题 - physics: NeverScrollableScrollPhysics(), - //禁用滑动事件 - itemCount: 8, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 8, childAspectRatio: 1 / 1), - //每行显示的数量 - itemBuilder: (BuildContext context, int index) { - //构建每个item的样式 - return Container( - color: index == this.currentWeekDayIndex - ? Color(0xf7f7f7) //如果是当前周,就显示灰色 - : Colors.white, - child: Center( - child: index == 0 - ? Column( - //第一行显示第几周 - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - // height: 10, - // width: 6, - child: Text( - '第' + weekCount.toString() + '周', //显示周数 - style: TextStyle( - fontSize: 12, - color: currentWeek == - weekCount //如果是当前周,就显示蓝色 - ? Colors.amber - : Colors.black87)), - ), - ], - ) - : Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(weekList[index - 1], //显示周数 - style: TextStyle( - fontSize: 14, - color: index == - currentWeekDayIndex //如果是当前周,就显示蓝色 - ? Colors.lightBlue - : Colors.black87)), - SizedBox( - height: 5, - ), - Text(dateListstr[index - 1], //显示日期 - style: TextStyle( - fontSize: 12, - color: index == - currentWeekDayIndex //如果是当前周,就显示蓝色 - ? Colors.lightBlue - : Colors.black87)), - ], - ), - ), - ); - }), - ), - //显示下面的界面中的两个stack,一个下层的时间轴,一个是上层课程或者人物的方块 - Expanded( - child: SingleChildScrollView( - child: Row( - children: [ - //借助两个stack重叠,实现效果 - Container( - width: deviceWidth, - height: 2000, - child: Stack( - alignment: Alignment.center, - children: [ - // 第一个Stack - Positioned( - top: 0, - left: 0, - child: Container( - width: deviceWidth, - height: 2000, - child: Stack( - children: List.generate( - //根据时间轴的长度,生成对应的时间轴 - positions.length, - (index) => Positioned( - top: positions[index].dy, - left: positions[index].dx, - child: Row( - children: [ - Text( - timePoints[index] - .hour - .toString() - .padLeft(2, '0') + - ':' + - timePoints[index] - .minute - .toString() - .padLeft(2, '0'), - ), - - Container( - width: deviceWidth * 0.04, - height: 10, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: Colors.amber, - width: 2, - ), + Widget build(BuildContext contexvoidt) { + return Consumer( + builder: (ctx, timePro, child) { + print('Rebuild timePro.updatTimtTablecount = ' + timePro.updatTimtTablecount.toString()); + return FutureBuilder( + future: futureDo(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + // 请求已结束 + if (snapshot.connectionState == ConnectionState.done) { + return RefreshIndicator( + onRefresh: () { + return futureDo().then((value) => setState(() {})); + }, + child: GestureDetector( + onHorizontalDragEnd: (details) { + if (details.primaryVelocity! > 0) { + // 右滑 + setState(() { + weekCount--; + updateDateByWeekCount(); + }); + } else if (details.primaryVelocity! < 0) { + // 左滑 + setState(() { + weekCount++; + updateDateByWeekCount(); + }); + } + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, //垂直方向居中对齐 + children: [ + SizedBox( + //顶部的周数和日期 + //显示第一行的周天数和日期 + child: GridView.builder( + shrinkWrap: true, + //解决无限高度问题 + physics: NeverScrollableScrollPhysics(), + //禁用滑动事件 + itemCount: 8, + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 8, childAspectRatio: 1 / 1), + //每行显示的数量 + itemBuilder: (BuildContext context, int index) { + //构建每个item的样式 + return Container( + color: index == this.currentWeekDayIndex + ? Color(0xf7f7f7) //如果是当前周,就显示灰色 + : Colors.white, + child: Center( + child: index == 0 + ? Column( + //第一行显示第几周 + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Container( + // height: 10, + // width: 6, + child: Text( + '第' + + weekCount.toString() + + '周', //显示周数 + style: TextStyle( + fontSize: 12, + color: currentWeek == + weekCount //如果是当前周,就显示蓝色 + ? Colors.amber + : Colors.black87)), + ), + ], + ) + : Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Text(weekList[index - 1], //显示周数 + style: TextStyle( + fontSize: 14, + color: index == + currentWeekDayIndex //如果是当前周,就显示蓝色 + ? Colors.lightBlue + : Colors.black87)), + SizedBox( + height: 5, ), - ), - Container( - width: deviceWidth * 0.84, - height: 2, - color: const Color.fromARGB( - 255, 136, 61, 61), - ), - ], + Text(dateListstr[index - 1], //显示日期 + style: TextStyle( + fontSize: 12, + color: index == + currentWeekDayIndex //如果是当前周,就显示蓝色 + ? Colors.lightBlue + : Colors.black87)), + ], + ), ), - ), - ), - ), - )), - //第二个Stack - Container( - constraints: - BoxConstraints.expand(), // 使用constraints来自适应 - // width: 390, - // height: 2000, - child: Stack( - children: List.generate( - //根据课程的数量,生成对应的课程方块 - courseWeekMap.containsKey(weekCount) - ? courseWeekMap[weekCount]!.length - : 0, - ((index) => Positioned( - top: courseWeekMap[weekCount]![index] - .getdy() + - 10, - left: courseWeekMap[weekCount]![index] - .getdx() + - deviceWidth*0.15, - child: SingleChildScrollView( - child: Container( - //课程方块 - width: deviceWidth * 0.115, - height: - courseWeekMap[weekCount]![index] - .getHeight(), - decoration: BoxDecoration( - color: Colors.tealAccent, - // 设置颜色 - borderRadius: BorderRadius.all( - Radius.circular( - 10.0)), // 添加圆角 - ), - child: SingleChildScrollView( - child: Column( - //课程方块中的文字 - children: [ - Text( - courseWeekMap[weekCount]![ - index] - .name, - style: TextStyle( - fontSize: 10, - fontWeight: - FontWeight.bold), - overflow: TextOverflow - .clip, //name加粗 - ), - Text( - courseWeekMap[weekCount]![ - index] - .teacher, - style: - TextStyle(fontSize: 8), - overflow: TextOverflow.clip, - ), - Text( - courseWeekMap[weekCount]![ - index] - .location, - style: - TextStyle(fontSize: 10), - overflow: TextOverflow.clip, - ), - Text( - courseWeekMap[weekCount]![ - index] - .start - .hour - .toString() + - ':' + - courseWeekMap[ - weekCount]![ - index] - .start - .minute - .toString(), - style: - TextStyle(fontSize: 10), - overflow: TextOverflow.clip, - ), - Text( - courseWeekMap[weekCount]![ - index] - .end - .hour - .toString() + - ':' + - courseWeekMap[ - weekCount]![ - index] - .end - .minute - .toString(), - style: - TextStyle(fontSize: 10), - overflow: TextOverflow.clip, - ), - Text( - courseWeekMap[weekCount]![ - index] - .remark, - style: - TextStyle(fontSize: 10), - overflow: TextOverflow.clip, + ); + }), + ), + //显示下面的界面中的两个stack,一个下层的时间轴,一个是上层课程或者人物的方块 + Expanded( + child: SingleChildScrollView( + child: Row( + children: [ + //借助两个stack重叠,实现效果 + Container( + width: deviceWidth, + height: 2000, + child: Stack( + alignment: Alignment.center, + children: [ + // 第一个Stack + Positioned( + top: 0, + left: 0, + child: Container( + width: deviceWidth, + height: 2000, + child: Stack( + children: List.generate( + //根据时间轴的长度,生成对应的时间轴 + positions.length, + (index) => Positioned( + top: positions[index].dy, + left: positions[index].dx, + child: Row( + children: [ + Text( + timePoints[index] + .hour + .toString() + .padLeft(2, '0') + + ':' + + timePoints[index] + .minute + .toString() + .padLeft(2, '0'), + ), + Container( + width: deviceWidth * 0.04, + height: 10, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: Colors.amber, + width: 2, + ), + ), + ), + Container( + width: deviceWidth * 0.84, + height: 2, + color: const Color.fromARGB( + 255, 136, 61, 61), + ), + ], + ), + ), ), - ], - ), - ), - ), - ), - ))), - )) - ], + ), + )), + //第二个Stack + Container( + constraints: BoxConstraints + .expand(), // 使用constraints来自适应 + // width: 390, + // height: 2000, + child: Stack( + children: List.generate( + //根据课程的数量,生成对应的课程方块 + courseWeekMap.containsKey(weekCount) + ? courseWeekMap[weekCount]!.length + : 0, + ((index) => Positioned( + top: courseWeekMap[weekCount]![ + index] + .getdy() + + 10, + left: courseWeekMap[weekCount]![ + index] + .getdx() + + deviceWidth * 0.15, + child: SingleChildScrollView( + child: Container( + //课程方块 + width: deviceWidth * 0.115, + height: courseWeekMap[ + weekCount]![index] + .getHeight(), + decoration: BoxDecoration( + color: Colors.tealAccent, + // 设置颜色 + borderRadius: BorderRadius + .all(Radius.circular( + 10.0)), // 添加圆角 + ), + child: + SingleChildScrollView( + child: Column( + //课程方块中的文字 + children: [ + Text( + courseWeekMap[ + weekCount]![ + index] + .name, + style: TextStyle( + fontSize: 10, + fontWeight: + FontWeight + .bold), + overflow: TextOverflow + .clip, //name加粗 + ), + Text( + courseWeekMap[ + weekCount]![ + index] + .teacher, + style: TextStyle( + fontSize: 8), + overflow: + TextOverflow + .clip, + ), + Text( + courseWeekMap[ + weekCount]![ + index] + .location, + style: TextStyle( + fontSize: 10), + overflow: + TextOverflow + .clip, + ), + Text( + courseWeekMap[weekCount]![ + index] + .start + .hour + .toString() + + ':' + + courseWeekMap[ + weekCount]![ + index] + .start + .minute + .toString(), + style: TextStyle( + fontSize: 10), + overflow: + TextOverflow + .clip, + ), + Text( + courseWeekMap[weekCount]![ + index] + .end + .hour + .toString() + + ':' + + courseWeekMap[ + weekCount]![ + index] + .end + .minute + .toString(), + style: TextStyle( + fontSize: 10), + overflow: + TextOverflow + .clip, + ), + Text( + courseWeekMap[ + weekCount]![ + index] + .remark, + style: TextStyle( + fontSize: 10), + overflow: + TextOverflow + .clip, + ), + ], + ), + ), + ), + ), + ))), + )) + ], + ), + ), + ], + ), + )) + ], + ), ), - ), - ], - ), - )) - ], - ), - ); - } - return Container( - child: Text('加载中'), + ); + } else { + return Center( + child: CircularProgressIndicator(), + ); + } + }); + } ); + } } diff --git a/src/timemanagerapp/pubspec.lock b/src/timemanagerapp/pubspec.lock index 9c5c20d..85ca9a2 100644 --- a/src/timemanagerapp/pubspec.lock +++ b/src/timemanagerapp/pubspec.lock @@ -168,6 +168,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "4.1.3" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" path: dependency: "direct main" description: @@ -240,6 +248,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.1.6" + provider: + dependency: "direct main" + description: + name: provider + sha256: "59471e0a4595e264625d3496af567ac85bdae1148ec985aff1e0555786f53ecf" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.0" shared_preferences: dependency: "direct main" description: diff --git a/src/timemanagerapp/pubspec.yaml b/src/timemanagerapp/pubspec.yaml index 5273524..43f7566 100644 --- a/src/timemanagerapp/pubspec.yaml +++ b/src/timemanagerapp/pubspec.yaml @@ -42,6 +42,7 @@ dependencies: multi_select_flutter: 4.1.3 http: ^1.1.0 device_info: + provider: ^5.0.0 dev_dependencies: