From a06a207a1e3d373c4ef86b4f7bc99efa630bcb72 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Fri, 16 Aug 2019 15:09:23 +0800 Subject: [PATCH 01/34] Update to v3 test host information --- lib/api/helper.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index e3c33111..2b57fb8a 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -10,10 +10,10 @@ import 'package:nkust_ap/models/api/leave_response.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:shared_preferences/shared_preferences.dart'; -const HOST = "nkust-ap-api.rainvisitor.me"; -const PORT = '2087'; +const HOST = 'nkust.taki.dog'; +const PORT = '443'; -const VERSION = 'v2'; +const VERSION = 'v3'; class Helper { static Helper _instance; From 60810589edb5c9b309ff73253d5978a6caccb69e Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Fri, 16 Aug 2019 15:13:53 +0800 Subject: [PATCH 02/34] Update feature login to api v3 --- lib/api/helper.dart | 14 +++++-- lib/models/api/login_response.dart | 63 ++++++++++-------------------- lib/pages/login_page.dart | 7 +--- 3 files changed, 32 insertions(+), 52 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 2b57fb8a..f84d94c1 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -84,9 +84,17 @@ class Helper { Future login(String username, String password) async { dio.options.headers = _createBasicAuth(username, password); try { - var response = await dio.get("/$VERSION/token"); - if (response == null) print("null"); - return LoginResponse.fromJson(response.data); + var response = await dio.post( + '/oauth/token', + data: { + 'username': username, + 'password': password, + }, + ); + if (response == null) print('null'); + var loginResponse = LoginResponse.fromJson(response.data); + options.headers = _createBearerTokenAuth(loginResponse.token); + return loginResponse; } on DioError catch (dioError) { throw dioError; } diff --git a/lib/models/api/login_response.dart b/lib/models/api/login_response.dart index 75983e24..375ed639 100644 --- a/lib/models/api/login_response.dart +++ b/lib/models/api/login_response.dart @@ -1,50 +1,27 @@ -class LoginResponse { - String authToken; - int duration; - IsLogin isLogin; - String tokenType; - - LoginResponse({this.authToken, this.duration, this.isLogin, this.tokenType}); +import 'dart:convert'; - LoginResponse.fromJson(Map json) { - authToken = json['auth_token']; - duration = json['duration']; - isLogin = json['is_login'] != null - ? new IsLogin.fromJson(json['is_login']) - : null; - tokenType = json['token_type']; - } +class LoginResponse { + DateTime expireTime; + String token; - Map toJson() { - final Map data = new Map(); - data['auth_token'] = this.authToken; - data['duration'] = this.duration; - if (this.isLogin != null) { - data['is_login'] = this.isLogin.toJson(); - } - data['token_type'] = this.tokenType; - return data; - } -} + LoginResponse({ + this.expireTime, + this.token, + }); -class IsLogin { - bool ap; - bool bus; - bool leave; + factory LoginResponse.fromRawJson(String str) => + LoginResponse.fromJson(json.decode(str)); - IsLogin({this.ap, this.bus, this.leave}); + String toRawJson() => json.encode(toJson()); - IsLogin.fromJson(Map json) { - ap = json['ap']; - bus = json['bus']; - leave = json['leave']; - } + factory LoginResponse.fromJson(Map json) => + new LoginResponse( + expireTime: DateTime.parse(json["expireTime"]), + token: json["token"], + ); - Map toJson() { - final Map data = new Map(); - data['ap'] = this.ap; - data['bus'] = this.bus; - data['leave'] = this.leave; - return data; - } + Map toJson() => { + "expireTime": expireTime.toIso8601String(), + "token": token, + }; } diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index 249b40f6..29ad4914 100644 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -310,12 +310,7 @@ class LoginPageState extends State .then((LoginResponse response) async { if (Navigator.canPop(context)) Navigator.of(context, rootNavigator: true).pop(); - if (response.isLogin != null) { - Preferences.setBool(Constants.PREF_AP_ENABLE, response.isLogin.ap); - Preferences.setBool(Constants.PREF_BUS_ENABLE, response.isLogin.bus); - Preferences.setBool( - Constants.PREF_LEAVE_ENABLE, response.isLogin.leave); - } + ShareDataWidget.of(context).data.loginResponse = response; Preferences.setString(Constants.PREF_USERNAME, _username.text); if (isRememberPassword) { Preferences.setStringSecurity( From 1560f4a3c7520f703e8463e093b66d0cb2ac8ebb Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Fri, 16 Aug 2019 15:20:10 +0800 Subject: [PATCH 03/34] Add create Bearer token method --- lib/api/helper.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index f84d94c1..fbb1f16e 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -227,4 +227,10 @@ class Helper { "Authorization": "Basic " + base64.encode(encoded.toList(growable: false)) }; } + + _createBearerTokenAuth(String token) { + return { + 'Authorization': 'Bearer $token', + }; + } } From fb6961ed9798370c4a98a59ceae33c0dbe189dcb Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Fri, 16 Aug 2019 15:21:22 +0800 Subject: [PATCH 04/34] Add lose parameter --- lib/main.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/main.dart b/lib/main.dart index 0a44beaa..e6e39412 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,6 +21,7 @@ import 'package:nkust_ap/utils/preferences.dart'; import 'package:nkust_ap/utils/utils.dart'; import 'package:nkust_ap/widgets/share_data_widget.dart'; +import 'models/api/login_response.dart'; import 'models/user_info.dart'; void main() async { @@ -90,6 +91,7 @@ class MyAppState extends State { FirebaseMessaging firebaseMessaging; ThemeData themeData; UserInfo userInfo; + LoginResponse loginResponse; bool isLogin = false, offlineLogin = false; setThemeData(ThemeData themeData) { From 8c281be4cb71d1687199c84b6baa8e2d165e799d Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Fri, 16 Aug 2019 15:23:33 +0800 Subject: [PATCH 05/34] Update feature user info to api v3 --- lib/api/helper.dart | 5 +- lib/models/user_info.dart | 79 +++++++++++---------------- lib/pages/home/user_info_page.dart | 4 +- lib/pages/home_page.dart | 8 +-- lib/pages/search_student_id_page.dart | 6 +- lib/utils/nkust_helper.dart | 4 +- lib/widgets/drawer_body.dart | 62 +++++++-------------- 7 files changed, 67 insertions(+), 101 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index fbb1f16e..e413b146 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -113,9 +113,8 @@ class Helper { Future getUsersInfo() async { try { - var response = await dio.get("/$VERSION/ap/users/info"); - var json = jsonCodec.decode(response.data); - return UserInfo.fromJson(json); + var response = await dio.get('/user/info'); + return UserInfo.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } diff --git a/lib/models/user_info.dart b/lib/models/user_info.dart index e296b294..00a8d14c 100644 --- a/lib/models/user_info.dart +++ b/lib/models/user_info.dart @@ -1,55 +1,42 @@ +import 'dart:convert'; + class UserInfo { String educationSystem; String department; String className; - String studentId; - String studentNameCht; - String studentNameEng; - int status = 200; - String message; + String id; + String name; + String pictureUrl; + + UserInfo({ + this.educationSystem, + this.department, + this.className, + this.id, + this.name, + this.pictureUrl, + }); - UserInfo( - {this.educationSystem = "", - this.department = "", - this.className = "", - this.studentId = "", - this.studentNameCht = "", - this.studentNameEng = "", - this.status, - this.message = ""}); + factory UserInfo.fromRawJson(String str) => + UserInfo.fromJson(json.decode(str)); - UserInfo.fromJson(Map json) { - educationSystem = json['education_system']; - department = json['department']; - className = json['class']; - studentId = json['student_id']; - studentNameCht = json['student_name_cht']; - studentNameEng = json['student_name_eng']; - status = json['status']; - message = json['message']; - } + String toRawJson() => json.encode(toJson()); - Map toJson() { - final Map data = new Map(); - data['education_system'] = this.educationSystem; - data['department'] = this.department; - data['class'] = this.className; - data['student_id'] = this.studentId; - data['student_name_cht'] = this.studentNameCht; - data['student_name_eng'] = this.studentNameEng; - data['status'] = this.status; - data['message'] = this.message; - return data; - } + factory UserInfo.fromJson(Map json) => new UserInfo( + educationSystem: json["educationSystem"], + department: json["department"], + className: json["className"], + id: json["id"], + name: json["name"], + pictureUrl: json["pictureUrl"], + ); - void setData(UserInfo userInfo) { - educationSystem = userInfo.educationSystem; - department = userInfo.department; - className = userInfo.className; - studentId = userInfo.studentId; - studentNameCht = userInfo.studentNameCht; - studentNameEng = userInfo.studentNameEng; - status = userInfo.status; - message = userInfo.message; - } + Map toJson() => { + "educationSystem": educationSystem, + "department": department, + "className": className, + "id": id, + "name": name, + "pictureUrl": pictureUrl, + }; } diff --git a/lib/pages/home/user_info_page.dart b/lib/pages/home/user_info_page.dart index 1ae0f16a..8b40ee10 100644 --- a/lib/pages/home/user_info_page.dart +++ b/lib/pages/home/user_info_page.dart @@ -75,7 +75,7 @@ class UserInfoPageState extends State SizedBox(height: 8.0), ListTile( title: Text(app.studentNameCht), - subtitle: Text(widget.userInfo.studentNameCht), + subtitle: Text(widget.userInfo.name), ), Divider(height: 1.0), ListTile( @@ -95,7 +95,7 @@ class UserInfoPageState extends State Divider(height: 1.0), ListTile( title: Text(app.studentId), - subtitle: Text(widget.userInfo.studentId), + subtitle: Text(widget.userInfo.id), ), ], ), diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 250907c1..e7c48108 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -24,7 +24,7 @@ class HomePage extends StatefulWidget { } class HomePageState extends State { - _State state = _State.loading; + _State state = _State.offline; AppLocalizations app; UserInfo userInfo = UserInfo(); @@ -35,7 +35,7 @@ class HomePageState extends State { @override void initState() { FA.setCurrentScreen("HomePage", "home_page.dart"); - _getNewsAll(); +// _getNewsAll(); _getUserInfo(); if (Preferences.getBool(Constants.PREF_AUTO_LOGIN, false)) Utils.checkUpdate(context); @@ -306,8 +306,8 @@ class HomePageState extends State { this.userInfo = userInfo; }); FA.setUserProperty('department', userInfo.department); - FA.setUserProperty('student_id', userInfo.studentId); - FA.setUserId(userInfo.studentId); + FA.setUserProperty('student_id', userInfo.id); + FA.setUserId(userInfo.id); FA.logUserInfo(userInfo.department); ShareDataWidget.of(context).data.userInfo = userInfo; CacheUtils.saveUserInfo(userInfo); diff --git a/lib/pages/search_student_id_page.dart b/lib/pages/search_student_id_page.dart index 6daa982f..a6b812df 100644 --- a/lib/pages/search_student_id_page.dart +++ b/lib/pages/search_student_id_page.dart @@ -183,7 +183,7 @@ class SearchStudentIdPageState extends State { } else { UserInfo result = await NKUSTHelper.instance.getUsername(_id.text); if (result != null && isAutoFill) { - Navigator.pop(context, result.studentId); + Navigator.pop(context, result.id); } else { showDialog( context: context, @@ -206,8 +206,8 @@ class SearchStudentIdPageState extends State { : sprintf( app.searchStudentIdFormat, [ - result.studentNameCht, - result.studentId, + result.name, + result.id, ], ), style: TextStyle(fontWeight: FontWeight.bold), diff --git a/lib/utils/nkust_helper.dart b/lib/utils/nkust_helper.dart index 1620a6c9..d30db8e5 100644 --- a/lib/utils/nkust_helper.dart +++ b/lib/utils/nkust_helper.dart @@ -33,8 +33,8 @@ class NKUSTHelper { var elements = document.getElementsByTagName('b'); if (elements.length >= 4) return UserInfo( - studentId: elements[4].text.replaceAll(' ', ''), - studentNameCht: elements[2].text, + id: elements[4].text.replaceAll(' ', ''), + name: elements[2].text, ); else return null; diff --git a/lib/widgets/drawer_body.dart b/lib/widgets/drawer_body.dart index d543e154..c556f35a 100644 --- a/lib/widgets/drawer_body.dart +++ b/lib/widgets/drawer_body.dart @@ -1,10 +1,8 @@ import 'dart:io'; import 'dart:typed_data'; -import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; -import 'package:nkust_ap/api/helper.dart'; import 'package:nkust_ap/config/constants.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/pages/page.dart'; @@ -59,17 +57,11 @@ class DrawerBodyState extends State { children: [ GestureDetector( onTap: () { - if (widget.userInfo == null) return; - if ((widget.userInfo.status == null - ? 200 - : widget.userInfo.status) == - 200) + if (widget.userInfo != null) Utils.pushCupertinoStyle( context, UserInfoPage(userInfo: widget.userInfo), ); - else - Utils.showToast(context, widget.userInfo.message); }, child: Stack( children: [ @@ -106,11 +98,11 @@ class DrawerBodyState extends State { ), ), accountName: Text( - '${widget.userInfo?.studentNameCht}', + '${widget.userInfo?.name}', style: TextStyle(color: Colors.white), ), accountEmail: Text( - '${widget.userInfo?.studentId}', + '${widget.userInfo?.id}', style: TextStyle(color: Colors.white), ), decoration: BoxDecoration( @@ -294,39 +286,27 @@ class DrawerBodyState extends State { }, ); - _getUserPicture() { - Helper.instance.getUsersPicture().then((url) async { - try { - var response = await http.get(url); - if (!response.body.contains('html')) { - if (mounted) { - setState(() { - pictureBytes = response.bodyBytes; - }); - } - CacheUtils.savePictureData(response.bodyBytes); - } else { - var bytes = await CacheUtils.loadPictureData(); - if (mounted) { - setState(() { - pictureBytes = bytes; - }); - } - } - } catch (e) {} - }).catchError((e) { - if (e is DioError) { - switch (e.type) { - case DioErrorType.RESPONSE: - Utils.handleResponseError(context, 'getUserPicture', mounted, e); - break; - default: - break; + _getUserPicture() async { + try { + var response = await http.get(widget.userInfo.pictureUrl); + if (!response.body.contains('html')) { + if (mounted) { + setState(() { + pictureBytes = response.bodyBytes; + }); } + CacheUtils.savePictureData(response.bodyBytes); } else { - throw e; + var bytes = await CacheUtils.loadPictureData(); + if (mounted) { + setState(() { + pictureBytes = bytes; + }); + } } - }); + } catch (e) { + throw e; + } } _getPreference() async { From b4cefed3837870573c62d3a73e20825ac8f46374 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Fri, 16 Aug 2019 15:41:22 +0800 Subject: [PATCH 06/34] Update feature semester to api v3 --- lib/api/helper.dart | 2 +- lib/models/semester_data.dart | 77 +++++++++++++----------- lib/pages/home/calculate_units_page.dart | 19 +++--- lib/widgets/semester_picker.dart | 10 +-- 4 files changed, 58 insertions(+), 50 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index e413b146..47eace4c 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -131,7 +131,7 @@ class Helper { Future getSemester() async { try { - var response = await dio.get("/$VERSION/ap/semester"); + var response = await dio.get("/user/semesters"); return SemesterData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; diff --git a/lib/models/semester_data.dart b/lib/models/semester_data.dart index 19c5bd2d..50f7e3d5 100644 --- a/lib/models/semester_data.dart +++ b/lib/models/semester_data.dart @@ -1,60 +1,69 @@ +// To parse this JSON data, do +// +// final semesterData = semesterDataFromJson(jsonString); + +import 'dart:convert'; + class SemesterData { - List semesters; + List data; Semester defaultSemester; + int defaultIndex; SemesterData({ - this.semesters, + this.data, this.defaultSemester, - }); + }) { + defaultIndex = getDefaultIndex(); + } - static SemesterData fromJson(Map json) { - return SemesterData( - semesters: Semester.toList(json['semester']), - defaultSemester: Semester.fromJson(json['default']), - ); + getDefaultIndex() { + for (var i = 0; i < data.length; i++) + if (defaultSemester.text == data[i].text) return i; + return 0; } + factory SemesterData.fromRawJson(String str) => + SemesterData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SemesterData.fromJson(Map json) => new SemesterData( + data: new List.from( + json["data"].map((x) => Semester.fromJson(x))), + defaultSemester: Semester.fromJson(json["default"]), + ); + Map toJson() => { - 'semester': semesters, - 'default': defaultSemester, + "data": new List.from(data.map((x) => x.toJson())), + "default": defaultSemester.toJson(), }; - - int get defaultIndex { - if (semesters == null) return -1; - for (var i = 0; i < semesters.length; i++) - if (semesters[i].text == defaultSemester.text) return i; - return 0; - } } class Semester { + String year; String value; - int selected; String text; Semester({ + this.year, this.value, - this.selected, this.text, }); - static List toList(List jsonArray) { - List list = []; - for (var item in (jsonArray ?? [])) list.add(Semester.fromJson(item)); - return list; - } + factory Semester.fromRawJson(String str) => + Semester.fromJson(json.decode(str)); - static Semester fromJson(Map json) { - return Semester( - value: json['value'], - selected: json['selected'], - text: json['text'], - ); - } + String toRawJson() => json.encode(toJson()); + + factory Semester.fromJson(Map json) => new Semester( + year: json["year"], + value: json["value"], + text: json["text"], + ); Map toJson() => { - 'value': value, - 'selected': selected, - 'text': text, + "year": year, + "value": value, + "text": text, }; } diff --git a/lib/pages/home/calculate_units_page.dart b/lib/pages/home/calculate_units_page.dart index 43cd5f30..97dd454a 100644 --- a/lib/pages/home/calculate_units_page.dart +++ b/lib/pages/home/calculate_units_page.dart @@ -103,7 +103,7 @@ class CalculateUnitsPageState extends State _scoreBorder(Semester semester, ScoreData score) { return TableRow(children: [ - _scoreTextBorder(semester.text, false), + _scoreTextBorder(semester.year, false), _scoreTextBorder("${score.content.detail.average}", false), _scoreTextBorder("${score.content.detail.classRank}", false) ]); @@ -318,18 +318,17 @@ class CalculateUnitsPageState extends State setState(() { state = _State.loading; }); - if (semesterData == null || semesterData.semesters == null) { + if (semesterData == null || semesterData.data == null) { _getSemester(); return; } - var textList = - semesterData.semesters[currentSemesterIndex].value.split(","); + var textList = semesterData.data[currentSemesterIndex].value.split(","); if (textList.length == 2) { Helper.instance.getScores(textList[0], textList[1]).then((response) { if (response.status == 200) { if (startYear == -1) startYear = int.parse(textList[0]); //scoreWeightList.add(_scoreTitle()); - semesterList.add(semesterData.semesters[currentSemesterIndex]); + semesterList.add(semesterData.data[currentSemesterIndex]); scoreDataList.add(response); for (var score in response.content.scores) { var finalScore = double.tryParse(score.finalScore); @@ -352,7 +351,7 @@ class CalculateUnitsPageState extends State } } var currentYear = int.parse(textList[0]); - if (currentSemesterIndex < semesterData.semesters.length - 1 && + if (currentSemesterIndex < semesterData.data.length - 1 && ((startYear - currentYear).abs() <= 6 || startYear == -1)) { currentSemesterIndex++; if (mounted) _getSemesterScore(); @@ -404,12 +403,12 @@ class CalculateUnitsPageState extends State state = _State.loading; }); print('_getSemesterScore'); - print(semesterData.semesters.length); - if (semesterData == null || semesterData.semesters == null) { + print(semesterData.data.length); + if (semesterData == null || semesterData.data == null) { _getSemester(); return; } - semesterData.semesters.forEach((s) { + semesterData.data.forEach((s) { var textList = s.value.split(","); if (textList.length == 2) { Helper.instance.getScores(textList[0], textList[1]).then((response) { @@ -443,7 +442,7 @@ class CalculateUnitsPageState extends State print('startYear = $startYear'); print('currentYear = $currentYear'); count++; - if (count == semesterData.semesters.length) { + if (count == semesterData.data.length) { unitsTotal = requiredUnitsTotal + electiveUnitsTotal + otherUnitsTotal; if (mounted) { diff --git a/lib/widgets/semester_picker.dart b/lib/widgets/semester_picker.dart index b4a0ee2c..9079079b 100644 --- a/lib/widgets/semester_picker.dart +++ b/lib/widgets/semester_picker.dart @@ -118,10 +118,10 @@ class SemesterPickerState extends State { ), ), children: [ - for (var i = 0; i < semesterData.semesters.length; i++) ...[ + for (var i = 0; i < semesterData.data.length; i++) ...[ DialogOption( - text: semesterData.semesters[i].text, - check: semesterData.semesters[i].text == selectSemester.text, + text: semesterData.data[i].text, + check: semesterData.data[i].text == selectSemester.text, onPressed: () { Navigator.pop(context, i); }), @@ -133,9 +133,9 @@ class SemesterPickerState extends State { ), ).then((int position) async { if (position != null) { - widget.onSelect(semesterData.semesters[position], position); + widget.onSelect(semesterData.data[position], position); setState(() { - selectSemester = semesterData.semesters[position]; + selectSemester = semesterData.data[position]; }); } }); From 6f75baa302f443ee3c4073fd6670b4df6381ebbe Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Fri, 16 Aug 2019 17:48:53 +0800 Subject: [PATCH 07/34] Update feature scores to api v3 --- lib/api/helper.dart | 9 +- lib/models/score_data.dart | 150 ++++++++++------------- lib/pages/home/calculate_units_page.dart | 92 ++++++-------- lib/pages/home/score_page.dart | 104 ++++++++-------- 4 files changed, 164 insertions(+), 191 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 47eace4c..2dd9f3b5 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -141,8 +141,13 @@ class Helper { Future getScores(String year, String semester) async { try { var response = await dio.get( - "/$VERSION/ap/users/scores/" + year + "/" + semester, - cancelToken: cancelToken); + "/user/scores", + queryParameters: { + 'year': year, + 'value': semester, + }, + cancelToken: cancelToken, + ); return ScoreData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; diff --git a/lib/models/score_data.dart b/lib/models/score_data.dart index 461110be..c94442c1 100644 --- a/lib/models/score_data.dart +++ b/lib/models/score_data.dart @@ -1,48 +1,64 @@ +// To parse this JSON data, do +// +// final scoreData = scoreDataFromJson(jsonString); + +import 'dart:convert'; + class ScoreData { - int status; - String messages; - Content content; + List scores; + Detail detail; ScoreData({ - this.status, - this.messages, - this.content, + this.scores, + this.detail, }); - static ScoreData fromJson(Map json) { - return ScoreData( - status: json['status'], - messages: json['messages'], - content: json['scores'] != null ? Content.fromJson(json['scores']) : null, - ); - } + factory ScoreData.fromRawJson(String str) => + ScoreData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ScoreData.fromJson(Map json) => new ScoreData( + scores: + new List.from(json["scores"].map((x) => Score.fromJson(x))), + detail: Detail.fromJson(json["detail"]), + ); Map toJson() => { - 'status': status, - 'messages': messages, - 'scores': content, + "scores": new List.from(scores.map((x) => x.toJson())), + "detail": detail.toJson(), }; } -class Content { - List scores; - Detail detail; +class Detail { + int conduct; + int average; + String classRank; + int classPercentage; - Content({ - this.scores, - this.detail, + Detail({ + this.conduct, + this.average, + this.classRank, + this.classPercentage, }); - static Content fromJson(Map json) { - return Content( - scores: Score.toList(json['scores']), - detail: json['detail'] == null ? null : Detail.fromJson(json['detail']), - ); - } + factory Detail.fromRawJson(String str) => Detail.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Detail.fromJson(Map json) => new Detail( + conduct: json["conduct"], + average: json["average"], + classRank: json["classRank"], + classPercentage: json["classPercentage"], + ); Map toJson() => { - 'scores': scores, - 'detail': detail, + "conduct": conduct, + "average": average, + "classRank": classRank, + "classPercentage": classPercentage, }; } @@ -67,63 +83,29 @@ class Score { this.remark, }); - static List toList(List jsonArray) { - List list = []; - for (var item in (jsonArray ?? [])) list.add(Score.fromJson(item)); - return list; - } - - static Score fromJson(Map json) { - return Score( - title: json['title'], - units: json['units'], - hours: json['hours'], - required: json['required'], - at: json['at'], - middleScore: json['middle_score'], - finalScore: json['final_score'], - remark: json['remark'], - ); - } + factory Score.fromRawJson(String str) => Score.fromJson(json.decode(str)); - Map toJson() => { - 'title': title, - 'units': units, - 'hours': hours, - 'required': required, - 'at': at, - 'middle_score': middleScore, - 'final_score': finalScore, - 'remark': remark, - }; -} - -class Detail { - double conduct; - double average; - String classRank; - double classPercentage; - - Detail({ - this.conduct, - this.average, - this.classRank, - this.classPercentage, - }); + String toRawJson() => json.encode(toJson()); - static Detail fromJson(Map json) { - return Detail( - conduct: json['conduct'], - average: json['average'], - classRank: json['class_rank'], - classPercentage: json['class_percentage'], - ); - } + factory Score.fromJson(Map json) => new Score( + title: json["title"], + units: json["units"], + hours: json["hours"], + required: json["required"], + at: json["at"], + middleScore: json["middleScore"], + finalScore: json["finalScore"], + remark: json["remark"], + ); Map toJson() => { - 'conduct': conduct, - 'average': average, - 'class_rank': classRank, - 'class_percentage': classPercentage, + "title": title, + "units": units, + "hours": hours, + "required": required, + "at": at, + "middleScore": middleScore, + "finalScore": finalScore, + "remark": remark, }; } diff --git a/lib/pages/home/calculate_units_page.dart b/lib/pages/home/calculate_units_page.dart index 97dd454a..1f88cae4 100644 --- a/lib/pages/home/calculate_units_page.dart +++ b/lib/pages/home/calculate_units_page.dart @@ -27,7 +27,7 @@ class CalculateUnitsPageState extends State Semester selectSemester; SemesterData semesterData; List semesterList; - List scoreDataList; + List scores; double unitsTotal; double requiredUnitsTotal; @@ -101,14 +101,6 @@ class CalculateUnitsPageState extends State ); } - _scoreBorder(Semester semester, ScoreData score) { - return TableRow(children: [ - _scoreTextBorder(semester.year, false), - _scoreTextBorder("${score.content.detail.average}", false), - _scoreTextBorder("${score.content.detail.classRank}", false) - ]); - } - _generalEducationsBorder(Score score) { return TableRow(children: [ _scoreTextBorder(score.title, false), @@ -273,7 +265,7 @@ class CalculateUnitsPageState extends State count = 0; currentSemesterIndex = 0; semesterList = []; - scoreDataList = []; + scores = []; coreGeneralEducations = []; extendGeneralEducations = []; start = DateTime.now(); @@ -325,27 +317,25 @@ class CalculateUnitsPageState extends State var textList = semesterData.data[currentSemesterIndex].value.split(","); if (textList.length == 2) { Helper.instance.getScores(textList[0], textList[1]).then((response) { - if (response.status == 200) { - if (startYear == -1) startYear = int.parse(textList[0]); - //scoreWeightList.add(_scoreTitle()); - semesterList.add(semesterData.data[currentSemesterIndex]); - scoreDataList.add(response); - for (var score in response.content.scores) { - var finalScore = double.tryParse(score.finalScore); - if (finalScore != null) { - if (finalScore >= 60.0) { - if (score.required == "【必修】") { - requiredUnitsTotal += double.parse(score.units); - } else if (score.required == "【選修】") { - electiveUnitsTotal += double.parse(score.units); - } else { - otherUnitsTotal += double.parse(score.units); - } - if (score.title.contains("延伸通識")) { - extendGeneralEducations.add(score); - } else if (score.title.contains("核心通識")) { - coreGeneralEducations.add(score); - } + if (startYear == -1) startYear = int.parse(textList[0]); + //scoreWeightList.add(_scoreTitle()); + semesterList.add(semesterData.data[currentSemesterIndex]); + scores = response.scores; + for (var score in response.scores) { + var finalScore = double.tryParse(score.finalScore); + if (finalScore != null) { + if (finalScore >= 60.0) { + if (score.required == "【必修】") { + requiredUnitsTotal += double.parse(score.units); + } else if (score.required == "【選修】") { + electiveUnitsTotal += double.parse(score.units); + } else { + otherUnitsTotal += double.parse(score.units); + } + if (score.title.contains("延伸通識")) { + extendGeneralEducations.add(score); + } else if (score.title.contains("核心通識")) { + coreGeneralEducations.add(score); } } } @@ -412,27 +402,25 @@ class CalculateUnitsPageState extends State var textList = s.value.split(","); if (textList.length == 2) { Helper.instance.getScores(textList[0], textList[1]).then((response) { - if (response.status == 200) { - if (startYear == -1) startYear = int.parse(textList[0]); - //scoreWeightList.add(_scoreTitle()); - semesterList.add(s); - scoreDataList.add(response); - for (var score in response.content.scores) { - var finalScore = double.tryParse(score.finalScore); - if (finalScore != null) { - if (finalScore >= 60.0) { - if (score.required == "【必修】") { - requiredUnitsTotal += double.parse(score.units); - } else if (score.required == "【選修】") { - electiveUnitsTotal += double.parse(score.units); - } else { - otherUnitsTotal += double.parse(score.units); - } - if (score.title.contains("延伸通識")) { - extendGeneralEducations.add(score); - } else if (score.title.contains("核心通識")) { - coreGeneralEducations.add(score); - } + if (startYear == -1) startYear = int.parse(textList[0]); + //scoreWeightList.add(_scoreTitle()); + semesterList.add(s); + scores = response.scores; + for (var score in response.scores) { + var finalScore = double.tryParse(score.finalScore); + if (finalScore != null) { + if (finalScore >= 60.0) { + if (score.required == "【必修】") { + requiredUnitsTotal += double.parse(score.units); + } else if (score.required == "【選修】") { + electiveUnitsTotal += double.parse(score.units); + } else { + otherUnitsTotal += double.parse(score.units); + } + if (score.title.contains("延伸通識")) { + extendGeneralEducations.add(score); + } else if (score.title.contains("核心通識")) { + coreGeneralEducations.add(score); } } } diff --git a/lib/pages/home/score_page.dart b/lib/pages/home/score_page.dart index a1d79c35..034b2435 100644 --- a/lib/pages/home/score_page.dart +++ b/lib/pages/home/score_page.dart @@ -159,7 +159,7 @@ class ScorePageState extends State { _scoreTextBorder(app.finalScore, true), ], ), - for (var score in scoreData.content.scores) + for (var score in scoreData.scores) _scoreTableRowTitle(score) ], ), @@ -177,16 +177,14 @@ class ScorePageState extends State { child: Column( children: [ _textBorder( - '${app.conductScore}:${scoreData.content.detail.conduct}', + '${app.conductScore}:${scoreData.detail.conduct}', true), _textBorder( - '${app.average}:${scoreData.content.detail.average}', - false), + '${app.average}:${scoreData.detail.average}', false), _textBorder( - '${app.rank}:${scoreData.content.detail.classRank}', - false), + '${app.rank}:${scoreData.detail.classRank}', false), _textBorder( - '${app.percentage}:${scoreData.content.detail.classPercentage}', + '${app.percentage}:${scoreData.detail.classPercentage}', false), ], ), @@ -241,50 +239,51 @@ class ScorePageState extends State { _getSemesterScore() async { Helper.cancelToken?.cancel(''); Helper.cancelToken = CancelToken(); - var textList = selectSemester.value.split(','); - if (textList.length == 2) { - if (Preferences.getBool(Constants.PREF_IS_OFFLINE_LOGIN, false)) - _loadOfflineScoreData(); - else - Helper.instance.getScores(textList[0], textList[1]).then((response) { - if (mounted) - setState(() { - scoreData = response; - if (scoreData.status == 204) - state = _State.empty; - else { - state = _State.finish; - } - CacheUtils.saveScoreData(selectSemester.value, scoreData); - }); - }).catchError((e) { - if (e is DioError) { - switch (e.type) { - case DioErrorType.RESPONSE: - Utils.handleResponseError( - context, 'getSemesterScore', mounted, e); - break; - case DioErrorType.CANCEL: - break; - default: + if (Preferences.getBool(Constants.PREF_IS_OFFLINE_LOGIN, false)) + _loadOfflineScoreData(); + else + Helper.instance + .getScores(selectSemester.year, selectSemester.value) + .then((response) { + if (mounted) + setState(() { + scoreData = response; + state = _State.finish; + CacheUtils.saveScoreData(selectSemester.value, scoreData); + }); + }).catchError((e) { + if (e is DioError) { + switch (e.type) { + case DioErrorType.RESPONSE: + print(e.response.data); + if (e.response.statusCode == 204) { if (mounted) { setState(() { - state = _State.error; + state = _State.empty; Utils.handleDioError(context, e); }); } - break; - } - } else { - throw e; + } else + Utils.handleResponseError( + context, 'getSemesterScore', mounted, e); + break; + case DioErrorType.CANCEL: + break; + default: + if (mounted) { + setState(() { + state = _State.error; + Utils.handleDioError(context, e); + }); + } + throw e; + break; } - _loadOfflineScoreData(); - }); - } else { - setState(() { - state = _State.error; + } else { + throw e; + } + _loadOfflineScoreData(); }); - } } _loadOfflineScoreData() async { @@ -292,15 +291,14 @@ class ScorePageState extends State { if (mounted) { setState(() { isOffline = true; - if (scoreData == null) - state = _State.offlineEmpty; - else if (scoreData.status == 204) - state = _State.empty; - else if (scoreData.status == 200) { - state = _State.finish; - } else { - state = _State.error; - } + if (scoreData == null) state = _State.offlineEmpty; +// else if (scoreData.status == 204) +// state = _State.empty; +// else if (scoreData.status == 200) { +// state = _State.finish; +// } else { +// state = _State.error; +// } }); } } From 470a0d07b94c570fc25a40b3e02080ab20f105a3 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Tue, 20 Aug 2019 23:19:15 +0800 Subject: [PATCH 08/34] Fix course page format --- lib/api/helper.dart | 19 ++++-- lib/models/course_data.dart | 38 ++++++------ lib/pages/home/course_page.dart | 80 ++++++++++--------------- lib/utils/firebase_analytics_utils.dart | 2 +- 4 files changed, 68 insertions(+), 71 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 2dd9f3b5..7d30b966 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -148,7 +148,10 @@ class Helper { }, cancelToken: cancelToken, ); - return ScoreData.fromJson(response.data); + if (response.statusCode == 204) + return null; + else + return ScoreData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } @@ -157,9 +160,17 @@ class Helper { Future getCourseTables(String year, String semester) async { try { var response = await dio.get( - "/$VERSION/ap/users/coursetables/" + year + "/" + semester, - cancelToken: cancelToken); - return CourseData.fromJson(response.data); + '/user/coursetable', + queryParameters: { + 'year': year, + 'value': semester, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return CourseData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } diff --git a/lib/models/course_data.dart b/lib/models/course_data.dart index f01780d5..41111708 100644 --- a/lib/models/course_data.dart +++ b/lib/models/course_data.dart @@ -9,20 +9,20 @@ class CourseData { CourseData({this.status, this.messages, this.courseTables}); CourseData.fromJson(Map json) { - status = json['status']; - messages = json['messages']; - if (status == 200) - courseTables = json['coursetables'] != null - ? CourseTables.fromJson(json['coursetables']) - : null; + courseTables = json['coursetable'] != null + ? CourseTables.fromJson(json['coursetable']) + : null; + } + + bool get hasHoliday { + return ((courseTables.saturday?.isEmpty) ?? false) && + ((courseTables.sunday?.isEmpty) ?? false); } Map toJson() { final Map data = Map(); - data['status'] = this.status; - data['messages'] = this.messages; if (this.courseTables != null) { - data['coursetables'] = this.courseTables.toJson(); + data['coursetable'] = this.courseTables.toJson(); } return data; } @@ -91,7 +91,7 @@ class CourseTables { sunday.add(Course.fromJson(v)); }); } - timeCode = json['timecode'].cast(); + timeCode = new List.from(json["timeCodes"].map((x) => x)); } Map toJson() { @@ -117,7 +117,7 @@ class CourseTables { if (this.sunday != null) { data['Sunday'] = this.sunday.map((v) => v.toJson()).toList(); } - data['timecode'] = this.timeCode; + data['timeCodes'] = this.timeCode; return data; } @@ -238,16 +238,16 @@ class Date { Date({this.startTime, this.endTime, this.weekday, this.section}); Date.fromJson(Map json) { - startTime = json['start_time']; - endTime = json['end_time']; - weekday = json['weekday']; - section = json['section']; + startTime = json['startTime'] ?? ''; + endTime = json['endTime'] ?? ''; + weekday = json['weekday'] ?? ''; + section = json['section'] ?? ''; } Map toJson() { final Map data = Map(); - data['start_time'] = this.startTime; - data['end_time'] = this.endTime; + data['startTime'] = this.startTime; + data['endTime'] = this.endTime; data['weekday'] = this.weekday; data['section'] = this.section; return data; @@ -261,8 +261,8 @@ class Location { Location({this.building, this.room}); Location.fromJson(Map json) { - building = json['building']; - room = json['room']; + building = json['building'] ?? ''; + room = json['room'] ?? ''; } Map toJson() { diff --git a/lib/pages/home/course_page.dart b/lib/pages/home/course_page.dart index 4549e5a8..7767931d 100644 --- a/lib/pages/home/course_page.dart +++ b/lib/pages/home/course_page.dart @@ -33,12 +33,9 @@ class CoursePageState extends State { bool isOffline = false; - bool get hasHoliday => (courseData?.courseTables?.saturday == null && - courseData?.courseTables?.sunday == null); + int get base => (courseData.hasHoliday) ? 6 : 8; - int get base => (hasHoliday) ? 6 : 8; - - double get childAspectRatio => (hasHoliday) ? 1.5 : 1.1; + double get childAspectRatio => (courseData.hasHoliday) ? 1.5 : 1.1; @override void initState() { @@ -174,8 +171,7 @@ class CoursePageState extends State { ]; for (var week in app.weekdaysCourse.sublist(0, 4)) list[0].children.add(_titleBorder(week)); - if (courseData.courseTables.saturday == null && - courseData.courseTables.sunday == null) { + if (courseData.hasHoliday) { list[0].children.add(_titleBorder(app.weekdaysCourse[4])); } else { list[0].children.add(_titleBorder(app.weekdaysCourse[4])); @@ -296,50 +292,40 @@ class CoursePageState extends State { _getCourseTables() async { Helper.cancelToken.cancel(''); Helper.cancelToken = CancelToken(); - var textList = selectSemester.value.split(','); - if (textList.length == 2) { - Helper.instance - .getCourseTables(textList[0], textList[1]) - .then((response) { - if (mounted) - setState(() { + Helper.instance + .getCourseTables(selectSemester.year, selectSemester.value) + .then((response) { + if (mounted) + setState(() { + if (response == null) { + state = _State.empty; + } else { courseData = response; isOffline = false; CacheUtils.saveCourseData(selectSemester.value, courseData); - if (courseData.status == 204) { - state = _State.empty; - } else if (courseData.status == 200) { - state = _State.finish; - } else { - state = _State.error; - } - }); - }).catchError((e) { - if (e is DioError) { - switch (e.type) { - case DioErrorType.RESPONSE: - Utils.handleResponseError(context, 'getCourseTables', mounted, e); - break; - case DioErrorType.CANCEL: - break; - default: - if (mounted) - setState(() { - state = _State.error; - }); - Utils.handleDioError(context, e); - break; + state = _State.finish; } - } else { - throw e; - } - _loadCourseData(selectSemester.value); - }); - } else { - if (mounted) - setState(() { - state = _State.error; }); - } + }).catchError((e) { + if (e is DioError) { + switch (e.type) { + case DioErrorType.RESPONSE: + Utils.handleResponseError(context, 'getCourseTables', mounted, e); + break; + case DioErrorType.CANCEL: + break; + default: + if (mounted) + setState(() { + state = _State.error; + }); + Utils.handleDioError(context, e); + break; + } + } else { + throw e; + } + _loadCourseData(selectSemester.value); + }); } } diff --git a/lib/utils/firebase_analytics_utils.dart b/lib/utils/firebase_analytics_utils.dart index 645459fd..b6e50427 100644 --- a/lib/utils/firebase_analytics_utils.dart +++ b/lib/utils/firebase_analytics_utils.dart @@ -35,7 +35,7 @@ class FA { await analytics.logEvent( name: 'user_info', parameters: { - 'department': department, + 'department': department ?? '', 'platform': Platform.operatingSystem, }, ); From 61c64959e14e63bedfc196a2e3cbec1f617bc0b8 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Tue, 20 Aug 2019 23:19:46 +0800 Subject: [PATCH 09/34] Fix scores page format --- lib/models/score_data.dart | 6 +++--- lib/pages/home/score_page.dart | 23 +++++++++-------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/lib/models/score_data.dart b/lib/models/score_data.dart index c94442c1..5352f31f 100644 --- a/lib/models/score_data.dart +++ b/lib/models/score_data.dart @@ -31,10 +31,10 @@ class ScoreData { } class Detail { - int conduct; - int average; + double conduct; + double average; String classRank; - int classPercentage; + double classPercentage; Detail({ this.conduct, diff --git a/lib/pages/home/score_page.dart b/lib/pages/home/score_page.dart index 034b2435..586cd267 100644 --- a/lib/pages/home/score_page.dart +++ b/lib/pages/home/score_page.dart @@ -247,25 +247,20 @@ class ScorePageState extends State { .then((response) { if (mounted) setState(() { - scoreData = response; - state = _State.finish; - CacheUtils.saveScoreData(selectSemester.value, scoreData); + if (response == null) { + state = _State.empty; + } else { + scoreData = response; + state = _State.finish; + CacheUtils.saveScoreData(selectSemester.value, scoreData); + } }); }).catchError((e) { if (e is DioError) { switch (e.type) { case DioErrorType.RESPONSE: - print(e.response.data); - if (e.response.statusCode == 204) { - if (mounted) { - setState(() { - state = _State.empty; - Utils.handleDioError(context, e); - }); - } - } else - Utils.handleResponseError( - context, 'getSemesterScore', mounted, e); + Utils.handleResponseError( + context, 'getSemesterScore', mounted, e); break; case DioErrorType.CANCEL: break; From 81895b7d7938e5a521f8c211cdd7c653a53bbcfc Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Wed, 21 Aug 2019 00:54:53 +0800 Subject: [PATCH 10/34] Add feature midterm alerts page --- ios/Flutter/flutter_export_environment.sh | 4 +- lib/api/helper.dart | 21 +++ lib/models/midterm_alerts_data.dart | 74 ++++++++ lib/pages/home/midterm_alerts_page.dart | 214 ++++++++++++++++++++++ lib/utils/app_localizations.dart | 13 ++ lib/widgets/drawer_body.dart | 6 + 6 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 lib/models/midterm_alerts_data.dart create mode 100644 lib/pages/home/midterm_alerts_page.dart diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh index 552c4bdb..0186d2e4 100755 --- a/ios/Flutter/flutter_export_environment.sh +++ b/ios/Flutter/flutter_export_environment.sh @@ -6,5 +6,5 @@ export "FLUTTER_TARGET=lib/main.dart" export "FLUTTER_BUILD_DIR=build" export "SYMROOT=${SOURCE_ROOT}/../build/ios" export "FLUTTER_FRAMEWORK_DIR=/Users/rainvisitor/development/flutter/bin/cache/artifacts/engine/ios" -export "FLUTTER_BUILD_NAME=3.2.0" -export "FLUTTER_BUILD_NUMBER=30200" +export "FLUTTER_BUILD_NAME=3.2.1" +export "FLUTTER_BUILD_NUMBER=30201" diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 7d30b966..37f991d8 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -7,6 +7,7 @@ import 'package:intl/intl.dart'; import 'package:nkust_ap/config/constants.dart'; import 'package:nkust_ap/models/api/api_models.dart'; import 'package:nkust_ap/models/api/leave_response.dart'; +import 'package:nkust_ap/models/midterm_alerts_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -188,6 +189,26 @@ class Helper { } } + Future getMidtermAlerts( + String year, String semester) async { + try { + var response = await dio.get( + "/user/midterm-alerts", + queryParameters: { + 'year': year, + 'value': semester, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return MidtermAlertsData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + Future getBusReservations() async { try { var response = await dio.get("/$VERSION/bus/reservations"); diff --git a/lib/models/midterm_alerts_data.dart b/lib/models/midterm_alerts_data.dart new file mode 100644 index 00000000..8256cd0a --- /dev/null +++ b/lib/models/midterm_alerts_data.dart @@ -0,0 +1,74 @@ +// To parse this JSON data, do +// +// final midtermAlertData = midtermAlertDataFromJson(jsonString); + +import 'dart:convert'; + +class MidtermAlertsData { + List courses; + + MidtermAlertsData({ + this.courses, + }); + + factory MidtermAlertsData.fromRawJson(String str) => + MidtermAlertsData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory MidtermAlertsData.fromJson(Map json) => + new MidtermAlertsData( + courses: new List.from( + json["courses"].map((x) => MidtermAlerts.fromJson(x))), + ); + + Map toJson() => { + "courses": new List.from(courses.map((x) => x.toJson())), + }; +} + +class MidtermAlerts { + String entry; + String className; + String title; + String group; + String instructors; + String reason; + String remark; + + MidtermAlerts({ + this.entry, + this.className, + this.title, + this.group, + this.instructors, + this.reason, + this.remark, + }); + + factory MidtermAlerts.fromRawJson(String str) => + MidtermAlerts.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory MidtermAlerts.fromJson(Map json) => + new MidtermAlerts( + entry: json["entry"], + className: json["className"], + title: json["title"], + group: json["group"], + instructors: json["instructors"], + reason: json["reason"], + remark: json["remark"], + ); + + Map toJson() => { + "entry": entry, + "className": className, + "title": title, + "group": group, + "instructors": instructors, + "reason": reason, + "remark": remark, + }; +} diff --git a/lib/pages/home/midterm_alerts_page.dart b/lib/pages/home/midterm_alerts_page.dart new file mode 100644 index 00000000..ecf110b6 --- /dev/null +++ b/lib/pages/home/midterm_alerts_page.dart @@ -0,0 +1,214 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:nkust_ap/api/helper.dart'; +import 'package:nkust_ap/config/constants.dart'; +import 'package:nkust_ap/models/midterm_alerts_data.dart'; +import 'package:nkust_ap/models/semester_data.dart'; +import 'package:nkust_ap/res/app_icon.dart'; +import 'package:nkust_ap/res/resource.dart' as Resource; +import 'package:nkust_ap/utils/app_localizations.dart'; +import 'package:nkust_ap/utils/firebase_analytics_utils.dart'; +import 'package:nkust_ap/utils/preferences.dart'; +import 'package:nkust_ap/utils/utils.dart'; +import 'package:nkust_ap/widgets/hint_content.dart'; +import 'package:nkust_ap/widgets/semester_picker.dart'; +import 'package:sprintf/sprintf.dart'; + +enum _State { loading, finish, error, empty, offline } + +class MidtermAlertsPage extends StatefulWidget { + static const String routerName = "/user/midtermAlerts"; + + @override + _MidtermAlertsPageState createState() => _MidtermAlertsPageState(); +} + +class _MidtermAlertsPageState extends State { + final key = GlobalKey(); + + AppLocalizations app; + + _State state = _State.loading; + + Semester selectSemester; + SemesterData semesterData; + MidtermAlertsData midtermAlertData; + + bool isOffline = false; + + TextStyle get _textBlueStyle => + TextStyle(color: Resource.Colors.blueText, fontSize: 16.0); + + TextStyle get _textStyle => TextStyle(fontSize: 15.0); + + @override + void initState() { + //FA.setCurrentScreen('ScorePage', 'score_page.dart'); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + app = AppLocalizations.of(context); + return Scaffold( + appBar: AppBar( + title: Text(app.midtermAlerts), + backgroundColor: Resource.Colors.blue, + ), + body: Container( + child: Flex( + direction: Axis.vertical, + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox(height: 8.0), + SemesterPicker( + key: key, + onSelect: (semester, index) { + setState(() { + selectSemester = semester; + state = _State.loading; + }); + _getMidtermAlertsData(); + }), + if (isOffline) + Text( + app.offlineScore, + style: TextStyle(color: Resource.Colors.grey), + ), + Expanded( + child: RefreshIndicator( + onRefresh: () async { + await _getMidtermAlertsData(); + FA.logAction('refresh', 'swipe'); + return null; + }, + child: _body(), + ), + ), + ], + ), + ), + ); + } + + _body() { + switch (state) { + case _State.loading: + return Container( + child: CircularProgressIndicator(), alignment: Alignment.center); + case _State.empty: + case _State.error: + return FlatButton( + onPressed: () { + if (state == _State.error) + _getMidtermAlertsData(); + else + key.currentState.pickSemester(); + FA.logAction('retry', 'click'); + }, + child: HintContent( + icon: AppIcon.classIcon, + content: state == _State.error + ? app.clickToRetry + : app.midtermAlertsEmpty, + ), + ); + case _State.offline: + return HintContent( + icon: AppIcon.classIcon, + content: app.noOfflineData, + ); + default: + return ListView.builder( + itemBuilder: (_, index) { + return _midtermAlertsItem(midtermAlertData.courses[index]); + }, + itemCount: midtermAlertData.courses.length, + ); + } + } + + Widget _midtermAlertsItem(MidtermAlerts item) { + return Card( + elevation: 4.0, + margin: const EdgeInsets.all(8.0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ListTile( + title: Text( + item.title, + style: TextStyle(fontSize: 18.0), + ), + subtitle: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Text( + sprintf( + app.midtermAlertsContent, + [ + item.reason ?? '', + item.remark ?? '', + ], + ), + ), + ), + ), + ), + ); + } + + _getMidtermAlertsData() async { + if (Preferences.getBool(Constants.PREF_IS_OFFLINE_LOGIN, false)) { + setState(() { + state = _State.offline; + }); + return; + } + Helper.cancelToken.cancel(''); + Helper.cancelToken = CancelToken(); + Helper.instance + .getMidtermAlerts(selectSemester.year, selectSemester.value) + .then((response) { + if (mounted) + setState(() { + if (response == null) { + state = _State.empty; + } else { + if (response.courses.length == 0) { + state = _State.empty; + } else { + midtermAlertData = response; + state = _State.finish; + } + } + }); + }).catchError((e) { + if (e is DioError) { + switch (e.type) { + case DioErrorType.RESPONSE: + Utils.handleResponseError(context, 'getCourseTables', mounted, e); + break; + case DioErrorType.CANCEL: + break; + default: + if (mounted) + setState(() { + state = _State.error; + }); + Utils.handleDioError(context, e); + break; + } + } else { + throw e; + } + }); + } +} diff --git a/lib/utils/app_localizations.dart b/lib/utils/app_localizations.dart index 52f549e2..e3cf8e9c 100644 --- a/lib/utils/app_localizations.dart +++ b/lib/utils/app_localizations.dart @@ -361,6 +361,10 @@ class AppLocalizations { 'For first-time login, please fill in the last four number of your ID as your password', 'searchStudentIdFormat': 'Name:%s\nStudent ID:%s\n', 'searchStudentIdError': 'Search no data.', + 'midtermAlerts': 'Midterm Alerts', + 'midtermAlertsEmpty': + 'Very Good! No Midterm warning class for this semester~\n Please choose another semester \uD83D\uDE0B', + 'midtermAlertsContent': 'Reason:%s\nRemark:%s', }, 'zh': { 'app_name': '高科校務通', @@ -644,6 +648,9 @@ class AppLocalizations { 'firstLoginHint': '首次登入密碼預設為身分證末四碼', 'searchStudentIdFormat': '姓名:%s\n學號:%s\n', 'searchStudentIdError': '查無資料', + 'midtermAlerts': '期中預警', + 'midtermAlertsEmpty': '太好了!本學期沒有任何科目被預警哦~\n請選擇其他學期 \uD83D\uDE0B', + 'midtermAlertsContent': '原因:%s\n備註:%s', }, }; @@ -1143,6 +1150,12 @@ class AppLocalizations { String get searchStudentIdFormat => _vocabularies['searchStudentIdFormat']; String get searchStudentIdError => _vocabularies['searchError']; + + String get midtermAlerts => _vocabularies['midtermAlerts']; + + String get midtermAlertsEmpty => _vocabularies['midtermAlertsEmpty']; + + String get midtermAlertsContent => _vocabularies['midtermAlertsContent']; } class AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/drawer_body.dart b/lib/widgets/drawer_body.dart index c556f35a..635f3550 100644 --- a/lib/widgets/drawer_body.dart +++ b/lib/widgets/drawer_body.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:nkust_ap/config/constants.dart'; import 'package:nkust_ap/models/models.dart'; +import 'package:nkust_ap/pages/home/midterm_alerts_page.dart'; import 'package:nkust_ap/pages/page.dart'; import 'package:nkust_ap/res/app_icon.dart'; import 'package:nkust_ap/res/app_theme.dart'; @@ -156,6 +157,11 @@ class DrawerBodyState extends State { title: app.calculateUnits, page: CalculateUnitsPage(), ), + _subItem( + icon: Icons.warning, + title: app.midtermAlerts, + page: MidtermAlertsPage(), + ), ], ), ExpansionTile( From 050ac98b38b3a710ee1d4d488278ff24669e5fe2 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Wed, 21 Aug 2019 01:25:26 +0800 Subject: [PATCH 11/34] Add feature reward and penalty page --- lib/api/helper.dart | 21 ++ lib/models/reward_and_penalty_data.dart | 77 +++++++ lib/pages/home/reward_and_penalty_page.dart | 221 ++++++++++++++++++++ lib/utils/app_localizations.dart | 14 ++ lib/widgets/drawer_body.dart | 6 + 5 files changed, 339 insertions(+) create mode 100644 lib/models/reward_and_penalty_data.dart create mode 100644 lib/pages/home/reward_and_penalty_page.dart diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 37f991d8..ab379c3e 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -9,6 +9,7 @@ import 'package:nkust_ap/models/api/api_models.dart'; import 'package:nkust_ap/models/api/leave_response.dart'; import 'package:nkust_ap/models/midterm_alerts_data.dart'; import 'package:nkust_ap/models/models.dart'; +import 'package:nkust_ap/models/reward_and_penalty_data.dart'; import 'package:shared_preferences/shared_preferences.dart'; const HOST = 'nkust.taki.dog'; @@ -189,6 +190,26 @@ class Helper { } } + Future getRewardAndPenalty( + String year, String semester) async { + try { + var response = await dio.get( + "/user/reward-and-penalty", + queryParameters: { + 'year': year, + 'value': semester, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return RewardAndPenaltyData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + Future getMidtermAlerts( String year, String semester) async { try { diff --git a/lib/models/reward_and_penalty_data.dart b/lib/models/reward_and_penalty_data.dart new file mode 100644 index 00000000..ae79dcd9 --- /dev/null +++ b/lib/models/reward_and_penalty_data.dart @@ -0,0 +1,77 @@ +// To parse this JSON data, do +// +// final rewardAndPenaltyData = rewardAndPenaltyDataFromJson(jsonString); + +import 'dart:convert'; + +class RewardAndPenaltyData { + List data; + + RewardAndPenaltyData({ + this.data, + }); + + factory RewardAndPenaltyData.fromRawJson(String str) => + RewardAndPenaltyData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory RewardAndPenaltyData.fromJson(Map json) => + new RewardAndPenaltyData( + data: new List.from( + json["data"].map((x) => RewardAndPenalty.fromJson(x))), + ); + + Map toJson() => { + "data": new List.from(data.map((x) => x.toJson())), + }; +} + +class RewardAndPenalty { + String date; + String type; + String counts; + String reason; + + RewardAndPenalty({ + this.date, + this.type, + this.counts, + this.reason, + }); + + factory RewardAndPenalty.fromRawJson(String str) => + RewardAndPenalty.fromJson(json.decode(str)); + + get isReward { + switch (type) { + case '警告': + case '小過': + case '大過': + case '申誡': + return false; + case '嘉獎': + case '小功': + case '大功': + default: + return true; + } + } + + String toRawJson() => json.encode(toJson()); + + factory RewardAndPenalty.fromJson(Map json) => + new RewardAndPenalty( + date: json["date"], + type: json["type"], + counts: json["counts"], + reason: json["reason"], + ); + + Map toJson() => { + "date": date, + "type": type, + "counts": counts, + "reason": reason, + }; +} diff --git a/lib/pages/home/reward_and_penalty_page.dart b/lib/pages/home/reward_and_penalty_page.dart new file mode 100644 index 00000000..7ad54d01 --- /dev/null +++ b/lib/pages/home/reward_and_penalty_page.dart @@ -0,0 +1,221 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:nkust_ap/api/helper.dart'; +import 'package:nkust_ap/config/constants.dart'; +import 'package:nkust_ap/models/reward_and_penalty_data.dart'; +import 'package:nkust_ap/models/semester_data.dart'; +import 'package:nkust_ap/res/app_icon.dart'; +import 'package:nkust_ap/res/resource.dart' as Resource; +import 'package:nkust_ap/utils/app_localizations.dart'; +import 'package:nkust_ap/utils/firebase_analytics_utils.dart'; +import 'package:nkust_ap/utils/preferences.dart'; +import 'package:nkust_ap/utils/utils.dart'; +import 'package:nkust_ap/widgets/hint_content.dart'; +import 'package:nkust_ap/widgets/semester_picker.dart'; +import 'package:sprintf/sprintf.dart'; + +enum _State { loading, finish, error, empty, offline } + +class RewardAndPenaltyPage extends StatefulWidget { + static const String routerName = "/user/reward-and-penalty"; + + @override + _RewardAndPenaltyPageState createState() => _RewardAndPenaltyPageState(); +} + +class _RewardAndPenaltyPageState extends State { + final key = GlobalKey(); + + AppLocalizations app; + + _State state = _State.loading; + + Semester selectSemester; + SemesterData semesterData; + RewardAndPenaltyData rewardAndPenaltyData; + + bool isOffline = false; + + TextStyle get _textBlueStyle => + TextStyle(color: Resource.Colors.blueText, fontSize: 16.0); + + TextStyle get _textStyle => TextStyle(fontSize: 15.0); + + @override + void initState() { + //FA.setCurrentScreen('ScorePage', 'score_page.dart'); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + app = AppLocalizations.of(context); + return Scaffold( + appBar: AppBar( + title: Text(app.rewardAndPenalty), + backgroundColor: Resource.Colors.blue, + ), + body: Container( + child: Flex( + direction: Axis.vertical, + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox(height: 8.0), + SemesterPicker( + key: key, + onSelect: (semester, index) { + setState(() { + selectSemester = semester; + state = _State.loading; + }); + _getMidtermAlertsData(); + }), + if (isOffline) + Text( + app.offlineScore, + style: TextStyle(color: Resource.Colors.grey), + ), + Expanded( + child: RefreshIndicator( + onRefresh: () async { + await _getMidtermAlertsData(); + FA.logAction('refresh', 'swipe'); + return null; + }, + child: _body(), + ), + ), + ], + ), + ), + ); + } + + _body() { + switch (state) { + case _State.loading: + return Container( + child: CircularProgressIndicator(), alignment: Alignment.center); + case _State.empty: + case _State.error: + return FlatButton( + onPressed: () { + if (state == _State.error) + _getMidtermAlertsData(); + else + key.currentState.pickSemester(); + FA.logAction('retry', 'click'); + }, + child: HintContent( + icon: AppIcon.classIcon, + content: state == _State.error + ? app.clickToRetry + : app.rewardAndPenaltyEmpty, + ), + ); + case _State.offline: + return HintContent( + icon: AppIcon.classIcon, + content: app.noOfflineData, + ); + default: + return ListView.builder( + itemBuilder: (_, index) { + return _midtermAlertsItem(rewardAndPenaltyData.data[index]); + }, + itemCount: rewardAndPenaltyData.data.length, + ); + } + } + + Widget _midtermAlertsItem(RewardAndPenalty item) { + return Card( + elevation: 4.0, + margin: const EdgeInsets.all(8.0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ListTile( + title: Text( + item.reason, + style: TextStyle(fontSize: 18.0), + ), + trailing: Text( + '${item.type}', + style: TextStyle( + fontSize: 16.0, + color: item.isReward ? Colors.green : Colors.red, + ), + ), + subtitle: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Text( + sprintf( + app.rewardAndPenaltyContent, + [ + item.counts ?? '', + item.date ?? '', + ], + ), + ), + ), + ), + ), + ); + } + + _getMidtermAlertsData() async { + if (Preferences.getBool(Constants.PREF_IS_OFFLINE_LOGIN, false)) { + setState(() { + state = _State.offline; + }); + return; + } + Helper.cancelToken.cancel(''); + Helper.cancelToken = CancelToken(); + Helper.instance + .getRewardAndPenalty(selectSemester.year, selectSemester.value) + .then((response) { + if (mounted) + setState(() { + if (response == null) { + state = _State.empty; + } else { + if (response.data.length == 0) { + state = _State.empty; + } else { + rewardAndPenaltyData = response; + state = _State.finish; + } + } + }); + }).catchError((e) { + if (e is DioError) { + switch (e.type) { + case DioErrorType.RESPONSE: + Utils.handleResponseError(context, 'getCourseTables', mounted, e); + break; + case DioErrorType.CANCEL: + break; + default: + if (mounted) + setState(() { + state = _State.error; + }); + Utils.handleDioError(context, e); + break; + } + } else { + throw e; + } + }); + } +} diff --git a/lib/utils/app_localizations.dart b/lib/utils/app_localizations.dart index e3cf8e9c..4ef4bb40 100644 --- a/lib/utils/app_localizations.dart +++ b/lib/utils/app_localizations.dart @@ -365,6 +365,10 @@ class AppLocalizations { 'midtermAlertsEmpty': 'Very Good! No Midterm warning class for this semester~\n Please choose another semester \uD83D\uDE0B', 'midtermAlertsContent': 'Reason:%s\nRemark:%s', + 'rewardAndPenalty': 'Reward and Penalty', + 'rewardAndPenaltyEmpty': + 'Oops!No reward and penalty for this semester~\n Please choose another semester \uD83D\uDE0B', + 'rewardAndPenaltyContent': 'Counts:%s\nDate:%s', }, 'zh': { 'app_name': '高科校務通', @@ -651,6 +655,9 @@ class AppLocalizations { 'midtermAlerts': '期中預警', 'midtermAlertsEmpty': '太好了!本學期沒有任何科目被預警哦~\n請選擇其他學期 \uD83D\uDE0B', 'midtermAlertsContent': '原因:%s\n備註:%s', + 'rewardAndPenalty': '獎懲紀錄', + 'rewardAndPenaltyEmpty': 'Oops!本學期沒有任何獎懲紀錄哦~\n請選擇其他學期 \uD83D\uDE0B', + 'rewardAndPenaltyContent': '數量:%s\n日期:%s', }, }; @@ -1156,6 +1163,13 @@ class AppLocalizations { String get midtermAlertsEmpty => _vocabularies['midtermAlertsEmpty']; String get midtermAlertsContent => _vocabularies['midtermAlertsContent']; + + String get rewardAndPenalty => _vocabularies['rewardAndPenalty']; + + String get rewardAndPenaltyEmpty => _vocabularies['rewardAndPenaltyEmpty']; + + String get rewardAndPenaltyContent => + _vocabularies['rewardAndPenaltyContent']; } class AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/drawer_body.dart b/lib/widgets/drawer_body.dart index 635f3550..e1d2ae4f 100644 --- a/lib/widgets/drawer_body.dart +++ b/lib/widgets/drawer_body.dart @@ -6,6 +6,7 @@ import 'package:http/http.dart' as http; import 'package:nkust_ap/config/constants.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/pages/home/midterm_alerts_page.dart'; +import 'package:nkust_ap/pages/home/reward_and_penalty_page.dart'; import 'package:nkust_ap/pages/page.dart'; import 'package:nkust_ap/res/app_icon.dart'; import 'package:nkust_ap/res/app_theme.dart'; @@ -162,6 +163,11 @@ class DrawerBodyState extends State { title: app.midtermAlerts, page: MidtermAlertsPage(), ), + _subItem( + icon: Icons.folder, + title: app.rewardAndPenalty, + page: RewardAndPenaltyPage(), + ), ], ), ExpansionTile( From 34545fcbfe3852f56df8cde4558178483b219353 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sat, 24 Aug 2019 16:17:04 +0800 Subject: [PATCH 12/34] Update api news to api v3 announcements --- lib/api/helper.dart | 5 +- lib/models/announcements_data.dart | 78 +++++++++++++++++++++++++++ lib/pages/home/news_content_page.dart | 16 +++--- lib/pages/home_page.dart | 52 ++++++++++-------- 4 files changed, 118 insertions(+), 33 deletions(-) create mode 100644 lib/models/announcements_data.dart diff --git a/lib/api/helper.dart b/lib/api/helper.dart index ab379c3e..01882418 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -5,6 +5,7 @@ import 'package:dio/dio.dart'; import 'package:encrypt/encrypt.dart'; import 'package:intl/intl.dart'; import 'package:nkust_ap/config/constants.dart'; +import 'package:nkust_ap/models/announcements_data.dart'; import 'package:nkust_ap/models/api/api_models.dart'; import 'package:nkust_ap/models/api/leave_response.dart'; import 'package:nkust_ap/models/midterm_alerts_data.dart'; @@ -102,11 +103,11 @@ class Helper { } } - Future> getAllNews() async { + Future getAllAnnouncements() async { try { var response = await dio.get("/$VERSION/news/all"); var jsonArray = jsonCodec.decode(response.data); - return News.toList(jsonArray); + return AnnouncementsData.fromJson(jsonArray); } on DioError catch (dioError) { print(dioError); throw dioError; diff --git a/lib/models/announcements_data.dart b/lib/models/announcements_data.dart new file mode 100644 index 00000000..928f7ffa --- /dev/null +++ b/lib/models/announcements_data.dart @@ -0,0 +1,78 @@ +import 'dart:convert'; + +class AnnouncementsData { + List data; + + AnnouncementsData({ + this.data, + }); + + factory AnnouncementsData.fromRawJson(String str) => + AnnouncementsData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory AnnouncementsData.fromJson(Map json) => + AnnouncementsData( + data: List.from( + json["data"].map((x) => Announcements.fromJson(x))), + ); + + Map toJson() => { + "data": List.from(data.map((x) => x.toJson())), + }; + + static sample() { + return AnnouncementsData.fromRawJson( + '{ "data": [ { "title": "高科校務通IOS版 回歸", "id": 1, "nextId": 2, "lastId": 2, "imgUrl": "https://i.imgur.com/faSwvRv.jpg", "url": "https://nkustap.page.link/bCK1", "description": "重新推出 IOS 版本 高科校務通 此版本還在測試中 迎同學私訊粉專意見回饋", "publishedTime": "2019-03-16T20:16:04+08:00" }, { "title": "宿舍直達高鐵站專車", "id": 2, "nextId": -1, "lastId": 2, "imgUrl": "https://i.imgur.com/wwxD4Xa.png", "url": "", "description": "從燕巢宿舍直接發車,不用再走到公車站排隊 人數達25人即發車,一人只要30元喔", "publishedTime": "2019-03-16T20:16:04+08:00" } ] }'); + } +} + +class Announcements { + String title; + int id; + int nextId; + int lastId; + String imgUrl; + String url; + String description; + String publishedTime; + + Announcements({ + this.title, + this.id, + this.nextId, + this.lastId, + this.imgUrl, + this.url, + this.description, + this.publishedTime, + }); + + factory Announcements.fromRawJson(String str) => + Announcements.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Announcements.fromJson(Map json) => Announcements( + title: json["title"], + id: json["id"], + nextId: json["nextId"], + lastId: json["lastId"], + imgUrl: json["imgUrl"], + url: json["url"], + description: json["description"], + publishedTime: json["publishedTime"], + ); + + Map toJson() => { + "title": title, + "id": id, + "nextId": nextId, + "lastId": lastId, + "imgUrl": imgUrl, + "url": url, + "description": description, + "publishedTime": publishedTime, + }; +} diff --git a/lib/pages/home/news_content_page.dart b/lib/pages/home/news_content_page.dart index 7d474d69..a40dc1ca 100644 --- a/lib/pages/home/news_content_page.dart +++ b/lib/pages/home/news_content_page.dart @@ -2,7 +2,7 @@ import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; -import 'package:nkust_ap/models/models.dart'; +import 'package:nkust_ap/models/announcements_data.dart'; import 'package:nkust_ap/res/app_icon.dart'; import 'package:nkust_ap/res/resource.dart' as Resource; import 'package:nkust_ap/utils/global.dart'; @@ -12,7 +12,7 @@ enum _Status { loading, finish, error, empty } class NewsContentPage extends StatefulWidget { static const String routerName = "/news/content"; - final News news; + final Announcements news; NewsContentPage(this.news); @@ -78,10 +78,10 @@ class NewsContentPageState extends State { tag: widget.news.hashCode, child: (Platform.isIOS || Platform.isAndroid) ? CachedNetworkImage( - imageUrl: widget.news.image, + imageUrl: widget.news.imgUrl, errorWidget: (context, url, error) => Icon(Icons.error), ) - : Image.network(widget.news.image), + : Image.network(widget.news.imgUrl), ), ); final List newsContent = [ @@ -108,7 +108,7 @@ class NewsContentPageState extends State { padding: EdgeInsets.symmetric( horizontal: orientation == Orientation.portrait ? 16.0 : 0.0), child: Text( - widget.news.content, + widget.news.description, textAlign: TextAlign.center, style: TextStyle( fontSize: 16.0, @@ -126,9 +126,9 @@ class NewsContentPageState extends State { ), onPressed: () { Utils.launchUrl(widget.news.url); - String message = widget.news.content.length > 12 - ? widget.news.content - : widget.news.content.substring(0, 12); + String message = widget.news.description.length > 12 + ? widget.news.description + : widget.news.description.substring(0, 12); FA.logAction('news_link', 'click', message: message); }, padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 0.0), diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index e7c48108..577232ac 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:nkust_ap/models/announcements_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/res/app_icon.dart'; import 'package:nkust_ap/res/colors.dart' as Resource; @@ -24,18 +25,20 @@ class HomePage extends StatefulWidget { } class HomePageState extends State { - _State state = _State.offline; + _State state = _State.finish; AppLocalizations app; UserInfo userInfo = UserInfo(); int _currentNewsIndex = 0; - List newsList = []; + AnnouncementsData announcementsResponse; @override void initState() { FA.setCurrentScreen("HomePage", "home_page.dart"); -// _getNewsAll(); + // _getNewsAll(); + //TODO: Revert getData from v3 api + announcementsResponse = AnnouncementsData.sample(); _getUserInfo(); if (Preferences.getBool(Constants.PREF_AUTO_LOGIN, false)) Utils.checkUpdate(context); @@ -104,7 +107,8 @@ class HomePageState extends State { }); } - Widget _newsImage(News news, Orientation orientation, bool active) { + Widget _newsImage( + Announcements announcement, Orientation orientation, bool active) { return AnimatedContainer( duration: Duration(milliseconds: 500), curve: Curves.easeOutQuint, @@ -115,21 +119,21 @@ class HomePageState extends State { onTap: () { Utils.pushCupertinoStyle( context, - NewsContentPage(news), + NewsContentPage(announcement), ); - String message = news.content.length > 12 - ? news.content - : news.content.substring(0, 12); + String message = announcement.description.length > 12 + ? announcement.description + : announcement.description.substring(0, 12); FA.logAction('news_image', 'click', message: message); }, child: Hero( - tag: news.hashCode, + tag: announcement.hashCode, child: (Platform.isIOS || Platform.isAndroid) ? CachedNetworkImage( - imageUrl: news.image, + imageUrl: announcement.imgUrl, errorWidget: (context, url, error) => Icon(Icons.error), ) - : Image.network(news.image), + : Image.network(announcement.imgUrl), ), ), ); @@ -167,7 +171,7 @@ class HomePageState extends State { child: Material( color: Colors.transparent, child: Text( - newsList[_currentNewsIndex].title, + announcementsResponse.data[_currentNewsIndex].title, textAlign: TextAlign.center, style: TextStyle( fontSize: 20.0, @@ -183,11 +187,11 @@ class HomePageState extends State { Expanded( child: PageView.builder( controller: pageController, - itemCount: newsList.length, + itemCount: announcementsResponse.data.length, itemBuilder: (context, int currentIndex) { bool active = (currentIndex == _currentNewsIndex); - return _newsImage( - newsList[currentIndex], orientation, active); + return _newsImage(announcementsResponse.data[currentIndex], + orientation, active); }, ), ), @@ -199,10 +203,10 @@ class HomePageState extends State { children: [ TextSpan( text: - '${newsList.length >= 10 && _currentNewsIndex < 9 ? '0' : ''}' + '${announcementsResponse.data.length >= 10 && _currentNewsIndex < 9 ? '0' : ''}' '${_currentNewsIndex + 1}', style: TextStyle(color: Resource.Colors.red)), - TextSpan(text: ' / ${newsList.length}'), + TextSpan(text: ' / ${announcementsResponse.data.length}'), ], ), ), @@ -242,13 +246,15 @@ class HomePageState extends State { state = _State.offline; }); } else - Helper.instance.getAllNews().then((newsList) { - this.newsList = newsList; - this.newsList.sort((a, b) { - return b.weight.compareTo(a.weight); - }); + Helper.instance.getAllAnnouncements().then((announcementsResponse) { + this.announcementsResponse = announcementsResponse; +// this.announcementsList.data.sort((a, b) { +// return b.weight.compareTo(a.weight); +// }); setState(() { - state = newsList.length == 0 ? _State.empty : _State.finish; + state = announcementsResponse.data.length == 0 + ? _State.empty + : _State.finish; }); }).catchError((e) { if (e is DioError) { From 2e00d5eecc6b9fb00e9ed047f15228e9b688ae96 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sat, 24 Aug 2019 16:31:29 +0800 Subject: [PATCH 13/34] Update feature notifications to api v3 --- lib/api/helper.dart | 11 +- lib/models/notification_data.dart | 115 ++++++++++++++------- lib/pages/home/info/notification_page.dart | 12 ++- 3 files changed, 88 insertions(+), 50 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 01882418..6b402aa1 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -105,9 +105,8 @@ class Helper { Future getAllAnnouncements() async { try { - var response = await dio.get("/$VERSION/news/all"); - var jsonArray = jsonCodec.decode(response.data); - return AnnouncementsData.fromJson(jsonArray); + var response = await dio.get("/news/announcements/all"); + return AnnouncementsData.fromJson(response.data); } on DioError catch (dioError) { print(dioError); throw dioError; @@ -268,10 +267,10 @@ class Helper { } } - Future getNotifications(int page) async { + Future getNotifications(int page) async { try { - var response = await dio.get("/$VERSION/notifications/$page"); - return NotificationData.fromJson(response.data); + var response = await dio.get("/news/school/$page"); + return NotificationsData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } diff --git a/lib/models/notification_data.dart b/lib/models/notification_data.dart index 92e8fa58..3e46824b 100644 --- a/lib/models/notification_data.dart +++ b/lib/models/notification_data.dart @@ -1,51 +1,86 @@ -class NotificationData { +// To parse this JSON data, do +// +// final notificationsData = notificationsDataFromJson(jsonString); + +import 'dart:convert'; + +class NotificationsData { + Data data; + + NotificationsData({ + this.data, + }); + + factory NotificationsData.fromRawJson(String str) => + NotificationsData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory NotificationsData.fromJson(Map json) => + new NotificationsData( + data: Data.fromJson(json["data"]), + ); + + Map toJson() => { + "data": data.toJson(), + }; + + static NotificationsData sample() { + return NotificationsData.fromRawJson( + '{ "data": { "page": 1, "notification": [ { "link": "http://kuasnews.kuas.edu.tw/files/13-1018-70766-1.php", "info": { "id": "1", "title": "2019年高科大高雄亮點日語導覽競賽", "department": "觀光系", "date": "2019-03-13" } }, { "link": "http://gec.kuas.edu.tw/files/13-1012-70765-1.php", "info": { "id": "2", "title": "快來拿獎金!!!第22屆優質通識課程學生學習檔案e化徵選活動~", "department": "通識中心", "date": "2019-03-13" } } ] } }'); + } +} + +class Data { int page; - List notifications; + List notifications; - NotificationData({ + Data({ this.page, this.notifications, }); - static NotificationData fromJson(Map json) { - return NotificationData( - page: json['page'], - notifications: NotificationModel.toList(json['notification']), - ); - } + factory Data.fromRawJson(String str) => Data.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Data.fromJson(Map json) => new Data( + page: json["page"], + notifications: new List.from( + json["notification"].map((x) => Notifications.fromJson(x))), + ); Map toJson() => { - 'page': page, - 'notification': notifications, + "page": page, + "notification": + new List.from(notifications.map((x) => x.toJson())), }; } -class NotificationModel { +class Notifications { String link; Info info; - NotificationModel({ + Notifications({ this.link, this.info, }); - static NotificationModel fromJson(Map json) { - return NotificationModel( - link: json['link'], - info: Info.fromJson(json['info']), - ); - } + factory Notifications.fromRawJson(String str) => + Notifications.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Notifications.fromJson(Map json) => + new Notifications( + link: json["link"], + info: Info.fromJson(json["info"]), + ); Map toJson() => { - 'link': link, - 'info': info, + "link": link, + "info": info.toJson(), }; - - static List toList(List jsonArray) { - List list = []; - for (var item in (jsonArray ?? [])) list.add(NotificationModel.fromJson(item)); - return list; - } } class Info { @@ -61,19 +96,21 @@ class Info { this.date, }); - static Info fromJson(Map json) { - return Info( - id: json['id'], - title: json['title'], - department: json['department'], - date: json['date'], - ); - } + factory Info.fromRawJson(String str) => Info.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Info.fromJson(Map json) => new Info( + id: json["id"], + title: json["title"], + department: json["department"], + date: json["date"], + ); Map toJson() => { - 'id': id, - 'title': title, - 'department': department, - 'date': date, + "id": id, + "title": title, + "department": department, + "date": date, }; } diff --git a/lib/pages/home/info/notification_page.dart b/lib/pages/home/info/notification_page.dart index f02857d6..30604032 100644 --- a/lib/pages/home/info/notification_page.dart +++ b/lib/pages/home/info/notification_page.dart @@ -21,12 +21,12 @@ class NotificationPageState extends State @override bool get wantKeepAlive => true; - _State state = _State.loading; + _State state = _State.finish; AppLocalizations app; ScrollController controller; - List notificationList = []; + List notificationList = []; int page = 1; @@ -44,7 +44,9 @@ class NotificationPageState extends State void initState() { FA.setCurrentScreen("NotificationPage", "notification_page.dart"); controller = ScrollController()..addListener(_scrollListener); - _getNotifications(); + //_getNotifications(); + //TODO: Revert getData from v3 api + notificationList = NotificationsData.sample().data.notifications; super.initState(); } @@ -54,7 +56,7 @@ class NotificationPageState extends State controller.removeListener(_scrollListener); } - Widget _notificationItem(NotificationModel notification) { + Widget _notificationItem(Notifications notification) { return GestureDetector( onLongPress: () { Utils.shareTo("${notification.info.title}\n${notification.link}"); @@ -183,7 +185,7 @@ class NotificationPageState extends State } Helper.instance.getNotifications(page).then((response) { var notificationData = response; - for (var notification in notificationData.notifications) { + for (var notification in notificationData.data.notifications) { notificationList.add(notification); } if (mounted) { From 0a56be56deb88b18d0ce1b8436e3c9a73ba81cfe Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 00:59:25 +0800 Subject: [PATCH 14/34] Update feature bus reserve to api v3 --- lib/api/helper.dart | 14 ++- lib/models/bus_data.dart | 135 +++++++++++++---------- lib/pages/home/bus/bus_reserve_page.dart | 24 ++-- 3 files changed, 98 insertions(+), 75 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 6b402aa1..2e433fb8 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -182,9 +182,17 @@ class Helper { var formatter = new DateFormat('yyyy-MM-dd'); var date = formatter.format(dateTime); try { - var response = await dio.get("/$VERSION/bus/timetables?date=$date", - cancelToken: cancelToken); - return BusData.fromJson(response.data); + var response = await dio.get( + '/$VERSION/bus/timetables', + queryParameters: { + 'date': date, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return BusData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } diff --git a/lib/models/bus_data.dart b/lib/models/bus_data.dart index 8650ff20..18c597d2 100644 --- a/lib/models/bus_data.dart +++ b/lib/models/bus_data.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; @@ -13,44 +15,52 @@ class BusData { this.timetable, }); - static BusData fromJson(Map json) { - return BusData( - date: json['date'], - timetable: BusTime.toList(json["timetable"]), - ); - } + factory BusData.fromRawJson(String str) => BusData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory BusData.fromJson(Map json) => new BusData( + date: json["date"], + timetable: new List.from( + json["data"].map((x) => BusTime.fromJson(x))), + ); Map toJson() => { - 'date': date, - 'timetable': timetable, + "date": date, + "data": List.from(timetable.map((x) => x.toJson())), }; + + static BusData sample() { + return BusData.fromRawJson( + '{ "date": "2019-03-17T16:51:57Z", "data": [ { "endEnrollDateTime": "2019-03-17T16:51:57Z", "departureTime": "2019-03-17T16:51:57Z", "startStation": "建工", "busId": "42705", "reserveCount": 2, "limitCount": 999, "isReserve": true, "specialTrain": "0", "discription": "", "cancelKey": "0", "homeCharteredBus": false }, { "endEnrollDateTime": "2020-03-17T16:51:57Z", "departureTime": "2020-03-17T16:51:57Z", "startStation": "建工", "busId": "42711", "reserveCount": 11, "limitCount": 999, "isReserve": false, "SpecialTrain": "0", "discription": "", "cancelKey": "0", "homeCharteredBus": false } ] }'); + } } class BusTime { String endEnrollDateTime; - String runDateTime; - String time; - String endStation; + String departureTime; + String startStation; String busId; - String reserveCount; - String limitCount; - int isReserve; + int reserveCount; + int limitCount; + bool isReserve; String specialTrain; - String specialTrainRemark; + String discription; String cancelKey; + bool homeCharteredBus; BusTime({ this.endEnrollDateTime, - this.runDateTime, - this.time, - this.endStation, + this.departureTime, + this.startStation, this.busId, this.reserveCount, this.limitCount, this.isReserve, this.specialTrain, - this.specialTrainRemark, + this.discription, this.cancelKey, + this.homeCharteredBus, }); String getSpecialTrainTitle(AppLocalizations local) { @@ -64,13 +74,13 @@ class BusTime { } } - String getSpecialTrainRemark() { - print(specialTrainRemark); - if (specialTrainRemark.length == 0) - return ""; - else - return "${specialTrainRemark.replaceAll("\n", "").replaceAll("
", "\n")}\n"; - } +// String getSpecialTrainRemark() { +// print(specialTrainRemark); +// if (specialTrainRemark.length == 0) +// return ""; +// else +// return "${specialTrainRemark.replaceAll("\n", "").replaceAll("
", "\n")}\n"; +// } static List toList(List jsonArray) { List list = []; @@ -78,75 +88,78 @@ class BusTime { return list; } - static BusTime fromJson(Map json) { - return BusTime( - endEnrollDateTime: json['EndEnrollDateTime'], - runDateTime: json['runDateTime'], - time: json['Time'], - endStation: json['endStation'], - busId: json['busId'], - reserveCount: json['reserveCount'], - limitCount: json['limitCount'], - isReserve: json['isReserve'], - specialTrain: json['SpecialTrain'], - specialTrainRemark: json['SpecialTrainRemark'], - cancelKey: "${json['cancelKey']}", - ); - } + factory BusTime.fromRawJson(String str) => BusTime.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory BusTime.fromJson(Map json) => new BusTime( + endEnrollDateTime: json["endEnrollDateTime"], + departureTime: json["departureTime"], + startStation: json["startStation"], + busId: json["busId"], + reserveCount: json["reserveCount"], + limitCount: json["limitCount"], + isReserve: json["isReserve"], + specialTrain: json["SpecialTrain"], + discription: json["discription"], + cancelKey: json["cancelKey"], + homeCharteredBus: json["homeCharteredBus"], + ); Map toJson() => { - 'EndEnrollDateTime': endEnrollDateTime, - 'runDateTime': runDateTime, - 'Time': time, - 'endStation': endStation, - 'busId': busId, - 'reserveCount': reserveCount, - 'limitCount': limitCount, - 'isReserve': isReserve, - 'SpecialTrain': specialTrain, - 'SpecialTrainRemark': specialTrainRemark, - 'cancelKey': cancelKey, + "endEnrollDateTime": endEnrollDateTime, + "departureTime": departureTime, + "startStation": startStation, + "busId": busId, + "reserveCount": reserveCount, + "limitCount": limitCount, + "isReserve": isReserve, + "SpecialTrain": specialTrain, + "discription": discription, + "cancelKey": cancelKey, + "homeCharteredBus": homeCharteredBus, }; bool canReserve() { var now = new DateTime.now(); initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-dd HH:mm', 'zh'); + var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var endEnrollDateTime = formatter.parse(this.endEnrollDateTime); - //print(endEnrollDateTime); + print(endEnrollDateTime); return now.millisecondsSinceEpoch <= endEnrollDateTime.millisecondsSinceEpoch; } Color getColorState() { - return isReserve == 1 + return isReserve ? Resource.Colors.blueAccent : canReserve() ? Resource.Colors.grey : Resource.Colors.disabled; } String getReserveState(AppLocalizations local) { - return isReserve == 1 + return isReserve ? local.reserved : canReserve() ? local.reserve : local.canNotReserve; } String getDate() { initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-dd HH:mm', 'zh'); + var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var formatterTime = new DateFormat('yyyy-MM-dd'); - var time = formatter.parse(this.runDateTime); + var time = formatter.parse(this.departureTime); return formatterTime.format(time); } String getTime() { initializeDateFormatting(); + var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var formatterTime = new DateFormat('HH:mm', 'zh'); - var time = formatterTime.parse(this.time); + var time = formatter.parse(this.departureTime); return formatterTime.format(time); } String getStart(AppLocalizations local) { - switch (endStation) { + switch (startStation) { case "建工": return local.yanchao; case "燕巢": @@ -157,7 +170,7 @@ class BusTime { } String getEnd(AppLocalizations local) { - switch (endStation) { + switch (startStation) { case "建工": return local.jiangong; case "燕巢": diff --git a/lib/pages/home/bus/bus_reserve_page.dart b/lib/pages/home/bus/bus_reserve_page.dart index 74c26148..d91c3922 100644 --- a/lib/pages/home/bus/bus_reserve_page.dart +++ b/lib/pages/home/bus/bus_reserve_page.dart @@ -29,7 +29,7 @@ class BusReservePageState extends State AppLocalizations app; - _State state = _State.loading; + _State state = _State.finish; Station selectStartStation = Station.janGong; DateTime dateTime = DateTime.now(); @@ -41,7 +41,9 @@ class BusReservePageState extends State @override void initState() { FA.setCurrentScreen("BusReservePage", "bus_reserve_page.dart"); - _getBusTimeTables(); + //_getBusTimeTables(); + busData = BusData.sample(); + print(busData.timetable.length); super.initState(); } @@ -187,10 +189,10 @@ class BusReservePageState extends State List list = []; if (busData != null) { for (var i in busData.timetable) { - if (selectStartStation == Station.janGong && i.endStation == "燕巢") - list.add(_busTimeWidget(i)); - else if (selectStartStation == Station.yanchao && i.endStation == "建工") + if (selectStartStation == Station.janGong && i.startStation == "建工") list.add(_busTimeWidget(i)); + else if (selectStartStation == Station.yanchao && + i.startStation == "燕巢") list.add(_busTimeWidget(i)); } } return list; @@ -200,7 +202,7 @@ class BusReservePageState extends State children: [ FlatButton( padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0), - onPressed: busTime.canReserve() && busTime.isReserve == 0 + onPressed: busTime.canReserve() && busTime.isReserve ? () { String start = ""; if (selectStartStation == Station.janGong) @@ -226,7 +228,7 @@ class BusReservePageState extends State ), TextSpan( text: - '${busTime.getSpecialTrainRemark()}${app.busReserveConfirmTitle}\n', + '${busTime.specialTrain}${app.busReserveConfirmTitle}\n', style: TextStyle( color: Resource.Colors.grey, height: 1.3, @@ -248,7 +250,7 @@ class BusReservePageState extends State ), ); } - : busTime.isReserve != 0 + : busTime.isReserve ? () { showDialog( context: context, @@ -350,10 +352,10 @@ class BusReservePageState extends State busData = response; if (mounted) { setState(() { - if (busData.timetable.length != 0) - state = _State.finish; - else + if (busData == null) state = _State.empty; + else + state = _State.finish; }); } }).catchError((e) { From 9794d561edd0bb0975f868383d30949c8b4e1245 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 01:05:26 +0800 Subject: [PATCH 15/34] Update feature bus reservations to api v3 Update get , booking , cancel. --- lib/api/helper.dart | 51 +++++---- lib/models/bus_reservations_data.dart | 101 +++++++++++------- lib/pages/home/bus/bus_reservations_page.dart | 11 +- 3 files changed, 101 insertions(+), 62 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 2e433fb8..f23d8b85 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -178,31 +178,31 @@ class Helper { } } - Future getBusTimeTables(DateTime dateTime) async { - var formatter = new DateFormat('yyyy-MM-dd'); - var date = formatter.format(dateTime); + Future getRewardAndPenalty( + String year, String semester) async { try { var response = await dio.get( - '/$VERSION/bus/timetables', + "/user/reward-and-penalty", queryParameters: { - 'date': date, + 'year': year, + 'value': semester, }, cancelToken: cancelToken, ); if (response.statusCode == 204) return null; else - return BusData.fromJson(response.data); + return RewardAndPenaltyData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } } - Future getRewardAndPenalty( + Future getMidtermAlerts( String year, String semester) async { try { var response = await dio.get( - "/user/reward-and-penalty", + "/user/midterm-alerts", queryParameters: { 'year': year, 'value': semester, @@ -212,27 +212,27 @@ class Helper { if (response.statusCode == 204) return null; else - return RewardAndPenaltyData.fromJson(response.data); + return MidtermAlertsData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } } - Future getMidtermAlerts( - String year, String semester) async { + Future getBusTimeTables(DateTime dateTime) async { + var formatter = new DateFormat('yyyy-MM-dd'); + var date = formatter.format(dateTime); try { var response = await dio.get( - "/user/midterm-alerts", + '/$VERSION/bus/timetables', queryParameters: { - 'year': year, - 'value': semester, + 'date': date, }, cancelToken: cancelToken, ); if (response.statusCode == 204) return null; else - return MidtermAlertsData.fromJson(response.data); + return BusData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } @@ -240,8 +240,11 @@ class Helper { Future getBusReservations() async { try { - var response = await dio.get("/$VERSION/bus/reservations"); - return BusReservationsData.fromJson(response.data); + var response = await dio.get("/bus/reservations"); + if (response.statusCode == 204) + return null; + else + return BusReservationsData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } @@ -249,7 +252,12 @@ class Helper { Future bookingBusReservation(String busId) async { try { - var response = await dio.put("/$VERSION/bus/reservations/$busId"); + var response = await dio.put( + "/$VERSION/bus/reservations", + queryParameters: { + 'busId': busId, + }, + ); return response; } on DioError catch (dioError) { throw dioError; @@ -258,7 +266,12 @@ class Helper { Future cancelBusReservation(String cancelKey) async { try { - var response = await dio.delete("/$VERSION/bus/reservations/$cancelKey"); + var response = await dio.delete( + "/bus/reservations/", + queryParameters: { + 'cancelKey': cancelKey, + }, + ); return response; } on DioError catch (dioError) { throw dioError; diff --git a/lib/models/bus_reservations_data.dart b/lib/models/bus_reservations_data.dart index b4c3ebae..04771729 100644 --- a/lib/models/bus_reservations_data.dart +++ b/lib/models/bus_reservations_data.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; @@ -11,44 +13,66 @@ class BusReservationsData { this.reservations, }); - static BusReservationsData fromJson(Map json) { - return BusReservationsData( - reservations: BusReservation.toList(json['reservation']), - ); - } + factory BusReservationsData.fromRawJson(String str) => + BusReservationsData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory BusReservationsData.fromJson(Map json) => + new BusReservationsData( + reservations: new List.from( + json["data"].map((x) => BusReservation.fromJson(x))), + ); Map toJson() => { - 'reservation': reservations, + "data": new List.from(reservations.map((x) => x.toJson())), }; + + static BusReservationsData sample() { + return BusReservationsData.fromRawJson( + '{ "data": [ { "dateTime": "2019-03-17T16:51:57Z", "endTime": "2019-03-14T08:20:00Z", "cancelKey": "2004434", "start": "建工", "state": "0", "travelState": "0" }, { "dateTime": "2019-03-18T00:20:00Z", "endTime": "2019-03-17T09:20:00Z", "cancelKey": "2006005", "start": "建工", "state": "0", "travelState": "0" }, { "dateTime": "2019-03-18T08:40:00Z", "endTime": "2019-03-18T03:40:00Z", "cancelKey": "2006006", "start": "燕巢", "state": "0", "travelState": "0" } ] }'); + } } class BusReservation { - String time; + String dateTime; String endTime; String cancelKey; - String end; + String start; + String state; + String travelState; BusReservation({ - this.time, + this.dateTime, this.endTime, this.cancelKey, - this.end, + this.start, + this.state, + this.travelState, }); - static BusReservation fromJson(Map json) { - return BusReservation( - time: json['time'], - endTime: json['endTime'], - cancelKey: json['cancelKey'], - end: json['end'], - ); - } + factory BusReservation.fromRawJson(String str) => + BusReservation.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory BusReservation.fromJson(Map json) => + new BusReservation( + dateTime: json["dateTime"], + endTime: json["endTime"], + cancelKey: json["cancelKey"], + start: json["start"], + state: json["state"], + travelState: json["travelState"], + ); Map toJson() => { - 'time': time, - 'endTime': endTime, - 'cancelKey': cancelKey, - 'end': end, + "dateTime": dateTime, + "endTime": endTime, + "cancelKey": cancelKey, + "start": start, + "state": state, + "travelState": travelState, }; static List toList(List jsonArray) { @@ -63,37 +87,38 @@ class BusReservation { String getDate() { initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-dd HH:mm', 'zh'); + var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var formatterTime = new DateFormat('yyyy-MM-dd'); - var time = formatter.parse(this.time); + var time = formatter.parse(this.dateTime); return formatterTime.format(time); } String getTime() { initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-dd HH:mm', 'zh'); - var formatterTime = new DateFormat('HH:mm', 'zh'); - var time = formatter.parse(this.time); + var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); + var formatterTime = new DateFormat('HH:mm'); + var time = formatter.parse(this.dateTime); return formatterTime.format(time); } DateTime getDateTime() { initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-dd HH:mm', 'zh'); - return formatter.parse(this.time); + var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); + return formatter.parse(this.dateTime); } String getDateTimeStr() { initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-dd HH:mm', 'zh'); - return formatter.format(formatter.parse(this.time)); + var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); + var formatterTime = new DateFormat('yyyy-MM-dd HH:mm'); + return formatterTime.format(formatter.parse(this.dateTime)); } String getStart(AppLocalizations local) { - switch (end) { - case "建工": - return local.yanchao; + switch (start) { case "燕巢": + return local.yanchao; + case "建工": return local.jiangong; default: return local.unknown; @@ -101,10 +126,10 @@ class BusReservation { } String getEnd(AppLocalizations local) { - switch (end) { - case "建工": - return local.jiangong; + switch (start) { case "燕巢": + return local.jiangong; + case "建工": return local.yanchao; default: return local.unknown; @@ -114,7 +139,7 @@ class BusReservation { bool canCancel() { var now = new DateTime.now(); initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-dd HH:mm', 'zh'); + var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var endEnrollDateTime = formatter.parse(this.endTime); return now.millisecondsSinceEpoch < endEnrollDateTime.millisecondsSinceEpoch; diff --git a/lib/pages/home/bus/bus_reservations_page.dart b/lib/pages/home/bus/bus_reservations_page.dart index 6e60e651..15fd43a5 100644 --- a/lib/pages/home/bus/bus_reservations_page.dart +++ b/lib/pages/home/bus/bus_reservations_page.dart @@ -25,7 +25,7 @@ class BusReservationsPageState extends State @override bool get wantKeepAlive => true; - _State state = _State.loading; + _State state = _State.finish; BusReservationsData busReservationsData; DateTime dateTime = DateTime.now(); @@ -36,7 +36,8 @@ class BusReservationsPageState extends State @override void initState() { FA.setCurrentScreen("BusReservationsPage", "bus_reservations_page.dart"); - _getBusReservations(); + //_getBusReservations(); + busReservationsData = BusReservationsData.sample(); super.initState(); } @@ -220,10 +221,10 @@ class BusReservationsPageState extends State busReservationsData = response; if (mounted) { setState(() { - if (busReservationsData.reservations.length != 0) - state = _State.finish; - else + if (busReservationsData == null) state = _State.empty; + else + state = _State.finish; }); } CacheUtils.saveBusReservationsData(busReservationsData); From 14aea6644e53f7f00e3654a18ad81b3ae9baad8f Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 01:12:19 +0800 Subject: [PATCH 16/34] Add feature bus violation records api --- lib/api/helper.dart | 13 +++++ lib/models/bus_violation_records_data.dart | 62 ++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 lib/models/bus_violation_records_data.dart diff --git a/lib/api/helper.dart b/lib/api/helper.dart index f23d8b85..32ba9d19 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -8,6 +8,7 @@ import 'package:nkust_ap/config/constants.dart'; import 'package:nkust_ap/models/announcements_data.dart'; import 'package:nkust_ap/models/api/api_models.dart'; import 'package:nkust_ap/models/api/leave_response.dart'; +import 'package:nkust_ap/models/bus_violation_records_data.dart'; import 'package:nkust_ap/models/midterm_alerts_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/models/reward_and_penalty_data.dart'; @@ -288,6 +289,18 @@ class Helper { } } + Future getBusViolationRecords() async { + try { + var response = await dio.get('/bus/violation-records'); + if (response.statusCode == 204) + return null; + else + return BusViolationRecordsData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + Future getNotifications(int page) async { try { var response = await dio.get("/news/school/$page"); diff --git a/lib/models/bus_violation_records_data.dart b/lib/models/bus_violation_records_data.dart new file mode 100644 index 00000000..fca1c656 --- /dev/null +++ b/lib/models/bus_violation_records_data.dart @@ -0,0 +1,62 @@ +import 'dart:convert'; + +class BusViolationRecordsData { + List reservation; + + BusViolationRecordsData({ + this.reservation, + }); + + factory BusViolationRecordsData.fromRawJson(String str) => + BusViolationRecordsData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory BusViolationRecordsData.fromJson(Map json) => + new BusViolationRecordsData( + reservation: new List.from( + json["reservation"].map((x) => Reservation.fromJson(x))), + ); + + Map toJson() => { + "reservation": + new List.from(reservation.map((x) => x.toJson())), + }; +} + +class Reservation { + DateTime time; + String startStation; + bool homeCharteredBus; + int amountend; + String isPayment; + + Reservation({ + this.time, + this.startStation, + this.homeCharteredBus, + this.amountend, + this.isPayment, + }); + + factory Reservation.fromRawJson(String str) => + Reservation.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Reservation.fromJson(Map json) => new Reservation( + time: DateTime.parse(json["time"]), + startStation: json["startStation"], + homeCharteredBus: json["homeCharteredBus"], + amountend: json["amountend"], + isPayment: json["isPayment"], + ); + + Map toJson() => { + "time": time.toIso8601String(), + "startStation": startStation, + "homeCharteredBus": homeCharteredBus, + "amountend": amountend, + "isPayment": isPayment, + }; +} From 5326e612346b72a58a5315cbf09796b9cf7271d1 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 16:10:25 +0800 Subject: [PATCH 17/34] Fix if picture url is null error --- lib/widgets/drawer_body.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/widgets/drawer_body.dart b/lib/widgets/drawer_body.dart index e1d2ae4f..98080f04 100644 --- a/lib/widgets/drawer_body.dart +++ b/lib/widgets/drawer_body.dart @@ -300,6 +300,7 @@ class DrawerBodyState extends State { _getUserPicture() async { try { + if (widget.userInfo.pictureUrl == null) return; var response = await http.get(widget.userInfo.pictureUrl); if (!response.body.contains('html')) { if (mounted) { From 8f0213a6c21c8a6a29c674cd5b4c66bf47416d12 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 16:13:04 +0800 Subject: [PATCH 18/34] Update feature leaves record to api v3 Refactor leave response to leave data. Rearrange leave api lines --- lib/api/helper.dart | 26 +++-- lib/models/api/leave_response.dart | 95 ++++++++--------- lib/pages/home/leaves/leave_record_page.dart | 106 +++++++++---------- lib/utils/cache_utils.dart | 6 +- 4 files changed, 118 insertions(+), 115 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 32ba9d19..33212f07 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -279,16 +279,6 @@ class Helper { } } - Future getLeaves(String year, String semester) async { - try { - var response = await dio.get("/$VERSION/leaves/$year/$semester", - cancelToken: cancelToken); - return LeaveResponse.fromJson(response.data); - } on DioError catch (dioError) { - throw dioError; - } - } - Future getBusViolationRecords() async { try { var response = await dio.get('/bus/violation-records'); @@ -310,6 +300,22 @@ class Helper { } } + Future getLeaves(String year, String semester) async { + try { + var response = await dio.get( + '/leaves', + queryParameters: { + 'year': year, + 'value': semester, + }, + cancelToken: cancelToken, + ); + return LeavesData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + _createBasicAuth(String username, String password) { var text = username + ":" + password; var encoded = utf8.encode(text); diff --git a/lib/models/api/leave_response.dart b/lib/models/api/leave_response.dart index 3495524c..3bea5be6 100644 --- a/lib/models/api/leave_response.dart +++ b/lib/models/api/leave_response.dart @@ -1,32 +1,33 @@ -class LeaveResponse { - int status; - String messages; +import 'dart:convert'; + +class LeavesData { List leaves; - List timeCode; - - LeaveResponse({this.status, this.messages, this.leaves, this.timeCode}); - - LeaveResponse.fromJson(Map json) { - status = json['status']; - messages = json['messages']; - if (json['leaves'] != null) { - leaves = new List(); - json['leaves'].forEach((v) { - leaves.add(new Leaves.fromJson(v)); - }); - } - if (json['timecode'] != null) timeCode = json['timecode'].cast(); - } + List timeCodes; - Map toJson() { - final Map data = new Map(); - data['status'] = this.status; - data['messages'] = this.messages; - if (this.leaves != null) { - data['leaves'] = this.leaves.map((v) => v.toJson()).toList(); - } - data['timecode'] = this.timeCode; - return data; + LeavesData({ + this.leaves, + this.timeCodes, + }); + + factory LeavesData.fromRawJson(String str) => + LeavesData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory LeavesData.fromJson(Map json) => new LeavesData( + leaves: + new List.from(json["leave"].map((x) => Leaves.fromJson(x))), + timeCodes: new List.from(json["timeCodes"].map((x) => x)), + ); + + Map toJson() => { + "leave": new List.from(leaves.map((x) => x.toJson())), + "timeCodes": new List.from(timeCodes.map((x) => x)), + }; + + static LeavesData sample() { + return LeavesData.fromRawJson( + '{ "leave": [ { "leaveSheetId": "", "date": "107/11/14", "instructorsComment": "", "sections": [ { "section": "5", "reason": "曠" }, { "section": "6", "reason": "曠" } ] } ], "timeCodes": [ "A", "1", "2", "3", "4", "B", "5", "6", "7", "8", "C", "11", "12", "13", "14" ] }'); } } @@ -42,29 +43,25 @@ class Leaves { this.instructorsComment, this.leaveSections}); - Leaves.fromJson(Map json) { - leaveSheetId = json['leave_sheet_id']; - date = json['date']; - instructorsComment = json['instructors_comment']; - if (json['leave_sections'] != null) { - leaveSections = new List(); - json['leave_sections'].forEach((v) { - leaveSections.add(new LeaveSections.fromJson(v)); - }); - } - } + factory Leaves.fromRawJson(String str) => Leaves.fromJson(json.decode(str)); - Map toJson() { - final Map data = new Map(); - data['leave_sheet_id'] = this.leaveSheetId; - data['date'] = this.date; - data['instructors_comment'] = this.instructorsComment; - if (this.leaveSections != null) { - data['leave_sections'] = - this.leaveSections.map((v) => v.toJson()).toList(); - } - return data; - } + String toRawJson() => json.encode(toJson()); + + factory Leaves.fromJson(Map json) => new Leaves( + leaveSheetId: json["leaveSheetId"], + date: json["date"], + instructorsComment: json["instructorsComment"], + leaveSections: new List.from( + json["sections"].map((x) => LeaveSections.fromJson(x))), + ); + + Map toJson() => { + "leaveSheetId": leaveSheetId, + "date": date, + "instructorsComment": instructorsComment, + "sections": + new List.from(leaveSections.map((x) => x.toJson())), + }; String getReason(String timeCode) { if (leaveSections == null) return ""; diff --git a/lib/pages/home/leaves/leave_record_page.dart b/lib/pages/home/leaves/leave_record_page.dart index 79df7240..07a1c379 100644 --- a/lib/pages/home/leaves/leave_record_page.dart +++ b/lib/pages/home/leaves/leave_record_page.dart @@ -35,7 +35,7 @@ class LeaveRecordPageState extends State Semester selectSemester; SemesterData semesterData; - LeaveResponse leaveResponse; + LeavesData leaveData; double count = 1.0; @@ -133,7 +133,7 @@ class LeaveRecordPageState extends State ); default: hasNight = _checkHasNight(); - final leaveTitle = _leaveTitle(leaveResponse.timeCode); + final leaveTitle = _leaveTitle(leaveData.timeCodes); return SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: Padding( @@ -164,8 +164,8 @@ class LeaveRecordPageState extends State ), children: [ leaveTitle, - for (var leave in leaveResponse.leaves) - _leaveBorder(leave, leaveResponse.timeCode) + for (var leave in leaveData.leaves) + _leaveBorder(leave, leaveData.timeCodes) ], ), ), @@ -177,9 +177,9 @@ class LeaveRecordPageState extends State } bool _checkHasNight() { - if (leaveResponse == null) return false; - if (leaveResponse.leaves == null) return false; - for (var leave in leaveResponse.leaves) { + if (leaveData == null) return false; + if (leaveData.leaves == null) return false; + for (var leave in leaveData.leaves) { if (leave.leaveSections == null) continue; for (var section in leave.leaveSections) { if (section.section.length > 1) return true; @@ -268,62 +268,62 @@ class LeaveRecordPageState extends State _getSemesterLeaveRecord() async { Helper.cancelToken.cancel(''); Helper.cancelToken = CancelToken(); - var textList = selectSemester.value.split(','); - if (textList.length == 2) { - Helper.instance.getLeaves(textList[0], textList[1]).then((response) { - if (mounted) - setState(() { - leaveResponse = response; - if (leaveResponse.status == 204) - state = _State.empty; - else { - state = _State.finish; - } - }); - CacheUtils.saveLeaveData(selectSemester.value, leaveResponse); - }).catchError((e) { - if (e is DioError) { - switch (e.type) { - case DioErrorType.RESPONSE: - Utils.handleResponseError( - context, 'getSemesterLeaveRecord', mounted, e); - break; - case DioErrorType.CANCEL: - break; - default: - if (mounted) { - setState(() { - state = _State.error; - Utils.handleDioError(context, e); - }); - } - break; + setState(() { + leaveData = LeavesData.sample(); + if (leaveData == null) + state = _State.empty; + else { + state = _State.finish; + } + }); + return; + Helper.instance + .getLeaves(selectSemester.year, selectSemester.value) + .then((response) { + if (mounted) + setState(() { + leaveData = response; + if (leaveData == null) + state = _State.empty; + else { + state = _State.finish; } - _loadOfflineLeaveData(); - } else { - throw e; + }); + CacheUtils.saveLeaveData(selectSemester.value, leaveData); + }).catchError((e) { + if (e is DioError) { + switch (e.type) { + case DioErrorType.RESPONSE: + Utils.handleResponseError( + context, 'getSemesterLeaveRecord', mounted, e); + break; + case DioErrorType.CANCEL: + break; + default: + if (mounted) { + setState(() { + state = _State.error; + Utils.handleDioError(context, e); + }); + } + break; } - }); - } else { - setState(() { - state = _State.error; - }); - } + _loadOfflineLeaveData(); + } else { + throw e; + } + }); } void _loadOfflineLeaveData() async { - leaveResponse = await CacheUtils.loadLeaveData(selectSemester.value); + leaveData = await CacheUtils.loadLeaveData(selectSemester.value); if (mounted) { setState(() { isOffline = true; - if (this.leaveResponse == null) { + if (this.leaveData == null) { state = _State.offlineEmpty; - } else if (leaveResponse.status == 204) { - state = _State.empty; - } else if (leaveResponse.status == 200) { - state = _State.finish; } else { - state = _State.error; + state = _State.finish; } }); } diff --git a/lib/utils/cache_utils.dart b/lib/utils/cache_utils.dart index 8e99d61e..6755115b 100644 --- a/lib/utils/cache_utils.dart +++ b/lib/utils/cache_utils.dart @@ -86,7 +86,7 @@ class CacheUtils { return UserInfo.fromJson(jsonDecode(json)); } - static void saveLeaveData(String value, LeaveResponse leaveData) async { + static void saveLeaveData(String value, LeavesData leaveData) async { if (leaveData == null) return; String username = Preferences.getString(Constants.PREF_USERNAME, ''); await Preferences.setString( @@ -94,12 +94,12 @@ class CacheUtils { jsonEncode(leaveData)); } - static Future loadLeaveData(String value) async { + static Future loadLeaveData(String value) async { String username = Preferences.getString(Constants.PREF_USERNAME, ''); String json = Preferences.getString( '${Constants.PREF_LEAVE_DATA}_${username}_$value', ''); if (json == '') return null; - return LeaveResponse.fromJson(jsonDecode(json)); + return LeavesData.fromJson(jsonDecode(json)); } static void saveBusReservationsData( From 3065c9346d57980848ec3d28f8f2b32b91b0ae10 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 17:02:07 +0800 Subject: [PATCH 19/34] Add feature leaves submit api --- lib/api/helper.dart | 27 +++++++ lib/models/leave_info_data.dart | 111 +++++++++++++++++++++++++++++ lib/models/leaves_submit_data.dart | 63 ++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 lib/models/leave_info_data.dart create mode 100644 lib/models/leaves_submit_data.dart diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 33212f07..02815993 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -9,6 +9,8 @@ import 'package:nkust_ap/models/announcements_data.dart'; import 'package:nkust_ap/models/api/api_models.dart'; import 'package:nkust_ap/models/api/leave_response.dart'; import 'package:nkust_ap/models/bus_violation_records_data.dart'; +import 'package:nkust_ap/models/leave_info_data.dart'; +import 'package:nkust_ap/models/leaves_submit_data.dart'; import 'package:nkust_ap/models/midterm_alerts_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/models/reward_and_penalty_data.dart'; @@ -316,6 +318,31 @@ class Helper { } } + Future getLeavesSubmitInfo() async { + try { + var response = await dio.get( + '/leaves/submit/info', + cancelToken: cancelToken, + ); + return LeavesSubmitInfoData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + + Future sendLeavesSubmit(LeavesSubmitData data) async { + try { + var response = await dio.post( + '/leaves/submit', + data: data.toJson(), + cancelToken: cancelToken, + ); + return response; + } on DioError catch (dioError) { + throw dioError; + } + } + _createBasicAuth(String username, String password) { var text = username + ":" + password; var encoded = utf8.encode(text); diff --git a/lib/models/leave_info_data.dart b/lib/models/leave_info_data.dart new file mode 100644 index 00000000..f757f5ae --- /dev/null +++ b/lib/models/leave_info_data.dart @@ -0,0 +1,111 @@ +// To parse this JSON data, do +// +// final leavesInfoData = leavesInfoDataFromJson(jsonString); + +import 'dart:convert'; + +class LeavesSubmitInfoData { + Tutors tutors; + List type; + List teacherList; + List timeCodes; + + LeavesSubmitInfoData({ + this.tutors, + this.type, + this.teacherList, + this.timeCodes, + }); + + factory LeavesSubmitInfoData.fromRawJson(String str) => + LeavesSubmitInfoData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory LeavesSubmitInfoData.fromJson(Map json) => + new LeavesSubmitInfoData( + tutors: Tutors.fromJson(json["tutors"]), + type: new List.from( + json["type"].map((x) => LeaveType.fromJson(x))), + teacherList: new List.from( + json["teacherList"].map((x) => Teacher.fromJson(x))), + timeCodes: new List.from(json["timeCodes"].map((x) => x)), + ); + + Map toJson() => { + "tutors": tutors.toJson(), + "type": new List.from(type.map((x) => x.toJson())), + "teacherList": + new List.from(teacherList.map((x) => x.toJson())), + "timeCodes": new List.from(timeCodes.map((x) => x)), + }; +} + +class Teacher { + String teacherName; + String teacherId; + + Teacher({ + this.teacherName, + this.teacherId, + }); + + factory Teacher.fromRawJson(String str) => Teacher.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Teacher.fromJson(Map json) => new Teacher( + teacherName: json["teacherName"], + teacherId: json["teacherId"], + ); + + Map toJson() => { + "teacherName": teacherName, + "teacherId": teacherId, + }; +} + +class Tutors { + String name; + + Tutors({ + this.name, + }); + + factory Tutors.fromRawJson(String str) => Tutors.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Tutors.fromJson(Map json) => new Tutors( + name: json["name"], + ); + + Map toJson() => { + "name": name, + }; +} + +class LeaveType { + String id; + String title; + + LeaveType({ + this.id, + this.title, + }); + + factory LeaveType.fromRawJson(String str) => + LeaveType.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory LeaveType.fromJson(Map json) => new LeaveType( + id: json["id"], + title: json["title"], + ); + + Map toJson() => { + "id": id, + "title": title, + }; +} diff --git a/lib/models/leaves_submit_data.dart b/lib/models/leaves_submit_data.dart new file mode 100644 index 00000000..c9d4ab18 --- /dev/null +++ b/lib/models/leaves_submit_data.dart @@ -0,0 +1,63 @@ +// To parse this JSON data, do +// +// final leavesSubmitData = leavesSubmitDataFromJson(jsonString); + +import 'dart:convert'; + +class LeavesSubmitData { + List days; + String leaveTypeId; + String teacherId; + String reasonText; + + LeavesSubmitData({ + this.days, + this.leaveTypeId, + this.teacherId, + this.reasonText, + }); + + factory LeavesSubmitData.fromRawJson(String str) => + LeavesSubmitData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory LeavesSubmitData.fromJson(Map json) => + new LeavesSubmitData( + days: new List.from(json["days"].map((x) => Day.fromJson(x))), + leaveTypeId: json["leaveType"], + teacherId: json["teacherId"], + reasonText: json["reasonText"], + ); + + Map toJson() => { + "days": new List.from(days.map((x) => x.toJson())), + "leaveType": leaveTypeId, + "teacherId": teacherId, + "reasonText": reasonText, + }; +} + +class Day { + String day; + List dayClass; + + Day({ + this.day, + this.dayClass, + }); + + factory Day.fromRawJson(String str) => Day.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Day.fromJson(Map json) => new Day( + day: json["day"], + dayClass: new List.from(json["class"].map((x) => x)), + ); + + Map toJson() => { + "day": day, + "class": new List.from(dayClass.map((x) => x)), + }; +} From 1fb746e84600440f3bed30ad5b51474dbd1cfab0 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 17:08:53 +0800 Subject: [PATCH 20/34] Add feature library info api --- lib/api/helper.dart | 16 ++++++ lib/models/library_info_data.dart | 93 +++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 lib/models/library_info_data.dart diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 02815993..0ba7801f 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -11,6 +11,7 @@ import 'package:nkust_ap/models/api/leave_response.dart'; import 'package:nkust_ap/models/bus_violation_records_data.dart'; import 'package:nkust_ap/models/leave_info_data.dart'; import 'package:nkust_ap/models/leaves_submit_data.dart'; +import 'package:nkust_ap/models/library_info_data.dart'; import 'package:nkust_ap/models/midterm_alerts_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/models/reward_and_penalty_data.dart'; @@ -343,6 +344,21 @@ class Helper { } } + Future getLibraryInfo() async { + try { + var response = await dio.get( + '/leaves/submit/info', + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return LibraryInfoData.fromJson(response.data).data; + } on DioError catch (dioError) { + throw dioError; + } + } + _createBasicAuth(String username, String password) { var text = username + ":" + password; var encoded = utf8.encode(text); diff --git a/lib/models/library_info_data.dart b/lib/models/library_info_data.dart new file mode 100644 index 00000000..957d0bd9 --- /dev/null +++ b/lib/models/library_info_data.dart @@ -0,0 +1,93 @@ +// To parse this JSON data, do +// +// final libraryInfoData = libraryInfoDataFromJson(jsonString); + +import 'dart:convert'; + +class LibraryInfoData { + LibraryInfo data; + + LibraryInfoData({ + this.data, + }); + + factory LibraryInfoData.fromRawJson(String str) => + LibraryInfoData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory LibraryInfoData.fromJson(Map json) => + new LibraryInfoData( + data: LibraryInfo.fromJson(json["data"]), + ); + + Map toJson() => { + "data": data.toJson(), + }; + + static LibraryInfoData sample() { + return LibraryInfoData.fromRawJson( + '{ "data": { "department": "智慧商務系QQ", "libraryId": "1106133333", "name": "柯博昌", "record": { "borrowing": 1, "reserve-rental": 2, "userFine": 300 } } }'); + } +} + +class LibraryInfo { + String department; + String libraryId; + String name; + Record record; + + LibraryInfo({ + this.department, + this.libraryId, + this.name, + this.record, + }); + + factory LibraryInfo.fromRawJson(String str) => + LibraryInfo.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory LibraryInfo.fromJson(Map json) => new LibraryInfo( + department: json["department"], + libraryId: json["libraryId"], + name: json["name"], + record: Record.fromJson(json["record"]), + ); + + Map toJson() => { + "department": department, + "libraryId": libraryId, + "name": name, + "record": record.toJson(), + }; +} + +class Record { + int borrowing; + int reserveRental; + int userFine; + + Record({ + this.borrowing, + this.reserveRental, + this.userFine, + }); + + factory Record.fromRawJson(String str) => Record.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Record.fromJson(Map json) => new Record( + borrowing: json["borrowing"], + reserveRental: json["reserve-rental"], + userFine: json["userFine"], + ); + + Map toJson() => { + "borrowing": borrowing, + "reserve-rental": reserveRental, + "userFine": userFine, + }; +} From eb93900de7ca8141f5a954bf0b8d2d1d9adffb9e Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 17:22:19 +0800 Subject: [PATCH 21/34] Add feature room data and course table api --- lib/api/helper.dart | 41 ++++++++++++++++++++++++++++++++ lib/models/room_data.dart | 50 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 lib/models/room_data.dart diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 0ba7801f..8adcd5db 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -15,6 +15,7 @@ import 'package:nkust_ap/models/library_info_data.dart'; import 'package:nkust_ap/models/midterm_alerts_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/models/reward_and_penalty_data.dart'; +import 'package:nkust_ap/models/room_data.dart'; import 'package:shared_preferences/shared_preferences.dart'; const HOST = 'nkust.taki.dog'; @@ -222,6 +223,46 @@ class Helper { } } + //1=建工 /2=燕巢/3=第一/4=楠梓/5=旗津 + Future getRoomList(int campus) async { + try { + var response = await dio.get( + '/user/room/list', + queryParameters: { + 'campus': campus, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return RoomData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + + Future getRoomCourseTables( + String roomId, String year, String semester) async { + try { + var response = await dio.get( + '/user/empty-room/info', + queryParameters: { + 'roomId': roomId, + 'year': year, + 'value': semester, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return CourseData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + Future getBusTimeTables(DateTime dateTime) async { var formatter = new DateFormat('yyyy-MM-dd'); var date = formatter.format(dateTime); diff --git a/lib/models/room_data.dart b/lib/models/room_data.dart new file mode 100644 index 00000000..1516b2fb --- /dev/null +++ b/lib/models/room_data.dart @@ -0,0 +1,50 @@ +// To parse this JSON data, do +// +// final roomData = roomDataFromJson(jsonString); + +import 'dart:convert'; + +class RoomData { + List data; + + RoomData({ + this.data, + }); + + factory RoomData.fromRawJson(String str) => + RoomData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory RoomData.fromJson(Map json) => new RoomData( + data: new List.from(json["data"].map((x) => Room.fromJson(x))), + ); + + Map toJson() => { + "data": new List.from(data.map((x) => x.toJson())), + }; +} + +class Room { + String roomName; + String roomId; + + Room({ + this.roomName, + this.roomId, + }); + + factory Room.fromRawJson(String str) => Room.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Room.fromJson(Map json) => new Room( + roomName: json["roomName"], + roomId: json["roomId"], + ); + + Map toJson() => { + "roomName": roomName, + "roomId": roomId, + }; +} From 4f370281eedcb1f8deed59262d8e6c58059c7e00 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 17:31:07 +0800 Subject: [PATCH 22/34] Add delete token api --- lib/api/helper.dart | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 8adcd5db..fbede2f0 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -108,6 +108,28 @@ class Helper { } } + Future deleteToken() async { + try { + var response = await dio.delete( + '/oauth/token', + ); + return response; + } on DioError catch (dioError) { + throw dioError; + } + } + + Future deleteAllToken() async { + try { + var response = await dio.delete( + '/oauth/token/all', + ); + return response; + } on DioError catch (dioError) { + throw dioError; + } + } + Future getAllAnnouncements() async { try { var response = await dio.get("/news/announcements/all"); From 18bc6f75ecf2d1e4a0dec6614b586c9b4608af87 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 25 Aug 2019 17:33:34 +0800 Subject: [PATCH 23/34] Add feature server info data api --- lib/api/helper.dart | 10 ++++++ lib/models/server_info_data.dart | 61 ++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 lib/models/server_info_data.dart diff --git a/lib/api/helper.dart b/lib/api/helper.dart index fbede2f0..3c5f30eb 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -16,6 +16,7 @@ import 'package:nkust_ap/models/midterm_alerts_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/models/reward_and_penalty_data.dart'; import 'package:nkust_ap/models/room_data.dart'; +import 'package:nkust_ap/models/server_info_data.dart'; import 'package:shared_preferences/shared_preferences.dart'; const HOST = 'nkust.taki.dog'; @@ -130,6 +131,15 @@ class Helper { } } + Future getServerInfoData() async { + try { + var response = await dio.get("​/server​/info"); + return ServerInfoData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + Future getAllAnnouncements() async { try { var response = await dio.get("/news/announcements/all"); diff --git a/lib/models/server_info_data.dart b/lib/models/server_info_data.dart new file mode 100644 index 00000000..089f4a6f --- /dev/null +++ b/lib/models/server_info_data.dart @@ -0,0 +1,61 @@ +// To parse this JSON data, do +// +// final serverInfoData = serverInfoDataFromJson(jsonString); + +import 'dart:convert'; + +class ServerInfoData { + String date; + List data; + + ServerInfoData({ + this.date, + this.data, + }); + + factory ServerInfoData.fromRawJson(String str) => + ServerInfoData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ServerInfoData.fromJson(Map json) => + new ServerInfoData( + date: json["date"], + data: new List.from( + json["data"].map((x) => ServerInfo.fromJson(x))), + ); + + Map toJson() => { + "date": date, + "data": new List.from(data.map((x) => x.toJson())), + }; +} + +class ServerInfo { + String service; + bool isAlive; + String description; + + ServerInfo({ + this.service, + this.isAlive, + this.description, + }); + + factory ServerInfo.fromRawJson(String str) => + ServerInfo.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ServerInfo.fromJson(Map json) => new ServerInfo( + service: json["service"], + isAlive: json["isAlive"], + description: json["description"], + ); + + Map toJson() => { + "service": service, + "isAlive": isAlive, + "description": description, + }; +} From 5dd63dd7e60126a9ffdacafd8e56ec37911425c4 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Tue, 27 Aug 2019 00:41:03 +0800 Subject: [PATCH 24/34] Fix feature bus api format error Comment feature bus and leaves limit --- lib/api/helper.dart | 6 +- lib/models/bus_data.dart | 17 +++--- lib/models/bus_violation_records_data.dart | 2 +- lib/pages/home/bus/bus_reservations_page.dart | 15 +++-- lib/pages/home/bus/bus_reserve_page.dart | 61 ++++++++++--------- lib/pages/home_page.dart | 9 ++- lib/widgets/drawer_body.dart | 31 +++++----- 7 files changed, 75 insertions(+), 66 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 3c5f30eb..079b24ec 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -296,11 +296,11 @@ class Helper { } Future getBusTimeTables(DateTime dateTime) async { - var formatter = new DateFormat('yyyy-MM-dd'); + var formatter = DateFormat('yyyy-MM-dd'); var date = formatter.format(dateTime); try { var response = await dio.get( - '/$VERSION/bus/timetables', + '/bus/timetables', queryParameters: { 'date': date, }, @@ -358,6 +358,8 @@ class Helper { Future getBusViolationRecords() async { try { var response = await dio.get('/bus/violation-records'); + print(response.statusCode); + print(response.data); if (response.statusCode == 204) return null; else diff --git a/lib/models/bus_data.dart b/lib/models/bus_data.dart index 18c597d2..a1bbeb03 100644 --- a/lib/models/bus_data.dart +++ b/lib/models/bus_data.dart @@ -19,10 +19,10 @@ class BusData { String toRawJson() => json.encode(toJson()); - factory BusData.fromJson(Map json) => new BusData( + factory BusData.fromJson(Map json) => BusData( date: json["date"], - timetable: new List.from( - json["data"].map((x) => BusTime.fromJson(x))), + timetable: + List.from(json["data"].map((x) => BusTime.fromJson(x))), ); Map toJson() => { @@ -92,7 +92,7 @@ class BusTime { String toRawJson() => json.encode(toJson()); - factory BusTime.fromJson(Map json) => new BusTime( + factory BusTime.fromJson(Map json) => BusTime( endEnrollDateTime: json["endEnrollDateTime"], departureTime: json["departureTime"], startStation: json["startStation"], @@ -100,7 +100,7 @@ class BusTime { reserveCount: json["reserveCount"], limitCount: json["limitCount"], isReserve: json["isReserve"], - specialTrain: json["SpecialTrain"], + specialTrain: json["specialTrain"], discription: json["discription"], cancelKey: json["cancelKey"], homeCharteredBus: json["homeCharteredBus"], @@ -114,18 +114,17 @@ class BusTime { "reserveCount": reserveCount, "limitCount": limitCount, "isReserve": isReserve, - "SpecialTrain": specialTrain, + "specialTrain": specialTrain, "discription": discription, "cancelKey": cancelKey, "homeCharteredBus": homeCharteredBus, }; bool canReserve() { - var now = new DateTime.now(); + var now = DateTime.now(); initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); + var formatter = DateFormat('yyyy-MM-ddTHH:mm:ss'); var endEnrollDateTime = formatter.parse(this.endEnrollDateTime); - print(endEnrollDateTime); return now.millisecondsSinceEpoch <= endEnrollDateTime.millisecondsSinceEpoch; } diff --git a/lib/models/bus_violation_records_data.dart b/lib/models/bus_violation_records_data.dart index fca1c656..c4da5000 100644 --- a/lib/models/bus_violation_records_data.dart +++ b/lib/models/bus_violation_records_data.dart @@ -29,7 +29,7 @@ class Reservation { String startStation; bool homeCharteredBus; int amountend; - String isPayment; + bool isPayment; Reservation({ this.time, diff --git a/lib/pages/home/bus/bus_reservations_page.dart b/lib/pages/home/bus/bus_reservations_page.dart index 15fd43a5..49f35c76 100644 --- a/lib/pages/home/bus/bus_reservations_page.dart +++ b/lib/pages/home/bus/bus_reservations_page.dart @@ -36,8 +36,7 @@ class BusReservationsPageState extends State @override void initState() { FA.setCurrentScreen("BusReservationsPage", "bus_reservations_page.dart"); - //_getBusReservations(); - busReservationsData = BusReservationsData.sample(); + _getBusReservations(); super.initState(); } @@ -221,7 +220,8 @@ class BusReservationsPageState extends State busReservationsData = response; if (mounted) { setState(() { - if (busReservationsData == null) + if (busReservationsData == null || + busReservationsData.reservations.length == 0) state = _State.empty; else state = _State.finish; @@ -232,8 +232,13 @@ class BusReservationsPageState extends State if (e is DioError) { switch (e.type) { case DioErrorType.RESPONSE: - Utils.handleResponseError( - context, 'getBusReservations', mounted, e); + if (e.response.statusCode == 401) { + setState(() { + state = _State.error; + }); + } else + Utils.handleResponseError( + context, 'getBusReservations', mounted, e); break; case DioErrorType.DEFAULT: if (e.message.contains("HttpException")) { diff --git a/lib/pages/home/bus/bus_reserve_page.dart b/lib/pages/home/bus/bus_reserve_page.dart index d91c3922..4ce0f113 100644 --- a/lib/pages/home/bus/bus_reserve_page.dart +++ b/lib/pages/home/bus/bus_reserve_page.dart @@ -41,9 +41,7 @@ class BusReservePageState extends State @override void initState() { FA.setCurrentScreen("BusReservePage", "bus_reserve_page.dart"); - //_getBusTimeTables(); - busData = BusData.sample(); - print(busData.timetable.length); + _getBusTimeTables(); super.initState(); } @@ -202,7 +200,7 @@ class BusReservePageState extends State children: [ FlatButton( padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0), - onPressed: busTime.canReserve() && busTime.isReserve + onPressed: busTime.canReserve() && !busTime.isReserve ? () { String start = ""; if (selectStartStation == Station.janGong) @@ -217,29 +215,30 @@ class BusReservePageState extends State contentWidget: RichText( textAlign: TextAlign.center, text: TextSpan( - style: TextStyle( - color: Resource.Colors.grey, - height: 1.3, - fontSize: 16.0), - children: [ - TextSpan( - text: '${busTime.getTime()} $start\n', - style: TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: - '${busTime.specialTrain}${app.busReserveConfirmTitle}\n', - style: TextStyle( - color: Resource.Colors.grey, - height: 1.3, - fontSize: 14.0), - ), - TextSpan( - text: '${app.reserveDeadline}:\n', - style: - TextStyle(fontWeight: FontWeight.bold)), - TextSpan(text: '${busTime.endEnrollDateTime}'), - ]), + style: TextStyle( + color: Resource.Colors.grey, + height: 1.3, + fontSize: 16.0), + children: [ + TextSpan( + text: '${busTime.getTime()} $start\n', + style: TextStyle(fontWeight: FontWeight.bold), + ), + TextSpan( + text: + '${busTime.discription}${app.busReserveConfirmTitle}\n', + style: TextStyle( + color: Resource.Colors.grey, + height: 1.3, + fontSize: 14.0), + ), + TextSpan( + text: '${app.reserveDeadline}:\n', + style: + TextStyle(fontWeight: FontWeight.bold)), + TextSpan(text: '${busTime.endEnrollDateTime}'), + ], + ), ), leftActionText: app.cancel, rightActionText: app.reserve, @@ -364,7 +363,13 @@ class BusReservePageState extends State // dioError.message = HttpException: Connection closed before full header was received switch (e.type) { case DioErrorType.RESPONSE: - Utils.handleResponseError(context, 'getBusTimeTables', mounted, e); + if (e.response.statusCode == 401) { + setState(() { + state = _State.error; + }); + } else + Utils.handleResponseError( + context, 'getBusTimeTables', mounted, e); break; case DioErrorType.DEFAULT: if (e.message.contains("HttpException")) { diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 577232ac..70d39c1b 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -223,13 +223,12 @@ class HomePageState extends State { } void onTabTapped(int index) async { - bool bus = Preferences.getBool(Constants.PREF_BUS_ENABLE, true); switch (index) { case 0: - if (bus) - Utils.pushCupertinoStyle(context, BusPage()); - else - Utils.showToast(context, app.canNotUseFeature); +// if (bus) + Utils.pushCupertinoStyle(context, BusPage()); +// else +// Utils.showToast(context, app.canNotUseFeature); break; case 1: Utils.pushCupertinoStyle(context, CoursePage()); diff --git a/lib/widgets/drawer_body.dart b/lib/widgets/drawer_body.dart index 98080f04..410ffea6 100644 --- a/lib/widgets/drawer_body.dart +++ b/lib/widgets/drawer_body.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/material.dart'; @@ -278,21 +277,21 @@ class DrawerBodyState extends State { leading: Icon(icon, color: Resource.Colors.grey), title: Text(title, style: _defaultStyle), onTap: () async { - if (Platform.isAndroid || Platform.isIOS) { - if (page is BusPage) { - bool bus = Preferences.getBool(Constants.PREF_BUS_ENABLE, true); - if (!bus) { - Utils.showToast(context, app.canNotUseFeature); - return; - } - } else if (page is LeavePage) { - bool leave = Preferences.getBool(Constants.PREF_BUS_ENABLE, true); - if (!leave) { - Utils.showToast(context, app.canNotUseFeature); - return; - } - } - } +// if (Platform.isAndroid || Platform.isIOS) { +// if (page is BusPage) { +// bool bus = Preferences.getBool(Constants.PREF_BUS_ENABLE, true); +// if (!bus) { +// Utils.showToast(context, app.canNotUseFeature); +// return; +// } +// } else if (page is LeavePage) { +// bool leave = Preferences.getBool(Constants.PREF_BUS_ENABLE, true); +// if (!leave) { +// Utils.showToast(context, app.canNotUseFeature); +// return; +// } +// } +// } Navigator.of(context).pop(); Utils.pushCupertinoStyle(context, page); }, From ec87f4e37a554c034d137b87fe18eecc3b6127ff Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Tue, 27 Aug 2019 00:41:31 +0800 Subject: [PATCH 25/34] Add force time zone adjust --- lib/models/bus_data.dart | 6 +++--- lib/models/bus_reservations_data.dart | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/models/bus_data.dart b/lib/models/bus_data.dart index a1bbeb03..a6148926 100644 --- a/lib/models/bus_data.dart +++ b/lib/models/bus_data.dart @@ -126,7 +126,7 @@ class BusTime { var formatter = DateFormat('yyyy-MM-ddTHH:mm:ss'); var endEnrollDateTime = formatter.parse(this.endEnrollDateTime); return now.millisecondsSinceEpoch <= - endEnrollDateTime.millisecondsSinceEpoch; + endEnrollDateTime.add(Duration(hours: 8)).millisecondsSinceEpoch; } Color getColorState() { @@ -146,7 +146,7 @@ class BusTime { var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var formatterTime = new DateFormat('yyyy-MM-dd'); var time = formatter.parse(this.departureTime); - return formatterTime.format(time); + return formatterTime.format(time.add(Duration(hours: 8))); } String getTime() { @@ -154,7 +154,7 @@ class BusTime { var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var formatterTime = new DateFormat('HH:mm', 'zh'); var time = formatter.parse(this.departureTime); - return formatterTime.format(time); + return formatterTime.format(time.add(Duration(hours: 8))); } String getStart(AppLocalizations local) { diff --git a/lib/models/bus_reservations_data.dart b/lib/models/bus_reservations_data.dart index 04771729..05e7e336 100644 --- a/lib/models/bus_reservations_data.dart +++ b/lib/models/bus_reservations_data.dart @@ -90,7 +90,7 @@ class BusReservation { var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var formatterTime = new DateFormat('yyyy-MM-dd'); var time = formatter.parse(this.dateTime); - return formatterTime.format(time); + return formatterTime.format(time.add(Duration(hours: 8))); } String getTime() { @@ -98,7 +98,7 @@ class BusReservation { var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var formatterTime = new DateFormat('HH:mm'); var time = formatter.parse(this.dateTime); - return formatterTime.format(time); + return formatterTime.format(time.add(Duration(hours: 8))); } DateTime getDateTime() { @@ -111,7 +111,8 @@ class BusReservation { initializeDateFormatting(); var formatter = new DateFormat('yyyy-MM-ddTHH:mm:ssZ'); var formatterTime = new DateFormat('yyyy-MM-dd HH:mm'); - return formatterTime.format(formatter.parse(this.dateTime)); + return formatterTime + .format(formatter.parse(this.dateTime).add(Duration(hours: 8))); } String getStart(AppLocalizations local) { From 940e7b0aefa99ae685523306c004153aa423e90d Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sat, 31 Aug 2019 12:49:05 +0800 Subject: [PATCH 26/34] Fix booking and cancel bus error --- lib/api/helper.dart | 4 ++-- lib/pages/home/bus/bus_reserve_page.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 079b24ec..1da54932 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -330,7 +330,7 @@ class Helper { Future bookingBusReservation(String busId) async { try { var response = await dio.put( - "/$VERSION/bus/reservations", + "/bus/reservations", queryParameters: { 'busId': busId, }, @@ -344,7 +344,7 @@ class Helper { Future cancelBusReservation(String cancelKey) async { try { var response = await dio.delete( - "/bus/reservations/", + "/bus/reservations", queryParameters: { 'cancelKey': cancelKey, }, diff --git a/lib/pages/home/bus/bus_reserve_page.dart b/lib/pages/home/bus/bus_reserve_page.dart index 4ce0f113..e624e27c 100644 --- a/lib/pages/home/bus/bus_reserve_page.dart +++ b/lib/pages/home/bus/bus_reserve_page.dart @@ -351,7 +351,7 @@ class BusReservePageState extends State busData = response; if (mounted) { setState(() { - if (busData == null) + if (busData == null || busData.timetable.length == 0) state = _State.empty; else state = _State.finish; From 40477944915db08e36f903cf5586acd8e8ec7db2 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sat, 31 Aug 2019 16:43:26 +0800 Subject: [PATCH 27/34] Refactor api models class --- lib/api/helper.dart | 4 +-- lib/main.dart | 2 +- lib/models/api/api_models.dart | 1 - lib/models/api/error_response.dart | 33 ------------------- .../leave_response.dart => leaves_data.dart} | 0 lib/models/{api => }/login_response.dart | 0 lib/pages/home/leaves/leave_record_page.dart | 2 +- lib/pages/login_page.dart | 2 +- lib/utils/cache_utils.dart | 2 +- 9 files changed, 6 insertions(+), 40 deletions(-) delete mode 100644 lib/models/api/api_models.dart delete mode 100644 lib/models/api/error_response.dart rename lib/models/{api/leave_response.dart => leaves_data.dart} (100%) rename lib/models/{api => }/login_response.dart (100%) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 1da54932..6c920c18 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -6,12 +6,12 @@ import 'package:encrypt/encrypt.dart'; import 'package:intl/intl.dart'; import 'package:nkust_ap/config/constants.dart'; import 'package:nkust_ap/models/announcements_data.dart'; -import 'package:nkust_ap/models/api/api_models.dart'; -import 'package:nkust_ap/models/api/leave_response.dart'; import 'package:nkust_ap/models/bus_violation_records_data.dart'; import 'package:nkust_ap/models/leave_info_data.dart'; +import 'package:nkust_ap/models/leaves_data.dart'; import 'package:nkust_ap/models/leaves_submit_data.dart'; import 'package:nkust_ap/models/library_info_data.dart'; +import 'package:nkust_ap/models/login_response.dart'; import 'package:nkust_ap/models/midterm_alerts_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/models/reward_and_penalty_data.dart'; diff --git a/lib/main.dart b/lib/main.dart index e6e39412..bbfe32db 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,7 +21,7 @@ import 'package:nkust_ap/utils/preferences.dart'; import 'package:nkust_ap/utils/utils.dart'; import 'package:nkust_ap/widgets/share_data_widget.dart'; -import 'models/api/login_response.dart'; +import 'models/login_response.dart'; import 'models/user_info.dart'; void main() async { diff --git a/lib/models/api/api_models.dart b/lib/models/api/api_models.dart deleted file mode 100644 index ce16585e..00000000 --- a/lib/models/api/api_models.dart +++ /dev/null @@ -1 +0,0 @@ -export 'package:nkust_ap/models/api/login_response.dart'; diff --git a/lib/models/api/error_response.dart b/lib/models/api/error_response.dart deleted file mode 100644 index b1593e35..00000000 --- a/lib/models/api/error_response.dart +++ /dev/null @@ -1,33 +0,0 @@ -class ErrorResponse { - int status; - String developerMessage; - String userMessage; - int errorCode; - String moreInfo; - - ErrorResponse({ - this.status, - this.developerMessage, - this.userMessage, - this.errorCode, - this.moreInfo, - }); - - static ErrorResponse fromJson(Map json) { - return ErrorResponse( - status: json['status'], - developerMessage: json['developer_message'], - userMessage: json['user_message'], - errorCode: json['error_code'], - moreInfo: json['more_info'], - ); - } - - Map toJson() => { - 'status': status, - 'developer_message': developerMessage, - 'user_message': userMessage, - 'error_code': errorCode, - 'more_info': moreInfo, - }; -} diff --git a/lib/models/api/leave_response.dart b/lib/models/leaves_data.dart similarity index 100% rename from lib/models/api/leave_response.dart rename to lib/models/leaves_data.dart diff --git a/lib/models/api/login_response.dart b/lib/models/login_response.dart similarity index 100% rename from lib/models/api/login_response.dart rename to lib/models/login_response.dart diff --git a/lib/pages/home/leaves/leave_record_page.dart b/lib/pages/home/leaves/leave_record_page.dart index 07a1c379..124629cd 100644 --- a/lib/pages/home/leaves/leave_record_page.dart +++ b/lib/pages/home/leaves/leave_record_page.dart @@ -1,6 +1,6 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; -import 'package:nkust_ap/models/api/leave_response.dart'; +import 'package:nkust_ap/models/leaves_data.dart'; import 'package:nkust_ap/models/models.dart'; import 'package:nkust_ap/res/app_icon.dart'; import 'package:nkust_ap/res/resource.dart' as Resource; diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index 29ad4914..aa54f700 100644 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -1,7 +1,7 @@ import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:nkust_ap/models/api/login_response.dart'; +import 'package:nkust_ap/models/login_response.dart'; import 'package:nkust_ap/pages/search_student_id_page.dart'; import 'package:nkust_ap/res/assets.dart'; import 'package:nkust_ap/res/colors.dart' as Resource; diff --git a/lib/utils/cache_utils.dart b/lib/utils/cache_utils.dart index 6755115b..c671cd4a 100644 --- a/lib/utils/cache_utils.dart +++ b/lib/utils/cache_utils.dart @@ -3,9 +3,9 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:nkust_ap/config/constants.dart'; -import 'package:nkust_ap/models/api/leave_response.dart'; import 'package:nkust_ap/models/bus_reservations_data.dart'; import 'package:nkust_ap/models/course_data.dart'; +import 'package:nkust_ap/models/leaves_data.dart'; import 'package:nkust_ap/models/schedule_data.dart'; import 'package:nkust_ap/models/score_data.dart'; import 'package:nkust_ap/models/semester_data.dart'; From 2063db968f3c5609836fd056c8d1bad1c40b30e5 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sat, 31 Aug 2019 17:00:43 +0800 Subject: [PATCH 28/34] Fix feature calculate unit to api v3 format --- lib/pages/home/calculate_units_page.dart | 127 +++++++++++------------ 1 file changed, 61 insertions(+), 66 deletions(-) diff --git a/lib/pages/home/calculate_units_page.dart b/lib/pages/home/calculate_units_page.dart index 1f88cae4..c241e61d 100644 --- a/lib/pages/home/calculate_units_page.dart +++ b/lib/pages/home/calculate_units_page.dart @@ -27,7 +27,6 @@ class CalculateUnitsPageState extends State Semester selectSemester; SemesterData semesterData; List semesterList; - List scores; double unitsTotal; double requiredUnitsTotal; @@ -265,7 +264,6 @@ class CalculateUnitsPageState extends State count = 0; currentSemesterIndex = 0; semesterList = []; - scores = []; coreGeneralEducations = []; extendGeneralEducations = []; start = DateTime.now(); @@ -314,13 +312,16 @@ class CalculateUnitsPageState extends State _getSemester(); return; } - var textList = semesterData.data[currentSemesterIndex].value.split(","); - if (textList.length == 2) { - Helper.instance.getScores(textList[0], textList[1]).then((response) { - if (startYear == -1) startYear = int.parse(textList[0]); - //scoreWeightList.add(_scoreTitle()); - semesterList.add(semesterData.data[currentSemesterIndex]); - scores = response.scores; + Helper.instance + .getScores(semesterData.data[currentSemesterIndex].year, + semesterData.data[currentSemesterIndex].value) + .then((response) { + if (startYear == -1) + startYear = int.parse(semesterData.data[currentSemesterIndex].year); + //scoreWeightList.add(_scoreTitle()); + semesterList.add(semesterData.data[currentSemesterIndex]); + + if (response?.scores != null) { for (var score in response.scores) { var finalScore = double.tryParse(score.finalScore); if (finalScore != null) { @@ -340,50 +341,43 @@ class CalculateUnitsPageState extends State } } } - var currentYear = int.parse(textList[0]); - if (currentSemesterIndex < semesterData.data.length - 1 && - ((startYear - currentYear).abs() <= 6 || startYear == -1)) { - currentSemesterIndex++; - if (mounted) _getSemesterScore(); - } else { - DateTime end = DateTime.now(); - var second = - (end.millisecondsSinceEpoch - start.millisecondsSinceEpoch) / - 1000; - FA.logCalculateUnits(second); - unitsTotal = - requiredUnitsTotal + electiveUnitsTotal + otherUnitsTotal; - if (mounted) { + } + var currentYear = int.parse(semesterData.data[currentSemesterIndex].year); + if (currentSemesterIndex < semesterData.data.length - 1 && + ((startYear - currentYear).abs() <= 6 || startYear == -1)) { + currentSemesterIndex++; + if (mounted) _getSemesterScore(); + } else { + DateTime end = DateTime.now(); + var second = + (end.millisecondsSinceEpoch - start.millisecondsSinceEpoch) / 1000; + FA.logCalculateUnits(second); + unitsTotal = requiredUnitsTotal + electiveUnitsTotal + otherUnitsTotal; + if (mounted) { + setState(() { + state = _State.finish; + }); + } + } + }).catchError((e) { + if (e is DioError) { + switch (e.type) { + case DioErrorType.RESPONSE: + Utils.handleResponseError(context, 'getSemesterScore', mounted, e); + break; + case DioErrorType.CANCEL: + break; + default: setState(() { - state = _State.finish; + state = _State.error; }); - } - } - }).catchError((e) { - if (e is DioError) { - switch (e.type) { - case DioErrorType.RESPONSE: - Utils.handleResponseError( - context, 'getSemesterScore', mounted, e); - break; - case DioErrorType.CANCEL: - break; - default: - setState(() { - state = _State.error; - }); - Utils.handleDioError(context, e); - break; - } - } else { - throw e; + Utils.handleDioError(context, e); + break; } - }); - } else { - setState(() { - state = _State.error; - }); - } + } else { + throw e; + } + }); } void _getByMuti() { @@ -405,22 +399,23 @@ class CalculateUnitsPageState extends State if (startYear == -1) startYear = int.parse(textList[0]); //scoreWeightList.add(_scoreTitle()); semesterList.add(s); - scores = response.scores; - for (var score in response.scores) { - var finalScore = double.tryParse(score.finalScore); - if (finalScore != null) { - if (finalScore >= 60.0) { - if (score.required == "【必修】") { - requiredUnitsTotal += double.parse(score.units); - } else if (score.required == "【選修】") { - electiveUnitsTotal += double.parse(score.units); - } else { - otherUnitsTotal += double.parse(score.units); - } - if (score.title.contains("延伸通識")) { - extendGeneralEducations.add(score); - } else if (score.title.contains("核心通識")) { - coreGeneralEducations.add(score); + if (response?.scores == null) { + for (var score in response.scores) { + var finalScore = double.tryParse(score.finalScore); + if (finalScore != null) { + if (finalScore >= 60.0) { + if (score.required == "【必修】") { + requiredUnitsTotal += double.parse(score.units); + } else if (score.required == "【選修】") { + electiveUnitsTotal += double.parse(score.units); + } else { + otherUnitsTotal += double.parse(score.units); + } + if (score.title.contains("延伸通識")) { + extendGeneralEducations.add(score); + } else if (score.title.contains("核心通識")) { + coreGeneralEducations.add(score); + } } } } From 1a9597ec7846f16ad95d93f6fa038c5dee7fd0a6 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sat, 31 Aug 2019 18:36:58 +0800 Subject: [PATCH 29/34] Improve feature booking and cancel response to class --- lib/api/helper.dart | 10 +-- lib/models/booking_bus_data.dart | 63 ++++++++++++++++ lib/models/bus_data.dart | 8 +++ lib/models/cancel_bus_data.dart | 71 +++++++++++++++++++ lib/pages/home/bus/bus_reservations_page.dart | 6 +- lib/pages/home/bus/bus_reserve_page.dart | 16 ++--- 6 files changed, 159 insertions(+), 15 deletions(-) create mode 100644 lib/models/booking_bus_data.dart create mode 100644 lib/models/cancel_bus_data.dart diff --git a/lib/api/helper.dart b/lib/api/helper.dart index 6c920c18..f96f35e1 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -6,7 +6,9 @@ import 'package:encrypt/encrypt.dart'; import 'package:intl/intl.dart'; import 'package:nkust_ap/config/constants.dart'; import 'package:nkust_ap/models/announcements_data.dart'; +import 'package:nkust_ap/models/booking_bus_data.dart'; import 'package:nkust_ap/models/bus_violation_records_data.dart'; +import 'package:nkust_ap/models/cancel_bus_data.dart'; import 'package:nkust_ap/models/leave_info_data.dart'; import 'package:nkust_ap/models/leaves_data.dart'; import 'package:nkust_ap/models/leaves_submit_data.dart'; @@ -327,7 +329,7 @@ class Helper { } } - Future bookingBusReservation(String busId) async { + Future bookingBusReservation(String busId) async { try { var response = await dio.put( "/bus/reservations", @@ -335,13 +337,13 @@ class Helper { 'busId': busId, }, ); - return response; + return BookingBusData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } } - Future cancelBusReservation(String cancelKey) async { + Future cancelBusReservation(String cancelKey) async { try { var response = await dio.delete( "/bus/reservations", @@ -349,7 +351,7 @@ class Helper { 'cancelKey': cancelKey, }, ); - return response; + return CancelBusData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } diff --git a/lib/models/booking_bus_data.dart b/lib/models/booking_bus_data.dart new file mode 100644 index 00000000..b987759f --- /dev/null +++ b/lib/models/booking_bus_data.dart @@ -0,0 +1,63 @@ +import 'dart:convert'; + +class BookingBusData { + bool success; + int code; + String message; + int count; + Data data; + + BookingBusData({ + this.success, + this.code, + this.message, + this.count, + this.data, + }); + + factory BookingBusData.fromRawJson(String str) => + BookingBusData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory BookingBusData.fromJson(Map json) => + new BookingBusData( + success: json["success"], + code: json["code"], + message: json["message"], + count: json["count"], + data: Data.fromJson(json["data"]), + ); + + Map toJson() => { + "success": success, + "code": code, + "message": message, + "count": count, + "data": data.toJson(), + }; +} + +class Data { + String startTime; + int budId; + + Data({ + this.startTime, + this.budId, + }); + + factory Data.fromRawJson(String str) => Data.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Data.fromJson(Map json) => new Data( + startTime: json["startTime"], + budId: json["budId"], + ); + + Map toJson() => { + "startTime": startTime, + "budId": budId, + }; +} diff --git a/lib/models/bus_data.dart b/lib/models/bus_data.dart index a6148926..2ede2855 100644 --- a/lib/models/bus_data.dart +++ b/lib/models/bus_data.dart @@ -129,6 +129,14 @@ class BusTime { endEnrollDateTime.add(Duration(hours: 8)).millisecondsSinceEpoch; } + String getEndEnrollDateTime() { + initializeDateFormatting(); + var formatter = DateFormat('yyyy-MM-ddTHH:mm:ssZ'); + var dateFormat = DateFormat('yyyy-MM-dd HH:mm:ss '); + var endEnrollDateTime = formatter.parse(this.endEnrollDateTime); + return dateFormat.format(endEnrollDateTime.add(Duration(hours: 8))); + } + Color getColorState() { return isReserve ? Resource.Colors.blueAccent diff --git a/lib/models/cancel_bus_data.dart b/lib/models/cancel_bus_data.dart new file mode 100644 index 00000000..fdf565bc --- /dev/null +++ b/lib/models/cancel_bus_data.dart @@ -0,0 +1,71 @@ +import 'dart:convert'; + +class CancelBusData { + bool success; + int code; + String message; + int count; + Data data; + + CancelBusData({ + this.success, + this.code, + this.message, + this.count, + this.data, + }); + + factory CancelBusData.fromRawJson(String str) => + CancelBusData.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory CancelBusData.fromJson(Map json) => + new CancelBusData( + success: json["success"], + code: json["code"], + message: json["message"], + count: json["count"], + data: Data.fromJson(json["data"]), + ); + + Map toJson() => { + "success": success, + "code": code, + "message": message, + "count": count, + "data": data.toJson(), + }; +} + +class Data { + String message; + int busId; + String runTime; + String reserveMemberId; + + Data({ + this.message, + this.busId, + this.runTime, + this.reserveMemberId, + }); + + factory Data.fromRawJson(String str) => Data.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Data.fromJson(Map json) => new Data( + message: json["message"], + busId: json["busId"], + runTime: json["runTime"], + reserveMemberId: json["reserveMemberId"], + ); + + Map toJson() => { + "message": message, + "busId": busId, + "runTime": runTime, + "reserveMemberId": reserveMemberId, + }; +} diff --git a/lib/pages/home/bus/bus_reservations_page.dart b/lib/pages/home/bus/bus_reservations_page.dart index 49f35c76..18d02e2f 100644 --- a/lib/pages/home/bus/bus_reservations_page.dart +++ b/lib/pages/home/bus/bus_reservations_page.dart @@ -289,15 +289,15 @@ class BusReservationsPageState extends State .then((response) { String title = "", message = ""; Widget messageWidget; - if (!response.data["success"]) { + if (!response.success) { title = app.busCancelReserveFail; messageWidget = Text( - response.data["message"], + response.data.message, style: TextStyle( color: Resource.Colors.grey, height: 1.3, fontSize: 16.0), ); FA.logAction('cancel_bus', 'status', - message: 'fail_${response.data["message"]}'); + message: 'fail_${response.data.message}'); } else { title = app.busCancelReserveSuccess; messageWidget = RichText( diff --git a/lib/pages/home/bus/bus_reserve_page.dart b/lib/pages/home/bus/bus_reserve_page.dart index e624e27c..32637532 100644 --- a/lib/pages/home/bus/bus_reserve_page.dart +++ b/lib/pages/home/bus/bus_reserve_page.dart @@ -236,7 +236,8 @@ class BusReservePageState extends State text: '${app.reserveDeadline}:\n', style: TextStyle(fontWeight: FontWeight.bold)), - TextSpan(text: '${busTime.endEnrollDateTime}'), + TextSpan( + text: '${busTime.getEndEnrollDateTime()}'), ], ), ), @@ -411,15 +412,14 @@ class BusReservePageState extends State //TODO to object String title = ""; Widget messageWidget; - if (!response.data["success"]) { + if (response.success) { title = app.busReserveFailTitle; messageWidget = Text( - response.data["message"], + response.message, style: TextStyle( color: Resource.Colors.grey, height: 1.3, fontSize: 16.0), ); - FA.logAction('book_bus', 'status', - message: 'fail_${response.data["message"]}'); + FA.logAction('book_bus', 'status', message: 'fail_${response.message}'); } else { title = app.busReserveSuccess; messageWidget = RichText( @@ -508,15 +508,15 @@ class BusReservePageState extends State Helper.instance.cancelBusReservation(busTime.cancelKey).then((response) { String title = ""; Widget messageWidget; - if (!response.data["success"]) { + if (!response.success) { title = app.busCancelReserveFail; messageWidget = Text( - response.data["message"], + response.data.message, style: TextStyle( color: Resource.Colors.grey, height: 1.3, fontSize: 16.0), ); FA.logAction('cancel_bus', 'status', - message: 'fail_${response.data["message"]}'); + message: 'fail_${response.data.message}'); } else { title = app.busCancelReserveSuccess; messageWidget = RichText( From c089013717a98f63fe1e5553c2e4acaf3244521b Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Sun, 1 Sep 2019 19:31:34 +0800 Subject: [PATCH 30/34] Fix api request parameter value to semester --- lib/api/helper.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index f96f35e1..dca23f59 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -185,7 +185,7 @@ class Helper { "/user/scores", queryParameters: { 'year': year, - 'value': semester, + 'semester': semester, }, cancelToken: cancelToken, ); @@ -204,7 +204,7 @@ class Helper { '/user/coursetable', queryParameters: { 'year': year, - 'value': semester, + 'semester': semester, }, cancelToken: cancelToken, ); @@ -224,7 +224,7 @@ class Helper { "/user/reward-and-penalty", queryParameters: { 'year': year, - 'value': semester, + 'semester': semester, }, cancelToken: cancelToken, ); @@ -244,7 +244,7 @@ class Helper { "/user/midterm-alerts", queryParameters: { 'year': year, - 'value': semester, + 'semester': semester, }, cancelToken: cancelToken, ); @@ -284,7 +284,7 @@ class Helper { queryParameters: { 'roomId': roomId, 'year': year, - 'value': semester, + 'semester': semester, }, cancelToken: cancelToken, ); @@ -386,7 +386,7 @@ class Helper { '/leaves', queryParameters: { 'year': year, - 'value': semester, + 'semester': semester, }, cancelToken: cancelToken, ); From be7eb6cafce8099fd2282fb6a1b462c3a593d681 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Mon, 2 Sep 2019 15:00:05 +0800 Subject: [PATCH 31/34] Revert leave get data source --- lib/models/leaves_data.dart | 6 ++++-- lib/pages/home/leaves/leave_record_page.dart | 11 +---------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/models/leaves_data.dart b/lib/models/leaves_data.dart index 3bea5be6..c5fca4e9 100644 --- a/lib/models/leaves_data.dart +++ b/lib/models/leaves_data.dart @@ -16,8 +16,10 @@ class LeavesData { factory LeavesData.fromJson(Map json) => new LeavesData( leaves: - new List.from(json["leave"].map((x) => Leaves.fromJson(x))), - timeCodes: new List.from(json["timeCodes"].map((x) => x)), + new List.from(json["data"].map((x) => Leaves.fromJson(x))), + timeCodes: json["timeCodes"] == null + ? null + : new List.from(json["timeCodes"].map((x) => x)), ); Map toJson() => { diff --git a/lib/pages/home/leaves/leave_record_page.dart b/lib/pages/home/leaves/leave_record_page.dart index 124629cd..cf595b52 100644 --- a/lib/pages/home/leaves/leave_record_page.dart +++ b/lib/pages/home/leaves/leave_record_page.dart @@ -268,22 +268,13 @@ class LeaveRecordPageState extends State _getSemesterLeaveRecord() async { Helper.cancelToken.cancel(''); Helper.cancelToken = CancelToken(); - setState(() { - leaveData = LeavesData.sample(); - if (leaveData == null) - state = _State.empty; - else { - state = _State.finish; - } - }); - return; Helper.instance .getLeaves(selectSemester.year, selectSemester.value) .then((response) { if (mounted) setState(() { leaveData = response; - if (leaveData == null) + if (leaveData == null || leaveData.leaves.length == 0) state = _State.empty; else { state = _State.finish; From c6cf91355954909030fa4e96239df9302f93b9d7 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Mon, 2 Sep 2019 15:37:49 +0800 Subject: [PATCH 32/34] Fix feature school news and leaves format error Revert comment feature school news and news --- lib/api/helper.dart | 5 ++++- lib/models/notification_data.dart | 2 +- lib/pages/home/info/notification_page.dart | 7 +++---- lib/pages/home/news_content_page.dart | 2 +- lib/pages/home_page.dart | 6 ++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/api/helper.dart b/lib/api/helper.dart index dca23f59..814a16fa 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -373,7 +373,10 @@ class Helper { Future getNotifications(int page) async { try { - var response = await dio.get("/news/school/$page"); + var response = await dio.get( + "/news/school", + queryParameters: {'page': page}, + ); return NotificationsData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; diff --git a/lib/models/notification_data.dart b/lib/models/notification_data.dart index 3e46824b..f80d9be4 100644 --- a/lib/models/notification_data.dart +++ b/lib/models/notification_data.dart @@ -84,7 +84,7 @@ class Notifications { } class Info { - String id; + int id; String title; String department; String date; diff --git a/lib/pages/home/info/notification_page.dart b/lib/pages/home/info/notification_page.dart index 30604032..1d66a1e6 100644 --- a/lib/pages/home/info/notification_page.dart +++ b/lib/pages/home/info/notification_page.dart @@ -21,7 +21,7 @@ class NotificationPageState extends State @override bool get wantKeepAlive => true; - _State state = _State.finish; + _State state = _State.loading; AppLocalizations app; @@ -44,9 +44,7 @@ class NotificationPageState extends State void initState() { FA.setCurrentScreen("NotificationPage", "notification_page.dart"); controller = ScrollController()..addListener(_scrollListener); - //_getNotifications(); - //TODO: Revert getData from v3 api - notificationList = NotificationsData.sample().data.notifications; + _getNotifications(); super.initState(); } @@ -194,6 +192,7 @@ class NotificationPageState extends State }); } }).catchError((e) { + throw e; if (e is DioError) { switch (e.type) { case DioErrorType.RESPONSE: diff --git a/lib/pages/home/news_content_page.dart b/lib/pages/home/news_content_page.dart index a40dc1ca..4b8d27d1 100644 --- a/lib/pages/home/news_content_page.dart +++ b/lib/pages/home/news_content_page.dart @@ -116,7 +116,7 @@ class NewsContentPageState extends State { ), ), ), - if (widget.news.url.isNotEmpty) ...[ + if (widget.news.url != null && widget.news.url.isNotEmpty) ...[ SizedBox(height: 16.0), RaisedButton( shape: RoundedRectangleBorder( diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 70d39c1b..819db1be 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -25,7 +25,7 @@ class HomePage extends StatefulWidget { } class HomePageState extends State { - _State state = _State.finish; + _State state = _State.loading; AppLocalizations app; UserInfo userInfo = UserInfo(); @@ -36,9 +36,7 @@ class HomePageState extends State { @override void initState() { FA.setCurrentScreen("HomePage", "home_page.dart"); - // _getNewsAll(); - //TODO: Revert getData from v3 api - announcementsResponse = AnnouncementsData.sample(); + _getNewsAll(); _getUserInfo(); if (Preferences.getBool(Constants.PREF_AUTO_LOGIN, false)) Utils.checkUpdate(context); From 9360c3f7b5a84212419e93d8c7c7fb0d83960d89 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Mon, 2 Sep 2019 15:52:25 +0800 Subject: [PATCH 33/34] Fix leaves data toJson format error --- lib/models/leaves_data.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/leaves_data.dart b/lib/models/leaves_data.dart index c5fca4e9..e1ae74c6 100644 --- a/lib/models/leaves_data.dart +++ b/lib/models/leaves_data.dart @@ -23,7 +23,7 @@ class LeavesData { ); Map toJson() => { - "leave": new List.from(leaves.map((x) => x.toJson())), + "data": new List.from(leaves.map((x) => x.toJson())), "timeCodes": new List.from(timeCodes.map((x) => x)), }; From 146247dab600112226ee443e720bbaea75d05f35 Mon Sep 17 00:00:00 2001 From: RainVisitor Date: Mon, 2 Sep 2019 16:55:33 +0800 Subject: [PATCH 34/34] Update to v3.2.3 Start this version, begin test v3 api. --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 8dd77a06..56b9fe40 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: nkust_ap description: A new Flutter application. -version: 3.2.2+30202 +version: 3.2.3+30203 environment: sdk: ">=2.2.2 <3.0.0"