Compare commits

..

3 Commits

54
.gitignore vendored

@ -1,54 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
**/.history
**/.svn/
**/migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
**/.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
**/vscode/
# Flutter/Dart/Pub related
**/src/timemanagerapp/.*
**/doc/api/
**/build/
**/ios/
**/linux/
**/macos/
**/web/
**/windows/
**/android/
**/.dart_tool/
**/.flutter-plugins
**/.flutter-plugins-dependencies
**/.packages
**/.pub-cache/
**/.pub/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
!.gitignore

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

@ -1,8 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="timemanagerapp"
android:label="多为时间"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/logo">
<activity
android:name=".MainActivity"
android:exported="true"
@ -30,4 +30,9 @@
android:name="flutterEmbedding"
android:value="2" />
</application>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@ -4,4 +4,9 @@
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

@ -0,0 +1,134 @@
/*
Navicat MySQL Data Transfer
Source Server : LRC_debian
Source Server Version : 50742
Source Host : 5902e9v900.zicp.fun:33006
Source Database : expressFrame02
Target Server Type : MYSQL
Target Server Version : 50742
File Encoding : 65001
Date: 2023-10-26 12:49:35
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for clocks
-- ----------------------------
DROP TABLE IF EXISTS `clocks`;
CREATE TABLE `clocks` (
`id` bigint(20) NOT NULL,
`clockId` bigint(20) NOT NULL,
`userId` bigint(20) NOT NULL,
`text` text,
`img` text,
`music` text,
PRIMARY KEY (`id`) USING BTREE,
KEY `fk_clocks_clocks_1` (`userId`),
CONSTRAINT `fk_clocks_clocks_1` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for course
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
`id` bigint(20) NOT NULL,
`userId` bigint(20) DEFAULT NULL,
`courseId` bigint(20) NOT NULL,
`name` text NOT NULL,
`credit` double DEFAULT NULL,
`teacher` text,
`location` text,
`remark` text,
`startTime` text NOT NULL,
`endTime` text NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `fk_course_course_1` (`userId`),
CONSTRAINT `fk_course_course_1` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for tasks
-- ----------------------------
DROP TABLE IF EXISTS `tasks`;
CREATE TABLE `tasks` (
`id` bigint(20) NOT NULL,
`taskId` bigint(20) NOT NULL,
`userId` bigint(20) NOT NULL,
`content` text,
`name` text NOT NULL,
`startTime` text NOT NULL,
`endTime` text NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `fk_tasks_tasks_1` (`userId`),
CONSTRAINT `fk_tasks_tasks_1` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for teams
-- ----------------------------
DROP TABLE IF EXISTS `teams`;
CREATE TABLE `teams` (
`id` bigint(20) NOT NULL,
`leaderId` bigint(20) NOT NULL,
`teamName` varchar(200) NOT NULL,
`maxNumber` bigint(20) DEFAULT NULL,
`introduce` text,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `teamName` (`teamName`) USING BTREE,
KEY `fk_teams_teams_1` (`leaderId`),
CONSTRAINT `fk_teams_teams_1` FOREIGN KEY (`leaderId`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` bigint(20) NOT NULL,
`username` varchar(255) NOT NULL,
`password` text NOT NULL,
`role` bigint(20) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for userteams
-- ----------------------------
DROP TABLE IF EXISTS `userteams`;
CREATE TABLE `userteams` (
`id` bigint(20) NOT NULL,
`userId` bigint(20) NOT NULL,
`teamId` bigint(20) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `fk_userteams_userteams_1` (`userId`),
KEY `fk_userteams_userteams_2` (`teamId`),
CONSTRAINT `fk_userteams_userteams_1` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_userteams_userteams_2` FOREIGN KEY (`teamId`) REFERENCES `teams` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for works
-- ----------------------------
DROP TABLE IF EXISTS `works`;
CREATE TABLE `works` (
`id` bigint(20) NOT NULL,
`userId` bigint(20) NOT NULL,
`workId` bigint(20) NOT NULL,
`teamId` bigint(20) NOT NULL,
`name` text NOT NULL,
`content` text,
`status` text,
`endTime` text NOT NULL,
`startTime` text NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `fk_works_works_1` (`userId`),
KEY `fk_works_works_2` (`teamId`),
CONSTRAINT `fk_works_works_1` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_works_works_2` FOREIGN KEY (`teamId`) REFERENCES `teams` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

@ -5,36 +5,16 @@ import 'package:timemanagerapp/entity/Task.dart';
import '../entity/Course.dart';
import '../entity/Course.dart';
import '../entity/FreeTime.dart';
import '../entity/Team.dart';
import '../entity/User.dart';
import '../entity/Work.dart';
class NetWorkController {
String baseUrl = "http://192.168.111.226:3000/";
// String baseUrl = "http://192.168.111.226:3000/";
// String baseUrl = "http://5902e9v900.zicp.fun:30002/";
// String baseUrl = "http://5902e9v900.zicp.fun:3000/";
//getLIst
// Future<List<Team>?> getTeamList(int leaderId) async {
// final response = await http.get(
// Uri.parse(baseUrl + 'get_team').replace(queryParameters: {'leaderId': leaderId.toString()}),
// headers: <String, String>{
// 'Content-Type': 'application/json; charset=UTF-8',
// },
//
// );
//
// final jsonResponse = json.decode(response.body);
// if (jsonResponse['code'] == 200) {
// List<Team> teamList = (jsonResponse['data'] as List)
// .map((team) => Team.fromJson(team as Map<String, dynamic>))
// .toList();
// return teamList;
// } else {
// return null;
// }
// }
String baseUrl = "http://5902e9v900.zicp.fun:3000/";
//--------------------------------------------------
//getUserList
@ -51,6 +31,7 @@ class NetWorkController {
.toList();
return userList;
} else {
print("获取用户列表");
return null;
}
}
@ -70,7 +51,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return User.fromJson(jsonResponse['data']['user'][0]);
} else {
print("login failed");
print("登录失败");
return null;
}
}
@ -88,7 +69,26 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("login failed");
print("注册失败");
return false;
}
}
//updeateUser
Future<bool> updateUser(User user) async {
final response = await http.post(
Uri.parse(baseUrl+'update_user'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(user.toMap()),
);
final jsonResponse = json.decode(response.body);
if (jsonResponse['code'] == 200) {
return true;
} else {
print("更新用户信息失败");
return false;
}
}
@ -107,6 +107,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("删除所有用户失败");
return false;
}
}
@ -128,11 +129,12 @@ class NetWorkController {
.toList();
return teamList;
} else {
print("获取My团队列表失败");
return null;
}
}
Future<List<Team>?> getAllTeamList(int userId) async {
Future<List<Team>?> getAllTeamListByUserId(int userId) async {
final response = await http.get(
Uri.parse(baseUrl + 'get_team').replace(queryParameters: {'userId': userId.toString()}),
headers: <String, String>{
@ -148,10 +150,59 @@ class NetWorkController {
.toList();
return teamList;
} else {
print("获取All团队列表ByUserId失败");
return null;
}
}
//getTeamByTeamName
Future<Team?> getTeamByTeamName(String teamName) async {
final response = await http.get(
Uri.parse(baseUrl + 'get_team').replace(queryParameters: {'teamName': teamName}),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
final jsonResponse = json.decode(response.body);
if (jsonResponse['code'] == 200) {
List<Team> teamList = (jsonResponse['data'] as List)
.map((team) => Team.fromJson(team as Map<String, dynamic>))
.toList();
if(teamList.length > 1) {
print("存在重复团队名");
return null;
}
return teamList[0];
} else {
print("获取团队列表ByTeamName失败");
return null;
}
}
Future<List<Team>> getAllTeamList() async {
final response = await http.get(
Uri.parse(baseUrl + 'get_team'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
final jsonResponse = json.decode(response.body);
if (jsonResponse['code'] == 200) {
List<Team> teamList = (jsonResponse['data'] as List)
.map((team) => Team.fromJson(team as Map<String, dynamic>))
.toList();
return teamList;
} else {
print("获取All团队列表失败");
return [];
}
}
Future<bool> insertTeam(Team team) async {
final response = await http.post(
Uri.parse(baseUrl+'add_team'),
@ -165,6 +216,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("insert team 失败:");
return false;
}
}
@ -176,7 +228,7 @@ class NetWorkController {
'Content-Type': 'application/json; charset=UTF-8',
},
body: JsonEncoder().convert({
'teamId': teamId,
'teamId':teamId,
}),
);
@ -184,6 +236,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("delete team 失败:" + jsonResponse['data'].toString());
return false;
}
}
@ -247,14 +300,14 @@ class NetWorkController {
}
}
Future<bool> deleteTeamUser(int teamid, int userId) async {
Future<bool> deleteTeamUser(int teamId, int userId) async {
final response = await http.post(
Uri.parse(baseUrl+'delete_team_member'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: JsonEncoder().convert({
'teamId': teamid,
'teamId': teamId,
'userId': userId,
}),
);
@ -263,6 +316,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("delete team user 失败:");
return false;
}
}
@ -270,7 +324,27 @@ class NetWorkController {
//--------------------------------------------------
Future<List<Work>?> getTeamWorkList(int teamId) async {
final response = await http.get(
Uri.parse(baseUrl + 'get_work').replace(queryParameters: {'id': teamId.toString()}),
Uri.parse(baseUrl + 'get_work').replace(queryParameters: {'teamId': teamId.toString()}),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
final jsonResponse = json.decode(response.body);
if (jsonResponse['code'] == 200) {
List<Work> teamWorkList = (jsonResponse['data'] as List)
.map((work) => Work.fromJson(work as Map<String, dynamic>))
.toList();
return teamWorkList;
} else {
return null;
}
}
//work
Future<List<Work>?> getALlTeamWorkList() async {
final response = await http.get(
Uri.parse(baseUrl + 'get_work'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
@ -303,6 +377,8 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("TeamWork插入失败");
print("body:"+ workList.map((work) => work.toMap()).toList().toString());
return false;
}
}
@ -327,9 +403,9 @@ class NetWorkController {
}
//server todo
Future<List<Work>?> getSameFreeWork(int teamid) async {
Future<List<FreeTime>?> getFreeTime(int teamid) async {
final response = await http.get(
Uri.parse(baseUrl + 'same_free_work').replace(queryParameters: {'teamid': teamid.toString()}),
Uri.parse(baseUrl + 'get_freeTime').replace(queryParameters: {'teamId': teamid.toString()}),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
@ -337,11 +413,12 @@ class NetWorkController {
final jsonResponse = json.decode(response.body);
if (jsonResponse['code'] == 200) {
List<Work> teamWorkList = (jsonResponse['data'] as List)
.map((work) => Work.fromJson(work as Map<String, dynamic>))
List<FreeTime> freeTimeList = (jsonResponse['data'] as List)
.map((freeTime) => FreeTime.fromJson(freeTime as Map<String, dynamic>))
.toList();
return teamWorkList;
return freeTimeList;
} else {
print("获取空闲时间失败");
return null;
}
}
@ -362,6 +439,7 @@ class NetWorkController {
.toList();
return courseList;
} else {
print("获取课程失败");
return null;
}
}
@ -379,6 +457,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("插入课程失败");
return false;
}
}
@ -396,6 +475,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("更新课程失败");
return false;
}
}
@ -413,6 +493,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("删除课程失败");
return false;
}
}
@ -433,6 +514,7 @@ class NetWorkController {
.toList();
return taskList;
} else {
print("获取个人计划失败");
return null;
}
}
@ -450,6 +532,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("更新个人计划失败");
return false;
}
}
@ -467,6 +550,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("插入个人计划失败");
return false;
}
}
@ -484,6 +568,7 @@ class NetWorkController {
if (jsonResponse['code'] == 200) {
return true;
} else {
print("删除个人计划失败");
return false;
}
}
@ -518,7 +603,17 @@ class NetWorkController {
if(data['code'] == 1000){
return resJson;
}else{
print("获取导入课程失败");
return null;
}
}
Future<String> getText() async{
final response=await http.get(Uri.parse("https://api.xygeng.cn/one"));
final jsonResponse = json.decode(response.body);
String content=jsonResponse['data']['content'];
print(content);
return content;
}
}

@ -1,6 +1,7 @@
import 'package:timemanagerapp/controller/NetWorkController.dart';
import 'package:timemanagerapp/entity/User.dart';
import '../entity/FreeTime.dart';
import '../entity/ScheduleForm.dart';
import '../entity/Team.dart';
import '../entity/Work.dart';
@ -65,7 +66,7 @@ class TeamController {
//
joindedTeamList = [];
allTeamList = [];
List<Team>? res = await netWorkController.getAllTeamList(Setting.user!.getId!);
List<Team>? res = await netWorkController.getAllTeamListByUserId(Setting.user!.getId!);
if(res==null){
return [];
}else{
@ -74,7 +75,7 @@ class TeamController {
for(Team team in allTeamList){
teamIdMap[team.id!] = team;
}
joindedTeamList = allTeamList;
joindedTeamList.addAll(allTeamList); //=
for(Team team in myTeamList){
// myTeamList
joindedTeamList.removeWhere((element) => element.id == team.id);
@ -83,14 +84,19 @@ class TeamController {
}
}
// Future<void> insertTeamList(List<Team> myTeamList) async {
// for (Team team in myTeamList) {
// await netWorkController.insertTeam(team);
// }
// }
Future<bool> deleteTeam(int teamid) async {
return await netWorkController.deleteTeam(teamid);
Future<bool> deleteTeam(Team team) async {
// List<User> memberList = await getTeamUserList(team.getId!); //
// for(User user in memberList){
// deleteTeamUser(team, user.getId!);
// }
return await netWorkController.deleteTeam(team.getId!);
}
Future<bool> insertTeam(Team team) async {
@ -104,6 +110,23 @@ class TeamController {
return true;
}
//joinTeam
Future<bool> joinTeam(String teamName) async {
//
for(Team team in allTeamList){
if(team.getTeamName == teamName){
return false;
}
}
Team ? team = await netWorkController.getTeamByTeamName(teamName);
if(team == null){
return false;
}
int id = await idGenerator.generateId();
return await netWorkController.insertTeamUser(id,team!.getId!, Setting.user!.getUsername!);
}
Future<bool> updateTeam(Team team) async {
return await netWorkController.updateTeam(team);
@ -135,8 +158,12 @@ class TeamController {
return await netWorkController.insertTeamUser(id,teamid, membername);
}
Future<bool> deleteTeamUser(int teamid, int userId) async {
return await netWorkController.deleteTeamUser(teamid, userId);
Future<bool> deleteTeamUser(Team team, int userId) async {
if(team.getLeaderId == userId){
return await deleteTeam(team);
}else{
return await netWorkController.deleteTeamUser(team.getId!, userId);
}
}
//---------------------------Work----------------------
@ -230,8 +257,8 @@ class TeamController {
// await netWorkController.u(work);
// }
Future<List<Work>> getSameFreeWork(int teamid)async{
var res = await netWorkController.getSameFreeWork(teamid);
Future<List<FreeTime>> getFreeTime(int teamid)async{
var res = await netWorkController.getFreeTime(teamid);
if(res == null){
return [];
}else{

@ -1,13 +1,33 @@
import 'dart:ui';
import 'package:timemanagerapp/entity/Course.dart';
import 'package:timemanagerapp/entity/FreeTime.dart';
import 'package:timemanagerapp/setting/Setting.dart';
class TimetableWidgetController {
late List<Course> courseList;
late DateTime mondayTime;
late int weekCount;
late DateTime termStartDate;
static late DateTime mondayTime = getmondayTime();
static late int weekCount = getWeekCount();
static late DateTime termStartDate = Setting.startdate;
static List<DateTime> timePoints = [
DateTime(2023, 9, 22, 7, 00),
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),
DateTime(2023, 9, 22, 23, 00),
];
TimetableWidgetController() {
mondayTime = getmondayTime();
@ -21,7 +41,8 @@ class TimetableWidgetController {
}
//piexl
List<Offset> convertTimeList(List<DateTime> timePoints, double deviceWidth) {
static List<Offset> convertTimeList(List<DateTime> timePoints) {
print("deviceWidth: ${Setting.deviceWidth.toString()}");
List<Offset> convertedTimes = [];
for (var time in timePoints) {
int hour = time.hour;
@ -29,19 +50,76 @@ class TimetableWidgetController {
int totalMinutes = (hour - 7) * 60 + minute;
double convertedTime = totalMinutes * Setting.pixelToMinuteRatio_ratio;
convertedTimes.add(Offset(deviceWidth * 0.015, convertedTime));
convertedTimes.add(Offset(Setting.deviceWidth * 0.015, convertedTime));
}
// print("convertedTimesOffset: $convertedTimes");
return convertedTimes;
}
int getWeekCount() {
weekCount = DateTime.now().difference(termStartDate).inDays ~/ 7 + 1;
//
List<FreeTime> repairFreeTimeBlockList(List freeTimeBlockList) {
List<FreeTime> repairedFreeTimeBlockList = [];
DateTime termStartDate = Setting.startdate;
DateTime termEndDate = termStartDate.add(Duration(days: 7 * Setting.termAllWeekCout));
//termEndDate23:00:00
termEndDate = DateTime(termEndDate.year, termEndDate.month, termEndDate.day, 23, 00, 00);
Set<DateTime> freeTimeBlockSet = {}; //,
for (var freeTimeBlock in freeTimeBlockList) {
//,
//
bool keepFlag = true;
if(freeTimeBlock.startTime.isBefore(termStartDate)){
keepFlag = false;
}
if(freeTimeBlock.endTime.isAfter(termEndDate)){
keepFlag = false;
}
if (freeTimeBlock.startTime.hour < 7) {
keepFlag = false;
}
if (freeTimeBlock.endTime.hour > 23) {
keepFlag = false;
}
// if(freeTimeBlock.startTime.compareTo(freeTimeBlock.endTime)==0){ //
// keepFlag = false; //,,freeTimeBlockSet,
// freeTimeBlockSet.add(DateTime(freeTimeBlock.startTime.year, freeTimeBlock.startTime.month, freeTimeBlock.startTime.day));
// }
if(keepFlag){
freeTimeBlockSet.add(DateTime(freeTimeBlock.startTime.year, freeTimeBlock.startTime.month, freeTimeBlock.startTime.day));
repairedFreeTimeBlockList.add(freeTimeBlock);
}else{
freeTimeBlockList.remove(freeTimeBlock);
}
}
//
for(var date = termStartDate; date.isBefore(termEndDate); date = date.add(Duration(days: 1))){
date = DateTime(date.year, date.month, date.day);
if(freeTimeBlockSet.contains(date)){
//,
continue;
}
DateTime startTime = DateTime(date.year, date.month, date.day, 7, 0);
DateTime endTime = DateTime(date.year, date.month, date.day, 23, 0);
FreeTime freeTime = FreeTime(startTime: startTime, endTime: endTime);
repairedFreeTimeBlockList.add(freeTime);
}
return repairedFreeTimeBlockList;
}
static int getWeekCount({DateTime ? dateTime}) {
dateTime ??= DateTime.now();
weekCount = dateTime.difference(termStartDate).inDays ~/ 7 + 1;
return weekCount;
}
DateTime getmondayTime() {
static DateTime getmondayTime() {
mondayTime = DateTime.now();
print("获取mondayTime: $mondayTime");
//
while (mondayTime.weekday != 1) {
mondayTime = mondayTime.subtract(Duration(days: 1));
@ -49,7 +127,37 @@ class TimetableWidgetController {
return mondayTime;
}
Map<int, List> transformCourseMap(List blockList) {
static List<String> getSelectDayList(DateTime date) {
List<String> selectedDayList = [];
//dataselectedDayList
int day = date.weekday;
switch (day) {
case 1:
selectedDayList.add("周一");
break;
case 2:
selectedDayList.add("周二");
break;
case 3:
selectedDayList.add("周三");
break;
case 4:
selectedDayList.add("周四");
break;
case 5:
selectedDayList.add("周五");
break;
case 6:
selectedDayList.add("周六");
break;
case 7:
selectedDayList.add("周日");
break;
}
return selectedDayList;
}
Map<int, List> transformTimeBlockMap(List blockList) {
Map<int, List> timeblockMap = {};
for (var timeBlock in blockList) {
int weekCount = timeBlock.startTime.difference(termStartDate).inDays ~/ 7 + 1; //
@ -63,7 +171,7 @@ class TimetableWidgetController {
}
//x
var weekListPixel=[0,Setting.deviceWidth*0.12,Setting.deviceWidth*0.24,Setting.deviceWidth*0.36,Setting.deviceWidth*0.48,Setting.deviceWidth*0.60,Setting.deviceWidth*0.72];
var weekListPixel=[0,0.12,0.24,0.36,0.48,0.60,0.72];
// Course(this.name, this.teacher, this.location, this.startTime, this.endTime);
double getdy(timeBlock)
@ -76,11 +184,11 @@ class TimetableWidgetController {
double getdx(timeBlock)
{
int x=timeBlock.startTime.weekday-1;
return weekListPixel[x].toDouble();
return Setting.deviceWidth*weekListPixel[x].toDouble();
}
double getHeight(timeBlock){
return ((timeBlock.endTime.hour*60+timeBlock.endTime.minute)-(timeBlock.startTime.hour*60+timeBlock.startTime.minute))*Setting.pixelToMinuteRatio_ratio;;
return ((timeBlock.endTime.hour*60+timeBlock.endTime.minute)-(timeBlock.startTime.hour*60+timeBlock.startTime.minute))*Setting.pixelToMinuteRatio_ratio;
}
}

@ -2,9 +2,12 @@ import 'package:timemanagerapp/database/dao/UserDao.dart';
import 'package:timemanagerapp/database/MyDatebase.dart';
import 'package:timemanagerapp/entity/User.dart';
import '../provider/TimeProvider.dart';
import '../setting/Setting.dart';
import '../util/dataUtil.dart';
import 'CourseController.dart';
import 'NetWorkController.dart';
import 'TaskController.dart';
/**
*
@ -38,6 +41,17 @@ class UserController {
return false;
}
await Setting.saveUser(user);
//
if(Setting.initFlag) {
//
await MyDatabase.reBuildDatabase();
print('从服务器初始化');
await CourseController().init();
await TaskController().init();
await Setting.saveInitFlag(false);
}
return true;
}
@ -51,11 +65,39 @@ class UserController {
print('注册失败');
return false;
}
await Setting.saveUser(postUser);
//
// await Setting.saveUser(postUser);
//todo:
return true;
}
//updateUser
Future<bool> updateUser(User postUser) async {
bool res = await netWorkController.updateUser(postUser);
if( !res ){
return false;
}else{
await Setting.saveUser(postUser);
return true;
}
}
// //
// Future<bool> deleteUser(User postUser) async {
// //todo:
// int userid = await idGenerator.generateId();
// postUser.id = userid;
// bool res = await netWorkController.register(postUser);
// //
// if(!res){
// print('注册失败');
// return false;
// }
// //
// // await Setting.saveUser(postUser);
// //todo:
// return true;
// }
Future<void> insertUser(User user) async {

@ -1,133 +1,133 @@
import 'package:timemanagerapp/entity/ScheduleForm.dart';
import '../database/dao/WorkDao.dart';
import '../entity/Work.dart';
import '../setting/Setting.dart';
import '../util/dataUtil.dart';
import 'NetWorkController.dart';
class WorkController {
static IdGenerator idGenerator = IdGenerator();
static List<Work> WorkList = []; //courseList
static NetWorkController netWorkController = NetWorkController();
DateTime termstartdate = Setting.startdate; //Setting.getStartDate();
Future<List<Work>> getWorks() async {
//todo http
List<Map<String, dynamic>> workMaps = await WorkDao().getWorks();
List<Work> Works = []; // Work
for (var workMap in workMaps) {
// 使WorkMapWork
Work work = Work(
id: workMap['id'],
userId: workMap['userId'],
content: workMap['content'],
workId: workMap['workId'],
name: workMap['name'],
startTime: DateTime.parse(workMap['startTime']),
endTime: DateTime.parse(workMap['endTime']),
status: workMap['status'],
teamId: workMap['teamId'],
);
Works.add(work);
}
WorkList = Works; // Work
return WorkList;
}
//addscheduleForm
Future<void> addScheduleForm(ScheduleForm scheduleForm,int teamId) async {
List<Work> WorkListToInsert = [];
int allWorkId = await idGenerator.generateId();
for (int week = scheduleForm.getStartWeek; week <= scheduleForm.getEndWeek; week++) {
for (int day in scheduleForm.selectedDays) {
//
final startDate = termstartdate.add(Duration(
days: (7 * (week - 1) + day! - 1),
hours: scheduleForm.getStartTime.hour,
minutes: scheduleForm.getStartTime.minute
));
final endDate = termstartdate.add(Duration(
days: (7 * (week - 1) + day! - 1),
hours: scheduleForm.getEndTime.hour,
minutes: scheduleForm.getEndTime.minute,
));
Work work = Work(
id: await idGenerator.generateId(),
name: scheduleForm.getName,
workId: allWorkId,
userId: Setting.user!.getId!,
status: "未完成",
content: scheduleForm.getContent,
teamId: teamId,
endTime: endDate,
startTime: startDate,
);
WorkListToInsert.add(work);
}
}
await insertWorkList(WorkListToInsert);
}
Future<int> insertWork(Work Work) async {
return await WorkDao().insertWork(Work);
}
Future<int> insertWorkList(List<Work> workList) async {
int result = 0;
for (Work work in workList) {
result += await WorkDao().insertWork(work);
}
return result;
}
//仿Taskwork
//query
Future<List<Work>> getWorkList() async {
List<Map<String, dynamic>> workMaps = await WorkDao().getWorks();
List<Work> workList = []; // Work
for (var workMap in workMaps) {
// 使WorkMapWork
Work work = Work(
id: workMap['id'],
userId: workMap['userId'],
content: workMap['content'],
workId: workMap['workId'],
name: workMap['name'],
startTime: DateTime.parse(workMap['startTime']),
endTime: DateTime.parse(workMap['endTime']),
status: workMap['status'],
teamId: workMap['teamId'],
);
workList.add(work);
}
WorkList = workList; // Work
return WorkList;
}
// //delete 仿Task
// Future<int> deleteWorkByid(int id) async{
// return await WorkDao().deleteWorkByid(id);
// }
Future<int> deleteWorkByWorkid(int workid) async {
return await WorkDao().deleteWorkByWorkid(workid);
}
Future<int> deleteAllWorks() async {
return await WorkDao().deleteAllWorks();
}
//update
Future<int> updateWork(Work work) async {
return await WorkDao().updateWork(work);
}
}
// import 'package:timemanagerapp/entity/ScheduleForm.dart';
//
// import '../database/dao/WorkDao.dart';
// import '../entity/Work.dart';
// import '../setting/Setting.dart';
// import '../util/dataUtil.dart';
// import 'NetWorkController.dart';
//
// class WorkController {
// static IdGenerator idGenerator = IdGenerator();
// static List<Work> WorkList = []; //courseList
// static NetWorkController netWorkController = NetWorkController();
//
// DateTime termstartdate = Setting.startdate; //Setting.getStartDate();
//
// Future<List<Work>> getWorks() async {
// //todo http
// List<Map<String, dynamic>> workMaps = await WorkDao().getWorks();
// List<Work> Works = []; // Work
//
// for (var workMap in workMaps) {
// // 使WorkMapWork
// Work work = Work(
// id: workMap['id'],
// userId: workMap['userId'],
// content: workMap['content'],
// workId: workMap['workId'],
// name: workMap['name'],
// startTime: DateTime.parse(workMap['startTime']),
// endTime: DateTime.parse(workMap['endTime']),
// status: workMap['status'],
// teamId: workMap['teamId'],
// );
// Works.add(work);
// }
// WorkList = Works; // Work
// return WorkList;
// }
//
// //addscheduleForm
// Future<void> addScheduleForm(ScheduleForm scheduleForm,int teamId) async {
// List<Work> WorkListToInsert = [];
// int allWorkId = await idGenerator.generateId();
// for (int week = scheduleForm.getStartWeek; week <= scheduleForm.getEndWeek; week++) {
// for (int day in scheduleForm.selectedDays) {
// //
// final startDate = termstartdate.add(Duration(
// days: (7 * (week - 1) + day! - 1),
// hours: scheduleForm.getStartTime.hour,
// minutes: scheduleForm.getStartTime.minute
// ));
//
// final endDate = termstartdate.add(Duration(
// days: (7 * (week - 1) + day! - 1),
// hours: scheduleForm.getEndTime.hour,
// minutes: scheduleForm.getEndTime.minute,
// ));
// Work work = Work(
// id: await idGenerator.generateId(),
// name: scheduleForm.getName,
// workId: allWorkId,
// userId: Setting.user!.getId!,
// status: "未完成",
// content: scheduleForm.getContent,
// teamId: teamId,
// endTime: endDate,
// startTime: startDate,
// );
// WorkListToInsert.add(work);
// }
// }
// await insertWorkList(WorkListToInsert);
// }
//
// Future<int> insertWork(Work Work) async {
// return await WorkDao().insertWork(Work);
// }
//
// Future<int> insertWorkList(List<Work> workList) async {
// int result = 0;
// for (Work work in workList) {
// result += await WorkDao().insertWork(work);
// }
// return result;
// }
//
// //仿Taskwork
// //query
// Future<List<Work>> getWorkList() async {
// List<Map<String, dynamic>> workMaps = await WorkDao().getWorks();
// List<Work> workList = []; // Work
//
// for (var workMap in workMaps) {
// // 使WorkMapWork
// Work work = Work(
// id: workMap['id'],
// userId: workMap['userId'],
// content: workMap['content'],
// workId: workMap['workId'],
// name: workMap['name'],
// startTime: DateTime.parse(workMap['startTime']),
// endTime: DateTime.parse(workMap['endTime']),
// status: workMap['status'],
// teamId: workMap['teamId'],
// );
// workList.add(work);
// }
// WorkList = workList; // Work
// return WorkList;
// }
//
// // //delete 仿Task
// // Future<int> deleteWorkByid(int id) async{
// // return await WorkDao().deleteWorkByid(id);
// // }
//
//
// Future<int> deleteWorkByWorkid(int workid) async {
// return await WorkDao().deleteWorkByWorkid(workid);
// }
//
// Future<int> deleteAllWorks() async {
// return await WorkDao().deleteAllWorks();
// }
//
// //update
// Future<int> updateWork(Work work) async {
// return await WorkDao().updateWork(work);
// }
//
//
//
// }

@ -72,9 +72,9 @@ class Course {
String get getRemark => remark;
DateTime get getstartTime => startTime;
DateTime get getStartTime => startTime;
DateTime get getendTime => endTime;
DateTime get getEndTime => endTime;
// Setter methods
set setId(int newId) {

@ -0,0 +1,83 @@
class FreeTime {
int? id;
int? userId;
String? content;
String? name;
DateTime startTime;
DateTime endTime;
FreeTime({
this.id,
this.userId,
this.content,
this.name,
required this.startTime,
required this.endTime,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'userId': userId,
'content': "$content",
'name': "$name",
'startTime': "${startTime.toIso8601String()}",
'endTime': "${endTime.toIso8601String()}"
};
}
factory FreeTime.fromJson(Map<String, dynamic> task) {
return FreeTime(
// id: task['id'],
// userId: task['userId'],
// content: task['content'],
// name: task['name'],
startTime: DateTime.parse(task['startTime']),
endTime: DateTime.parse(task['endTime']),
);
}
// Getter methods
int? get getId => id;
int? get getUserId => userId;
String? get getContent => content;
String? get getName => name;
DateTime get getStartTime => startTime;
DateTime get getEndTime => endTime;
// Setter methods
set setId(int newId) {
id = newId;
}
set setUserId(int newUserId) {
userId = newUserId;
}
set setContent(String newContent) {
content = newContent;
}
set setName(String newName) {
name = newName;
}
set setStartTime(DateTime newStartTime) {
startTime = newStartTime;
}
set setEndTime(DateTime newEndTime) {
endTime = newEndTime;
}
// toString method
@override
String toString() {
return 'FreeTime(id: $id, userId: $userId, content: $content, name: $name, startTime: $startTime, endTime: $endTime)';
}
}

@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
import 'package:timemanagerapp/provider/TeamProvider.dart';
import 'package:timemanagerapp/provider/TeamUserProvider.dart';
import 'package:timemanagerapp/setting/Setting.dart';
import 'package:timemanagerapp/util/MyLogger.dart';
import 'package:timemanagerapp/widgets/HomeWidget.dart';
import 'package:timemanagerapp/provider/TimeProvider.dart';
@ -11,9 +12,10 @@ init() async {
await Setting.init();
}
void main() async {
Future<void> main() async {
await init();
runApp(MyApp());
// Logger();
}
class MyApp extends StatelessWidget {
@ -21,7 +23,9 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Setting.deviceWidth = MediaQuery.of(context).size.width;
// print("deviceWidth获取1: ${Setting.deviceWidth}");
return MultiProvider( //Timetable
providers: [
ChangeNotifierProvider(create: (ctx) => TimeProvider()),
@ -30,7 +34,14 @@ class MyApp extends StatelessWidget {
],
child: MaterialApp(
home: Scaffold(
body: HomeWidget(),
body: LayoutBuilder(
builder: (context, constraints) {
Setting.deviceWidth = constraints.maxWidth;
// print("deviceWidth获取2: ${Setting.deviceWidth}");
// 使
return HomeWidget();
},
),
),
),
); // MaterialApp

@ -13,7 +13,7 @@ class AddCourseRoute extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('添加自定义课程'),
title: Text('编辑自定义课程'),
),
body: AddCourseFormWidget(exitCourse: exitCourse),
);

@ -9,7 +9,7 @@ class AddTeamRoute extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('添加团队'),
title: Text('编辑团队信息'),
),
body: AddTeamWidget(),
);

@ -1,17 +1,17 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../widgets/ManageUserTeamWidget.dart';
class ManageUserTeamRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('团队成员管理'),
),
// body: ManageUserTeamWidget(),
);
}
}
// import 'package:flutter/cupertino.dart';
// import 'package:flutter/material.dart';
//
// import '../widgets/ManageUserTeamWidget.dart';
//
// class ManageUserTeamRoute extends StatelessWidget {
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: AppBar(
// title: Text('团队成员管理'),
// ),
// // body: ManageUserTeamWidget(),
// );
// }
// }

@ -1,14 +1,27 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:timemanagerapp/controller/TeamController.dart';
import '../setting/Setting.dart';
import '../widgets/AddTeamWidget.dart';
import '../widgets/TeamWidgt.dart';
import '../widgets/JoinTeamWidget.dart';
import '../widgets/TeamWidget.dart';
class TeamRoute extends StatelessWidget {
//TeamWidgetKey
TeamController teamController = TeamController();
@override
initState() {
Setting.init();
}
@override
Widget build(BuildContext context) {
if(Setting.teamWidgetKey == null) {
Setting.teamWidgetKey =
GlobalKey(); // TeamWidgetKey,initStateStatefulWidget
}
if(Setting.user!.getId == -1){
return Scaffold(
appBar: AppBar(
@ -24,16 +37,55 @@ class TeamRoute extends StatelessWidget {
appBar: AppBar(
title: Text('我的团队'),
),
body: TeamWidget(),
body: TeamWidget(key: Setting.teamWidgetKey!),
floatingActionButton: FloatingActionButton(
//
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AddTeamWidget();
},
),
//
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('选择操作'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () async {
//
Navigator.of(context).pop(); //
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return JoinTeamWidget();
},
),
);
},
child: Text('加入团队'),
),
ElevatedButton(
onPressed: () async {
//
Navigator.of(context).pop();
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AddTeamWidget();
},
),
);
Setting.teamWidgetKey!.currentState!.futureDo();
},
child: Text('创建团队'),
),
SizedBox(height: 10),
],
),
);
},
);
},
child: Icon(Icons.add),

@ -2,12 +2,17 @@ import 'package:flutter/material.dart';
import 'package:timemanagerapp/widgets/TomatoClockWidget.dart';
class TomatoClockRoute extends StatelessWidget {
final int flag;
final double selectedDuration;
const TomatoClockRoute({super.key, required this.flag,required this.selectedDuration});
@override
Widget build(BuildContext context) {
return Scaffold(
body: TomatoClockWidget()
body: TomatoClockWidget(flag:flag,selectedDuration:selectedDuration)
);
}
}

@ -1,31 +1,43 @@
import 'dart:ffi';
import 'dart:core';
import 'package:flutter/cupertino.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../entity/User.dart';
import '../widgets/FreeTimetableWidget.dart';
import '../widgets/TeamWidget.dart';
import '../widgets/TimetableWidget.dart';
class Setting {
static SharedPreferences? prefs;
static bool initFlag = true;
static DateTime startdate_init = DateTime(2023, 8, 28);
static late DateTime startdate;
static late User? user;
static int termAllWeekCout = 20; //
static DateTime timeTableStartTime = DateTime(2023, 8, 28, 7, 00); //
static DateTime timeTableEndTime = DateTime(2023, 8, 28, 23, 00); //
static late User? user = User(id:-1, username: "null", password: "null", role: 0);
static User nullUser = User(id:-1, username: "null", password: "null", role: 0);
static double pixelToMinuteRatio_ratio = 1; //
static late double deviceWidth ; //
static double pixelToMinuteRatio_ratio = 300; //
static late double deviceWidth = 400; //
static bool isMusicPlaying = false; //
static bool isDeveloperButtonVisible = false; //
static GlobalKey<TimetableWidgetState>? timetableWidgetKey;
static GlobalKey<TeamWidgetState>? teamWidgetKey;
static GlobalKey<FreeTimetableWidgetState>? freeTimetableWidgeKey;
static late User testUer;
static init() async {
//
print("Setting初始化");
// prefs!.setString("startdate", startdate.toString());
prefs = await SharedPreferences.getInstance();
saveStartDate(startdate_init); //
startdate = getStartDate();
user = getUser();
isDeveloperButtonVisible = getIsDeveloperButtonVisible();
pixelToMinuteRatio_ratio = getpixelToMinuteRatio_ratio();
initFlag = getInitFlag();
getStartDate();
getUser();
getIsDeveloperButtonVisible();
getpixelToMinuteRatio_ratio();
getInitFlag();
print("Setting初始化成功");
}
@ -37,12 +49,14 @@ class Setting {
saveStartDate(startdate_init);
return startdate_init;
} else {
return DateTime.parse(res);
startdate = DateTime.parse(res);
return startdate;
}
}
static saveStartDate(DateTime startdate) async {
//
Setting.startdate = startdate;
await prefs?.setString("startdate", startdate.toString());
}

@ -1,38 +1,38 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:timemanagerapp/setting/Setting.dart';
import 'package:timemanagerapp/util/GetCourseByLogin.dart';
import 'package:timemanagerapp/widgets/AddCourseFormWidget.dart';
import 'package:timemanagerapp/widgets/LoginWidget.dart';
import 'package:timemanagerapp/widgets/TimetableWidget.dart';
init() async {
WidgetsFlutterBinding.ensureInitialized();
await Setting.init();
}
void main() async {
await init();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('课表'),
),
body: TimetableWidget(),
),
);
}
}
// import 'dart:developer';
//
// import 'package:flutter/material.dart';
// import 'package:shared_preferences/shared_preferences.dart';
// import 'package:timemanagerapp/setting/Setting.dart';
// import 'package:timemanagerapp/util/GetCourseByLogin.dart';
// import 'package:timemanagerapp/widgets/AddCourseFormWidget.dart';
// import 'package:timemanagerapp/widgets/LoginWidget.dart';
// import 'package:timemanagerapp/widgets/TimetableWidget.dart';
//
//
// init() async {
// WidgetsFlutterBinding.ensureInitialized();
// await Setting.init();
// }
//
// void main() async {
// await init();
// runApp(MyApp());
//
//
// }
//
// class MyApp extends StatelessWidget {
//
//
// @override
// Widget build(BuildContext context) {
// return MaterialApp(
// home: Scaffold(
// appBar: AppBar(
// title: Text('课表'),
// ),
// body: TimetableWidget(),
// ),
// );
// }
// }

@ -6,9 +6,9 @@ import 'package:timemanagerapp/setting/Setting.dart';
import 'package:timemanagerapp/util/dataUtil.dart';
class GetCourseByLogin {
String id = "210340156"; //
String passwd = "123111@qaq"; //
String year = "2022"; //
String id = ""; //
String passwd = ""; //
String year = "2023"; //
String term = "1"; //
DateTime termstartdate = Setting.startdate;
List<Course> courses = []; //
@ -94,7 +94,7 @@ class GetCourseByLogin {
final courseTitle = courseData['title'];
//
final timeRegex = RegExp(r'星期([一二三四五六日])第(\d)-(\d)节\{([^{}]+)\}');
final timeRegex = RegExp(r'星期([一二三四五六日])第(\d+)-(\d+)节\{([^{}]+)\}'); //Bug:/d+
final match = timeRegex.firstMatch(courseTime);
final Iterable<Match> allMatches = timeRegex.allMatches(courseTime); //Bug:
for(var match in allMatches){

@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import 'dart:convert';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:logger/src/logger.dart';
import 'package:logger/src/log_output.dart';
import 'dart:io' as io;
class MyLogger extends StatefulWidget {
@override
_MyLoggerState createState() => _MyLoggerState();
}
class _MyLoggerState extends State<MyLogger> {
late File file;
late Logger logger;
@override
void initState() {
getDirectoryForLogRecord().whenComplete(
() {
FileOutput fileOutPut = FileOutput(file: file);
ConsoleOutput consoleOutput = ConsoleOutput();
List<LogOutput> multiOutput = [fileOutPut, consoleOutput];
logger = Logger(
filter: DevelopmentFilter(),
// Use the default LogFilter (-> only log in debug mode)
printer: PrettyPrinter(
methodCount: 2,
// number of method calls to be displayed
errorMethodCount: 8,
// number of method calls if stacktrace is provided
lineLength: 120,
// width of the output
colors: false,
// Colorful log messages
printEmojis: true,
// Print an emoji for each log message
printTime: true // Should each log print contain a timestamp
),
// Use the PrettyPrinter to format and print log
output:
MultiOutput(multiOutput) // Use the default LogOutput (-> send everything to console)
);
},
);
// TODO: implement initState
super.initState();
}
Future<void> getDirectoryForLogRecord() async {
final Directory directory = await getApplicationDocumentsDirectory();
file = File('${directory.path}/withMultiOutput.txt');
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
print("you pressed it");
// logger.v("Verbose log");
//
// logger.d("Debug log");
//
// logger.i("Info log");
//
// logger.w("Warning log");
//
// logger.e("Error log");
//
// logger.wtf("What a terrible failure log");
showDialog(
context: context,
builder: (context) {
String content = file.readAsStringSync();
return AlertDialog(
title: Text('结果'),
content: SingleChildScrollView(
child: Text(content)),
);
},
);
},
// height: 60,
// minWidth: 120,
// color: Colors.blue,
child: Text(
'TEST WITH BOTH',
style: TextStyle(color: Colors.white),
),
);
}
}
/// Writes the log output to a file.
class FileOutput extends LogOutput {
late File file;
final bool overrideExisting;
final Encoding encoding;
IOSink ? _sink;
// IOSink? _sink;
FileOutput({
required this.file,
this.overrideExisting = false,
this.encoding = utf8,
});
@override
void init() {
_sink = file.openWrite(
mode: overrideExisting ? FileMode.writeOnly : FileMode.writeOnlyAppend,
encoding: encoding,
);
}
@override
void output(OutputEvent event) {
_sink?.writeAll(event.lines, '\n');
print('log-------'+event.lines.toString()+'\n');
}
@override
void destroy() async {
await _sink?.flush();
await _sink?.close();
}
}

@ -6,6 +6,7 @@ import 'package:timemanagerapp/controller/CourseController.dart';
import 'package:timemanagerapp/entity/Course.dart';
import 'package:timemanagerapp/entity/CourseForm.dart';
import '../controller/TimetableWidgetController.dart';
import '../provider/TimeProvider.dart';
class AddCourseFormWidget extends StatefulWidget {
const AddCourseFormWidget({Key? key,this.exitCourse}) : super(key: key);
@ -72,6 +73,9 @@ class _AddCourseFormWidgetState extends State<AddCourseFormWidget> {
note = exitCourse!.getRemark;
teacher = exitCourse!.getTeacher;
location = exitCourse!.getLocation;
selectedDays = TimetableWidgetController.getSelectDayList(exitCourse!.getStartTime);
startWeek = TimetableWidgetController.getWeekCount(dateTime:exitCourse!.getStartTime).toString();
endWeek = TimetableWidgetController.getWeekCount(dateTime:exitCourse!.getEndTime).toString();
}
_courseController = TextEditingController(text: course);
@ -121,6 +125,7 @@ class _AddCourseFormWidgetState extends State<AddCourseFormWidget> {
SizedBox(height: 16.0),
MultiSelectDialogField<String>(
items: daysList,
initialValue: selectedDays, //
title: Text('上课日*'),
validator: (values) {
if (values == null || values.isEmpty) {
@ -226,18 +231,14 @@ class _AddCourseFormWidgetState extends State<AddCourseFormWidget> {
},
child: Text('取消'),
),
Selector<TimeProvider, TimeProvider>( // time
selector: (ctx, provider) => provider,
shouldRebuild: (pre, next) => false,
builder: (ctx, timePro, child) {
return ElevatedButton(
ElevatedButton(
onPressed: () {
//
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
//
courseForm.course = course;
courseForm.credit = double.parse(credit);
courseForm.credit = double.parse(credit==''?'-1':credit);
courseForm.note = note;
courseForm.location = location;
courseForm.selectedDays = selectedDays.map((e) => weekdayMap[e]!).toList();
@ -250,7 +251,7 @@ class _AddCourseFormWidgetState extends State<AddCourseFormWidget> {
courseController.deleteCourse(exitCourse!.getCourseId).then((value){
courseController.addCourseForm(courseForm).then(((value){
//
timePro.updateTimetable();
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// timePro.updatTimtTablecount = 100;
Navigator.pop(context);
@ -259,19 +260,15 @@ class _AddCourseFormWidgetState extends State<AddCourseFormWidget> {
}else{
courseController.addCourseForm(courseForm).then(((value){
//
timePro.updateTimetable();
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// timePro.updatTimtTablecount = 100;
Navigator.pop(context);
}));
}
};
},
child: Text('确定'),
);
},
// child: Icon(Icons.add),
),
),
],
),
],

@ -8,6 +8,7 @@ import 'package:timemanagerapp/controller/WorkController.dart';
import 'package:timemanagerapp/entity/ScheduleForm.dart';
import 'package:timemanagerapp/entity/Task.dart';
import '../controller/TimetableWidgetController.dart';
import '../provider/TimeProvider.dart';
class AddScheduleFormWidget extends StatefulWidget {
AddScheduleFormWidget({Key? key,required this.scheduleType,this.teamId,this.exitSchedule}) : super(key: key);
@ -25,6 +26,8 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
late TextEditingController _nameController;
late TextEditingController _contenController;
late TextEditingController _startWeekController;
late TextEditingController _endWeekController;
final String scheduleType;//taskwork
final int? teamId ;
@ -46,7 +49,7 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
List<String> selectedDays = [];
List<MultiSelectItem<String>> daysList = [
static List<MultiSelectItem<String>> daysList = [
MultiSelectItem('周一', ''),
MultiSelectItem('周二', ''),
MultiSelectItem('周三', ''),
@ -72,10 +75,18 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
if(exitSchedule != null){
name = exitSchedule.getName;
content = exitSchedule.getContent;
startTime = exitSchedule.getStartTime;
endTime = exitSchedule.getEndTime;
selectedDays = TimetableWidgetController.getSelectDayList(exitSchedule!.getStartTime);
startWeek = TimetableWidgetController.getWeekCount(dateTime:exitSchedule!.getStartTime).toString();
endWeek = TimetableWidgetController.getWeekCount(dateTime:exitSchedule!.getEndTime).toString();
}
_nameController = TextEditingController(text: name);
_contenController = TextEditingController(text: content);
_startWeekController = TextEditingController(text: startWeek);
_endWeekController = TextEditingController(text: endWeek);
}
@override
@ -109,6 +120,7 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
SizedBox(height: 16.0),
MultiSelectDialogField<String>(
items: daysList,
initialValue: selectedDays, //
title: Text('星期几*'),
validator: (values) {
if (values == null || values.isEmpty) {
@ -124,6 +136,7 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
),
SizedBox(height: 16.0),
TextFormField(
controller: _startWeekController,
decoration: InputDecoration(labelText: '开始周'),
onSaved: (value) => startWeek = value ?? '',
validator: (value) {
@ -135,6 +148,7 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
),
SizedBox(height: 16.0),
TextFormField(
controller: _endWeekController,
decoration: InputDecoration(labelText: '结束周'),
onSaved: (value) => endWeek = value ?? '',
validator: (value) {
@ -151,7 +165,7 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
),
controller: TextEditingController(
text: startTime != null
? '${startTime!.hour}:${startTime!.minute}'
? '${startTime!.hour.toString().padLeft(2, '0')}:${startTime!.minute.toString().padLeft(2, '0')}'
: '',
),
readOnly: true,
@ -180,7 +194,7 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
),
controller: TextEditingController(
text: endTime != null
? '${endTime!.hour}:${endTime!.minute}'
? '${endTime!.hour.toString().padLeft(2, '0')}:${endTime!.minute.toString().padLeft(2, '0')}'
: '',
),
readOnly: true,
@ -213,18 +227,14 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
},
child: Text('取消'),
),
Selector<TimeProvider, TimeProvider>( // time
selector: (ctx, provider) => provider,
shouldRebuild: (pre, next) => false,
builder: (ctx, timePro, child) {
return ElevatedButton(
ElevatedButton(
onPressed: () {
//
if (_formKey.currentState!.validate()) {
if (_formKey.currentState!.validate()&&startTime!=endTime!&&startTime.isBefore(endTime!)) {
_formKey.currentState!.save();
//
scheduleForm.name = name;
scheduleForm.content = content;
scheduleForm.content = content ;
scheduleForm.selectedDays = selectedDays.map((e) => weekdayMap[e]!).toList();
scheduleForm.startWeek = int.parse(startWeek);
scheduleForm.endWeek = int.parse(endWeek);
@ -234,18 +244,18 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
if(exitSchedule != null){//
taskController.deleteTaskByTaskid(exitSchedule!.getTaskId).then((value){
taskController.addScheduleForm(scheduleForm).then(((value){
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
//
timePro.updateTimetable();
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// timePro.updatTimtTablecount++;
Navigator.pop(context);
}));
});
}else{
taskController.addScheduleForm(scheduleForm).then(((value){
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
//
timePro.updateTimetable();
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// timePro.updatTimtTablecount++;
Navigator.pop(context);
}));
@ -254,29 +264,60 @@ class _AddScheduleFormWidgetState extends State<AddScheduleFormWidget> {
if(exitSchedule != null){//
teamController.deleteWorkByWorkId(exitSchedule!.getWorkId).then((value){
teamController.addScheduleForm(scheduleForm,teamId!).then(((value){
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
//
timePro.updateTimetable();
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// timePro.updatTimtTablecount++;
Navigator.pop(context);
}));
});
}else{
teamController.addScheduleForm(scheduleForm,teamId!).then(((value){
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
//
timePro.updateTimetable();
// timePro.updatTimtTablecount++;
Navigator.pop(context);
}));
}
}
}else{
if(startTime==endTime){
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('时间错误'),
content: Text('开始时间和结束时间不能相同'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('确定'),
),
],
);
},
);
}else if(startTime!.isAfter(endTime!)){
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('时间错误'),
content: Text('开始时间不能晚于结束时间'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('确定'),
),
],
);
},
);
}
}
},
child: Text('确定'),
);
}
),
),
],
),
],

@ -5,6 +5,8 @@ import 'package:timemanagerapp/entity/Team.dart';
import '../setting/Setting.dart';
class AddTeamWidget extends StatefulWidget {
const AddTeamWidget({Key? key}) : super(key: key);
@override
_AddTeamWidgetState createState() => _AddTeamWidgetState();
}

@ -12,43 +12,30 @@ class AutoImportWidget extends StatefulWidget {
}
class _AutoImportWidgetState extends State<AutoImportWidget> {
final CourseController courseController = CourseController.getInstance();
final TextEditingController stuIdController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final TextEditingController yearController = TextEditingController();
final TextEditingController termController = TextEditingController();
late CourseController courseController = CourseController.getInstance();
late TextEditingController stuIdController = TextEditingController();
late TextEditingController passwordController = TextEditingController();
late TextEditingController yearController = TextEditingController();
late TextEditingController termController = TextEditingController();
bool loading = false;
Future<void> handleAutoImport(context) async {
// showDialog(
// context: context,
// builder: (BuildContext context) {
// return AlertDialog(
// // title: Text(''),
// content: Text('请稍等'),
// actions: [
// TextButton(
// child: Text('确定'),
// onPressed: () {
// Navigator.of(context).pop(); //
// },
// ),
// ],
// );
// },
// );
int stuId = int.parse(stuIdController.text);
String password = passwordController.text;
int year = int.parse(yearController.text);
int term = int.parse(termController.text);
setState(() {
loading = true;
});
courseController.autoImportCours(stuId, password, year, term).then((res){
setState(() {
loading = false;
});
if (res != 0) {
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Setting.timetableWidgetKey!.currentState!.localFutureDo();
Navigator.pop(context);
} else {
showDialog(
@ -71,15 +58,24 @@ class _AutoImportWidgetState extends State<AutoImportWidget> {
}
});
setState(() {
loading = true;
});
}
@override
void initState() {
super.initState();
yearController = TextEditingController(text:DateTime.now().year.toString());
if(DateTime.now().month<8) {
termController = TextEditingController(text: '2D:\Myprogramfile\Flutter\TimeManager\src\timemanagerapp\build\app\outputs\flutter-apk');
}else{
termController = TextEditingController(text: '1');
}
}
@override
Widget build(BuildContext context) {
if(loading){
return Scaffold(
appBar: AppBar(

@ -0,0 +1,135 @@
import 'package:flutter/material.dart';
import 'package:timemanagerapp/controller/UserController.dart';
import 'package:timemanagerapp/setting/Setting.dart';
import '../entity/User.dart';
class ChangeUserWidget extends StatefulWidget {
@override
_ChangeUserWidgetState createState() => _ChangeUserWidgetState();
}
class _ChangeUserWidgetState extends State<ChangeUserWidget> {
UserController userController = UserController.getInstance();
final TextEditingController usernameController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final TextEditingController confirmPasswordController = TextEditingController();
Future<void> handleRegister(context) async {
String username = usernameController.text;
String password = passwordController.text;
String confirmPassword = confirmPasswordController.text;
//
if (password == '' || confirmPassword == '') {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('结果'),
content: Text('密码不能为空'),
actions: [
TextButton(
child: Text('确定'),
onPressed: () {
Navigator.of(context).pop(); //
},
),
],
);
},
);
return;
}else if (password != confirmPassword) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('结果'),
content: Text('两次输入的密码不一致'),
actions: [
TextButton(
child: Text('确定'),
onPressed: () {
Navigator.of(context).pop(); //
},
),
],
);
},
);
return;
}else{
bool res = await userController.updateUser(User(id:Setting.user!.getId!,username:username, password:password, role:0));
if(res){
Navigator.pop(context);
}else{
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('结果'),
content: Text('修改失败'),
actions: [
TextButton(
child: Text('确定'),
onPressed: () {
Navigator.of(context).pop(); //
},
),
],
);
},
);
}
}
}
@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: <Widget>[
TextFormField(
controller: usernameController,
decoration: InputDecoration(
labelText: '用户名',
),
),
SizedBox(height: 16.0),
TextFormField(
controller: passwordController,
obscureText: true,
decoration: InputDecoration(
labelText: '密码',
),
),
SizedBox(height: 16.0),
TextFormField(
controller: confirmPasswordController,
obscureText: true,
decoration: InputDecoration(
labelText: '确认密码',
),
),
SizedBox(height: 24.0),
ElevatedButton(
onPressed:()=> handleRegister(context),
child: Text('提交'),
),
],
),
),
),
);
}
}

@ -0,0 +1,559 @@
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 '../entity/Work.dart';
import '../provider/TimeProvider.dart';
import '../ruters/AddScheduleRoute.dart';
import '../setting/Setting.dart';
class FreeTimetableWidget extends StatefulWidget {
FreeTimetableWidget({required Key key,required this.team}) : super(key: key);
final Team team;
@override
State<StatefulWidget> createState() =>
FreeTimetableWidgetState(team: team);
}
class FreeTimetableWidgetState extends State<FreeTimetableWidget> {
FreeTimetableWidgetState({required this.team});
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;
//DateTimePiexl
//Offset
var positions = [];
bool loading = true;
Future<void> serverFutureDo() async {
print('开始serverFutureDo');
//
freeTimeBlockList = await teamController.getFreeTime(team.getId!);
//
freeTimeBlockList = timetableWidgetController
.repairFreeTimeBlockList(freeTimeBlockList);
dataCaculateAfterFutherDo();
print('serverFutureDo 完成');
setState(() {});
}
//
@override
initState() {
super.initState();
//
freeTimeBlockWeekMap = {};
freeTimeBlockList = [];
//
currentWeek = TimetableWidgetController.getWeekCount();
showWeek = currentWeek;
currentWeekDayIndex = DateTime.now().weekday - 1;
// 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(TimetableWidgetController.timePoints);
}
@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){
});
},
child: GestureDetector(
onHorizontalDragEnd: (details) {
serverFutureDo();
if (details.primaryVelocity! > 0) {
//
setState(() {
showWeek--;
currentWeekDayIndex -= 7;
dataCaculateAfterFutherDo();
});
} else if (details.primaryVelocity! < 0) {
//
setState(() {
showWeek++;
currentWeekDayIndex += 7;
dataCaculateAfterFutherDo();
});
}
},
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: [
if(showWeek>0 && showWeek<Setting.termAllWeekCout)
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: Setting.deviceWidth,
height: 2000,
child: Stack(
alignment: Alignment.center,
children: [
// Stack
Positioned(
top: 0,
left: 0,
child: Container(
width: Setting.deviceWidth,
height: 2000,
child: Stack(
children: List.generate(
//
positions.length,
(index) => Positioned(
top: positions[index].dy,
left: positions[index].dx,
child: Row(
children: [
Text(
TimetableWidgetController.timePoints[index]
.hour
.toString()
.padLeft(2, '0') +
':' +
TimetableWidgetController.timePoints[index]
.minute
.toString()
.padLeft(2, '0'),
),
Container(
width: Setting.deviceWidth * 0.04,
height: 10,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.amber,
width: 2,
),
),
),
Container(
width: Setting.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) +
Setting.deviceWidth * 0.15,
child: SingleChildScrollView(
child: Container(
width: Setting.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,
team: team,
),
],
),
),
),
),
);
},
),
))
],
),
),
],
),
))
],
),
),
);
;
}),
);
}
//
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,
required this.team,
});
final currentItem;
final blockGestureWidgetChilld;
final Team team;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
//
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
// currentItem
title: Text('空闲时间'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
if (currentItem is FreeTime) ...{
ShowTimeTextWidget(currentItem: currentItem),
}
],
),
),
actions: <Widget>[
TextButton(
child: Text('关闭'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
},
onLongPress: () {
//
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('菜单'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () async {
//
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AddScheduleRoute(
scheduleType: "work",
teamId: team.id!,
exitSchedule: Work(
startTime: currentItem.startTime,
endTime: currentItem.endTime,
teamId: team.id!,
userId: Setting.user!.id!,
status: '',
content: '',
name: '',
workId: 0,
)
);
},
),
);
Navigator.of(context).pop();
Setting.freeTimetableWidgeKey!.currentState!.serverFutureDo();
},
child: Text('添加团队任务'),
),
SizedBox(height: 10),
],
),
);
},
);
},
child: blockGestureWidgetChilld,
);
}
}
class FreeTimeBlockContenWidget extends StatelessWidget {
const FreeTimeBlockContenWidget({
super.key,
required this.currentItem, required this.team,
});
final currentItem;
final Team team;
@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: 12,
color: Colors.black,
//
fontWeight: FontWeight.bold,
),
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: 12,
color: Colors.black,
//
fontWeight: FontWeight.bold,
),
overflow: TextOverflow.clip,
),
],
),
team: team,
);
}
}

@ -4,11 +4,11 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:timemanagerapp/controller/CourseController.dart';
import 'package:timemanagerapp/controller/UserController.dart';
import 'package:timemanagerapp/database/MyDatebase.dart';
import 'package:timemanagerapp/ruters/AddScheduleRoute.dart';
import 'package:timemanagerapp/ruters/TeamRoute.dart';
import 'package:timemanagerapp/ruters/TestRoute.dart';
import 'package:timemanagerapp/widgets/AutoImportWidget.dart';
import 'package:timemanagerapp/widgets/ChangeUserWidget.dart';
import 'package:timemanagerapp/widgets/RegisterWidget.dart';
import 'package:timemanagerapp/widgets/TimetableWidget.dart';
@ -28,7 +28,6 @@ class HomeWidget extends StatefulWidget {
}
class _HomeWidgetState extends State<HomeWidget> {
GlobalKey<TimetableWidgetState> timetableWidgetKey = GlobalKey(); //key
late UserController userController;
late CourseController courseController;
@ -36,10 +35,16 @@ class _HomeWidgetState extends State<HomeWidget> {
bool isLoggedIn = false; //
late Timer? _timer = null;
double selectedDuration=0;
String durationString='0.0';
@override
void initState() {
super.initState();
userController = UserController.getInstance();
Setting.timetableWidgetKey = GlobalKey(); //key,,TimetableWidgetState;
userController = UserController();
courseController = CourseController.getInstance();
}
@ -76,9 +81,10 @@ class _HomeWidgetState extends State<HomeWidget> {
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () {
onPressed: () async {
Navigator.of(context).pop();//
// AddCourseFormWidget
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -86,13 +92,20 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
// setState(() {
//
// });
//
// print("触发更新课程表");
Setting.timetableWidgetKey!.currentState!.localFutureDo();
},
child: Text('添加课程'),
),
ElevatedButton(
onPressed: () {
onPressed: () async {
Navigator.of(context).pop();//
// AddCourseFormWidget
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -103,6 +116,7 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
Setting.timetableWidgetKey!.currentState!.localFutureDo();
},
child: Text('添加个人计划'),
),
@ -116,24 +130,97 @@ class _HomeWidgetState extends State<HomeWidget> {
),
IconButton(
//todo 使
icon: const Icon(Icons.more),
icon: const Icon(Icons.access_alarm),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
//todo
return TomatoClockRoute();
},
),
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('选择时长'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
children: [
Text("$durationString 分钟"),
// Slider(
// value: selectedDuration,
// min: 0,
// max: 180,
// allowedInteraction: SliderInteraction.slideOnly,
// onChanged: (double value) {
// durationString=selectedDuration.toStringAsFixed(1);
// setState(() {
// selectedDuration = value;
// durationString=selectedDuration.toStringAsFixed(1);
// });
// },
// ),
],
),
SizedBox(height: 10),
Container(
height: 30,
child: TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: '请输入时长(分钟)',
border: OutlineInputBorder(),
),
onChanged: (value) {
setState(() {
selectedDuration =double.parse(value);
durationString=selectedDuration.toStringAsFixed(1);
});
},
),
),
SizedBox(height: 10),
// Text('时长:$selectedDuration 分钟'),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
child: Text('返回主界面'),
onPressed: () {
Navigator.of(context).pop();
},
),
ElevatedButton(
child: Text('进入番茄时钟'),
onPressed: () {
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
//todo
return TomatoClockRoute(flag:0,selectedDuration:selectedDuration);
},
),
);
},
),
],
)
],
),
);
},
);
},
),
IconButton(
icon: const Icon(Icons.group_add),
onPressed: () {
onPressed: () async {
//
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -142,6 +229,8 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
Setting.timetableWidgetKey!.currentState!.serverFutureDo();
Setting.timetableWidgetKey!.currentState!.localFutureDo();
},
),
Builder(
@ -162,10 +251,10 @@ class _HomeWidgetState extends State<HomeWidget> {
children: [
UserAccountsDrawerHeader(
accountName: GestureDetector(
onTap: () {
onTap: () async {
if (Setting.user!.getId! == -1) {
//
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -173,21 +262,25 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
Setting.timetableWidgetKey!.currentState!.localFutureDo();
Setting.timetableWidgetKey!.currentState!.serverFutureDo();
} else {
//退
Setting.saveUser(Setting.nullUser);
setState(() {});
await Setting.saveUser(Setting.nullUser);
await Setting.saveInitFlag(true);
}
setState(() {});
Setting.timetableWidgetKey!.currentState!.localFutureDo();
},
child: Setting.user!.getId! != -1
? Text(Setting.user!.getUsername!)
: Text('未登录'),
),
accountEmail: GestureDetector(
onTap: () {
onTap: () async {
if (Setting.user!.getId! == -1) {
//
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -195,11 +288,15 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
Setting.timetableWidgetKey!.currentState!.localFutureDo();
Setting.timetableWidgetKey!.currentState!.serverFutureDo();
} else {
//退
Setting.saveUser(Setting.nullUser);
setState(() {});
await Setting.saveUser(Setting.nullUser);
await Setting.saveInitFlag(true);
}
setState(() {});
Setting.timetableWidgetKey!.currentState!.localFutureDo();
},
child: Setting.user!.getId! != -1
? Text('退出登录')
@ -212,10 +309,10 @@ class _HomeWidgetState extends State<HomeWidget> {
),
ListTile(
title: Text('导入学校课程'),
onTap: () {
onTap: () async {
//todo
//
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -223,6 +320,7 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
Setting.timetableWidgetKey!.currentState!.localFutureDo();
},
),
GestureDetector(
@ -248,10 +346,10 @@ class _HomeWidgetState extends State<HomeWidget> {
},
child: ListTile(
title: Text('用户设置'),
onTap: () {
onTap: () async {
//todo
// deng
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -259,16 +357,17 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
Setting.timetableWidgetKey!.currentState!.localFutureDo();
},
),
),
if (Setting.user!.getId! == -1)
ListTile(
title: Text('注册'),
onTap: () {
onTap: () async {
//todo
// UserSettingWight
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -276,13 +375,30 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
setState(() {
});
},
),
if (Setting.user!.getId! != -1)//
ListTile(
title: Text('更改账号信息'),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ChangeUserWidget();
},
),
);
setState(() {});
},
),
if (Setting.isDeveloperButtonVisible)
if (Setting.isDeveloperButtonVisible&&Setting.user!.getRole! >=1 )
ListTile(
title: Text('开发者测试'),
onTap: () {
Navigator.push(
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
@ -290,13 +406,14 @@ class _HomeWidgetState extends State<HomeWidget> {
},
),
);
Setting.timetableWidgetKey!.currentState!.localFutureDo();
},
),
],
),
);
}),
body: TimetableWidget(),
body: TimetableWidget(key: Setting.timetableWidgetKey!),
);
}

@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import 'package:timemanagerapp/controller/TeamController.dart';
import 'package:timemanagerapp/entity/Team.dart';
import '../setting/Setting.dart';
class JoinTeamWidget extends StatefulWidget {
const JoinTeamWidget({Key? key}) : super(key: key);
@override
_JoinTeamWidgetState createState() => _JoinTeamWidgetState();
}
class _JoinTeamWidgetState extends State<JoinTeamWidget> {
TeamController teamController = TeamController();
TextEditingController teamNameController = TextEditingController();
// TextEditingController teamDescriptionController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('加入团队'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: teamNameController,
decoration: InputDecoration(
labelText: '团队名称',
),
),
SizedBox(height: 10),
// TextField(
// controller: teamDescriptionController,
// decoration: InputDecoration(
// labelText: '团队描述',
// ),
// ),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
String teamName = teamNameController.text;
// String teamDescription = teamDescriptionController.text;
bool res = await teamController.joinTeam(teamName);
if(res==false){
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('结果'),
content: Text('团队不存在或已加入'),
actions: [
TextButton(
child: Text('确定'),
onPressed: () {
Navigator.of(context).pop(); //
},
),
],
);
},
);
}else{
Setting.teamWidgetKey!.currentState!.futureDo();
Navigator.pop(context);
}
},
child: Text('确定'),
),
],
),
),
);
}
}

@ -23,15 +23,7 @@ class _LoginWidgetState extends State<LoginWidget> {
String password = passwordController.text;
bool res = await userController.login(User(username: username, password: password, role: 0));
if(res) {
//
if(Setting.initFlag) {
print('从服务器初始化');
await Setting.saveInitFlag(false);
await CourseController().init();
await TaskController().init();
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
}
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
Navigator.pop(context);
}else{
showDialog(

@ -77,7 +77,7 @@ class _ManageUserTeamWidgetState extends State<ManageUserTeamWidget> {
void removeMember(User member) {
//
teamController.deleteTeamUser(team.id!, member.getId!).then((value) {
teamController.deleteTeamUser(team, member.getId!).then((value) {
//
showDialog(
context: context,
@ -124,9 +124,8 @@ class _ManageUserTeamWidgetState extends State<ManageUserTeamWidget> {
child: CircularProgressIndicator(),
);
} else {
return Consumer<TeamProvider>(builder: (ctx, teamPro, child) {
print('Rebuild teamPro');
return Scaffold(
return
Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text('团队成员'),
@ -141,14 +140,14 @@ class _ManageUserTeamWidgetState extends State<ManageUserTeamWidget> {
padding: EdgeInsets.all(16.0),
child: Column(
children: [
if (team.leaderId == Setting.user!.getId!)
if (team.leaderId == Setting.user!.getId! || Setting.user!.getRole >= 2)
TextField(
controller: memberIdController,
decoration: InputDecoration(labelText: '成员ID'),
),
if (team.leaderId == Setting.user!.getId!)
if (team.leaderId == Setting.user!.getId! || Setting.user!.getRole >= 2)
SizedBox(height: 20),
if (team.leaderId == Setting.user!.getId!)
if (team.leaderId == Setting.user!.getId! || Setting.user!.getRole >= 2)
ElevatedButton(
onPressed: handleInviteButton,
child: Text('邀请'),
@ -162,15 +161,20 @@ class _ManageUserTeamWidgetState extends State<ManageUserTeamWidget> {
itemBuilder: (BuildContext context, int index) {
User member = memberList[index];
return ListTile(
title: Text(member.getUsername),
trailing: team.leaderId != Setting.user!.getId!
? null
: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
removeMember(member);
},
),
title: Text(team.leaderId != member.getId! ?member.getUsername:member.getUsername+'(管理员)',
style: TextStyle(
color: team.leaderId != member.getId!
? Colors.black
: Colors.orange)
), //leader
trailing: team.leaderId == Setting.user!.getId! || (team.leaderId != member.getId! && Setting.user!.getRole >= 2)
? IconButton(
icon: Icon(Icons.delete),
onPressed: () {
removeMember(member);
},
)
: null,
);
},
),
@ -180,7 +184,6 @@ class _ManageUserTeamWidgetState extends State<ManageUserTeamWidget> {
)
),
);
});
}
}
}
}

@ -20,7 +20,27 @@ class _RegisterWidgetState extends State<RegisterWidget> {
String password = passwordController.text;
String confirmPassword = confirmPasswordController.text;
if (password != confirmPassword) {
//
if (password == '' || confirmPassword == '') {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('结果'),
content: Text('密码不能为空'),
actions: [
TextButton(
child: Text('确定'),
onPressed: () {
Navigator.of(context).pop(); //
},
),
],
);
},
);
return;
}else if(password != confirmPassword) {
showDialog(
context: context,
builder: (BuildContext context) {

@ -1,27 +0,0 @@
import 'package:flutter/material.dart';
/**
* @desc 线
* @author xiedong
* @date 2020-02-24.
*/
class SpaceWidget extends StatelessWidget {
double height, width;
SpaceWidget({
this.height = 1,
this.width = 1,
}) : super();
@override
Widget build(BuildContext context) {
return
Container(
height: height,
width: width,
color: Colors.transparent,
);
}
}

@ -3,18 +3,20 @@ import 'package:provider/provider.dart';
import 'package:timemanagerapp/controller/TeamController.dart';
import 'package:timemanagerapp/provider/TeamUserProvider.dart';
import 'package:timemanagerapp/ruters/AddScheduleRoute.dart';
import 'package:timemanagerapp/widgets/FreeTimetableWidget.dart';
import 'package:timemanagerapp/widgets/ManageUserTeamWidget.dart';
import '../entity/Team.dart';
import '../setting/Setting.dart';
class TeamWidget extends StatefulWidget {
const TeamWidget({Key? key}) : super(key: key);
const TeamWidget({required key}) : super(key: key);
@override
_TeamWidgetState createState() => _TeamWidgetState();
TeamWidgetState createState() => TeamWidgetState();
}
class _TeamWidgetState extends State<TeamWidget> {
class TeamWidgetState extends State<TeamWidget> {
int firstInit = 0;
List<Team> myTeamList = [];
@ -33,39 +35,34 @@ class _TeamWidgetState extends State<TeamWidget> {
//
myTeamList = await teamController.getMyTeamList();
joinTeamList = await teamController.getJoinedTeamList();
}
dataInitAfterFutherDo() {}
if(Setting.user!.role >= 2){
//
myTeamList.addAll(joinTeamList);
joinTeamList = [];
}
updateAfterFutherDo() {}
setState(() {
});
}
@override
initState() {
super.initState();
Setting.freeTimetableWidgeKey = GlobalKey();
futureDo();
//todo: get teamList from database
}
@override
Widget build(BuildContext context) {
return Consumer<TeamUserProvider>(builder: (ctx, teamUserPro, child) {
print('Rebuild teamUserPro');
return FutureBuilder<void>(
future: futureDo(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
//
if (snapshot.connectionState == ConnectionState.done) {
if (firstInit == 0) {
//
dataInitAfterFutherDo();
firstInit = 1;
} else {
//
updateAfterFutherDo();
}
return RefreshIndicator(
print('Rebuild teamUserPro');
return RefreshIndicator(
onRefresh: () {
print('下拉refresh');
return futureDo().then((value) => setState(() {}));
return futureDo();
},
child: CustomScrollView(
slivers: [
@ -107,6 +104,50 @@ class _TeamWidgetState extends State<TeamWidget> {
},
);
},
onLongPress: () {
//
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(team.getTeamName),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () {
//
Navigator.of(context).pop(); //
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return FreeTimetableWidget(team: team,key:Setting.freeTimetableWidgeKey!);
},
),
);
},
child: Text('查看团队空闲时间'),
),
if (team.leaderId != Setting.user!.getId!)
SizedBox(height: 10),
if (team.leaderId != Setting.user!.getId!)
ElevatedButton(
onPressed: () {
// 退
Navigator.of(context).pop(); //
teamController.deleteTeamUser(team, Setting.user!.id!).then((value) {
futureDo();
});
},
child: Text('退出团队'),
),
],
),
);
},
);
},
child: Text(team.teamName), //
),
trailing: Row(
@ -137,7 +178,7 @@ class _TeamWidgetState extends State<TeamWidget> {
builder: (context) {
return AddScheduleRoute(
scheduleType: "work",
teamId: 1,
teamId: team.id!
);
},
),
@ -147,14 +188,33 @@ class _TeamWidgetState extends State<TeamWidget> {
IconButton(
//
icon: Icon(Icons.delete),
onPressed: () {
teamController
.deleteTeam(team.id!)
.then((value) {
setState(() {
myTeamList.remove(team);
});
});
onPressed: () async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('删除团队'),
content: Text('您确定要删除团队吗?'),
actions: <Widget>[
TextButton(
child: Text('取消'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text('确定'),
onPressed: () async {
print('删除团队'+ team.getTeamName + ' ' + team.id.toString());
await teamController.deleteTeam(team);
futureDo();
Navigator.of(context).pop();
},
),
],
);
},
);
},
),
],
@ -174,6 +234,7 @@ class _TeamWidgetState extends State<TeamWidget> {
children: [
ListTile(
//
//
leading: Icon(Icons.group), // icon
title: GestureDetector(
onTap: () {
@ -204,6 +265,49 @@ class _TeamWidgetState extends State<TeamWidget> {
},
);
},
onLongPress: () {
//
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(team.getTeamName),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () async {
//
Navigator.of(context).pop(); //
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return FreeTimetableWidget(team: team,key:Setting.freeTimetableWidgeKey!);
},
),
);
},
child: Text('查看团队空闲时间'),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () {
//
Navigator.of(context).pop(); //
teamController.deleteTeamUser(team, Setting.user!.id!).then((value) {
futureDo();
});
},
child: Text('退出团队'),
),
],
),
);
},
);
},
child: Text(team.teamName), //
),
trailing: Row(
@ -236,12 +340,5 @@ class _TeamWidgetState extends State<TeamWidget> {
],
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
});
});
}
}

@ -32,6 +32,7 @@ import 'package:timemanagerapp/entity/Course.dart';
import 'package:timemanagerapp/entity/Team.dart';
import 'package:timemanagerapp/entity/User.dart';
import 'package:timemanagerapp/database/MyDatebase.dart';
import 'package:timemanagerapp/util/MyLogger.dart';
import '../controller/TaskController.dart';
import '../controller/WorkController.dart';
@ -50,7 +51,7 @@ class _TestWidgetState extends State<TestWidget> {
late UserController userController;
late CourseController courseController;
late TaskController taskController;
late WorkController WwrkController;
// Logger logger = Logger();
@override
void initState() {
@ -192,6 +193,23 @@ class _TestWidgetState extends State<TestWidget> {
// onPressed: () => courseController.autoImportCours(jsonstr),
// child: Text('导入课程(待开发)'),
// ),
ElevatedButton(
onPressed: () {
NetWorkController().getText().then((res) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('结果'),
content: Text(res)
);
},
);
});
},
child: Text('番茄时钟文字获取'),
),
ElevatedButton(
onPressed: () => courseController.insertCourse(Course(
userId: 1,
@ -269,7 +287,7 @@ class _TestWidgetState extends State<TestWidget> {
),
ElevatedButton(
onPressed: () {
WorkController().getWorks().then((works) {
TeamController().getWorks().then((works) {
showDialog(
context: context,
builder: (context) {
@ -293,47 +311,47 @@ class _TestWidgetState extends State<TestWidget> {
},
child: Text('显示团队任务列表'),
),
// ElevatedButton(
// onPressed: () {
// UserController()
// .login(User(username: 'root', password: 'root', role: 1))
// .then((resUser) {
// showDialog(
// context: context,
// builder: (context) {
// return AlertDialog(
// title: Text('登录信息'),
// content: SingleChildScrollView(
// child: Text(resUser!.toString())),
// );
// },
// );
// });
// },
// child: Text('登录'),
// ),
// ElevatedButton(
// onPressed: () {
// NetWorkController()
// .register(User(id: Setting.user!.getId!, username:'testReg' , password: '123', role: 0))
// .then((res) {
// showDialog(
// context: context,
// builder: (context) {
// return AlertDialog(
// title: Text('注册'),
// content: SingleChildScrollView(
// child: Text(res.toString())),
// );
// },
// );
// });
// },
// child: Text('注册'),
// ),
ElevatedButton(
onPressed: () {
UserController()
.login(User(username: 'root', password: 'root', role: 1))
.then((resUser) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('登录信息'),
content: SingleChildScrollView(
child: Text(resUser!.toString())),
);
},
);
});
},
child: Text('登录'),
),
ElevatedButton(
onPressed: () {
NetWorkController()
.register(User(id: Setting.user!.getId!, username:'testReg' , password: '123', role: 0))
.then((res) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('注册'),
content: SingleChildScrollView(
child: Text(res.toString())),
);
},
);
});
},
child: Text('注册'),
),
ElevatedButton(
onPressed: () {
TeamController().getMyTeamList().then((teamList) {
NetWorkController().getAllTeamList().then((teamList) {
showDialog(
context: context,
builder: (context) {
@ -355,45 +373,35 @@ class _TestWidgetState extends State<TestWidget> {
);
});
},
child: Text('显示团队列表'),
),
ElevatedButton(
onPressed: () {
TeamController()
.insertTeam(Team(leaderId: Setting.user!.getId!, teamName: "test3", maxNumber: 5))
.then((resTeam) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(''),
content: SingleChildScrollView(
child: Text(resTeam.toString())),
);
},
);
});
},
child: Text('增加团队'),
child: Text('显示数据库所有团队列表(不可用)'),
),
// ElevatedButton(
// onPressed: () {
// TeamController()
// .insertTeam(Team(leaderId: Setting.user!.getId!, teamName: "test3", maxNumber: 5))
// .then((resTeam) {
// showDialog(
// context: context,
// builder: (context) {
// return AlertDialog(
// title: Text(''),
// content: SingleChildScrollView(
// child: Text(resTeam.toString())),
// );
// },
// );
// });
// },
// child: Text('增加团队'),
// ),
ElevatedButton(
onPressed: () {
NetWorkController()
.deleteTeam(2)
.then((resTeam) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(''),
content: SingleChildScrollView(
child: Text(resTeam.toString())),
);
},
);
});
User user = Setting.user!;
if(user.role == 1) user.role = 2;
else user.role = 1;
Setting.saveUser(user);
},
child: Text('删除团队'),
child: Text('修改role为2or!2(团队管理员)'),
),
ElevatedButton(
onPressed: () {
@ -437,6 +445,7 @@ class _TestWidgetState extends State<TestWidget> {
onPressed: () async => await Setting.saveInitFlag(true),
child: Text('重置initFlag'),
),
MyLogger(),
AddCourseButton(onCourseAdded: (jsonstr) {
// addCourse()
courseController.test_autoImportCours(jsonstr);

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import 'package:provider/provider.dart';
import 'package:timemanagerapp/controller/CourseController.dart';
import 'package:timemanagerapp/controller/TaskController.dart';
@ -9,7 +10,7 @@ import 'package:timemanagerapp/controller/TeamController.dart';
import 'package:timemanagerapp/controller/TimetableWidgetController.dart';
import 'package:timemanagerapp/ruters/AddCourseRoute.dart';
import 'package:timemanagerapp/ruters/AddScheduleRoute.dart';
import '../ruters/TomatoClockRoute.dart';
import '../controller/WorkController.dart';
import '../entity/Course.dart';
import '../entity/Task.dart';
@ -18,14 +19,13 @@ import '../provider/TimeProvider.dart';
import '../setting/Setting.dart';
class TimetableWidget extends StatefulWidget {
final double deviceWidth = Setting.deviceWidth;
TimetableWidget({required Key key}) : super(key: key);
@override
State<StatefulWidget> createState() =>
TimetableWidgetState(deviceWidth: deviceWidth);
TimetableWidgetState();
}
class TimetableWidgetState extends State<TimetableWidget> {
late double deviceWidth;
int firstInit = 0;
//
@ -61,83 +61,95 @@ class TimetableWidgetState extends State<TimetableWidget> {
final double hourHeight = 60.0 * 1.5;
//DateTimePiexl
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;
TimetableWidgetState({required this.deviceWidth});
updateDateByWeekCount() {}
TimetableWidgetState();
Future<void> futureDo() async {
print('开始futureDo');
Future<void> localFutureDo() async {
print('开始localFutureDo');
//
courseList = await courseController.getCourses();
taskList = await taskController.getTasks();
dataCaculateAfterFutherDo();
print('localFutureDo 完成');
setState(() {});
}
Future<void> serverFutureDo() async {
print('开始serverFutureDo');
//
workList = await teamController.getWorks();
dataCaculateAfterFutherDo();
print('serverFutureDo 完成');
setState(() {});
}
//
@override
initState() {
super.initState();
}
@override
dispose() {
super.dispose();
// Setting.saveInitFlag(false);
}
dataInitAfterFutherDo() {
//
timeBlockWeekMap = {};
timeBlockList = [];
//
currentWeek = timetableWidgetController.getWeekCount();
currentWeek = TimetableWidgetController.getWeekCount();
showWeek = currentWeek;
currentWeekDayIndex = DateTime.now().weekday - 1;
// showWeek = 1;
//
showMonth = DateTime.now().month;
dataCaculateAfterFutherDo();
serverFutureDo();
localFutureDo();
}
@override
dispose() {
super.dispose();
// Setting.saveInitFlag(false);
}
dataCaculateAfterFutherDo() {
timeBlockWeekMap = {};
timeBlockList = [];
timeBlockList.addAll(courseList);
timeBlockList.addAll(taskList);
timeBlockList.addAll(workList);
timeBlockWeekMap =
timetableWidgetController.transformCourseMap(timeBlockList);
timetableWidgetController.transformTimeBlockMap(timeBlockList);
var mondayTime = TimetableWidgetController.getmondayTime();
//showMon
showMonth =
mondayTime.add(Duration(days: 7 * (showWeek - currentWeek))).month;
//
var mondayTime = timetableWidgetController.getmondayTime();
//
dateListstr = [];
for (int i = 0; i < 7; i++) {
dateListstr.add((mondayTime.day + i).toString());
if ((mondayTime.day + i) == DateTime.now().day) {
currentWeekDayIndex = i + 1;
}
dateListstr.add(mondayTime
.add(Duration(days: i + 7 * (showWeek - currentWeek)))
.day
.toString());
}
//
positions =
timetableWidgetController.convertTimeList(timePoints, deviceWidth);
positions = TimetableWidgetController.convertTimeList(
TimetableWidgetController.timePoints);
}
updateAfterFutherDo() {
@ -149,12 +161,13 @@ class TimetableWidgetState extends State<TimetableWidget> {
timeBlockList.addAll(workList);
timeBlockWeekMap =
timetableWidgetController.transformCourseMap(timeBlockList); //
timetableWidgetController.transformTimeBlockMap(timeBlockList); //
var mondayTime = timetableWidgetController.getmondayTime();
var mondayTime = TimetableWidgetController.getmondayTime();
//showMon
showMonth = mondayTime.add(Duration(days: 7 * (showWeek - currentWeek))).month;
showMonth =
mondayTime.add(Duration(days: 7 * (showWeek - currentWeek))).month;
//
for (int i = 0; i < 7; i++) {
@ -164,276 +177,251 @@ class TimetableWidgetState extends State<TimetableWidget> {
.toString();
}
//
positions =
timetableWidgetController.convertTimeList(timePoints, deviceWidth);
positions = TimetableWidgetController.convertTimeList(
TimetableWidgetController.timePoints);
// print('Recent monday '+DateTime.now().day.toString());
}
@override
Widget build(BuildContext contexvoidt) {
return Consumer<TimeProvider>(builder: (ctx, timePro, child) {
print('Rebuild timePro');
return FutureBuilder<void>(
future: futureDo(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
//
if (snapshot.connectionState == ConnectionState.done) {
if (firstInit == 0) {
//
dataInitAfterFutherDo();
firstInit = 1;
} else {
//
updateAfterFutherDo();
}
return RefreshIndicator(
onRefresh: () {
print('下拉refresh');
return futureDo().then((value){
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
});
},
child: GestureDetector(
onHorizontalDragEnd: (details) {
if (details.primaryVelocity! > 0) {
//
setState(() {
showWeek--;
updateDateByWeekCount();
});
} else if (details.primaryVelocity! < 0) {
//
setState(() {
showWeek++;
updateDateByWeekCount();
});
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.start, //
return RefreshIndicator(
onRefresh: () {
print('下拉refresh');
return serverFutureDo().then((value) {
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
});
},
child: GestureDetector(
onHorizontalDragEnd: (details) {
teamController.getWorks().then((value) {
workList = value;
setState(() {});
});
if (details.primaryVelocity! > 0) {
//
setState(() {
showWeek--;
currentWeekDayIndex -= 7;
dataCaculateAfterFutherDo();
// updateDateByWeekCount();
});
} else if (details.primaryVelocity! < 0) {
//
setState(() {
showWeek++;
currentWeekDayIndex += 7;
dataCaculateAfterFutherDo();
// 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: [
if(showWeek>0 && showWeek<Setting.termAllWeekCout)
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: [
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,
//stack
Container(
width: Setting.deviceWidth,
height: 2000,
child: Stack(
alignment: Alignment.center,
children: [
// Stack
Positioned(
top: 0,
left: 0,
child: Container(
width: Setting.deviceWidth,
height: 2000,
child: Stack(
children: List.generate(
//
positions.length,
(index) => Positioned(
top: positions[index].dy,
left: positions[index].dx,
child: Row(
children: [
Container(
// height: 10,
// width: 6,
child: Text(
'' +
showWeek.toString() +
'', //
style: TextStyle(
fontSize: 12,
color: currentWeek ==
showWeek //
? Colors.amber
: Colors.black87)),
Text(
TimetableWidgetController
.timePoints[index].hour
.toString()
.padLeft(2, '0') +
':' +
TimetableWidgetController
.timePoints[index].minute
.toString()
.padLeft(2, '0'),
),
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,
//
width: Setting.deviceWidth * 0.04,
height: 10,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.amber,
width: 2,
),
),
),
Text(dateListstr[index - 1], //
style: TextStyle(
fontSize: 12,
color: index ==
currentWeekDayIndex //
? Colors.lightBlue
: Colors.black87)),
Container(
//线
width: Setting.deviceWidth * 0.90,//old:0.84
height: 2,
color: Colors.lightBlue),
],
),
),
);
}),
),
//stack
Expanded(
child: SingleChildScrollView(
child: Row(
children: [
//stack
),
),
),
)),
//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(
constraints:
BoxConstraints.expand(), // 使constraints
// width: 390,
// height: 2000,
child: Stack(
children: List.generate(
timeBlockWeekMap.containsKey(showWeek)
? timeBlockWeekMap[showWeek]!.length
: 0,
(index) {
var currentItem =
timeBlockWeekMap[showWeek]![index];
return Positioned(
top: timetableWidgetController
.getdy(currentItem),
left: timetableWidgetController
.getdx(currentItem) +
Setting.deviceWidth * 0.15,
child: SingleChildScrollView(
child: Container(
width: Setting.deviceWidth * 0.115,
height: timetableWidgetController
.getHeight(currentItem),
decoration: BoxDecoration(
color: getItemColor(currentItem),
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
child: SingleChildScrollView(
child: Column(
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
),
if (currentItem is Course)
CouresBlockContenWidget(
currentItem: currentItem),
if (currentItem is Task)
TaskBlockContentWidget(
currentItem: currentItem),
if (currentItem is Work)
WorkBlockContentWidget(
currentItem: currentItem),
],
),
),
),
),
)),
//Stack
Container(
constraints: BoxConstraints
.expand(), // 使constraints
// width: 390,
// height: 2000,
child: Stack(
children: List.generate(
timeBlockWeekMap
.containsKey(showWeek)
? timeBlockWeekMap[showWeek]!
.length
: 0,
(index) {
var currentItem = timeBlockWeekMap[
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: [
if (currentItem
is Course)
CouresBlockContenWidget(
currentItem:
currentItem),
if (currentItem is Task)
TaskBlockContentWidget(
currentItem:
currentItem),
if (currentItem is Work)
WorkBlockContentWidget(
currentItem:
currentItem),
],
),
),
),
),
);
},
),
))
],
),
),
);
},
),
))
],
),
))
),
],
),
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
});
});
))
],
),
),
);
}
//
@ -449,40 +437,36 @@ class TimetableWidgetState extends State<TimetableWidget> {
}
}
class ShowTimeTextWidget extends StatelessWidget{
const ShowTimeTextWidget({
super.key,
required this.currentItem
});
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}' +
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({
BlockGestureWidget({
super.key,
required this.currentItem,
required this.blockGestureWidgetChilld,
@ -506,21 +490,28 @@ class BlockGestureWidget extends StatelessWidget {
child: ListBody(
children: <Widget>[
if (currentItem is Course) ...{
Text('老师: ${(currentItem as Course).teacher ?? ""}'),
Text('地点: ${(currentItem as Course).location ?? ""}'),
Text(
'老师: ${currentItem.teacher == '' || currentItem.teacher == null ? "" : currentItem.teacher}'),
Text(
'地点: ${currentItem.location == '' || currentItem.location == null ? "" : currentItem.location}'),
ShowTimeTextWidget(currentItem: currentItem),
Text('学分: ${(currentItem as Course).credit ?? ""}'),
Text('备注: ${(currentItem as Course).remark ?? ""}'),
Text(
'学分: ${currentItem.credit == -1 || currentItem.credit == null ? "" : currentItem.credit.toString()}'),
Text(
'备注: ${currentItem.remark == '' || currentItem.remark == null ? "" : currentItem.remark}'),
} else if (currentItem is Task) ...{
Text('内容: ${(currentItem as Task).content ?? ""}'),
Text(
'内容: ${currentItem.content == "" || currentItem.content == null ? "" : currentItem.content}'),
ShowTimeTextWidget(currentItem: currentItem),
} else if (currentItem is Work) ...{
//0
// Text('团队名: ${(currentItem as Work).ge ?? ""}'),
if((currentItem as Work).teamName != null) ...{
Text('团队名: ${(currentItem as Work).teamName ?? ""}'),
if ((currentItem as Work).teamName != null) ...{
Text(
'团队名: ${currentItem.teamName == "" || currentItem.teamName == null ? "" : currentItem.teamName}'),
},
Text('工作内容: ${(currentItem as Work).content ?? ""}'),
Text(
'工作内容: ${currentItem.content == "" || currentItem.content == null ? "" : currentItem.content}'),
ShowTimeTextWidget(currentItem: currentItem),
}
],
@ -549,38 +540,52 @@ class BlockGestureWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () {
onPressed: () async {
//
Navigator.of(context).pop(); //
if (currentItem is Course) {
// AddCourseFormWidget
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AddCourseRoute(exitCourse:currentItem);
return AddCourseRoute(exitCourse: currentItem);
},
),
);
Setting.timetableWidgetKey!.currentState!
.localFutureDo();
} else if (currentItem is Task) {
// AddTaskFormWidget
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AddScheduleRoute(exitSchedule:currentItem, scheduleType: 'task');
return AddScheduleRoute(
exitSchedule: currentItem,
scheduleType: 'task');
},
),
);
Setting.timetableWidgetKey!.currentState!
.localFutureDo();
} else {
// AddWorkFormWidget
Navigator.push(
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AddScheduleRoute(exitSchedule:currentItem, scheduleType: 'work',teamId: (currentItem as Work).getTeamId);
return AddScheduleRoute(
exitSchedule: currentItem,
scheduleType: 'work',
teamId: (currentItem as Work).getTeamId);
},
),
);
Setting.timetableWidgetKey!.currentState!
.localFutureDo();
Setting.timetableWidgetKey!.currentState!
.serverFutureDo();
}
},
child: Text('编辑'),
@ -590,28 +595,61 @@ class BlockGestureWidget extends StatelessWidget {
// TODO:
if (currentItem is Course) {
CourseController()
.deleteCourse((currentItem as Course).getCourseId).then((value){
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
.deleteCourse((currentItem as Course).getCourseId)
.then((value) {
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Navigator.of(context).pop()
Setting.timetableWidgetKey!.currentState!
.localFutureDo();
});
} else if (currentItem is Task) {
TaskController().deleteTaskByTaskid(
(currentItem as Task).getTaskId).then((value){
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
TaskController()
.deleteTaskByTaskid((currentItem as Task).getTaskId)
.then((value) {
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Navigator.of(context).pop()
Setting.timetableWidgetKey!.currentState!
.localFutureDo();
});
} else {
TeamController().deleteWorkByWorkId((currentItem as Work).getWorkId).then((value){
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Navigator.of(context).pop()
});
TeamController()
.deleteWorkByWorkId((currentItem as Work).getWorkId)
.then((value) {
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Navigator.of(context).pop()
Setting.timetableWidgetKey!.currentState!
.localFutureDo();
Setting.timetableWidgetKey!.currentState!
.serverFutureDo();
});
}
Navigator.of(context).pop();
},
child: Text('删除'),
),
SizedBox(height: 10),
Visibility(
visible: currentItem is Task,
child: ElevatedButton(
child:Text("进入番茄时钟"),
onPressed:(){
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
int time=(currentItem as Task).getEndTime.difference((currentItem as Task).getStartTime).inMinutes;
double selectedDuration=time.toDouble();
return TomatoClockRoute(flag:(currentItem as Task).getId as int,selectedDuration:selectedDuration);
},
),
);
}
)
)
],
),
);
@ -662,7 +700,11 @@ class CouresBlockContenWidget extends StatelessWidget {
Text(
(currentItem as Course).startTime.hour.toString().padLeft(2, '0') +
':' +
(currentItem as Course).startTime.minute.toString().padLeft(2, '0'),
(currentItem as Course)
.startTime
.minute
.toString()
.padLeft(2, '0'),
style: TextStyle(
fontSize: 10,
),
@ -671,7 +713,11 @@ class CouresBlockContenWidget extends StatelessWidget {
Text(
(currentItem as Course).endTime.hour.toString().padLeft(2, '0') +
':' +
(currentItem as Course).endTime.minute.toString().padLeft(2, '0'),
(currentItem as Course)
.endTime
.minute
.toString()
.padLeft(2, '0'),
style: TextStyle(
fontSize: 10,
),
@ -722,7 +768,11 @@ class TaskBlockContentWidget extends StatelessWidget {
Text(
(currentItem as Task).startTime.hour.toString().padLeft(2, '0') +
':' +
(currentItem as Task).startTime.minute.toString().padLeft(2, '0'),
(currentItem as Task)
.startTime
.minute
.toString()
.padLeft(2, '0'),
style: TextStyle(
fontSize: 10,
),
@ -775,7 +825,11 @@ class WorkBlockContentWidget extends StatelessWidget {
Text(
(currentItem as Work).startTime.hour.toString().padLeft(2, '0') +
':' +
(currentItem as Work).startTime.minute.toString().padLeft(2, '0'),
(currentItem as Work)
.startTime
.minute
.toString()
.padLeft(2, '0'),
style: TextStyle(
fontSize: 10,
),

@ -1,18 +1,28 @@
import 'dart:async';
import 'dart:math';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:timemanagerapp/controller/TaskController.dart';
import 'package:timemanagerapp/setting/Setting.dart';
class TomatoClockWidget extends StatefulWidget {
final int flag;
final double selectedDuration;
const TomatoClockWidget({super.key, required this.flag,required this.selectedDuration});
@override
_TomatoClockWidgetState createState() => _TomatoClockWidgetState();
_TomatoClockWidgetState createState() => _TomatoClockWidgetState(flag:flag,selectedDuration:selectedDuration);
}
class _TomatoClockWidgetState extends State<TomatoClockWidget> {
static AudioPlayer audioPlayer = AudioPlayer(); //
final int flag;
final double selectedDuration;
static AudioPlayer audioPlayer = AudioPlayer();
_TomatoClockWidgetState({required this.flag,required this.selectedDuration}); //
int currentTextIndex = 0;
static bool isMusicPlaying = false;//
@ -21,7 +31,61 @@ class _TomatoClockWidgetState extends State<TomatoClockWidget> {
"趁此时风华正茂埋头苦干,免他年两鬓苍苍仰面奉承。",
"我的肩上是风,风上是闪烁的星群。",
"使人疲惫的不是远方的高山,而是鞋里的一粒沙子。",
"世界上 ,没有一拳解决不了的事,如果有,那就两拳。",
"就算一次也好,我想在这颗星球上尽情奔跑。",
"只要努力活下去,总有一天会笑着回忆。",
"这世界是个好地方,值得为它奋斗。后半句我同意。",
"秉忠贞之志,守谦退之德。君子仁以爱人,不宜如此",
"只顾着追求新事物,却不回顾历史,怎么会有未来。",
"今日已成往昔,明日即将到来,为此理所当然之事,感到无比痛心。",
"云深夜阑拥月色,少年携酒晚归程,酒香醉情抬眸间,白衣翩立似惊鸿。",
"也许我们都没有长大,只是世界变小了。",
"我们终此一生,就是要摆脱他人的期待,找到真正的自己。",
"我与我周旋久,宁做我。 ",
"就算没人赏识还是选择坚持就像三十岁的梵高。",
"不管是哪种结果,我都坦然接受。因为无论是哪种结果,这都是一次非凡的旅行。",
"时间不在于你拥有多少,而在于你怎样使用。",
"正因为有忘也忘不了的回忆,才会变得坚强,这就是所谓的成长吧!",
"选择道路的时候怎么犹豫都没有关系,但决定之后就一定要坚持到底!",
"休息对于生存而言,也是紧要问题",
];
List<Map<String, String>> data = [
{
'image': 'assets/images/rain.jpg',
'text': '雨声',
'music': 'musics/rain.mp3'
},
{
'image': 'assets/images/clock.jpg',
'text': '时钟滴答',
'music': 'musics/clock.mp3'
},
{
'image': 'assets/images/beach.jpg',
'text': '阳光沙滩',
'music': 'musics/beach.mp3'
},
{
'image': 'assets/images/river.jpg',
'text': '小河流水',
'music': 'musics/river.mp3'
},
{
'image': 'assets/images/jungle.jpg',
'text': '热带雨林',
'music': 'musics/jungle.mp3'
},
{
'image': 'assets/images/village.jpg',
'text': '夏日蝉鸣',
'music': 'musics/village.mp3'
},
{
'image': 'assets/images/coffee.jpg',
'text': '悠闲咖啡',
'music': 'musics/coffee.mp3'
},
];
List<String> backgroundImages = [
"assets/images/image1.jpg",
"assets/images/image2.jpg",
@ -29,11 +93,9 @@ class _TomatoClockWidgetState extends State<TomatoClockWidget> {
];
String currentBackgroundImage = "assets/images/image1.jpg";
int totalTime = 40 * 60; //
int remainingTime = 40 * 60; //
double progress = 1.0; // 1.0
late Timer timer; //
void toggleBackgroundImage() {
int currentIndex = backgroundImages.indexOf(currentBackgroundImage);
int nextIndex = (currentIndex + 1) % backgroundImages.length;
@ -50,23 +112,88 @@ class _TomatoClockWidgetState extends State<TomatoClockWidget> {
progress = remainingTime / totalTime;
} else {
timer.cancel();
Navigator.pop(context);
//
audioPlayer.stop();
if(flag==0){
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('定时已结束'),
content: Text('你的定时已结束'),
actions: [
TextButton(
child: Text('关闭'),
onPressed: () {
Navigator.pop(context); //
Navigator.pop(context); //
},
),
],
);
},
);
}
else
{
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('当前任务'),
content: Text('您的当前任务是否需要从当前界面删除?'),
actions: [
TextButton(
child: Text(''),
onPressed: () {
TaskController()
.deleteTaskByid(flag)
.then((value) {
Setting.timetableWidgetKey!.currentState!
.localFutureDo();
});
//
Navigator.pop(context); //
Navigator.pop(context); //
},
),
TextButton(
child: Text(''),
onPressed: () {
Navigator.pop(context); //
Navigator.pop(context);
},
),
],
);
},
);
}
}
});
});
}
void toggleText() {
int nextIndex = (currentTextIndex + 1) % texts.length;
var random = Random();
var nextIndex = random.nextInt(texts.length);
setState(() {
currentTextIndex = nextIndex;
});
}
Source source=AssetSource("musics/music.mp3");
late Source source;
void playPauseMusic() {
if (isMusicPlaying == false) {
audioPlayer.setReleaseMode(ReleaseMode.loop);
audioPlayer.play(source,volume: 1).then((value){
setState(() {
isMusicPlaying = !isMusicPlaying;
@ -80,10 +207,16 @@ class _TomatoClockWidgetState extends State<TomatoClockWidget> {
});
}
}
late int totalTime ; //
late int remainingTime ; //
double progress = 1.0; // 1.0
late Timer timer;
@override
void initState() {
super.initState();
totalTime=(selectedDuration*60).toInt();
remainingTime=(selectedDuration*60).toInt();
startTimer();
}
@ -112,13 +245,30 @@ class _TomatoClockWidgetState extends State<TomatoClockWidget> {
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Text(
texts[currentTextIndex],
style: TextStyle(
fontSize: 24,
color: Colors.white,
),
),
child:
Column(
children:[
Row(
mainAxisAlignment: MainAxisAlignment.start,
children:[
Icon(
Icons.bubble_chart_outlined,
size:40,
color:Colors.white
),
]
),
Text(
" "+texts[currentTextIndex],
style: TextStyle(
fontSize: 24,
color: Colors.white,
),
),
]
)
)
),
@ -151,14 +301,83 @@ class _TomatoClockWidgetState extends State<TomatoClockWidget> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:<Widget>[
IconButton(//
icon: Icon(
Icons.batch_prediction,
color:Colors.white,
size:48
),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ListView.builder(
shrinkWrap: true,
itemCount: data.length,
// prototypeItem:SizedBox(height: 0,),
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
source=AssetSource(data[index]['music'] as String);
audioPlayer.stop();
//
isMusicPlaying=false;
playPauseMusic();
},
child: Column(
children: [
SizedBox(height: 10,),
Container(
color:Colors.grey,
child: Row(
children: [
SizedBox(width:20),
Image.asset(
data[index]['image'] as String,
width: 50,
fit: BoxFit.contain,
height: 30,
),
SizedBox(width: 10),
Text(data[index]['text'] as String),
],
),
)
],)
);
},
),
ElevatedButton(
child: Text('关闭'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
);
},
);
},),
IconButton(//
icon: Icon(
isMusicPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white,
Icons.audiotrack_rounded,
color: isMusicPlaying?Colors.white:Colors.grey,
size:48
),
onPressed: () {
var random = Random();
var next = random.nextInt(data.length);
source=AssetSource(data[next]['music'] as String);
playPauseMusic();
},
),
@ -170,7 +389,97 @@ class _TomatoClockWidgetState extends State<TomatoClockWidget> {
size:48
),
onPressed: () {
Navigator.pop(context);
isMusicPlaying=false;
audioPlayer.stop();
if(flag==0)
{
showDialog(
context: context,
builder: (BuildContext context){
return AlertDialog(
title: Text('提示'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("是否确认要关闭当前时钟?关闭后将会返回课程主界面"),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () async {
audioPlayer.stop();
Navigator.of(context).pop();//
// AddCourseFormWidget
},
child: Text('取消'),
),
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();//
// AddCourseFormWidget
Navigator.pop(context);
},
child: Text('确定'),
),
],
)
],)
);
}
);
}
else
{
showDialog(
context: context,
builder: (BuildContext context){
return AlertDialog(
title: Text('提示'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("是否确认要关闭当前时钟?关闭后将会返回课程主界面并删除当前任务"),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();//
// AddCourseFormWidget
},
child: Text('取消'),
),
ElevatedButton(
onPressed: () async {
TaskController()
.deleteTaskByid(flag)
.then((value) {
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Navigator.of(context).pop()
Setting.timetableWidgetKey!.currentState!
.localFutureDo();
});
Navigator.of(context).pop();//
// AddCourseFormWidget
Navigator.pop(context);
},
child: Text('确定'),
),
],
)
],)
);
}
);
}
},
),
]

@ -32,9 +32,13 @@ class _UserSettingWightState extends State<UserSettingWidget> {
if(number < 0.1) number = 0.1;
if(number > 2) number = 2;
await savepixelToMinuteRatio_ratio(number);
DateTime date = DateTime.tryParse(_startDateController.text) ?? DateTime.now();
print('DateTime.tryParse'+DateTime.tryParse(_startDateController.text).toString());
var res = DateTime.tryParse(_startDateController.text);
DateTime date = res ?? Setting.startdate;// dateDateTime
print('date: $date');
date = date.weekday == 1 ? date : Setting.startdate; // date
await saveStartDate(date);
Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
// Provider.of<TimeProvider>(context, listen: false).updateTimetable(); //
setState(() {
});
}

@ -13,58 +13,58 @@ packages:
dependency: "direct main"
description:
name: audioplayers
sha256: d9f6ca8e9b3e5af5e73d4c814404566f72698ee7ba35487bdf2baa6749e7503f
sha256: "61583554386721772f9309f509e17712865b38565a903c761f96b1115a979282"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.2.0"
version: "4.1.0"
audioplayers_android:
dependency: transitive
description:
name: audioplayers_android
sha256: fb01b9481f431fe04ac60f1f97ce8158383f2dc754558820592f795d81ca9d53
sha256: dbdc9b7f2aa2440314c638aa55aadd45c7705e8340d5eddf2e3fb8da32d4ae2c
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.2"
version: "3.0.2"
audioplayers_darwin:
dependency: transitive
description:
name: audioplayers_darwin
sha256: "3034e99a6df8d101da0f5082dcca0a2a99db62ab1d4ddb3277bed3f6f81afe08"
sha256: "6aea96df1d12f7ad5a71d88c6d1b22a216211a9564219920124c16768e456e9d"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.2"
version: "4.1.0"
audioplayers_linux:
dependency: transitive
description:
name: audioplayers_linux
sha256: "60787e73fefc4d2e0b9c02c69885402177e818e4e27ef087074cf27c02246c9e"
sha256: "396b62ac62c92dd26c3bc5106583747f57a8b325ebd2b41e5576f840cfc61338"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.0"
version: "2.1.0"
audioplayers_platform_interface:
dependency: transitive
description:
name: audioplayers_platform_interface
sha256: "365c547f1bb9e77d94dd1687903a668d8f7ac3409e48e6e6a3668a1ac2982adb"
sha256: f7daaed4659143094151ecf6bacd927d29ab8acffba98c110c59f0b81ae51143
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.1.0"
version: "5.0.1"
audioplayers_web:
dependency: transitive
description:
name: audioplayers_web
sha256: "22cd0173e54d92bd9b2c80b1204eb1eb159ece87475ab58c9788a70ec43c2a62"
sha256: ec84fd46eed1577148ed4113f5998a36a18da4fce7170c37ce3e21b631393339
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.1.0"
version: "3.1.0"
audioplayers_windows:
dependency: transitive
description:
name: audioplayers_windows
sha256: "9536812c9103563644ada2ef45ae523806b0745f7a78e89d1b5fb1951de90e1a"
sha256: "1d3aaac98a192b8488167711ba1e67d8b96333e8d0572ede4e2912e5bbce69a3"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.0"
version: "2.0.2"
boolean_selector:
dependency: transitive
description:
@ -149,10 +149,10 @@ packages:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.0"
version: "6.1.4"
flutter:
dependency: "direct main"
description: flutter
@ -166,6 +166,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.3"
flutter_pickers:
dependency: "direct main"
description:
name: flutter_pickers
sha256: f38a9d9229afed75f76bae64e628b78b9c20194873e3c141783523cf21ac8a95
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.9"
flutter_test:
dependency: "direct dev"
description: flutter
@ -180,10 +188,10 @@ packages:
dependency: "direct main"
description:
name: http
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
version: "0.13.6"
http_parser:
dependency: transitive
description:
@ -208,6 +216,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.1"
logger:
dependency: "direct main"
description:
name: logger
sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.0"
matcher:
dependency: transitive
description:
@ -397,14 +413,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.10.0"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.0"
sqflite:
dependency: "direct main"
description:
@ -481,10 +489,10 @@ packages:
dependency: transitive
description:
name: uuid
sha256: b715b8d3858b6fa9f68f87d20d98830283628014750c2b09b6f516c1da4af2a7
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.1.0"
version: "3.0.7"
vector_math:
dependency: transitive
description:
@ -519,4 +527,4 @@ packages:
version: "1.0.3"
sdks:
dart: ">=3.1.0 <4.0.0"
flutter: ">=3.10.0"
flutter: ">=3.7.0"

@ -31,7 +31,8 @@ dependencies:
flutter:
sdk: flutter
shared_preferences: ^2.2.1
audioplayers: 5.2.0
audioplayers: ^4.0.1
flutter_pickers: 2.1.9
# The following adds the Cupertino Icons font to your application.
@ -41,9 +42,10 @@ dependencies:
path: ^1.8.3
path_provider: ^2.1.1
multi_select_flutter: 4.1.3
http: ^1.1.0
http: 0.13.6
device_info:
provider: ^5.0.0
logger: ^1.1.0
dev_dependencies:
@ -74,8 +76,22 @@ flutter:
- assets/images/userphoto.jpg
- assets/images/image1.jpg
- assets/images/image2.jpg
- assets/images/rain.jpg
- assets/images/clock.jpg
- assets/images/beach.jpg
- assets/images/river.jpg
- assets/images/jungle.jpg
- assets/images/village.jpg
- assets/images/coffee.jpg
- assets/images/image3.jpg
- assets/musics/music.mp3
- assets/musics/coffee.mp3
- assets/musics/village.mp3
- assets/musics/jungle.mp3
- assets/musics/river.mp3
- assets/musics/beach.mp3
- assets/musics/clock.mp3
- assets/musics/rain.mp3
# To add assets to your application, add an assets section, like this:
# assets:

@ -0,0 +1,17 @@
flutter/ephemeral/
# Visual Studio user-specific files.
*.suo
*.user
*.userosscache
*.sln.docstates
# Visual Studio build-related files.
x64/
x86/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

@ -0,0 +1,102 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.14)
project(timemanagerapp LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "timemanagerapp")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(VERSION 3.14...3.25)
# Define build configuration option.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
CACHE STRING "" FORCE)
else()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
endif()
# Define settings for the Profile build mode.
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
# Use Unicode for all projects.
add_definitions(-DUNICODE -D_UNICODE)
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
target_compile_options(${TARGET} PRIVATE /EHsc)
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner")
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# Support files are copied into place next to the executable, so that it can
# run in place. This is done instead of making a separate bundle (as on Linux)
# so that building and running from within Visual Studio will work.
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
# Make the "install" step default, as it's required to run.
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
CONFIGURATIONS Profile;Release
COMPONENT Runtime)

@ -0,0 +1,104 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.14)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
# === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"flutter_export.h"
"flutter_windows.h"
"flutter_messenger.h"
"flutter_plugin_registrar.h"
"flutter_texture_registrar.h"
)
list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
add_dependencies(flutter flutter_assemble)
# === Wrapper ===
list(APPEND CPP_WRAPPER_SOURCES_CORE
"core_implementations.cc"
"standard_codec.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
"plugin_registrar.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
list(APPEND CPP_WRAPPER_SOURCES_APP
"flutter_engine.cc"
"flutter_view_controller.cc"
)
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
# Wrapper sources needed for a plugin.
add_library(flutter_wrapper_plugin STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
)
apply_standard_settings(flutter_wrapper_plugin)
set_target_properties(flutter_wrapper_plugin PROPERTIES
POSITION_INDEPENDENT_CODE ON)
set_target_properties(flutter_wrapper_plugin PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
target_include_directories(flutter_wrapper_plugin PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_plugin flutter_assemble)
# Wrapper sources needed for the runner.
add_library(flutter_wrapper_app STATIC
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_APP}
)
apply_standard_settings(flutter_wrapper_app)
target_link_libraries(flutter_wrapper_app PUBLIC flutter)
target_include_directories(flutter_wrapper_app PUBLIC
"${WRAPPER_ROOT}/include"
)
add_dependencies(flutter_wrapper_app flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
${PHONY_OUTPUT}
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
windows-x64 $<CONFIG>
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
${CPP_WRAPPER_SOURCES_CORE}
${CPP_WRAPPER_SOURCES_PLUGIN}
${CPP_WRAPPER_SOURCES_APP}
)

@ -0,0 +1,14 @@
//
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
#include <audioplayers_windows/audioplayers_windows_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
}

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter/plugin_registry.h>
// Registers Flutter plugins.
void RegisterPlugins(flutter::PluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_

@ -0,0 +1,24 @@
#
# Generated file, do not edit.
#
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
)
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
endforeach(ffi_plugin)

@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.14)
project(runner LANGUAGES CXX)
# Define the application target. To change its name, change BINARY_NAME in the
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
# work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME} WIN32
"flutter_window.cpp"
"main.cpp"
"utils.cpp"
"win32_window.cpp"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
"Runner.rc"
"runner.exe.manifest"
)
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
# Add preprocessor definitions for the build version.
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
# Disable Windows macros that collide with C++ standard library functions.
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
# Add dependency libraries and include directories. Add any application-specific
# dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)

@ -0,0 +1,121 @@
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APP_ICON ICON "resources\\app_icon.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
#else
#define VERSION_AS_NUMBER 1,0,0,0
#endif
#if defined(FLUTTER_VERSION)
#define VERSION_AS_STRING FLUTTER_VERSION
#else
#define VERSION_AS_STRING "1.0.0"
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_AS_NUMBER
PRODUCTVERSION VERSION_AS_NUMBER
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "com.example" "\0"
VALUE "FileDescription", "timemanagerapp" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "timemanagerapp" "\0"
VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0"
VALUE "OriginalFilename", "timemanagerapp.exe" "\0"
VALUE "ProductName", "timemanagerapp" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

@ -0,0 +1,71 @@
#include "flutter_window.h"
#include <optional>
#include "flutter/generated_plugin_registrant.h"
FlutterWindow::FlutterWindow(const flutter::DartProject& project)
: project_(project) {}
FlutterWindow::~FlutterWindow() {}
bool FlutterWindow::OnCreate() {
if (!Win32Window::OnCreate()) {
return false;
}
RECT frame = GetClientArea();
// The size here must match the window dimensions to avoid unnecessary surface
// creation / destruction in the startup path.
flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
frame.right - frame.left, frame.bottom - frame.top, project_);
// Ensure that basic setup of the controller was successful.
if (!flutter_controller_->engine() || !flutter_controller_->view()) {
return false;
}
RegisterPlugins(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow());
flutter_controller_->engine()->SetNextFrameCallback([&]() {
this->Show();
});
// Flutter can complete the first frame before the "show window" callback is
// registered. The following call ensures a frame is pending to ensure the
// window is shown. It is a no-op if the first frame hasn't completed yet.
flutter_controller_->ForceRedraw();
return true;
}
void FlutterWindow::OnDestroy() {
if (flutter_controller_) {
flutter_controller_ = nullptr;
}
Win32Window::OnDestroy();
}
LRESULT
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
// Give Flutter, including plugins, an opportunity to handle window messages.
if (flutter_controller_) {
std::optional<LRESULT> result =
flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
lparam);
if (result) {
return *result;
}
}
switch (message) {
case WM_FONTCHANGE:
flutter_controller_->engine()->ReloadSystemFonts();
break;
}
return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
}

@ -0,0 +1,33 @@
#ifndef RUNNER_FLUTTER_WINDOW_H_
#define RUNNER_FLUTTER_WINDOW_H_
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <memory>
#include "win32_window.h"
// A window that does nothing but host a Flutter view.
class FlutterWindow : public Win32Window {
public:
// Creates a new FlutterWindow hosting a Flutter view running |project|.
explicit FlutterWindow(const flutter::DartProject& project);
virtual ~FlutterWindow();
protected:
// Win32Window:
bool OnCreate() override;
void OnDestroy() override;
LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
LPARAM const lparam) noexcept override;
private:
// The project to run.
flutter::DartProject project_;
// The Flutter instance hosted by this window.
std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
};
#endif // RUNNER_FLUTTER_WINDOW_H_

@ -0,0 +1,43 @@
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <windows.h>
#include "flutter_window.h"
#include "utils.h"
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command) {
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}
// Initialize COM, so that it is available for use in the library and/or
// plugins.
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
flutter::DartProject project(L"data");
std::vector<std::string> command_line_arguments =
GetCommandLineArguments();
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.Create(L"timemanagerapp", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
::MSG msg;
while (::GetMessage(&msg, nullptr, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::CoUninitialize();
return EXIT_SUCCESS;
}

@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Runner.rc
//
#define IDI_APP_ICON 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save