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 e3c33111..814a16fa 100644 --- a/lib/api/helper.dart +++ b/lib/api/helper.dart @@ -5,15 +5,26 @@ 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/api/api_models.dart'; -import 'package:nkust_ap/models/api/leave_response.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'; +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'; +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-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; @@ -84,19 +95,57 @@ 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; } } - Future> getAllNews() async { + Future deleteToken() async { try { - var response = await dio.get("/$VERSION/news/all"); - var jsonArray = jsonCodec.decode(response.data); - return News.toList(jsonArray); + 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 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"); + return AnnouncementsData.fromJson(response.data); } on DioError catch (dioError) { print(dioError); throw dioError; @@ -105,9 +154,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; } @@ -124,7 +172,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; @@ -134,9 +182,17 @@ class Helper { Future getScores(String year, String semester) async { try { var response = await dio.get( - "/$VERSION/ap/users/scores/" + year + "/" + semester, - cancelToken: cancelToken); - return ScoreData.fromJson(response.data); + "/user/scores", + queryParameters: { + 'year': year, + 'semester': semester, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return ScoreData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } @@ -145,21 +201,117 @@ 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, + 'semester': semester, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return CourseData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + + Future getRewardAndPenalty( + String year, String semester) async { + try { + var response = await dio.get( + "/user/reward-and-penalty", + queryParameters: { + 'year': year, + 'semester': 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 { + var response = await dio.get( + "/user/midterm-alerts", + queryParameters: { + 'year': year, + 'semester': semester, + }, + cancelToken: cancelToken, + ); + if (response.statusCode == 204) + return null; + else + return MidtermAlertsData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + + //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, + 'semester': 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 formatter = 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( + '/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; } @@ -167,45 +319,121 @@ 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; } } - Future bookingBusReservation(String busId) async { + Future bookingBusReservation(String busId) async { try { - var response = await dio.put("/$VERSION/bus/reservations/$busId"); - return response; + var response = await dio.put( + "/bus/reservations", + queryParameters: { + 'busId': busId, + }, + ); + 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("/$VERSION/bus/reservations/$cancelKey"); - return response; + var response = await dio.delete( + "/bus/reservations", + queryParameters: { + 'cancelKey': cancelKey, + }, + ); + return CancelBusData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + + 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 + return BusViolationRecordsData.fromJson(response.data); + } on DioError catch (dioError) { + throw dioError; + } + } + + Future getNotifications(int page) async { + try { + var response = await dio.get( + "/news/school", + queryParameters: {'page': page}, + ); + return NotificationsData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } } - Future getLeaves(String year, String semester) async { + Future getLeaves(String year, String semester) async { try { - var response = await dio.get("/$VERSION/leaves/$year/$semester", - cancelToken: cancelToken); - return LeaveResponse.fromJson(response.data); + var response = await dio.get( + '/leaves', + queryParameters: { + 'year': year, + 'semester': semester, + }, + cancelToken: cancelToken, + ); + return LeavesData.fromJson(response.data); } on DioError catch (dioError) { throw dioError; } } - Future getNotifications(int page) async { + Future getLeavesSubmitInfo() async { try { - var response = await dio.get("/$VERSION/notifications/$page"); - return NotificationData.fromJson(response.data); + 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; + } + } + + 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; } @@ -219,4 +447,10 @@ class Helper { "Authorization": "Basic " + base64.encode(encoded.toList(growable: false)) }; } + + _createBearerTokenAuth(String token) { + return { + 'Authorization': 'Bearer $token', + }; + } } diff --git a/lib/main.dart b/lib/main.dart index 0a44beaa..bbfe32db 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/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) { 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/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/api/leave_response.dart deleted file mode 100644 index 3495524c..00000000 --- a/lib/models/api/leave_response.dart +++ /dev/null @@ -1,96 +0,0 @@ -class LeaveResponse { - int status; - String messages; - 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(); - } - - 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; - } -} - -class Leaves { - String leaveSheetId; - String date; - String instructorsComment; - List leaveSections; - - Leaves( - {this.leaveSheetId, - this.date, - 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)); - }); - } - } - - 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 getReason(String timeCode) { - if (leaveSections == null) return ""; - if (leaveSections.length == 0) return ""; - for (var leaveSection in leaveSections) { - if (leaveSection.section == timeCode) return leaveSection.reason; - } - return ""; - } -} - -class LeaveSections { - String section; - String reason; - - LeaveSections({this.section, this.reason}); - - LeaveSections.fromJson(Map json) { - section = json['section']; - reason = json['reason']; - } - - Map toJson() { - final Map data = new Map(); - data['section'] = this.section; - data['reason'] = this.reason; - return data; - } -} diff --git a/lib/models/api/login_response.dart b/lib/models/api/login_response.dart deleted file mode 100644 index 75983e24..00000000 --- a/lib/models/api/login_response.dart +++ /dev/null @@ -1,50 +0,0 @@ -class LoginResponse { - String authToken; - int duration; - IsLogin isLogin; - String tokenType; - - LoginResponse({this.authToken, this.duration, this.isLogin, this.tokenType}); - - 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']; - } - - 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; - } -} - -class IsLogin { - bool ap; - bool bus; - bool leave; - - IsLogin({this.ap, this.bus, this.leave}); - - IsLogin.fromJson(Map json) { - ap = json['ap']; - bus = json['bus']; - leave = json['leave']; - } - - Map toJson() { - final Map data = new Map(); - data['ap'] = this.ap; - data['bus'] = this.bus; - data['leave'] = this.leave; - return data; - } -} 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 8650ff20..2ede2855 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) => BusData( + date: json["date"], + timetable: + 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,85 @@ 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) => 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(); + var now = DateTime.now(); initializeDateFormatting(); - var formatter = new DateFormat('yyyy-MM-dd HH:mm', 'zh'); + var formatter = DateFormat('yyyy-MM-ddTHH:mm:ss'); var endEnrollDateTime = formatter.parse(this.endEnrollDateTime); - //print(endEnrollDateTime); return now.millisecondsSinceEpoch <= - endEnrollDateTime.millisecondsSinceEpoch; + 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 == 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); - return formatterTime.format(time); + var time = formatter.parse(this.departureTime); + return formatterTime.format(time.add(Duration(hours: 8))); } 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); - return formatterTime.format(time); + var time = formatter.parse(this.departureTime); + return formatterTime.format(time.add(Duration(hours: 8))); } String getStart(AppLocalizations local) { - switch (endStation) { + switch (startStation) { case "建工": return local.yanchao; case "燕巢": @@ -157,7 +177,7 @@ class BusTime { } String getEnd(AppLocalizations local) { - switch (endStation) { + switch (startStation) { case "建工": return local.jiangong; case "燕巢": diff --git a/lib/models/bus_reservations_data.dart b/lib/models/bus_reservations_data.dart index b4c3ebae..05e7e336 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,39 @@ 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); - return formatterTime.format(time); + var time = formatter.parse(this.dateTime); + return formatterTime.format(time.add(Duration(hours: 8))); } 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); - return formatterTime.format(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.add(Duration(hours: 8))); } 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).add(Duration(hours: 8))); } 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 +127,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 +140,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/models/bus_violation_records_data.dart b/lib/models/bus_violation_records_data.dart new file mode 100644 index 00000000..c4da5000 --- /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; + bool 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, + }; +} 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/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/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_data.dart b/lib/models/leaves_data.dart new file mode 100644 index 00000000..e1ae74c6 --- /dev/null +++ b/lib/models/leaves_data.dart @@ -0,0 +1,95 @@ +import 'dart:convert'; + +class LeavesData { + List leaves; + List timeCodes; + + 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["data"].map((x) => Leaves.fromJson(x))), + timeCodes: json["timeCodes"] == null + ? null + : new List.from(json["timeCodes"].map((x) => x)), + ); + + Map toJson() => { + "data": 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" ] }'); + } +} + +class Leaves { + String leaveSheetId; + String date; + String instructorsComment; + List leaveSections; + + Leaves( + {this.leaveSheetId, + this.date, + this.instructorsComment, + this.leaveSections}); + + factory Leaves.fromRawJson(String str) => Leaves.fromJson(json.decode(str)); + + 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 ""; + if (leaveSections.length == 0) return ""; + for (var leaveSection in leaveSections) { + if (leaveSection.section == timeCode) return leaveSection.reason; + } + return ""; + } +} + +class LeaveSections { + String section; + String reason; + + LeaveSections({this.section, this.reason}); + + LeaveSections.fromJson(Map json) { + section = json['section']; + reason = json['reason']; + } + + Map toJson() { + final Map data = new Map(); + data['section'] = this.section; + data['reason'] = this.reason; + return data; + } +} 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)), + }; +} 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, + }; +} diff --git a/lib/models/login_response.dart b/lib/models/login_response.dart new file mode 100644 index 00000000..375ed639 --- /dev/null +++ b/lib/models/login_response.dart @@ -0,0 +1,27 @@ +import 'dart:convert'; + +class LoginResponse { + DateTime expireTime; + String token; + + LoginResponse({ + this.expireTime, + this.token, + }); + + factory LoginResponse.fromRawJson(String str) => + LoginResponse.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory LoginResponse.fromJson(Map json) => + new LoginResponse( + expireTime: DateTime.parse(json["expireTime"]), + token: json["token"], + ); + + Map toJson() => { + "expireTime": expireTime.toIso8601String(), + "token": token, + }; +} 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/models/notification_data.dart b/lib/models/notification_data.dart index 92e8fa58..f80d9be4 100644 --- a/lib/models/notification_data.dart +++ b/lib/models/notification_data.dart @@ -1,55 +1,90 @@ -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 { - String id; + int id; String title; String department; String date; @@ -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/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/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, + }; +} diff --git a/lib/models/score_data.dart b/lib/models/score_data.dart index 461110be..5352f31f 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 { + double conduct; + double average; + String classRank; + double 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'], - ); - } - - 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; + factory Score.fromRawJson(String str) => Score.fromJson(json.decode(str)); - 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/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/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, + }; +} 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/bus/bus_reservations_page.dart b/lib/pages/home/bus/bus_reservations_page.dart index 6e60e651..18d02e2f 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(); @@ -220,10 +220,11 @@ class BusReservationsPageState extends State busReservationsData = response; if (mounted) { setState(() { - if (busReservationsData.reservations.length != 0) - state = _State.finish; - else + if (busReservationsData == null || + busReservationsData.reservations.length == 0) state = _State.empty; + else + state = _State.finish; }); } CacheUtils.saveBusReservationsData(busReservationsData); @@ -231,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")) { @@ -283,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 74c26148..32637532 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(); @@ -187,10 +187,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 +200,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) @@ -215,29 +215,31 @@ 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.getSpecialTrainRemark()}${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.getEndEnrollDateTime()}'), + ], + ), ), leftActionText: app.cancel, rightActionText: app.reserve, @@ -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 || busData.timetable.length == 0) state = _State.empty; + else + state = _State.finish; }); } }).catchError((e) { @@ -362,7 +364,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")) { @@ -404,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( @@ -501,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( diff --git a/lib/pages/home/calculate_units_page.dart b/lib/pages/home/calculate_units_page.dart index 43cd5f30..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 scoreDataList; double unitsTotal; double requiredUnitsTotal; @@ -101,14 +100,6 @@ class CalculateUnitsPageState extends State ); } - _scoreBorder(Semester semester, ScoreData score) { - return TableRow(children: [ - _scoreTextBorder(semester.text, 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 +264,6 @@ class CalculateUnitsPageState extends State count = 0; currentSemesterIndex = 0; semesterList = []; - scoreDataList = []; coreGeneralEducations = []; extendGeneralEducations = []; start = DateTime.now(); @@ -318,83 +308,76 @@ 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(","); - 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]); - 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); - } + 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) { + 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); } } } } - var currentYear = int.parse(textList[0]); - if (currentSemesterIndex < semesterData.semesters.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() { @@ -404,21 +387,20 @@ 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) { - 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) { + if (startYear == -1) startYear = int.parse(textList[0]); + //scoreWeightList.add(_scoreTitle()); + semesterList.add(s); + if (response?.scores == null) { + for (var score in response.scores) { var finalScore = double.tryParse(score.finalScore); if (finalScore != null) { if (finalScore >= 60.0) { @@ -443,7 +425,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/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/pages/home/info/notification_page.dart b/lib/pages/home/info/notification_page.dart index f02857d6..1d66a1e6 100644 --- a/lib/pages/home/info/notification_page.dart +++ b/lib/pages/home/info/notification_page.dart @@ -26,7 +26,7 @@ class NotificationPageState extends State AppLocalizations app; ScrollController controller; - List notificationList = []; + List notificationList = []; int page = 1; @@ -54,7 +54,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 +183,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) { @@ -192,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/leaves/leave_record_page.dart b/lib/pages/home/leaves/leave_record_page.dart index 79df7240..cf595b52 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; @@ -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,53 @@ 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; + Helper.instance + .getLeaves(selectSemester.year, selectSemester.value) + .then((response) { + if (mounted) + setState(() { + leaveData = response; + if (leaveData == null || leaveData.leaves.length == 0) + 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/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/pages/home/news_content_page.dart b/lib/pages/home/news_content_page.dart index 7d474d69..4b8d27d1 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, @@ -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( @@ -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/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/pages/home/score_page.dart b/lib/pages/home/score_page.dart index a1d79c35..586cd267 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,46 @@ 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(() { + if (Preferences.getBool(Constants.PREF_IS_OFFLINE_LOGIN, false)) + _loadOfflineScoreData(); + else + Helper.instance + .getScores(selectSemester.year, selectSemester.value) + .then((response) { + if (mounted) + setState(() { + if (response == null) { + state = _State.empty; + } else { scoreData = response; - if (scoreData.status == 204) - state = _State.empty; - else { - state = _State.finish; - } + 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 (mounted) { - setState(() { - state = _State.error; - Utils.handleDioError(context, e); - }); - } - break; } - } else { - throw e; + }); + }).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 (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 +286,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; +// } }); } } 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..819db1be 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; @@ -30,7 +31,7 @@ class HomePageState extends State { int _currentNewsIndex = 0; - List newsList = []; + AnnouncementsData announcementsResponse; @override void initState() { @@ -104,7 +105,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 +117,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 +169,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 +185,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 +201,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}'), ], ), ), @@ -219,13 +221,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()); @@ -242,13 +243,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) { @@ -306,8 +309,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/login_page.dart b/lib/pages/login_page.dart index 249b40f6..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; @@ -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( 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/app_localizations.dart b/lib/utils/app_localizations.dart index 52f549e2..4ef4bb40 100644 --- a/lib/utils/app_localizations.dart +++ b/lib/utils/app_localizations.dart @@ -361,6 +361,14 @@ 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', + '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': '高科校務通', @@ -644,6 +652,12 @@ class AppLocalizations { 'firstLoginHint': '首次登入密碼預設為身分證末四碼', 'searchStudentIdFormat': '姓名:%s\n學號:%s\n', 'searchStudentIdError': '查無資料', + 'midtermAlerts': '期中預警', + 'midtermAlertsEmpty': '太好了!本學期沒有任何科目被預警哦~\n請選擇其他學期 \uD83D\uDE0B', + 'midtermAlertsContent': '原因:%s\n備註:%s', + 'rewardAndPenalty': '獎懲紀錄', + 'rewardAndPenaltyEmpty': 'Oops!本學期沒有任何獎懲紀錄哦~\n請選擇其他學期 \uD83D\uDE0B', + 'rewardAndPenaltyContent': '數量:%s\n日期:%s', }, }; @@ -1143,6 +1157,19 @@ 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']; + + String get rewardAndPenalty => _vocabularies['rewardAndPenalty']; + + String get rewardAndPenaltyEmpty => _vocabularies['rewardAndPenaltyEmpty']; + + String get rewardAndPenaltyContent => + _vocabularies['rewardAndPenaltyContent']; } class AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/lib/utils/cache_utils.dart b/lib/utils/cache_utils.dart index 8e99d61e..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'; @@ -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( 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, }, ); 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..410ffea6 100644 --- a/lib/widgets/drawer_body.dart +++ b/lib/widgets/drawer_body.dart @@ -1,12 +1,11 @@ -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/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'; @@ -59,17 +58,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 +99,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( @@ -164,6 +157,16 @@ class DrawerBodyState extends State { title: app.calculateUnits, page: CalculateUnitsPage(), ), + _subItem( + icon: Icons.warning, + title: app.midtermAlerts, + page: MidtermAlertsPage(), + ), + _subItem( + icon: Icons.folder, + title: app.rewardAndPenalty, + page: RewardAndPenaltyPage(), + ), ], ), ExpansionTile( @@ -274,59 +277,48 @@ 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); }, ); - _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 { + if (widget.userInfo.pictureUrl == null) return; + 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 { diff --git a/lib/widgets/semester_picker.dart b/lib/widgets/semester_picker.dart index 97802247..0d7704c7 100644 --- a/lib/widgets/semester_picker.dart +++ b/lib/widgets/semester_picker.dart @@ -109,8 +109,8 @@ class SemesterPickerState extends State { void pickSemester() { int index = 0; - for (var i = 0; i < semesterData.semesters.length; i++) { - if (semesterData.semesters[i].text == selectSemester.text) index = i; + for (var i = 0; i < semesterData.data.length; i++) { + if (semesterData.data[i].text == selectSemester.text) index = i; } showDialog( context: context, @@ -128,11 +128,10 @@ class SemesterPickerState extends State { child: ListView( controller: ScrollController(initialScrollOffset: index * 48.0), 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); }), @@ -146,9 +145,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]; }); } }); 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"