|
|
|
|
@ -0,0 +1,512 @@
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
import 'package:timemanagerapp/controller/TeamController.dart';
|
|
|
|
|
|
|
|
|
|
import '../controller/TimetableWidgetController.dart';
|
|
|
|
|
import '../entity/FreeTime.dart';
|
|
|
|
|
import '../entity/Team.dart';
|
|
|
|
|
import '../provider/TimeProvider.dart';
|
|
|
|
|
import '../setting/Setting.dart';
|
|
|
|
|
|
|
|
|
|
class FreeTimetableWidget extends StatefulWidget {
|
|
|
|
|
FreeTimetableWidget({Key ? key,required this.team}) : super(key: key);
|
|
|
|
|
final double deviceWidth = Setting.deviceWidth;
|
|
|
|
|
final Team team;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<StatefulWidget> createState() =>
|
|
|
|
|
FreeTimetableWidgetState(deviceWidth: deviceWidth,team: team);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class FreeTimetableWidgetState extends State<FreeTimetableWidget> {
|
|
|
|
|
FreeTimetableWidgetState({required this.deviceWidth,required this.team});
|
|
|
|
|
|
|
|
|
|
late double deviceWidth;
|
|
|
|
|
int firstInit = 0;
|
|
|
|
|
final Team team;
|
|
|
|
|
|
|
|
|
|
//控制器
|
|
|
|
|
late TimetableWidgetController timetableWidgetController =
|
|
|
|
|
TimetableWidgetController();
|
|
|
|
|
late TeamController teamController = TeamController();
|
|
|
|
|
|
|
|
|
|
late List freeTimeBlockList = [];
|
|
|
|
|
late Map<int,List> freeTimeBlockWeekMap = {};
|
|
|
|
|
|
|
|
|
|
//第一行显示的周几的数据
|
|
|
|
|
var weekList = ['一', '二', '三', '四', '五', '六', '日'];
|
|
|
|
|
//自定义的几个数据,其中信息并不很全,但是目前足够制作课表界面
|
|
|
|
|
|
|
|
|
|
//日期的列表,第一行周下面的数据相对应
|
|
|
|
|
var dateListstr = [];
|
|
|
|
|
//当前周的下标,会变为蓝色字体
|
|
|
|
|
var currentWeekDayIndex = 0;
|
|
|
|
|
|
|
|
|
|
//当前周数
|
|
|
|
|
int showWeek = 0;
|
|
|
|
|
int currentWeek = 0;
|
|
|
|
|
String showWeekstr = '第1周';
|
|
|
|
|
|
|
|
|
|
int showMonth = 0;
|
|
|
|
|
|
|
|
|
|
final double hourHeight = 60.0 * 1.5;
|
|
|
|
|
//预设的时间轴的值,由于时间轴是由课表得来,所以这里是DateTime类型,需要经过一次转换为Piexl的值
|
|
|
|
|
List<DateTime> timePoints = [
|
|
|
|
|
DateTime(2023, 9, 22, 7, 30),
|
|
|
|
|
DateTime(2023, 9, 22, 8, 0), // 8:00 AM
|
|
|
|
|
DateTime(2023, 9, 22, 9, 35), // 8:15 PM
|
|
|
|
|
DateTime(2023, 9, 22, 10, 5),
|
|
|
|
|
DateTime(2023, 9, 22, 11, 40),
|
|
|
|
|
DateTime(2023, 9, 22, 12, 30),
|
|
|
|
|
DateTime(2023, 9, 22, 13, 30),
|
|
|
|
|
DateTime(2023, 9, 22, 15, 5), // 8:00 AM
|
|
|
|
|
DateTime(2023, 9, 22, 15, 35), // 12:30 PM
|
|
|
|
|
DateTime(2023, 9, 22, 17, 10),
|
|
|
|
|
DateTime(2023, 9, 22, 18, 30),
|
|
|
|
|
DateTime(2023, 9, 22, 19, 15), // 8:00 AM
|
|
|
|
|
DateTime(2023, 9, 22, 20, 5), // 12:30 PM
|
|
|
|
|
DateTime(2023, 9, 22, 20, 55),
|
|
|
|
|
DateTime(2023, 9, 22, 21, 40),
|
|
|
|
|
];
|
|
|
|
|
//时间轴的集合,类型为Offset
|
|
|
|
|
var positions = [];
|
|
|
|
|
|
|
|
|
|
bool loading = true;
|
|
|
|
|
|
|
|
|
|
Future<void> serverFutureDo() async {
|
|
|
|
|
print('开始serverFutureDo');
|
|
|
|
|
|
|
|
|
|
//获取数据库课程表
|
|
|
|
|
freeTimeBlockList = await teamController.getFreeTime(team.getId!);
|
|
|
|
|
|
|
|
|
|
dataCaculateAfterFutherDo();
|
|
|
|
|
|
|
|
|
|
print('serverFutureDo 完成');
|
|
|
|
|
setState(() {});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//执行初始化,将需要的数值进行加工
|
|
|
|
|
@override
|
|
|
|
|
initState() {
|
|
|
|
|
super.initState();
|
|
|
|
|
//初始化
|
|
|
|
|
freeTimeBlockWeekMap = {};
|
|
|
|
|
freeTimeBlockList = [];
|
|
|
|
|
|
|
|
|
|
//设置当前周
|
|
|
|
|
currentWeek = timetableWidgetController.getWeekCount();
|
|
|
|
|
showWeek = currentWeek;
|
|
|
|
|
// showWeek = 1;
|
|
|
|
|
//
|
|
|
|
|
showMonth = DateTime.now().month;
|
|
|
|
|
|
|
|
|
|
dataCaculateAfterFutherDo();
|
|
|
|
|
|
|
|
|
|
serverFutureDo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dataCaculateAfterFutherDo() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
freeTimeBlockWeekMap = {};
|
|
|
|
|
freeTimeBlockWeekMap =
|
|
|
|
|
timetableWidgetController.transformTimeBlockMap(freeTimeBlockList);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var mondayTime = timetableWidgetController.getmondayTime();
|
|
|
|
|
|
|
|
|
|
//showMon
|
|
|
|
|
showMonth = mondayTime.add(Duration(days: 7 * (showWeek - currentWeek))).month;
|
|
|
|
|
|
|
|
|
|
//更新初始化日期列表
|
|
|
|
|
dateListstr = [];
|
|
|
|
|
for (int i = 0; i < 7; i++) {
|
|
|
|
|
dateListstr.add(mondayTime
|
|
|
|
|
.add(Duration(days: i + 7 * (showWeek - currentWeek)))
|
|
|
|
|
.day
|
|
|
|
|
.toString()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
//调用函数初始化时间轴的绝对坐标
|
|
|
|
|
positions =
|
|
|
|
|
timetableWidgetController.convertTimeList(timePoints, deviceWidth);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext contexvoidt) {
|
|
|
|
|
|
|
|
|
|
return Scaffold(
|
|
|
|
|
appBar: AppBar(
|
|
|
|
|
title: Text(team.getTeamName+'的空闲时间表'),
|
|
|
|
|
),
|
|
|
|
|
body: Consumer<TimeProvider>(builder: (ctx, timePro, child) {
|
|
|
|
|
print('Rebuild timePro');
|
|
|
|
|
|
|
|
|
|
return RefreshIndicator(
|
|
|
|
|
onRefresh: () {
|
|
|
|
|
print('下拉refresh');
|
|
|
|
|
return serverFutureDo().then((value){
|
|
|
|
|
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); // 更新时间表页面操作
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
child: GestureDetector(
|
|
|
|
|
onHorizontalDragEnd: (details) {
|
|
|
|
|
// teamController.getFreeTime(tea).then((value){
|
|
|
|
|
// workList = value;
|
|
|
|
|
// setState(() {
|
|
|
|
|
//
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
serverFutureDo();
|
|
|
|
|
if (details.primaryVelocity! > 0) {
|
|
|
|
|
// 右滑
|
|
|
|
|
setState(() {
|
|
|
|
|
showWeek--;
|
|
|
|
|
});
|
|
|
|
|
} else if (details.primaryVelocity! < 0) {
|
|
|
|
|
// 左滑
|
|
|
|
|
setState(() {
|
|
|
|
|
showWeek++;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
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(
|
|
|
|
|
'第' +
|
|
|
|
|
showWeek.toString() +
|
|
|
|
|
'周', //显示周数
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
color: currentWeek ==
|
|
|
|
|
showWeek //如果是当前周,就显示蓝色
|
|
|
|
|
? Colors.amber
|
|
|
|
|
: Colors.black87)),
|
|
|
|
|
),
|
|
|
|
|
Container(
|
|
|
|
|
// height: 10,
|
|
|
|
|
// width: 6,
|
|
|
|
|
child: Text(
|
|
|
|
|
showMonth.toString() + '月', //显示月数
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
color: currentWeek ==
|
|
|
|
|
showWeek //如果是当前周,就显示蓝色
|
|
|
|
|
? 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,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Container(
|
|
|
|
|
width: deviceWidth * 0.84,
|
|
|
|
|
height: 2,
|
|
|
|
|
color: Colors.lightBlue
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
)),
|
|
|
|
|
//第二个Stack
|
|
|
|
|
Container(
|
|
|
|
|
constraints: BoxConstraints
|
|
|
|
|
.expand(), // 使用constraints来自适应
|
|
|
|
|
// width: 390,
|
|
|
|
|
// height: 2000,
|
|
|
|
|
child: Stack(
|
|
|
|
|
children: List.generate(
|
|
|
|
|
freeTimeBlockWeekMap
|
|
|
|
|
.containsKey(showWeek)
|
|
|
|
|
? freeTimeBlockWeekMap[showWeek]!
|
|
|
|
|
.length
|
|
|
|
|
: 0,
|
|
|
|
|
(index) {
|
|
|
|
|
var currentItem = freeTimeBlockWeekMap[
|
|
|
|
|
showWeek]![index];
|
|
|
|
|
return Positioned(
|
|
|
|
|
top: timetableWidgetController
|
|
|
|
|
.getdy(currentItem),
|
|
|
|
|
left: timetableWidgetController
|
|
|
|
|
.getdx(currentItem) +
|
|
|
|
|
deviceWidth * 0.15,
|
|
|
|
|
child: SingleChildScrollView(
|
|
|
|
|
child: Container(
|
|
|
|
|
width: deviceWidth * 0.115,
|
|
|
|
|
height:
|
|
|
|
|
timetableWidgetController
|
|
|
|
|
.getHeight(
|
|
|
|
|
currentItem),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: getItemColor(
|
|
|
|
|
currentItem),
|
|
|
|
|
borderRadius:
|
|
|
|
|
BorderRadius.all(
|
|
|
|
|
Radius.circular(10.0),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
child: SingleChildScrollView(
|
|
|
|
|
child: Column(
|
|
|
|
|
children: [
|
|
|
|
|
FreeTimeBlockContenWidget(
|
|
|
|
|
currentItem:
|
|
|
|
|
currentItem),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
))
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
))
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
;
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据类型返回对应的颜色
|
|
|
|
|
Color getItemColor(dynamic item) {
|
|
|
|
|
return Colors.tealAccent; // 默认颜色
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ShowTimeTextWidget extends StatelessWidget{
|
|
|
|
|
const ShowTimeTextWidget({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.currentItem
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
final currentItem;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return
|
|
|
|
|
ListBody(
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
Text(
|
|
|
|
|
'开始时间: ${currentItem.startTime.year}年' +
|
|
|
|
|
'${currentItem.startTime.month}月' +
|
|
|
|
|
'${currentItem.startTime.day.toString().padLeft(2, '0')}日 ' +
|
|
|
|
|
'${currentItem.startTime.hour.toString().padLeft(2, '0')}' +
|
|
|
|
|
':${currentItem.startTime.minute.toString().padLeft(2, '0')}',
|
|
|
|
|
),
|
|
|
|
|
Text('结束时间: ${currentItem.endTime.year}年' +
|
|
|
|
|
'${currentItem.endTime.month}月' +
|
|
|
|
|
'${currentItem.endTime.day.toString().padLeft(2, '0')}日 ' +
|
|
|
|
|
'${currentItem.endTime.hour.toString().padLeft(2, '0')}' +
|
|
|
|
|
':${currentItem.endTime.minute.toString().padLeft(2, '0')}',
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class BlockGestureWidget extends StatelessWidget {
|
|
|
|
|
const BlockGestureWidget({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.currentItem,
|
|
|
|
|
required this.blockGestureWidgetChilld,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
final currentItem;
|
|
|
|
|
final blockGestureWidgetChilld;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return GestureDetector(
|
|
|
|
|
onTap: () {
|
|
|
|
|
// 弹出大号弹窗
|
|
|
|
|
showDialog(
|
|
|
|
|
context: context,
|
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
|
return AlertDialog(
|
|
|
|
|
// 根据currentItem显示更多信息
|
|
|
|
|
title: Text(currentItem.name),
|
|
|
|
|
content: SingleChildScrollView(
|
|
|
|
|
child: ListBody(
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
if (currentItem is FreeTime) ...{
|
|
|
|
|
ShowTimeTextWidget(currentItem: currentItem),
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
actions: <Widget>[
|
|
|
|
|
TextButton(
|
|
|
|
|
child: Text('关闭'),
|
|
|
|
|
onPressed: () {
|
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
child: blockGestureWidgetChilld,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class FreeTimeBlockContenWidget extends StatelessWidget {
|
|
|
|
|
const FreeTimeBlockContenWidget({
|
|
|
|
|
super.key,
|
|
|
|
|
required this.currentItem,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
final currentItem;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return BlockGestureWidget(
|
|
|
|
|
currentItem: currentItem,
|
|
|
|
|
blockGestureWidgetChilld: Column(
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
(currentItem as FreeTime).startTime.hour.toString().padLeft(2, '0') +
|
|
|
|
|
':' +
|
|
|
|
|
(currentItem as FreeTime).startTime.minute.toString().padLeft(2, '0'),
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 10,
|
|
|
|
|
),
|
|
|
|
|
overflow: TextOverflow.clip,
|
|
|
|
|
),
|
|
|
|
|
Text(
|
|
|
|
|
(currentItem as FreeTime).endTime.hour.toString().padLeft(2, '0') +
|
|
|
|
|
':' +
|
|
|
|
|
(currentItem as FreeTime).endTime.minute.toString().padLeft(2, '0'),
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: 10,
|
|
|
|
|
),
|
|
|
|
|
overflow: TextOverflow.clip,
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|