Skip to content
This repository has been archived by the owner on Feb 5, 2024. It is now read-only.

Fix offline bugs #4

Merged
merged 5 commits into from
Apr 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/data/database/database_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class DatabaseHelper {

Future<void> insertSchoolDay(SchoolDay schoolDay, DateTime date) async {
final db = await database;
await deleteSchoolDay(date);
for (final lesson in schoolDay.lessons) {
lesson.date = date;
await db.insert(
Expand All @@ -51,6 +52,15 @@ class DatabaseHelper {
}
}

Future<void> deleteSchoolDay(DateTime date) async {
final db = await database;
await db.delete(
'Lesson',
where: 'date = ?',
whereArgs: [DateHelper.convertDateTimeToSQLFormat(date)],
);
}

Future<SchoolDay> getSchoolDay(DateTime date) async {
final db = await database;
final List<Map<String, dynamic>> maps = await db.query('Lesson',
Expand Down
99 changes: 99 additions & 0 deletions lib/data/manager/data_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import 'package:uphf_edt/data/database/database_helper.dart';
import 'package:uphf_edt/data/models/school_day.dart';
import 'package:uphf_edt/data/web/session.dart';
import 'package:http/http.dart' as http;

class DataManager {
DataManager._internal();
static final DataManager instance = DataManager._internal();

final http.Client _client = http.Client();
late String _username;
late String _password;
DateTime currentDate = DateTime.now();

Future<SchoolDay> getSchoolDay(
String username,
String password,
) async {
_username = username;
_password = password;

late SchoolDay schoolDay;

try {
schoolDay = await Session.instance.get(_client, _username, _password);
await DatabaseHelper.instance.insertSchoolDay(schoolDay, currentDate);
} catch (e) {
try {
schoolDay = await DatabaseHelper.instance.getSchoolDay(currentDate);
} catch (e) {
throw Exception('Impossible de récupérer les données');
}
}

return schoolDay;
}

Future<SchoolDay> getNextSchoolDay() async {
currentDate = currentDate.add(const Duration(days: 1));

late SchoolDay schoolDay;

try {
schoolDay = await Session.instance.getSpecificDay(currentDate);
await DatabaseHelper.instance.insertSchoolDay(schoolDay, currentDate);
} catch (e) {
schoolDay = await reloadConnectionAtCurrentDate();
}

return schoolDay;
}

Future<SchoolDay> getPreviousSchoolDay() async {
currentDate = currentDate.subtract(const Duration(days: 1));

late SchoolDay schoolDay;

try {
schoolDay = await Session.instance.getSpecificDay(currentDate);
await DatabaseHelper.instance.insertSchoolDay(schoolDay, currentDate);
} catch (e) {
schoolDay = await reloadConnectionAtCurrentDate();
}

return schoolDay;
}

Future<SchoolDay> getSpecificDay(DateTime date) async {
currentDate = date;

late SchoolDay schoolDay;

try {
schoolDay = await Session.instance.getSpecificDay(date);
await DatabaseHelper.instance.insertSchoolDay(schoolDay, currentDate);
} catch (e) {
schoolDay = await reloadConnectionAtCurrentDate();
}

return schoolDay;
}

Future<SchoolDay> reloadConnectionAtCurrentDate() async {
late SchoolDay schoolDay;

try {
await Session.instance.get(_client, _username, _password);
schoolDay = await Session.instance.getSpecificDay(currentDate);
} catch (e) {
try {
schoolDay = await DatabaseHelper.instance.getSchoolDay(currentDate);
} catch (e) {
throw Exception('Impossible de récupérer les données');
}
}

return schoolDay;
}
}
80 changes: 0 additions & 80 deletions lib/data/web/session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -211,86 +211,6 @@ class Session {
return Scrap.scrapSchoolDayFromHTML(res.body);
}

Future<SchoolDay> getNextPage() async {
var headers = {
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0',
'Upgrade-Insecure-Requests': '1',
'Origin': 'https://vtmob.uphf.fr',
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': userAgent,
'Accept':
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Sec-GPC': '1',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-User': '?1',
'Sec-Fetch-Dest': 'document',
'Referer':
'https://vtmob.uphf.fr/esup-vtclient-up4/stylesheets/mobile/welcome.xhtml',
'Accept-Language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7',
'Cookie': 'JSESSIONID=$jSessionId; AGIMUS=$agimus',
'Accept-Encoding': 'gzip',
};

var data =
'org.apache.myfaces.trinidad.faces.FORM=redirectForm&_noJavaScript=false&javax.faces.ViewState=$viewState&source=redirectForm:semSuiv';

final res = await http.post(
Uri.parse(
'https://vtmob.uphf.fr/esup-vtclient-up4/stylesheets/mobile/welcome.xhtml'),
headers: headers,
body: data);

if (res.statusCode != 200) {
throw Exception('Erreur durant la récupération de la prochaine page');
}

updateViewStateFromHTMLPage(res.body);

return Scrap.scrapSchoolDayFromHTML(res.body);
}

Future<SchoolDay> getPreviousPage() async {
var headers = {
'Connection': 'keep-alive',
'Cache-Control': 'max-age=0',
'Upgrade-Insecure-Requests': '1',
'Origin': 'https://vtmob.uphf.fr',
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': userAgent,
'Accept':
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Sec-GPC': '1',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-User': '?1',
'Sec-Fetch-Dest': 'document',
'Referer':
'https://vtmob.uphf.fr/esup-vtclient-up4/stylesheets/mobile/welcome.xhtml',
'Accept-Language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7',
'Cookie': 'JSESSIONID=$jSessionId; AGIMUS=$agimus',
'Accept-Encoding': 'gzip',
};

var data =
'org.apache.myfaces.trinidad.faces.FORM=redirectForm&_noJavaScript=false&javax.faces.ViewState=$viewState&source=redirectForm:semPrec';

final res = await http.post(
Uri.parse(
'https://vtmob.uphf.fr/esup-vtclient-up4/stylesheets/mobile/welcome.xhtml'),
headers: headers,
body: data);

if (res.statusCode != 200) {
throw Exception('Erreur durant la récupération de la page precédente');
}

updateViewStateFromHTMLPage(res.body);

return Scrap.scrapSchoolDayFromHTML(res.body);
}

Future<SchoolDay> getSpecificDay(DateTime date) async {
var headers = {
'Connection': 'keep-alive',
Expand Down
4 changes: 4 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class MyHttpOverrides extends HttpOverrides {

void main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
HttpOverrides.global = MyHttpOverrides();
LicenseRegistry.addLicense(() async* {
final license = await rootBundle.loadString('google_fonts/OFL.txt');
Expand Down
76 changes: 25 additions & 51 deletions lib/screen/homescreen.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sqlite_viewer/sqlite_viewer.dart';
import 'package:uphf_edt/data/database/database_helper.dart';
import 'package:uphf_edt/data/manager/data_manager.dart';
import 'package:uphf_edt/data/models/school_day.dart';
import 'package:uphf_edt/data/utils/date_helper.dart';
import 'package:uphf_edt/data/web/session.dart';
import 'package:uphf_edt/screen/loginscreen.dart';
import 'package:uphf_edt/screen/widgets/bottom_bar.dart';
import 'package:uphf_edt/screen/widgets/floating_button.dart';
import 'package:http/http.dart' as http;
import 'package:uphf_edt/screen/widgets/lesson_tile.dart';

class HomeScreen extends StatefulWidget {
Expand All @@ -25,12 +25,11 @@ class HomeScreen extends StatefulWidget {

class _HomeScreenState extends State<HomeScreen> {
late Future<SchoolDay> schoolDay;
DateTime currentDate = DateTime.now();

@override
void initState() {
http.Client client = http.Client();
schoolDay = Session.instance.get(client, widget.username, widget.password);
schoolDay =
DataManager.instance.getSchoolDay(widget.username, widget.password);
super.initState();
}

Expand All @@ -52,22 +51,22 @@ class _HomeScreenState extends State<HomeScreen> {

AppBar buildAppBar() {
return AppBar(
title:
Text(DateHelper.convertDateTimeToLitteral(currentDate).toUpperCase()),
title: Text(
DateHelper.convertDateTimeToLitteral(DataManager.instance.currentDate)
.toUpperCase()),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.calendar_today),
onPressed: () => setState(() {
currentDate = DateTime.now();
schoolDay = Session.instance.getSpecificDay(DateTime.now());
schoolDay = DataManager.instance.getSpecificDay(DateTime.now());
}),
),
actions: [
IconButton(
onPressed: () async {
DateTime? selectedDate = await showDatePicker(
context: context,
initialDate: currentDate,
initialDate: DataManager.instance.currentDate,
firstDate: DateTime.now().subtract(const Duration(days: 365)),
lastDate: DateTime.now().add(
const Duration(days: 365),
Expand All @@ -76,8 +75,7 @@ class _HomeScreenState extends State<HomeScreen> {

if (selectedDate != null) {
setState(() {
schoolDay = Session.instance.getSpecificDay(selectedDate);
currentDate = selectedDate;
schoolDay = DataManager.instance.getSpecificDay(selectedDate);
});
}
},
Expand All @@ -103,69 +101,45 @@ class _HomeScreenState extends State<HomeScreen> {
future: schoolDay,
builder: (context, snapshot) {
if (snapshot.hasError) {
return buildOfflineSchoolDay();
return Center(
child: Text('Error: ${snapshot.error}'),
);
}
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const LinearProgressIndicator();
case ConnectionState.done:
return buildOnlineSchoolDay(snapshot);
return ListView.builder(
itemCount: snapshot.data!.lessons.length,
itemBuilder: (context, index) {
return LessonTile(snapshot.data!.lessons[index]);
},
);
default:
return Center(
child: Text('Error: ${snapshot.error}'),
child: Text('Erreur: ${snapshot.error}'),
);
}
},
);
}

ListView buildOnlineSchoolDay(AsyncSnapshot<SchoolDay> snapshot) {
DatabaseHelper.instance.insertSchoolDay(snapshot.data!, currentDate);
return buildSchoolDay(snapshot.data!);
}

FutureBuilder<SchoolDay> buildOfflineSchoolDay() {
return FutureBuilder<SchoolDay>(
future: DatabaseHelper.instance.getSchoolDay(currentDate),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
snapshot.error!.toString(),
),
);
} else if (snapshot.hasData) {
return buildSchoolDay(snapshot.data!);
}
return const LinearProgressIndicator();
},
);
}

ListView buildSchoolDay(SchoolDay data) {
return ListView.builder(
itemCount: data.lessons.length,
itemBuilder: (context, index) {
return LessonTile(data.lessons[index]);
},
);
}

void onNextDay() {
HapticFeedback.vibrate();
setState(() {
schoolDay = Session.instance.getNextPage();
currentDate = currentDate.add(const Duration(days: 1));
schoolDay = DataManager.instance.getNextSchoolDay();
});
}

void onPreviousDay() {
HapticFeedback.vibrate();
setState(() {
schoolDay = Session.instance.getPreviousPage();
currentDate = currentDate.subtract(const Duration(days: 1));
schoolDay = DataManager.instance.getPreviousSchoolDay();
});
}

void onDisconnect() async {
DatabaseHelper.instance.delete();
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove('username');
await prefs.remove('password');
Expand Down