diff --git a/app/build.gradle b/app/build.gradle index d17e983..e86b81b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "ch.lburgy.heiafrschedule" minSdkVersion 18 targetSdkVersion 29 - versionCode 2 - versionName "1.0.1" + versionCode 3 + versionName "1.0.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -29,7 +29,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation group: 'org.apache.httpcomponents', name: 'httpclient-android', version: '4.3.5.1' - implementation 'com.google.android.material:material:1.2.0' + implementation 'com.google.android.material:material:1.2.1' implementation 'com.squareup.okhttp3:okhttp:4.6.0' implementation 'com.squareup.moshi:moshi:1.9.3' implementation 'com.squareup.okio:okio:2.8.0' diff --git a/app/src/main/java/ch/lburgy/heiafrschedule/activities/MainActivity.java b/app/src/main/java/ch/lburgy/heiafrschedule/activities/MainActivity.java index 74323f4..cd8da88 100644 --- a/app/src/main/java/ch/lburgy/heiafrschedule/activities/MainActivity.java +++ b/app/src/main/java/ch/lburgy/heiafrschedule/activities/MainActivity.java @@ -138,7 +138,7 @@ public void run() { }).start(); if (savedInstanceState == null) { - getLessonsAndShowThem(false); + getLessonsAndShowThem(false, true); } else { lessonsCompletesByDay = (HashMap>) savedInstanceState.getSerializable(KEY_SAVED_LESSONS); @@ -146,10 +146,10 @@ public void run() { threadType = (ThreadType) savedInstanceState.getSerializable(KEY_SAVED_THREAD_TYPE); switch (threadType) { case getLessons: - getLessonsAndShowThem(false); + getLessonsAndShowThem(false, false); break; case getLessonsFromInternet: - getLessonsAndShowThem(true); + getLessonsAndShowThem(true, false); break; } } else { @@ -158,17 +158,57 @@ public void run() { } } - private void getLessonsAndShowThem(final boolean forceFromInternet) { + private boolean isNewer(boolean showToast) throws HttpBasicClient.HttpException, InterruptedIOException, HttpBasicClient.NoInternetConnectionException, UnknownHostException { + if (!httpBasicClient.isConnectedToInternet()) return false; + Date[] dates = httpBasicClient.getScheduleDates(); + + if (dates != null && dates.length == 2 && dates[0] != null && dates[1] != null) { + Date[] scheduleDates = prefManager.getScheduleDates(); + if (scheduleDates[1] == null || scheduleDates[1].compareTo(dates[0]) < 0) { + // Delete data + lessonDao.deleteLessons(); + roomHEIAFRDao.deleteRooms(); + teacherDao.deleteTeachers(); + prefManager.setLastUpdateRoomsLessons(null); + // Set the new schedule dates + prefManager.setScheduleDates(dates); + if (showToast) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(MainActivity.this, R.string.new_schedules, Toast.LENGTH_LONG).show(); + } + }); + } + return true; + } + } + return false; + } + + private void getLessonsAndShowThem(final boolean forceFromInternet, final boolean firstLaunch) { if (MainActivity.this.isDestroyed()) return; String progressTitle = getResources().getString(R.string.progress_refresh_lessons_title); progressDialog = ProgressDialog.show(this, progressTitle, null, true); threadType = ThreadType.getLessons; + if (currentThread != null && currentThread.isAlive()) + currentThread.interrupt(); currentThread = new Thread(new Runnable() { @Override public void run() { try { + boolean thisForceFromInternet = forceFromInternet; int httpCode = CODE_NO_PROBLEMS; - if (!forceFromInternet) { + try { + if (firstLaunch && isNewer(true)) + thisForceFromInternet = true; + } catch (HttpBasicClient.HttpException e) { + httpCode = e.getCode(); + } catch (UnknownHostException | HttpBasicClient.NoInternetConnectionException e) { + httpCode = CODE_NO_CONNECTION; + } + + if (!thisForceFromInternet) { lessonsCompletesByDay = new HashMap<>(); for (int i = 0; i < NB_DAYS; i++) lessonsCompletesByDay.put(i, new ArrayList()); @@ -284,6 +324,8 @@ private void refreshLessons() { String progressTitle = getResources().getString(R.string.progress_refresh_lessons_title); progressDialog = ProgressDialog.show(this, progressTitle, null, true); threadType = ThreadType.getLessonsFromInternet; + if (currentThread != null && currentThread.isAlive()) + currentThread.interrupt(); currentThread = new Thread(new Runnable() { @Override public void run() { @@ -327,6 +369,8 @@ private void getLessonsFromInternet(boolean deleteExisting) throws HttpBasicClie if (deleteExisting) { lessonClassJoinDao.deleteLessonsFromClass(classHEIAFR.getName()); lessonClassJoinDao.deleteLessonsNoClass(); + } else { + isNewer(false); } if (roomHEIAFRDao.getNbRoom() == 0) { @@ -351,7 +395,7 @@ private void getLessonsFromInternet(boolean deleteExisting) throws HttpBasicClie try { lessonClassJoinDao.insertLessonClassJoin(new LessonClassJoin(lesson.getId(), classHEIAFR.getName())); } catch (SQLiteConstraintException e) { - // do nothing, the association is allready in the DB + // do nothing, the association is already in the DB } ArrayList rooms = new ArrayList<>(); @@ -365,7 +409,7 @@ private void getLessonsFromInternet(boolean deleteExisting) throws HttpBasicClie try { lessonRoomJoinDao.insertLessonRoomJoin(new LessonRoomJoin(lesson.getId(), roomID)); } catch (SQLiteConstraintException e) { - // do nothing, the association is allready in the DB + // do nothing, the association is already in the DB } } @@ -390,6 +434,7 @@ private void getLessonsFromInternet(boolean deleteExisting) throws HttpBasicClie } classHEIAFR.setLastUpdate(new Date()); classHEIAFRDao.updateClassHEIAFR(classHEIAFR); + prefManager.setScheduleDates(httpBasicClient.getScheduleDates()); } private void showHttpErrorCode(int httpCode) { @@ -460,7 +505,7 @@ public void run() { }); } }).start(); - getLessonsAndShowThem(false); + getLessonsAndShowThem(false, false); } } if (prefManager.isLaunchWelcome()) { diff --git a/app/src/main/java/ch/lburgy/heiafrschedule/activities/SettingsActivity.java b/app/src/main/java/ch/lburgy/heiafrschedule/activities/SettingsActivity.java index 087d4f8..38dbdc7 100644 --- a/app/src/main/java/ch/lburgy/heiafrschedule/activities/SettingsActivity.java +++ b/app/src/main/java/ch/lburgy/heiafrschedule/activities/SettingsActivity.java @@ -19,7 +19,10 @@ import java.io.InterruptedIOException; import java.net.UnknownHostException; +import java.text.DateFormat; +import java.util.Date; import java.util.List; +import java.util.Locale; import ch.lburgy.heiafrschedule.R; import ch.lburgy.heiafrschedule.database.ClassHEIAFR; @@ -162,11 +165,18 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { findPreference(keyTheme9).setVisible(true); } - Preference btnDeleteDatas = findPreference(getString(R.string.settings_key_delete_datas)); - btnDeleteDatas.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + Date[] dates = prefManager.getScheduleDates(); + if (dates != null && dates.length == 2 && dates[0] != null && dates[1] != null) { + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()); + Preference preference = findPreference(getString(R.string.settings_key_data_schedule_dates)); + preference.setTitle(getResources().getString(R.string.data_schedule_dates, df.format(dates[0]), df.format(dates[1]))); + preference.setVisible(true); + } + + findPreference(getString(R.string.settings_key_delete_data)).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - deleteDatas(); + deleteData(); return true; } }); @@ -243,7 +253,7 @@ public void run() { }).start(); } - private void deleteDatas() { + private void deleteData() { new Thread(new Runnable() { @Override public void run() { @@ -251,10 +261,12 @@ public void run() { roomHEIAFRDao.deleteRooms(); teacherDao.deleteTeachers(); prefManager.setLastUpdateRoomsLessons(null); + prefManager.setScheduleDates(new Date[2]); classChanged = true; getActivity().runOnUiThread(new Runnable() { public void run() { - String message = getResources().getString(R.string.datas_deleted); + findPreference(getString(R.string.settings_key_data_schedule_dates)).setVisible(false); + String message = getResources().getString(R.string.data_deleted); Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show(); } }); diff --git a/app/src/main/java/ch/lburgy/heiafrschedule/http/HttpBasicClient.java b/app/src/main/java/ch/lburgy/heiafrschedule/http/HttpBasicClient.java index e61105c..4942fea 100644 --- a/app/src/main/java/ch/lburgy/heiafrschedule/http/HttpBasicClient.java +++ b/app/src/main/java/ch/lburgy/heiafrschedule/http/HttpBasicClient.java @@ -25,8 +25,12 @@ import java.io.IOException; import java.io.InterruptedIOException; import java.net.UnknownHostException; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -85,11 +89,46 @@ private void initCredentials(String username, String password) { } } + public Date[] getScheduleDates() throws HttpException, UnknownHostException, NoInternetConnectionException, InterruptedIOException { + Document doc = getDoc(URL_CLASSES, true); + if (doc == null) return null; + + Date[] dates = new Date[2]; + Element table = doc.getElementsByTag("table").get(4); + Element script = table.getElementsByTag("script").get(0); + String scriptContent = script.childNode(0).toString(); + + // Get the HTML from within the script tag + Pattern pattern = Pattern.compile("<.*>"); + Matcher matcher = pattern.matcher(scriptContent); + matcher.find(); + String datesString = Jsoup.parse(matcher.group(0)).text(); + + // Get the dates + pattern = Pattern.compile(".*?du (.*?) au (.*)"); + matcher = pattern.matcher(datesString); + matcher.find(); + String firstDate = matcher.group(1); + String secondDate = matcher.group(2); + + // Parse them + SimpleDateFormat parser = new SimpleDateFormat("dd MMM yyyy", Locale.FRENCH); + try { + dates[0] = parser.parse(firstDate); + dates[1] = parser.parse(secondDate); + } catch (ParseException e) { + e.printStackTrace(); + return null; + } + + return dates; + } + public List getClasses() throws HttpException, UnknownHostException, NoInternetConnectionException, InterruptedIOException { - ArrayList classes = new ArrayList<>(); Document doc = getDoc(URL_CLASSES, true); if (doc == null) return null; + ArrayList classes = new ArrayList<>(); Element select = doc.getElementsByTag("select").first(); Elements options = select.getElementsByTag("option"); for (Element option : options) { diff --git a/app/src/main/java/ch/lburgy/heiafrschedule/preferences/PrefManager.java b/app/src/main/java/ch/lburgy/heiafrschedule/preferences/PrefManager.java index 0334378..098e471 100644 --- a/app/src/main/java/ch/lburgy/heiafrschedule/preferences/PrefManager.java +++ b/app/src/main/java/ch/lburgy/heiafrschedule/preferences/PrefManager.java @@ -23,6 +23,8 @@ public class PrefManager { private static final String KEY_CLASS_ID = "class_id"; private static final String KEY_THEME = "theme"; private static final String KEY_LAST_UPDATE_ROOMS_LESSONS = "last_update_rooms_lessons"; + private static final String KEY_SCHEDULE_DATE_1 = "schedule_date_1"; + private static final String KEY_SCHEDULE_DATE_2 = "schedule_date_2"; private static final String KEY_IV = "-iv"; private static final String KEY_ENCRYPTED = "encrypted_key"; @@ -112,6 +114,21 @@ public Date getLastUpdateRoomsLessons() { return DateConverter.toDate(pref.getLong(KEY_LAST_UPDATE_ROOMS_LESSONS, -1)); } + public void setScheduleDates(Date[] scheduleDates) { + if (scheduleDates != null && scheduleDates.length == 2) { + editor.putLong(KEY_SCHEDULE_DATE_1, DateConverter.fromDate(scheduleDates[0])); + editor.putLong(KEY_SCHEDULE_DATE_2, DateConverter.fromDate(scheduleDates[1])); + editor.commit(); + } + } + + public Date[] getScheduleDates() { + Date[] scheduleDates = new Date[2]; + scheduleDates[0] = DateConverter.toDate(pref.getLong(KEY_SCHEDULE_DATE_1, -1)); + scheduleDates[1] = DateConverter.toDate(pref.getLong(KEY_SCHEDULE_DATE_2, -1)); + return scheduleDates; + } + public void setTheme(int theme) { editor.putInt(KEY_THEME, theme); editor.commit(); diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 700a9f6..e8ff75f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -21,7 +21,7 @@ Die Liste der Klassen wurde aktualisiert Informationen Display - Daten + Daten Design Wählen Sie Ihre Klasse Design auswählen @@ -32,8 +32,8 @@ Einen Raum finden Die Endzeit muss später als die Startzeit liegen Räume für Sie suchen … - Lokale Daten löschen - Lokale Daten wurden gelöscht + Lokale Daten löschen + Lokale Daten wurden gelöscht Da dies das erste Mal ist, dass Sie einen Raum finden wollen, muss die Anwendung alle Unterrichte aller Räume aus dem Internet abrufen, was bis zu 2 oder 3 Minuten dauern kann. Das Update herunterladen … Möchten Sie die Anwendung aktualisieren ? @@ -46,4 +46,6 @@ Über Lizenzen Siehe das Projekt auf GitHub + Zeitplan vom %1$s bis %2$s + Neue Zeitpläne sind verfügbar ! \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index b7832a5..86f89cb 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -22,7 +22,7 @@ Paramètres Affichage Informations - Données + Données Thème Choisissez votre classe Classe @@ -32,8 +32,8 @@ Trouver une salle L\'heure de fin doit être postérieure à l\'heure de début Recherche de salles pour vous … - Supprimer les données locales - Les données locales ont été supprimées + Supprimer les données locales + Les données locales ont été supprimées Etant donné que c\'est la première fois que vous voulez trouver une salle, l\'application doit obtenir tous les cours de toutes les salles à partir d\'Internet, ce qui peut prendre jusqu\'à 2 ou 3 minutes. Voulez-vous mettre à jour l\'application ? Téléchargement de la mise à jour … @@ -46,4 +46,6 @@ par Square Open Source, sous license Apache 2.0 par Jonathan Hedley, sous license MIT par The Apache Software Foundation, sous license Apache 2.0 + Horaires du %1$s au %2$s + De nouveaux horaires sont disponibles ! \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 89d9030..b0d7d4f 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -18,7 +18,7 @@ Impostazioni Errore HTTP Informazioni - Dati + Dati Tema Scelga la vostra classe Scelga tema @@ -32,8 +32,8 @@ Trovare una stanza L\'ora della fine deve essere successiva all\'ora del inizio Ricerca stanze per lei … - Cancellare i dati locali - I dati locali sono stati cancellati + Cancellare i dati locali + I dati locali sono stati cancellati Poiché è la prima volta che si desidera trovare una stanza, l\'applicazione deve recuperare tutte le lezioni di tutte le stanze da Internet, che può richiedere fino a 2 o 3 minuti. Vuole aggiornare l\'applicazione ? Il download del aggiornamento … @@ -46,4 +46,6 @@ About Licenze Vedi il progetto su GitHub + Orari dal %1$s al %2$s + Sono disponibili nuovi orari ! \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 089879e..8a08795 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ Retrieving lessons … + New schedules are available ! Monday @@ -43,7 +44,7 @@ Settings Display Informations - Datas + Data About Licenses @@ -51,7 +52,8 @@ theme_9 theme_10 class - delete_datas + delete_data + data_schedule_date github license_httpcomponents license_jsoup @@ -68,10 +70,11 @@ Class Choose your class - - Delete the local datas - The local datas have been deleted + + Delete the local data + The local data have been deleted The class list has been refreshed + Schedule from %1$s to %2$s See the project on GitHub diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 7648355..04b54d2 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -43,13 +43,18 @@ + app:title="@string/data_header"> + app:key="@string/settings_key_delete_data" + app:title="@string/delete_data" /> + +