From be8ee4c83501361955ae39d5bce7a381d917ff43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Fri, 11 May 2018 21:55:38 +0200 Subject: [PATCH 01/41] Fix parsing grade description with symbol containing special chars (#104) --- .circleci/config.yml | 2 ++ .../java/io/github/wulkanowy/api/grades/GradesList.java | 2 +- .../io/github/wulkanowy/api/grades/GradesListTest.java | 4 +++- .../wulkanowy/api/grades/OcenyWszystkie-filled.html | 8 ++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f55c7ec8..6f91f6b3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -227,5 +227,7 @@ workflows: requires: - instrumented filters: + branches: + only: master tags: only: /.*/ diff --git a/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java b/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java index 81e8f3ae..936c1533 100644 --- a/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java +++ b/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java @@ -56,7 +56,7 @@ public class GradesList { String descriptions = row.select("td:nth-child(3)").text(); String symbol = descriptions.split(", ")[0]; - String description = descriptions.replaceFirst(symbol, "").replaceFirst(", ", ""); + String description = descriptions.replaceFirst(Pattern.quote(symbol), "").replaceFirst(", ", ""); String color = getColor(row.select("td:nth-child(2) span.ocenaCzastkowa").attr("style")); String date = formatDate(row.select("td:nth-child(5)").text()); diff --git a/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java b/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java index c52fbb30..6eff84c9 100644 --- a/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java @@ -19,7 +19,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getAllTest() throws Exception { - Assert.assertEquals(6, filled.getAll().size()); // 2 items are skipped + Assert.assertEquals(7, filled.getAll().size()); // 2 items are skipped } @Test @@ -60,6 +60,7 @@ public class GradesListTest extends StudentAndParentTestCase { Assert.assertEquals("BW3", list.get(3).getSymbol()); Assert.assertEquals("STR", list.get(4).getSymbol()); Assert.assertEquals("K", list.get(5).getSymbol()); + Assert.assertEquals("+Odp", list.get(6).getSymbol()); } @Test @@ -70,6 +71,7 @@ public class GradesListTest extends StudentAndParentTestCase { Assert.assertEquals("Writing", list.get(3).getDescription()); Assert.assertEquals("", list.get(4).getDescription()); Assert.assertEquals("Kordian", list.get(5).getDescription()); + Assert.assertEquals("Kordian", list.get(6).getDescription()); } @Test diff --git a/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-filled.html b/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-filled.html index a229d1d5..d0cdb664 100644 --- a/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-filled.html +++ b/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-filled.html @@ -100,6 +100,14 @@ 06.02.2017 Amelia Stępień + + Język polski + 5 + +Odp, Kordian + 5,00 + 11.05.2017 + Amelia Stępień + From 23183c9d7addc1750a268f5754fc3237514ebd8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sun, 13 May 2018 15:25:56 +0200 Subject: [PATCH 02/41] Call of SyncJob only after user register in app (#105) --- .../main/java/io/github/wulkanowy/ui/main/MainActivity.java | 6 ++++++ .../main/java/io/github/wulkanowy/ui/main/MainContract.java | 2 ++ .../java/io/github/wulkanowy/ui/main/MainPresenter.java | 5 +++++ .../java/io/github/wulkanowy/ui/splash/SplashActivity.java | 6 ------ .../java/io/github/wulkanowy/ui/splash/SplashContract.java | 2 -- .../java/io/github/wulkanowy/ui/splash/SplashPresenter.java | 5 ----- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java index 11acc562..6b7d07cf 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java @@ -17,6 +17,7 @@ import javax.inject.Inject; import butterknife.BindView; import butterknife.ButterKnife; import io.github.wulkanowy.R; +import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.base.BasePagerAdapter; import io.github.wulkanowy.ui.main.attendance.AttendanceFragment; @@ -140,6 +141,11 @@ public class MainActivity extends BaseActivity implements MainContract.View, viewPager.setCurrentItem(tabPosition, false); } + @Override + public void startSyncService(int interval, boolean useOnlyWifi) { + SyncJob.start(getApplicationContext(), interval, useOnlyWifi); + } + @Override protected void onDestroy() { super.onDestroy(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java index d4d8156b..cc326654 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java @@ -18,6 +18,8 @@ public interface MainContract { void initiationViewPager(int tabPosition); void initiationBottomNav(int tabPosition); + + void startSyncService(int interval, boolean useOnlyWifi); } @PerActivity diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java index 3cbbfd86..ba5e41d8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java @@ -32,6 +32,11 @@ public class MainPresenter extends BasePresenter getView().initiationBottomNav(tabPosition); getView().initiationViewPager(tabPosition); + + if (getRepository().getSharedRepo().isServicesEnable()) { + getView().startSyncService(getRepository().getSharedRepo().getServicesInterval(), + getRepository().getSharedRepo().isMobileDisable()); + } } @Override diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java index 4acb5583..53994a16 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java @@ -5,7 +5,6 @@ import android.os.Bundle; import javax.inject.Inject; import butterknife.ButterKnife; -import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.services.notifies.NotificationService; import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.login.LoginActivity; @@ -44,11 +43,6 @@ public class SplashActivity extends BaseActivity implements SplashContract.View finish(); } - @Override - public void startSyncService(int interval, boolean useOnlyWifi) { - SyncJob.start(getApplicationContext(), interval, useOnlyWifi); - } - @Override public void cancelNotifications() { new NotificationService(getApplicationContext()).cancelAll(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java index 6d25853e..58d4447c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java @@ -12,8 +12,6 @@ public interface SplashContract { void openMainActivity(); - void startSyncService(int interval, boolean useOnlyWifi); - void cancelNotifications(); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java index 852d4ebe..8d20226f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java @@ -20,11 +20,6 @@ public class SplashPresenter extends BasePresenter super.onStart(activity); getView().cancelNotifications(); - if (getRepository().getSharedRepo().isServicesEnable()) { - getView().startSyncService(getRepository().getSharedRepo().getServicesInterval(), - getRepository().getSharedRepo().isMobileDisable()); - } - if (getRepository().getSharedRepo().isUserLoggedIn()) { getView().openMainActivity(); } else { From 2cf262130efb4f55d26550b7d61a4a7d9f3868d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 13 May 2018 16:02:51 +0200 Subject: [PATCH 03/41] [API] Get rid of NULL in timetable lesson descriptions (#106) --- .circleci/config.yml | 4 +- .../wulkanowy/api/timetable/Timetable.java | 20 +++++--- .../api/timetable/TimetableTest.java | 1 + .../api/timetable/PlanLekcji-full.html | 46 ++++++++++++++++++- 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6f91f6b3..822ae06c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -228,6 +228,6 @@ workflows: - instrumented filters: branches: - only: master + ignore: /.*/ tags: - only: /.*/ + only: /^\d+\.\d+\.\d+$/ diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index b5c7efc2..4e9cc18e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -94,14 +94,18 @@ public class Timetable { moveWarningToLessonNode(e); switch (e.size()) { + case 1: + addLessonInfoFromElement(lesson, e.first()); + break; case 2: Element span = e.last().select("span").first(); if (span.hasClass(LessonTypes.CLASS_MOVED_OR_CANCELED)) { lesson.setNewMovedInOrChanged(true); lesson.setDescription("poprzednio: " + getLessonAndGroupInfoFromSpan(span)[0]); + addLessonInfoFromElement(lesson, e.first()); + } else { + addLessonInfoFromElement(lesson, e.last()); } - case 1: - addLessonInfoFromElement(lesson, e.first()); break; case 3: addLessonInfoFromElement(lesson, e.get(1)); @@ -167,7 +171,8 @@ public class Timetable { lesson.setRoom(spans.get(5).text()); lesson.setMovedOrCanceled(false); lesson.setNewMovedInOrChanged(true); - lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")") + lesson.setDescription(StringUtils.defaultString(StringUtils.substringBetween( + spans.last().text(), "(", ")"), spans.last().text()) + " (poprzednio: " + spans.get(0).text() + ")"); } else if (9 == spans.size()) { String[] subjectAndGroupInfo = getLessonAndGroupInfoFromSpan(spans.get(4)); @@ -178,13 +183,15 @@ public class Timetable { lesson.setMovedOrCanceled(false); lesson.setNewMovedInOrChanged(true); lesson.setDivisionIntoGroups(true); - lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")") + lesson.setDescription(StringUtils.defaultString(StringUtils.substringBetween( + spans.last().text(), "(", ")"), spans.last().text()) + " (poprzednio: " + getLessonAndGroupInfoFromSpan(spans.get(0))[0] + ")"); } else if (4 <= spans.size()) { lesson.setSubject(spans.get(0).text()); lesson.setTeacher(spans.get(1).text()); lesson.setRoom(spans.get(2).text()); - lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")")); + lesson.setDescription(StringUtils.defaultString(StringUtils.substringBetween( + spans.last().text(), "(", ")"), spans.last().text())); } } @@ -212,7 +219,8 @@ public class Timetable { return new String[]{ span.text().replace(" " + groupName, ""), - StringUtils.substringBetween(groupName, "[", "]") + StringUtils.defaultString(StringUtils.substringBetween( + groupName, "[", "]"), groupName) }; } } diff --git a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java index d7df9411..818745f7 100644 --- a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java @@ -151,6 +151,7 @@ public class TimetableTest extends StudentAndParentTestCase { Assert.assertEquals("zastępstwo (poprzednio: Wychowanie fizyczne)", full.getWeekTable().getDay(3).getLesson(1).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(0).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription()); + Assert.assertEquals("bez nawiasów (poprzednio: Religia)", full.getWeekTable().getDay(4).getLesson(3).getDescription()); Assert.assertEquals("poprzednio: Wychowanie fizyczne", full.getWeekTable().getDay(4).getLesson(2).getDescription()); Assert.assertEquals("egzamin", full.getWeekTable().getDay(3).getLesson(0).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription()); diff --git a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html index c7dcef2e..4bce6c93 100644 --- a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html +++ b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html @@ -3,6 +3,40 @@ Witryna ucznia i rodzica – Plan lekcji +
@@ -238,7 +272,17 @@ - + +
+ Religia + Cyranka Krystian + 3 + Wychowanie do życia w rodzinie + Nowak Jadwiga + 3 + bez nawiasów +
+ 4 From cd6e14b13be70a4bb575ac9dbac6814dd3f23b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 13 May 2018 17:33:31 +0200 Subject: [PATCH 04/41] [API] Fix first login (#107) --- .../java/io/github/wulkanowy/api/Client.java | 6 +-- .../wulkanowy/api/StudentAndParent.java | 6 ++- .../io/github/wulkanowy/api/login/Login.java | 29 +++++++++----- .../github/wulkanowy/api/login/LoginTest.java | 39 +++++++++++++------ .../wulkanowy/api/login/Logowanie-error.html | 3 ++ .../wulkanowy/api/login/cert-no-symbols.xml | 13 +++++++ .../db/resources/ResourcesRepository.java | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 9 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index c3693c40..b5080e0c 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -23,7 +23,7 @@ public class Client { private String symbol; - private Date lastSuccessRequest = null; + private Date lastSuccessRequest; private Cookies cookies = new Cookies(); @@ -103,7 +103,7 @@ public class Client { return getPageByUrl(url, loginBefore, null); } - public Document getPageByUrl(String url, boolean loginBefore, Map cookies) throws IOException, VulcanException { + public synchronized Document getPageByUrl(String url, boolean loginBefore, Map cookies) throws IOException, VulcanException { if (loginBefore) { login(); } @@ -128,7 +128,7 @@ public class Client { return doc; } - public Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException { + public synchronized Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException { Connection connection = Jsoup.connect(getFilledUrl(url)); for (String[] data : params) { diff --git a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java index fbc14486..1acecfd3 100644 --- a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java +++ b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java @@ -106,7 +106,11 @@ public class StudentAndParent implements SnP { Document doc = client.getPageByUrl(getBaseUrl() + url, true, cookies); - if ("Witryna ucznia i rodzica – Strona główna".equals(doc.select("title").first().text())) { + if (!doc.title().startsWith("Witryna ucznia i rodzica")) { + throw new VulcanException("Expected SnP page, got page with title: " + doc.title()); + } + + if (doc.title().endsWith("Strona główna")) { throw new VulcanException("Sesja została nieprawidłowo zainicjowana"); } diff --git a/api/src/main/java/io/github/wulkanowy/api/login/Login.java b/api/src/main/java/io/github/wulkanowy/api/login/Login.java index 32e372c1..b8b52438 100644 --- a/api/src/main/java/io/github/wulkanowy/api/login/Login.java +++ b/api/src/main/java/io/github/wulkanowy/api/login/Login.java @@ -13,7 +13,7 @@ import io.github.wulkanowy.api.VulcanException; public class Login { - private static final String LOGIN_PAGE_URL = "{schema}://cufs.{host}/{symbol}/Account/LogOn" + + static final String LOGIN_PAGE_URL = "{schema}://cufs.{host}/{symbol}/Account/LogOn" + "?ReturnUrl=%2F{symbol}%2FFS%2FLS%3Fwa%3Dwsignin1.0%26wtrealm%3D" + "{schema}%253a%252f%252fuonetplus.{host}%252f{symbol}%252fLoginEndpoint.aspx%26wctx%3D" + "{schema}%253a%252f%252fuonetplus.{host}%252f{symbol}%252fLoginEndpoint.aspx"; @@ -47,6 +47,8 @@ public class Login { ); credentials = getFormStateParams(formSecond, email, password); nextUrl = formSecond.select("#form1").first().attr("abs:action"); + } else if (!"Logowanie".equals(loginPage.select("#h1Default").text())) { + throw new VulcanException("Expected login page, got page with title: " + loginPage.title()); } Document html = client.postPageByUrl(nextUrl, credentials); @@ -77,14 +79,17 @@ public class Login { String sendCertificate(Document doc, String defaultSymbol) throws IOException, VulcanException { String certificate = doc.select("input[name=wresult]").val(); - String symbol = findSymbol(defaultSymbol, certificate); - client.setSymbol(symbol); + if ("".equals(certificate)) { + throw new VulcanException("Expected certificate, got empty string. Page title: " + doc.title()); + } + + client.setSymbol(findSymbol(defaultSymbol, certificate)); Document targetDoc = sendCertData(doc); - String title = targetDoc.select("title").text(); + String title = targetDoc.title(); if ("Working...".equals(title)) { // on adfs login - title = sendCertData(targetDoc).select("title").text(); + title = sendCertData(targetDoc).title(); } if ("Logowanie".equals(title)) { @@ -95,12 +100,16 @@ public class Login { throw new LoginErrorException("Expected page title `UONET+`, got " + title); } - return symbol; + return client.getSymbol(); } private Document sendCertData(Document doc) throws IOException, VulcanException { String url = doc.select("form[name=hiddenform]").attr("action"); + if (!doc.title().equals("Working...")) { + throw new VulcanException("Expected certificate page, got page with title: " + doc.title()); + } + return client.postPageByUrl(url.replaceFirst("Default", "{symbol}"), new String[][]{ {"wa", "wsignin1.0"}, {"wresult", doc.select("input[name=wresult]").val()}, @@ -108,7 +117,7 @@ public class Login { }); } - private String findSymbol(String symbol, String certificate) { + private String findSymbol(String symbol, String certificate) throws AccountPermissionException { if ("Default".equals(symbol)) { return findSymbolInCertificate(certificate); } @@ -116,13 +125,13 @@ public class Login { return symbol; } - String findSymbolInCertificate(String certificate) { + String findSymbolInCertificate(String certificate) throws AccountPermissionException { Elements instances = Jsoup .parse(certificate.replaceAll(":", ""), "", Parser.xmlParser()) .select("[AttributeName=\"UserInstance\"] samlAttributeValue"); - if (instances.isEmpty()) { - return ""; + if (instances.size() < 2) { // 1st index is always `Default` + throw new AccountPermissionException("First login detected, specify symbol"); } return instances.get(1).text(); diff --git a/api/src/test/java/io/github/wulkanowy/api/login/LoginTest.java b/api/src/test/java/io/github/wulkanowy/api/login/LoginTest.java index 01602ebe..4a4f8915 100644 --- a/api/src/test/java/io/github/wulkanowy/api/login/LoginTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/login/LoginTest.java @@ -34,6 +34,10 @@ public class LoginTest { Client client = getClient("Logowanie-success.html"); Mockito.when(client.getPageByUrl(Mockito.anyString(), Mockito.anyBoolean())) .thenReturn(getFixtureAsDocument("Logowanie-error.html")); + Mockito.when(client.postPageByUrl(Mockito.eq(Login.LOGIN_PAGE_URL), Mockito.any(String[][].class))) + .thenReturn(getFixtureAsDocument("Logowanie-certyfikat.html")); + Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString()); + Mockito.when(client.getSymbol()).thenCallRealMethod(); Login login = new Login(client); Assert.assertEquals("d123", login.login("a@a", "pswd", "d123")); @@ -57,22 +61,31 @@ public class LoginTest { Login login = new Login(client); Assert.assertEquals( - getFixtureAsString("cert-stock.xml").replaceAll("\\s+",""), - login.sendCredentials("a@a", "passwd").select("input[name=wresult]").attr("value").replaceAll("\\s+","") + getFixtureAsString("cert-stock.xml").replaceAll("\\s+", ""), + login.sendCredentials("a@a", "passwd") + .select("input[name=wresult]") + .attr("value") + .replaceAll("\\s+", "") ); } @Test public void sendCertificateNotDefaultSymbolSuccessTest() throws Exception { - Login login = new Login(getClient("Logowanie-success.html")); + Client client = getClient("Logowanie-success.html"); + Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString()); + Mockito.when(client.getSymbol()).thenCallRealMethod(); + Login login = new Login(client); - Assert.assertEquals("wulkanowyschool321", - login.sendCertificate(new Document(""), "wulkanowyschool321")); + Assert.assertEquals("wulkanowyschool321", login.sendCertificate( + getFixtureAsDocument("Logowanie-certyfikat.html"), "wulkanowyschool321")); } @Test public void sendCertificateDefaultSymbolSuccessTest() throws Exception { - Login login = new Login(getClient("Logowanie-success.html")); + Client client = getClient("Logowanie-success.html"); + Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString()); + Mockito.when(client.getSymbol()).thenCallRealMethod(); + Login login = new Login(client); Assert.assertEquals("demo12345", login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "Default")); @@ -80,16 +93,18 @@ public class LoginTest { @Test(expected = AccountPermissionException.class) public void sendCertificateAccountPermissionTest() throws Exception { - Login login = new Login(getClient("Logowanie-brak-dostepu.html")); + Client client = getClient("Logowanie-brak-dostepu.html"); - login.sendCertificate(getFixtureAsDocument("cert-stock.xml"), "demo123"); + Login login = new Login(client); + + login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "demo123"); } @Test(expected = LoginErrorException.class) public void sendCertificateLoginErrorTest() throws Exception { Login login = new Login(getClient("Logowanie-certyfikat.html")); // change to other document - login.sendCertificate(getFixtureAsDocument("cert-stock.xml"), "demo123"); + login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "demo123"); } @Test @@ -101,10 +116,10 @@ public class LoginTest { Assert.assertEquals("demo12345", login.findSymbolInCertificate(certificate)); } - @Test - public void findSymbolInInvalidCertificateTest() throws Exception { + @Test(expected = AccountPermissionException.class) + public void findSymbolInCertificateWithoutSecondInstanceTest() throws Exception { Login login = new Login(getClient("Logowanie-certyfikat.html")); - Assert.assertEquals("", login.findSymbolInCertificate("")); // change to real cert with empty symbols + login.findSymbolInCertificate(getFixtureAsString("cert-no-symbols.xml")); } } diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html index 08713188..afb044d7 100644 --- a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html +++ b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html @@ -6,6 +6,9 @@
+
+

Logowanie

+
Zła nazwa użytkownika lub hasło
diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml b/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml new file mode 100644 index 00000000..ca14bdf5 --- /dev/null +++ b/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml @@ -0,0 +1,13 @@ + + + + + + + Default + + + + + + diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java index 26ec36dd..a430e335 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java @@ -52,7 +52,7 @@ public class ResourcesRepository implements ResourcesContract { } else if (exception instanceof SocketTimeoutException) { return resources.getString(R.string.generic_timeout_error); } else if (exception instanceof NotLoggedInErrorException || exception instanceof IOException) { - return resources.getString(R.string.login_denied_text); + return resources.getString(R.string.login_failed_text); } else { return exception.getMessage(); } diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 38169d81..aeb828d1 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -19,7 +19,7 @@ Pomyślnie zalogowano Niepoprawny e-mail lub hasło Brak uprawnień do otwarcia dziennika. Sprawdź wprowadzoną nazwę powiatu - Logowanie nie powiodło się. Spróbuj zrestartować aplikację + Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację Nie masz jeszcze konta? Załóż je Zapomniałeś hasła? diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2130120e..1ffea541 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,7 +19,7 @@ Login is successful Bad e-mail or password No permission to open log. Check entered symbol - Login is failed. Try restart the app + Login is failed. Try again or restart the app No account yet? Create one Forgot password? From 95caa21f2a8a1ecb80272a466e11fba0fb6dd2ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 13 May 2018 18:07:50 +0200 Subject: [PATCH 05/41] Version 0.4.1 --- .circleci/config.yml | 4 +--- README.md | 6 ++++-- app/build.gradle | 4 ++-- app/src/main/play/pl-PL/whatsnew | 14 +++----------- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 822ae06c..0e08617e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -228,6 +228,4 @@ workflows: - instrumented filters: branches: - ignore: /.*/ - tags: - only: /^\d+\.\d+\.\d+$/ + only: master diff --git a/README.md b/README.md index 12607f05..57578136 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,11 @@ [![Bitrise](https://img.shields.io/bitrise/daeff1893f3c8128/master.svg?token=Hjm1ACamk86JDeVVJHOeqQ&style=flat-square)](https://www.bitrise.io/app/daeff1893f3c8128) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![BCH compliance](https://bettercodehub.com/edge/badge/wulkanowy/wulkanowy?branch=master)](https://bettercodehub.com/) -[![Scrutinizer](https://img.shields.io/scrutinizer/g/wulkanowy/wulkanowy.svg)](https://scrutinizer-ci.com/g/wulkanowy/wulkanowy/?branch=master) -[![Known Vulnerabilities](https://snyk.io/test/github/wulkanowy/wulkanowy/badge.svg?targetFile=app%2Fbuild.gradle&style=flat-square)](https://snyk.io/test/github/wulkanowy/wulkanowy?targetFile=app%2Fbuild.gradle) +[![Scrutinizer](https://img.shields.io/scrutinizer/g/wulkanowy/wulkanowy.svg?style=flat-square)](https://scrutinizer-ci.com/g/wulkanowy/wulkanowy/?branch=master) [![Bintray](https://img.shields.io/bintray/v/wulkanowy/wulkanowy/api.svg?style=flat-square)](https://bintray.com/wulkanowy/wulkanowy/api) +[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/JMG2rhJ) + +[Pobierz wersję beta](https://play.google.com/store/apps/details?id=io.github.wulkanowy&utm_source=vcs) [Pobierz wersję rozwojową](https://bitrise-redirector.herokuapp.com/v0.1/apps/daeff1893f3c8128/builds/master/artifacts/app-debug-bitrise-signed.apk) diff --git a/app/build.gradle b/app/build.gradle index 58ab01d5..b4435348 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,8 +41,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 26 - versionCode 8 - versionName "0.4.0" + versionCode 9 + versionName "0.4.1" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true playAccountConfig = playAccountConfigs.defaultAccountConfig diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index 8c1807ab..94d5e6ce 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,11 +1,3 @@ -Wersja 0.4.0: -- dodano widget planu lekcji -- dodano widok sprawdzianów -- dodano informacje o końcowych ocenach z przedmiotu -- dodano przełącznik semestru w ocenach -- dodano opcję ukrycia obecności -- dodano wyróżnik aktualnego tygodnia -- dodano podstawową obsługę niestandardowych dzienników Vulcan (np. Opolska eSzkoła) -- naprawiono animacje w ocenach -- naprawiono wyświetlanie oceny w szczególnych przypadkach -- optymalizacja aplikacji +Wersja 0.4.1: +- naprawiono odświeżanie ocen +- wyeliminowano możliwość wystąpienia crashu w planie lekcji From 08dd316aee0c0558e253a77e10a32f3f3d225920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 14 May 2018 20:56:17 +0200 Subject: [PATCH 06/41] Fix adfs login (#110) --- api/src/main/java/io/github/wulkanowy/api/login/Login.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/src/main/java/io/github/wulkanowy/api/login/Login.java b/api/src/main/java/io/github/wulkanowy/api/login/Login.java index b8b52438..3ecfb7b6 100644 --- a/api/src/main/java/io/github/wulkanowy/api/login/Login.java +++ b/api/src/main/java/io/github/wulkanowy/api/login/Login.java @@ -130,6 +130,10 @@ public class Login { .parse(certificate.replaceAll(":", ""), "", Parser.xmlParser()) .select("[AttributeName=\"UserInstance\"] samlAttributeValue"); + if (instances.isEmpty()) { // on adfs login + return ""; + } + if (instances.size() < 2) { // 1st index is always `Default` throw new AccountPermissionException("First login detected, specify symbol"); } From 0014b74c6b82dc72ed6254e3353299979da722a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 14 May 2018 21:12:45 +0200 Subject: [PATCH 07/41] Fix certificate parsing issues (#109) --- api/src/main/java/io/github/wulkanowy/api/Client.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index b5080e0c..34e71398 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -58,7 +58,6 @@ public class Client { return; } - this.cookies = new Cookies(); this.symbol = new Login(this).login(email, password, symbol); } @@ -143,6 +142,8 @@ public class Client { this.cookies.addItems(response.cookies()); + response.bufferUp(); // fixes cert parsing issues + return checkForErrors(response.parse()); } From 052d5e3911d2dafd86d29a29e2b295aa91ac27a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 14 May 2018 21:39:09 +0200 Subject: [PATCH 08/41] Stopping job when user not registered in app (#111) --- .../java/io/github/wulkanowy/ui/splash/SplashActivity.java | 6 ++++++ .../java/io/github/wulkanowy/ui/splash/SplashContract.java | 2 ++ .../java/io/github/wulkanowy/ui/splash/SplashPresenter.java | 1 + 3 files changed, 9 insertions(+) diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java index 53994a16..cbed56d2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java @@ -5,6 +5,7 @@ import android.os.Bundle; import javax.inject.Inject; import butterknife.ButterKnife; +import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.services.notifies.NotificationService; import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.login.LoginActivity; @@ -47,4 +48,9 @@ public class SplashActivity extends BaseActivity implements SplashContract.View public void cancelNotifications() { new NotificationService(getApplicationContext()).cancelAll(); } + + @Override + public void stopSyncService() { + SyncJob.stop(getApplicationContext()); + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java index 58d4447c..f6fc23a6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java @@ -13,6 +13,8 @@ public interface SplashContract { void openMainActivity(); void cancelNotifications(); + + void stopSyncService(); } @PerActivity diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java index 8d20226f..14f696a5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java @@ -24,6 +24,7 @@ public class SplashPresenter extends BasePresenter getView().openMainActivity(); } else { getView().openLoginActivity(); + getView().stopSyncService(); } } } From 7d5072b529f654aea7552fbe28d4f3db42844fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 14 May 2018 22:13:08 +0200 Subject: [PATCH 09/41] Fix exams sync (#108) --- app/build.gradle | 2 +- .../wulkanowy/data/db/dao/DbHelper.java | 2 ++ .../wulkanowy/data/db/dao/entities/Exam.java | 4 +++- .../data/db/dao/migrations/Migration27.java | 24 +++++++++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration27.java diff --git a/app/build.gradle b/app/build.gradle index b4435348..d973c8e4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -91,7 +91,7 @@ play { } greendao { - schemaVersion 26 + schemaVersion 27 generateTests = true } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java index 07307e52..8aa9b1df 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java @@ -18,6 +18,7 @@ import io.github.wulkanowy.api.Vulcan; import io.github.wulkanowy.data.db.dao.entities.DaoMaster; import io.github.wulkanowy.data.db.dao.migrations.Migration23; import io.github.wulkanowy.data.db.dao.migrations.Migration26; +import io.github.wulkanowy.data.db.dao.migrations.Migration27; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.di.annotations.ApplicationContext; import io.github.wulkanowy.di.annotations.DatabaseInfo; @@ -76,6 +77,7 @@ public class DbHelper extends DaoMaster.OpenHelper { List migrations = new ArrayList<>(); migrations.add(new Migration23()); migrations.add(new Migration26()); + migrations.add(new Migration27()); // Sorting just to be safe, in case other people add migrations in the wrong order. Comparator migrationComparator = new Comparator() { diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Exam.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Exam.java index 076846e1..543b6859 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Exam.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Exam.java @@ -4,13 +4,15 @@ import org.greenrobot.greendao.DaoException; import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; +import org.greenrobot.greendao.annotation.Index; import org.greenrobot.greendao.annotation.Property; import java.io.Serializable; @Entity( nameInDb = "Exams", - active = true + active = true, + indexes = {@Index(value = "dayId,entryDate,subjectAndGroup,type,teacher", unique = true)} ) public class Exam implements Serializable { diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration27.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration27.java new file mode 100644 index 00000000..5c8c82f1 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration27.java @@ -0,0 +1,24 @@ +package io.github.wulkanowy.data.db.dao.migrations; + +import org.greenrobot.greendao.database.Database; + +import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.data.db.dao.DbHelper; +import io.github.wulkanowy.data.db.dao.entities.ExamDao; +import io.github.wulkanowy.data.db.shared.SharedPrefContract; + +public class Migration27 implements DbHelper.Migration { + + @Override + public Integer getVersion() { + return 27; + } + + @Override + public void runMigration(Database db, SharedPrefContract sharedPref, Vulcan vulcan) throws Exception { + ExamDao.dropTable(db, true); + ExamDao.createTable(db, true); + + db.execSQL("UPDATE Weeks SET exams_synced = 0"); + } +} From 3000c077c4813a7f540be2fcf8b28b16527a784c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 14 May 2018 22:20:17 +0200 Subject: [PATCH 10/41] Version 0.4.2 --- .circleci/config.yml | 28 +++++++++++++++---- app/build.gradle | 4 +-- .../main/play/pl-PL/listing/fulldescription | 2 ++ app/src/main/play/pl-PL/whatsnew | 7 +++-- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0e08617e..fe74ebe6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -199,24 +199,40 @@ jobs: workflows: version: 2 - build_check_tests: + build-test-deploy: jobs: - - build + - build: + filters: + tags: + only: /.*/ - lint: + filters: + tags: + only: /.*/ requires: - build - app-test: + filters: + tags: + only: /.*/ requires: - build - api-test: + filters: + tags: + only: /.*/ requires: - build - instrumented: - requires: - - build + filters: + tags: + only: /.*/ requires: - build - sonarcube: + filters: + tags: + only: /.*/ requires: - build - lint @@ -227,5 +243,7 @@ workflows: requires: - instrumented filters: + tags: + only: /\d+\.\d+\.\d+/ branches: - only: master + ignore: /.*/ diff --git a/app/build.gradle b/app/build.gradle index d973c8e4..b9f3cdd8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,8 +41,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 26 - versionCode 9 - versionName "0.4.1" + versionCode 10 + versionName "0.4.2" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true playAccountConfig = playAccountConfigs.defaultAccountConfig diff --git a/app/src/main/play/pl-PL/listing/fulldescription b/app/src/main/play/pl-PL/listing/fulldescription index e334a82b..37163709 100644 --- a/app/src/main/play/pl-PL/listing/fulldescription +++ b/app/src/main/play/pl-PL/listing/fulldescription @@ -1,3 +1,5 @@ +Aplikacja jest we wczesnej fazie rozwoju, ciągle pracujemy nad kolejnymi funkcjami. + Wyróżnione cechy i funkcje: - Całkowicie darmowa i otwarta (brak jakichkolwiek reklam i mikropłatności) - Powiadomienia diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index 94d5e6ce..ffb96b6d 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,3 +1,4 @@ -Wersja 0.4.1: -- naprawiono odświeżanie ocen -- wyeliminowano możliwość wystąpienia crashu w planie lekcji +Wersja 0.4.2: +- naprawiono logowanie do niestandardowych dzienników +- naprawiono synchronizację sprawdzianów +- naprawiono problemy z logowaniem (powinny występować rzadziej) From 54e6aee82e79efb40fa0a7904a7070e9bd3c2f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Wed, 16 May 2018 20:43:29 +0200 Subject: [PATCH 11/41] Stop SyncJob if user is not registered in app (#113) --- .../io/github/wulkanowy/data/sync/AccountSync.java | 4 ++-- .../data/sync/NotRegisteredUserException.java | 8 ++++++++ .../io/github/wulkanowy/services/jobs/SyncJob.java | 13 +++++++++++-- .../github/wulkanowy/ui/splash/SplashActivity.java | 6 ------ .../github/wulkanowy/ui/splash/SplashContract.java | 2 -- .../github/wulkanowy/ui/splash/SplashPresenter.java | 1 - 6 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/data/sync/NotRegisteredUserException.java diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java index d701edc0..a79540a6 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java @@ -118,12 +118,12 @@ public class AccountSync { daoSession.getSemesterDao().insertInTx(semesterList); } - public void initLastUser() throws IOException, CryptoException { + public void initLastUser() throws CryptoException { long userId = sharedPref.getCurrentUserId(); if (userId == 0) { - throw new IOException("Can't find saved user"); + throw new NotRegisteredUserException("Can't find user id in SharedPreferences"); } LogUtils.debug("Initialization current user id=" + userId); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/NotRegisteredUserException.java b/app/src/main/java/io/github/wulkanowy/data/sync/NotRegisteredUserException.java new file mode 100644 index 00000000..ddba1a21 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/sync/NotRegisteredUserException.java @@ -0,0 +1,8 @@ +package io.github.wulkanowy.data.sync; + +public class NotRegisteredUserException extends RuntimeException { + + public NotRegisteredUserException(String message) { + super(message); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java index 7ac91114..ab79034f 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java @@ -24,6 +24,7 @@ import io.github.wulkanowy.R; import io.github.wulkanowy.WulkanowyApp; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.data.db.dao.entities.Grade; +import io.github.wulkanowy.data.sync.NotRegisteredUserException; import io.github.wulkanowy.services.notifies.GradeNotify; import io.github.wulkanowy.ui.main.MainActivity; import io.github.wulkanowy.utils.LogUtils; @@ -74,9 +75,12 @@ public class SyncJob extends SimpleJobService { showNotification(); } return JobService.RESULT_SUCCESS; + } catch (NotRegisteredUserException e) { + logError(e); + stop(getApplicationContext()); + return JobService.RESULT_FAIL_NORETRY; } catch (Exception e) { - Crashlytics.logException(e); - LogUtils.error("During background synchronization an error occurred", e); + logError(e); return JobService.RESULT_FAIL_RETRY; } } @@ -116,4 +120,9 @@ public class SyncJob extends SimpleJobService { gradeList.size(), gradeList.size()); } } + + private void logError(Exception e) { + Crashlytics.logException(e); + LogUtils.error("During background synchronization an error occurred", e); + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java index cbed56d2..53994a16 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java @@ -5,7 +5,6 @@ import android.os.Bundle; import javax.inject.Inject; import butterknife.ButterKnife; -import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.services.notifies.NotificationService; import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.login.LoginActivity; @@ -48,9 +47,4 @@ public class SplashActivity extends BaseActivity implements SplashContract.View public void cancelNotifications() { new NotificationService(getApplicationContext()).cancelAll(); } - - @Override - public void stopSyncService() { - SyncJob.stop(getApplicationContext()); - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java index f6fc23a6..58d4447c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java @@ -13,8 +13,6 @@ public interface SplashContract { void openMainActivity(); void cancelNotifications(); - - void stopSyncService(); } @PerActivity diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java index 14f696a5..8d20226f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java @@ -24,7 +24,6 @@ public class SplashPresenter extends BasePresenter getView().openMainActivity(); } else { getView().openLoginActivity(); - getView().stopSyncService(); } } } From 62bc00cd68dee36b823c851a4853af769348a122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 19 May 2018 12:30:17 +0200 Subject: [PATCH 12/41] Delete non-existing lessons on sync (#112) --- .../api/attendance/AttendanceTable.java | 2 +- .../github/wulkanowy/api/generic/Lesson.java | 7 +- .../wulkanowy/api/timetable/Timetable.java | 2 +- .../api/timetable/TimetableTest.java | 10 +-- app/build.gradle | 2 +- .../wulkanowy/data/db/dao/DbHelper.java | 2 + .../wulkanowy/data/db/dao/entities/Day.java | 69 ++++++++++--------- .../data/db/dao/entities/TimetableLesson.java | 53 ++++++++++---- .../data/db/dao/migrations/Migration28.java | 20 ++++++ .../wulkanowy/data/sync/TimetableSync.java | 16 +++++ .../ui/main/timetable/TimetableSubItem.java | 2 +- .../wulkanowy/utils/DataObjectConverter.java | 2 +- 12 files changed, 128 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration28.java diff --git a/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java b/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java index c45cbe6a..d81a30b2 100644 --- a/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java +++ b/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java @@ -63,7 +63,7 @@ public class AttendanceTable { for (int i = 1; i < size; i++) { Lesson lesson = new Lesson(); lesson.setDate(days.get(i - 1).getDate()); - lesson.setNumber(hours.get(0).text()); + lesson.setNumber(Integer.valueOf(hours.get(0).text())); addLessonDetails(lesson, hours.get(i)); diff --git a/api/src/main/java/io/github/wulkanowy/api/generic/Lesson.java b/api/src/main/java/io/github/wulkanowy/api/generic/Lesson.java index 8dd65327..27bf9bf0 100644 --- a/api/src/main/java/io/github/wulkanowy/api/generic/Lesson.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Lesson.java @@ -2,7 +2,7 @@ package io.github.wulkanowy.api.generic; public class Lesson { - private String number = ""; + private int number = 0; private String subject = ""; @@ -48,12 +48,13 @@ public class Lesson { private boolean isExemption = false; - public String getNumber() { + public int getNumber() { return number; } - public void setNumber(String number) { + public Lesson setNumber(int number) { this.number = number; + return this; } public String getSubject() { diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 4e9cc18e..77ca41bd 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -81,7 +81,7 @@ public class Timetable { lesson.setStartTime(startEndEnd[0]); lesson.setEndTime(startEndEnd[1]); lesson.setDate(days.get(i - 2).getDate()); - lesson.setNumber(hours.get(0).text()); + lesson.setNumber(Integer.valueOf(hours.get(0).text())); addLessonDetails(lesson, hours.get(i).select("div")); diff --git a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java index 818745f7..8939b10f 100644 --- a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java @@ -83,11 +83,11 @@ public class TimetableTest extends StudentAndParentTestCase { @Test public void getLessonNumberTest() throws Exception { - Assert.assertEquals("2", std.getWeekTable().getDay(0).getLesson(1).getNumber()); - Assert.assertEquals("5", std.getWeekTable().getDay(2).getLesson(4).getNumber()); - Assert.assertEquals("0", full.getWeekTable().getDay(0).getLesson(0).getNumber()); - Assert.assertEquals("13", full.getWeekTable().getDay(4).getLesson(13).getNumber()); - Assert.assertEquals("3", holidays.getWeekTable().getDay(3).getLesson(3).getNumber()); + Assert.assertEquals(2, std.getWeekTable().getDay(0).getLesson(1).getNumber()); + Assert.assertEquals(5, std.getWeekTable().getDay(2).getLesson(4).getNumber()); + Assert.assertEquals(0, full.getWeekTable().getDay(0).getLesson(0).getNumber()); + Assert.assertEquals(13, full.getWeekTable().getDay(4).getLesson(13).getNumber()); + Assert.assertEquals(3, holidays.getWeekTable().getDay(3).getLesson(3).getNumber()); } @Test diff --git a/app/build.gradle b/app/build.gradle index b9f3cdd8..78df5c91 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -91,7 +91,7 @@ play { } greendao { - schemaVersion 27 + schemaVersion 28 generateTests = true } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java index 8aa9b1df..97bb7559 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java @@ -19,6 +19,7 @@ import io.github.wulkanowy.data.db.dao.entities.DaoMaster; import io.github.wulkanowy.data.db.dao.migrations.Migration23; import io.github.wulkanowy.data.db.dao.migrations.Migration26; import io.github.wulkanowy.data.db.dao.migrations.Migration27; +import io.github.wulkanowy.data.db.dao.migrations.Migration28; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.di.annotations.ApplicationContext; import io.github.wulkanowy.di.annotations.DatabaseInfo; @@ -78,6 +79,7 @@ public class DbHelper extends DaoMaster.OpenHelper { migrations.add(new Migration23()); migrations.add(new Migration26()); migrations.add(new Migration27()); + migrations.add(new Migration28()); // Sorting just to be safe, in case other people add migrations in the wrong order. Comparator migrationComparator = new Comparator() { diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java index 434affb0..c4857bc9 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java @@ -5,6 +5,7 @@ import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Index; +import org.greenrobot.greendao.annotation.OrderBy; import org.greenrobot.greendao.annotation.Property; import org.greenrobot.greendao.annotation.ToMany; @@ -35,9 +36,11 @@ public class Day { @Property(nameInDb = "free_day_name") private String freeDayName = ""; + @OrderBy("number ASC") @ToMany(referencedJoinProperty = "dayId") private List timetableLessons; + @OrderBy("number ASC") @ToMany(referencedJoinProperty = "dayId") private List attendanceLessons; @@ -50,9 +53,7 @@ public class Day { @Generated(hash = 2040040024) private transient DaoSession daoSession; - /** - * Used for active entity operations. - */ + /** Used for active entity operations. */ @Generated(hash = 312167767) private transient DayDao myDao; @@ -185,6 +186,36 @@ public class Day { attendanceLessons = null; } + /** + * To-many relationship, resolved on first access (and after reset). + * Changes to to-many relations are not persisted, make changes to the target entity. + */ + @Generated(hash = 1231531946) + public List getExams() { + if (exams == null) { + final DaoSession daoSession = this.daoSession; + if (daoSession == null) { + throw new DaoException("Entity is detached from DAO context"); + } + ExamDao targetDao = daoSession.getExamDao(); + List examsNew = targetDao._queryDay_Exams(id); + synchronized (this) { + if (exams == null) { + exams = examsNew; + } + } + } + return exams; + } + + /** + * Resets a to-many relationship, making the next get call to query for a fresh result. + */ + @Generated(hash = 841969952) + public synchronized void resetExams() { + exams = null; + } + /** * Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}. * Entity must attached to an entity context. @@ -222,39 +253,13 @@ public class Day { } /** - * To-many relationship, resolved on first access (and after reset). - * Changes to to-many relations are not persisted, make changes to the target entity. + * called by internal mechanisms, do not call yourself. */ - @Generated(hash = 1231531946) - public List getExams() { - if (exams == null) { - final DaoSession daoSession = this.daoSession; - if (daoSession == null) { - throw new DaoException("Entity is detached from DAO context"); - } - ExamDao targetDao = daoSession.getExamDao(); - List examsNew = targetDao._queryDay_Exams(id); - synchronized (this) { - if (exams == null) { - exams = examsNew; - } - } - } - return exams; - } - - /** - * Resets a to-many relationship, making the next get call to query for a fresh result. - */ - @Generated(hash = 841969952) - public synchronized void resetExams() { - exams = null; - } - - /** called by internal mechanisms, do not call yourself. */ @Generated(hash = 1409317752) public void __setDaoSession(DaoSession daoSession) { this.daoSession = daoSession; myDao = daoSession != null ? daoSession.getDayDao() : null; } + + } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/TimetableLesson.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/TimetableLesson.java index 28761b6b..f3fdf6a8 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/TimetableLesson.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/TimetableLesson.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.data.db.dao.entities; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; import org.greenrobot.greendao.DaoException; import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; @@ -12,7 +14,7 @@ import java.io.Serializable; @Entity( nameInDb = "TimetableLessons", active = true, - indexes = {@Index(value = "dayId,date,startTime,endTime", unique = true)} + indexes = {@Index(value = "dayId,date,number,startTime,endTime", unique = true)} ) public class TimetableLesson implements Serializable { @@ -25,7 +27,7 @@ public class TimetableLesson implements Serializable { private Long dayId; @Property(nameInDb = "number") - private String number; + private int number = 0; @Property(nameInDb = "subject") private String subject = ""; @@ -75,18 +77,15 @@ public class TimetableLesson implements Serializable { @Generated(hash = 2040040024) private transient DaoSession daoSession; - /** - * Used for active entity operations. - */ + /** Used for active entity operations. */ @Generated(hash = 1119360138) private transient TimetableLessonDao myDao; - @Generated(hash = 1955911128) - public TimetableLesson(Long id, Long dayId, String number, String subject, - String teacher, String room, String description, String group, - String startTime, String endTime, String date, boolean empty, - boolean divisionIntoGroups, boolean planning, boolean realized, - boolean movedOrCanceled, boolean newMovedInOrChanged) { + @Generated(hash = 1665905034) + public TimetableLesson(Long id, Long dayId, int number, String subject, String teacher, + String room, String description, String group, String startTime, String endTime, + String date, boolean empty, boolean divisionIntoGroups, boolean planning, + boolean realized, boolean movedOrCanceled, boolean newMovedInOrChanged) { this.id = id; this.dayId = dayId; this.number = number; @@ -109,7 +108,7 @@ public class TimetableLesson implements Serializable { @Generated(hash = 1878030142) public TimetableLesson() { } - + public Long getId() { return this.id; } @@ -127,11 +126,11 @@ public class TimetableLesson implements Serializable { return this; } - public String getNumber() { + public int getNumber() { return this.number; } - public TimetableLesson setNumber(String number) { + public TimetableLesson setNumber(int number) { this.number = number; return this; } @@ -262,6 +261,32 @@ public class TimetableLesson implements Serializable { return this; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + TimetableLesson lesson = (TimetableLesson) o; + + return new EqualsBuilder() + .append(number, lesson.number) + .append(startTime, lesson.startTime) + .append(endTime, lesson.endTime) + .append(date, lesson.date) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(number) + .append(startTime) + .append(endTime) + .append(date) + .toHashCode(); + } + /** * Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}. * Entity must attached to an entity context. diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration28.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration28.java new file mode 100644 index 00000000..3970df4c --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration28.java @@ -0,0 +1,20 @@ +package io.github.wulkanowy.data.db.dao.migrations; + +import org.greenrobot.greendao.database.Database; + +import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.data.db.dao.DbHelper; +import io.github.wulkanowy.data.db.shared.SharedPrefContract; + +public class Migration28 implements DbHelper.Migration { + + @Override + public Integer getVersion() { + return 28; + } + + @Override + public void runMigration(final Database db, final SharedPrefContract sharedPref, final Vulcan vulcan) throws Exception { + throw new Exception("No migrations"); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java index 69ebafcf..3fe22aff 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.data.sync; +import org.apache.commons.collections4.CollectionUtils; + import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; @@ -125,6 +127,16 @@ public class TimetableSync { List lessonsFromApiEntities = DataObjectConverter .lessonsToTimetableLessonsEntities(lessons); + List lessonsFromDbEntities = getLessonsFromDb(dayId); + + if (!lessonsFromDbEntities.isEmpty()) { + List lessonToRemove = new ArrayList<>(CollectionUtils.removeAll(lessonsFromDbEntities, lessonsFromApiEntities)); + + for (TimetableLesson timetableLesson : lessonToRemove) { + daoSession.getTimetableLessonDao().delete(timetableLesson); + } + } + for (TimetableLesson apiLessonEntity : lessonsFromApiEntities) { TimetableLesson lessonFromDb = getLessonFromDb(apiLessonEntity, dayId); @@ -148,4 +160,8 @@ public class TimetableSync { TimetableLessonDao.Properties.EndTime.eq(apiEntity.getEndTime())) .unique(); } + + private List getLessonsFromDb(long dayId) { + return daoSession.getDayDao().load(dayId).getTimetableLessons(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java index 8d65956e..a3e84dfa 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java @@ -106,7 +106,7 @@ public class TimetableSubItem lessonName.setText(lesson.getSubject()); lessonTime.setText(getLessonTimeString()); - numberOfLesson.setText(lesson.getNumber()); + numberOfLesson.setText(String.valueOf(lesson.getNumber())); room.setText(getRoomString()); alert.setVisibility(lesson.getMovedOrCanceled() || lesson.getNewMovedInOrChanged() ? View.VISIBLE : View.INVISIBLE); diff --git a/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java b/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java index 3b599c8f..3f733ad6 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java +++ b/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java @@ -156,7 +156,7 @@ public final class DataObjectConverter { for (io.github.wulkanowy.api.generic.Lesson lesson : lessonList) { lessonEntityList.add(new AttendanceLesson() - .setNumber(Integer.valueOf(lesson.getNumber())) + .setNumber(lesson.getNumber()) .setSubject(lesson.getSubject()) .setDate(lesson.getDate()) .setPresence(lesson.isPresence()) From e9b357e92dce133917f6895fa7cf3aa7ee0a56e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 19 May 2018 12:48:12 +0200 Subject: [PATCH 13/41] Remove the root check (#114) --- .../ui/main/exams/ExamsTabFragment.java | 2 +- .../github/wulkanowy/utils/RootChecker.java | 38 ------------------- .../wulkanowy/utils/security/Scrambler.java | 12 +----- 3 files changed, 3 insertions(+), 49 deletions(-) delete mode 100644 app/src/main/java/io/github/wulkanowy/utils/RootChecker.java diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java index ccc3da17..d41e34d2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java @@ -135,7 +135,7 @@ public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.V @Override public void onDestroyView() { - super.onDestroyView(); presenter.onDestroy(); + super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/utils/RootChecker.java b/app/src/main/java/io/github/wulkanowy/utils/RootChecker.java deleted file mode 100644 index 9c23c217..00000000 --- a/app/src/main/java/io/github/wulkanowy/utils/RootChecker.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.wulkanowy.utils; - -import android.os.Build; - -import java.io.File; - -public final class RootChecker { - - private RootChecker() { - throw new IllegalStateException("Utility class"); - } - - public static boolean isRooted() { - return checkOne() || checkTwo() || checkThree(); - } - - private static boolean checkOne() { - return Build.TAGS != null && Build.TAGS.contains("test-keys"); - } - - private static boolean checkTwo() { - return new File("/system/app/Superuser.apk").exists(); - } - - private static boolean checkThree() { - String[] commands = {"/system/xbin/which su", "/system/bin/which su", "which su"}; - for (String command : commands) { - try { - Runtime.getRuntime().exec(command); - return true; - } catch (Exception e) { - // ignore - } - } - return false; - } - -} diff --git a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java index 93da1d0b..dc0c409a 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java +++ b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java @@ -27,7 +27,6 @@ import javax.crypto.CipherOutputStream; import javax.security.auth.x500.X500Principal; import io.github.wulkanowy.utils.LogUtils; -import io.github.wulkanowy.utils.RootChecker; public final class Scrambler { @@ -46,23 +45,16 @@ public final class Scrambler { loadKeyStore(); generateNewKey(email, context); return encryptString(email, plainText); - } else { - if (RootChecker.isRooted()) { - return new String(Base64.encode(plainText.getBytes(), Base64.DEFAULT)); - } else { - throw new UnsupportedOperationException("Stored data in this devices " + - "isn't safe because android is rooted"); - } } + return new String(Base64.encode(plainText.getBytes(), Base64.DEFAULT)); } public static String decrypt(String email, String encryptedText) throws CryptoException { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { loadKeyStore(); return decryptString(email, encryptedText); - } else { - return new String(Base64.decode(encryptedText, Base64.DEFAULT)); } + return new String(Base64.decode(encryptedText, Base64.DEFAULT)); } private static void loadKeyStore() throws CryptoException { From 5685e73e465b7c31bf0ad42c03b9b29caafd8ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 19 May 2018 19:58:33 +0200 Subject: [PATCH 14/41] Fix text alignment <= lv l20 (#117) --- app/src/main/res/layout/activity_login.xml | 6 +++--- app/src/main/res/layout/fragment_attendance_tab.xml | 2 +- app/src/main/res/layout/fragment_exams_tab.xml | 2 +- app/src/main/res/layout/fragment_grades.xml | 2 +- app/src/main/res/layout/fragment_timetable_tab.xml | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 67095982..ec3872da 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -25,7 +25,7 @@ style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentTop="true" + android:layout_below="@id/login_activity_progress_text" android:layout_centerHorizontal="true" android:indeterminate="true" android:minHeight="30dp" @@ -35,9 +35,9 @@ android:id="@+id/login_activity_progress_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignBottom="@+id/login_activity_progress_bar" android:layout_centerHorizontal="true" - android:layout_marginBottom="42dp" /> + android:layout_marginBottom="15dp" + android:text="@string/app_name" /> diff --git a/app/src/main/res/layout/fragment_exams_tab.xml b/app/src/main/res/layout/fragment_exams_tab.xml index 7eda29e1..e446b2fb 100644 --- a/app/src/main/res/layout/fragment_exams_tab.xml +++ b/app/src/main/res/layout/fragment_exams_tab.xml @@ -43,8 +43,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="46dp" + android:gravity="center" android:text="@string/exams_no_entries" - android:textAlignment="center" android:textSize="20sp" /> diff --git a/app/src/main/res/layout/fragment_grades.xml b/app/src/main/res/layout/fragment_grades.xml index f1ab1fbe..f00b3108 100644 --- a/app/src/main/res/layout/fragment_grades.xml +++ b/app/src/main/res/layout/fragment_grades.xml @@ -31,7 +31,7 @@ android:layout_height="wrap_content" android:layout_marginTop="46dp" android:text="@string/fragment_no_grades" - android:textAlignment="center" + android:gravity="center" android:textSize="20sp" /> diff --git a/app/src/main/res/layout/fragment_timetable_tab.xml b/app/src/main/res/layout/fragment_timetable_tab.xml index 749a6b34..47aa5101 100644 --- a/app/src/main/res/layout/fragment_timetable_tab.xml +++ b/app/src/main/res/layout/fragment_timetable_tab.xml @@ -1,6 +1,6 @@ + android:textSize="20sp" /> Date: Sat, 19 May 2018 21:11:04 +0200 Subject: [PATCH 15/41] Add condition to exam query (#116) --- app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java index fad38c20..53470882 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java @@ -135,6 +135,7 @@ public class ExamsSync { .where(ExamDao.Properties.DayId.eq(dayId), ExamDao.Properties.EntryDate.eq(examApi.getEntryDate()), ExamDao.Properties.SubjectAndGroup.eq(examApi.getSubjectAndGroup()), + ExamDao.Properties.Type.eq(examApi.getType()), ExamDao.Properties.Teacher.eq(examApi.getTeacher())) .unique(); } From a4445a8a9738d02808f8b21638a508354c30a67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sat, 19 May 2018 23:02:54 +0200 Subject: [PATCH 16/41] Fix api login error (#115) --- .../java/io/github/wulkanowy/api/Client.java | 8 ++-- .../io/github/wulkanowy/api/login/Login.java | 48 ++++++++----------- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index 34e71398..53300788 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -63,7 +63,7 @@ public class Client { private boolean isLoggedIn() { return getCookies().size() > 0 && lastSuccessRequest != null && - 29 > TimeUnit.MILLISECONDS.toMinutes(new Date().getTime() - lastSuccessRequest.getTime()); + 5 > TimeUnit.MILLISECONDS.toMinutes(new Date().getTime() - lastSuccessRequest.getTime()); } @@ -142,7 +142,7 @@ public class Client { this.cookies.addItems(response.cookies()); - response.bufferUp(); // fixes cert parsing issues + response.bufferUp(); // fixes cert parsing issues #109 return checkForErrors(response.parse()); } @@ -195,8 +195,8 @@ public class Client { throw new NotLoggedInErrorException(singIn); } - if ("Błąd strony".equals(title)) { - throw new VulcanException("Nieznany błąd"); + if (title.startsWith("Błąd")) { + throw new NotLoggedInErrorException(title + " " + doc.selectFirst("p, body")); } return doc; diff --git a/api/src/main/java/io/github/wulkanowy/api/login/Login.java b/api/src/main/java/io/github/wulkanowy/api/login/Login.java index 3ecfb7b6..a734501e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/login/Login.java +++ b/api/src/main/java/io/github/wulkanowy/api/login/Login.java @@ -36,29 +36,29 @@ public class Login { {"Password", password} }; - String nextUrl = LOGIN_PAGE_URL; - Document loginPage = client.getPageByUrl(nextUrl, false); + Document nextDoc = sendCredentialsData(credentials, LOGIN_PAGE_URL); - Element formFirst = loginPage.select("#form1").first(); - if (null != formFirst) { // on adfs login - Document formSecond = client.postPageByUrl( - formFirst.attr("abs:action"), - getFormStateParams(formFirst, "", "") - ); - credentials = getFormStateParams(formSecond, email, password); - nextUrl = formSecond.select("#form1").first().attr("abs:action"); - } else if (!"Logowanie".equals(loginPage.select("#h1Default").text())) { - throw new VulcanException("Expected login page, got page with title: " + loginPage.title()); - } - - Document html = client.postPageByUrl(nextUrl, credentials); - - Element errorMessage = html.select(".ErrorMessage, #ErrorTextLabel").first(); + Element errorMessage = nextDoc.selectFirst(".ErrorMessage, #ErrorTextLabel"); if (null != errorMessage) { throw new BadCredentialsException(errorMessage.text()); } - return html; + return nextDoc; + } + + private Document sendCredentialsData(String[][] credentials, String nextUrl) throws IOException, VulcanException { + Element formFirst = client.getPageByUrl(nextUrl, false).selectFirst("#form1"); + + if (null != formFirst) { // only on adfs login + Document formSecond = client.postPageByUrl( + formFirst.attr("abs:action"), + getFormStateParams(formFirst, "", "") + ); + credentials = getFormStateParams(formSecond, credentials[0][1], credentials[1][1]); + nextUrl = formSecond.selectFirst("#form1").attr("abs:action"); + } + + return client.postPageByUrl(nextUrl, credentials); } private String[][] getFormStateParams(Element form, String email, String password) { @@ -77,13 +77,7 @@ public class Login { } String sendCertificate(Document doc, String defaultSymbol) throws IOException, VulcanException { - String certificate = doc.select("input[name=wresult]").val(); - - if ("".equals(certificate)) { - throw new VulcanException("Expected certificate, got empty string. Page title: " + doc.title()); - } - - client.setSymbol(findSymbol(defaultSymbol, certificate)); + client.setSymbol(findSymbol(defaultSymbol, doc.select("input[name=wresult]").val())); Document targetDoc = sendCertData(doc); String title = targetDoc.title(); @@ -106,10 +100,6 @@ public class Login { private Document sendCertData(Document doc) throws IOException, VulcanException { String url = doc.select("form[name=hiddenform]").attr("action"); - if (!doc.title().equals("Working...")) { - throw new VulcanException("Expected certificate page, got page with title: " + doc.title()); - } - return client.postPageByUrl(url.replaceFirst("Default", "{symbol}"), new String[][]{ {"wa", "wsignin1.0"}, {"wresult", doc.select("input[name=wresult]").val()}, From 9c97962e89052e7e91a01549aa4cf3f77f80e238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sat, 19 May 2018 23:37:32 +0200 Subject: [PATCH 17/41] Version 0.4.3 --- README.md | 2 +- app/build.gradle | 4 ++-- .../io/github/wulkanowy/data/db/dao/entities/Day.java | 4 +--- app/src/main/play/pl-PL/listing/fulldescription | 2 +- app/src/main/play/pl-PL/whatsnew | 8 ++++---- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 57578136..6ccaa20a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![BCH compliance](https://bettercodehub.com/edge/badge/wulkanowy/wulkanowy?branch=master)](https://bettercodehub.com/) [![Scrutinizer](https://img.shields.io/scrutinizer/g/wulkanowy/wulkanowy.svg?style=flat-square)](https://scrutinizer-ci.com/g/wulkanowy/wulkanowy/?branch=master) [![Bintray](https://img.shields.io/bintray/v/wulkanowy/wulkanowy/api.svg?style=flat-square)](https://bintray.com/wulkanowy/wulkanowy/api) -[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/JMG2rhJ) +[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [Pobierz wersję beta](https://play.google.com/store/apps/details?id=io.github.wulkanowy&utm_source=vcs) diff --git a/app/build.gradle b/app/build.gradle index 78df5c91..8a831d4f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,8 +41,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 26 - versionCode 10 - versionName "0.4.2" + versionCode 11 + versionName "0.4.3" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true playAccountConfig = playAccountConfigs.defaultAccountConfig diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java index c4857bc9..c5472e98 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java @@ -252,9 +252,7 @@ public class Day { myDao.update(this); } - /** - * called by internal mechanisms, do not call yourself. - */ + /** called by internal mechanisms, do not call yourself. */ @Generated(hash = 1409317752) public void __setDaoSession(DaoSession daoSession) { this.daoSession = daoSession; diff --git a/app/src/main/play/pl-PL/listing/fulldescription b/app/src/main/play/pl-PL/listing/fulldescription index 37163709..4af6238a 100644 --- a/app/src/main/play/pl-PL/listing/fulldescription +++ b/app/src/main/play/pl-PL/listing/fulldescription @@ -7,4 +7,4 @@ Wyróżnione cechy i funkcje: - Aktywne wsparcie i rozwój GitHub: https://github.com/wulkanowy/wulkanowy -Discord: https://discord.gg/JMG2rhJ +Discord: https://discord.gg/vccAQBr diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index ffb96b6d..8bce40fa 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,4 +1,4 @@ -Wersja 0.4.2: -- naprawiono logowanie do niestandardowych dzienników -- naprawiono synchronizację sprawdzianów -- naprawiono problemy z logowaniem (powinny występować rzadziej) +Wersja 0.4.3: +- naprawiono błąd z pokazywaniem usuniętych lekcji w planie +- naprawiono drobne błędy z wyrównaniem tekstu na starszych urządzeniach +- poprawiono synchronizację w tle spowodowaną błędem w komunikacji z serwerem From 859f8dc3197813e5da9ed5e6f88cdee7831882e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Wed, 23 May 2018 18:44:04 +0200 Subject: [PATCH 18/41] Avoid null if cell second div not contain span (#118) --- .../github/wulkanowy/api/timetable/Timetable.java | 6 ++++-- .../wulkanowy/api/timetable/TimetableTest.java | 1 + .../wulkanowy/api/timetable/PlanLekcji-full.html | 13 ++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 77ca41bd..3aaebf6b 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -98,8 +98,10 @@ public class Timetable { addLessonInfoFromElement(lesson, e.first()); break; case 2: - Element span = e.last().select("span").first(); - if (span.hasClass(LessonTypes.CLASS_MOVED_OR_CANCELED)) { + Element span = e.last().selectFirst("span"); + if (null == span) { + addLessonInfoFromElement(lesson, e.first()); + } else if (span.hasClass(LessonTypes.CLASS_MOVED_OR_CANCELED)) { lesson.setNewMovedInOrChanged(true); lesson.setDescription("poprzednio: " + getLessonAndGroupInfoFromSpan(span)[0]); addLessonInfoFromElement(lesson, e.first()); diff --git a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java index 8939b10f..b517436b 100644 --- a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java @@ -105,6 +105,7 @@ public class TimetableTest extends StudentAndParentTestCase { Assert.assertEquals("Zajęcia techniczne", std.getWeekTable().getDay(2).getLesson(4).getSubject()); Assert.assertEquals("Wychowanie fizyczne", std.getWeekTable().getDay(1).getLesson(1).getSubject()); Assert.assertEquals("Język angielski", full.getWeekTable().getDay(0).getLesson(1).getSubject()); + Assert.assertEquals("Wychowanie fizyczne", full.getWeekTable().getDay(0).getLesson(9).getSubject()); Assert.assertEquals("Wychowanie do życia w rodzinie", full.getWeekTable().getDay(2).getLesson(0).getSubject()); Assert.assertEquals("Wychowanie fizyczne", full.getWeekTable().getDay(3).getLesson(1).getSubject()); Assert.assertEquals("Uroczyste zakończenie roku szkolnego", full.getWeekTable().getDay(4).getLesson(0).getSubject()); diff --git a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html index 4bce6c93..14026d8f 100644 --- a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html +++ b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html @@ -461,7 +461,18 @@ 9 14:50 15:35 - + +
+ Wychowanie fizyczne [zaw2] + + + G3 + (przeniesiona z lekcji 7, 01.12.2017) +
+
+ +
+
Język niemiecki [J1] From 3592946e6f2d59be10b66cd10441bd99be109852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Wed, 23 May 2018 19:21:35 +0200 Subject: [PATCH 19/41] Fix api login(#119) --- api/src/main/java/io/github/wulkanowy/api/Client.java | 10 +++++----- .../java/io/github/wulkanowy/api/StudentAndParent.java | 6 +++--- .../main/java/io/github/wulkanowy/api/login/Login.java | 5 +++++ .../test/java/io/github/wulkanowy/api/ClientTest.java | 6 +++--- .../io/github/wulkanowy/api/StudentAndParentTest.java | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index 53300788..277b8039 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -118,7 +118,7 @@ public class Client { this.cookies.addItems(response.cookies()); - Document doc = checkForErrors(response.parse()); + Document doc = checkForErrors(response.parse(), response.statusCode()); if (loginBefore) { lastSuccessRequest = new Date(); @@ -144,7 +144,7 @@ public class Client { response.bufferUp(); // fixes cert parsing issues #109 - return checkForErrors(response.parse()); + return checkForErrors(response.parse(), response.statusCode()); } public String getJsonStringByUrl(String url) throws IOException, VulcanException { @@ -182,7 +182,7 @@ public class Client { return response.body(); } - Document checkForErrors(Document doc) throws VulcanException { + Document checkForErrors(Document doc, int code) throws VulcanException { lastSuccessRequest = null; String title = doc.select("title").text(); @@ -195,8 +195,8 @@ public class Client { throw new NotLoggedInErrorException(singIn); } - if (title.startsWith("Błąd")) { - throw new NotLoggedInErrorException(title + " " + doc.selectFirst("p, body")); + if ("Błąd strony".equals(title)) { + throw new NotLoggedInErrorException(title + " " + doc.selectFirst("p, body") + ", status: " + code); } return doc; diff --git a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java index 1acecfd3..16ee002e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java +++ b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java @@ -65,12 +65,12 @@ public class StudentAndParent implements SnP { return getBaseUrl(); } - // get url to uonetplus-opiekun.vulcan.net.pl + // get url to uonetplus-opiekun.fakelog.cf Document startPage = client.getPageByUrl(START_PAGE_URL); Element studentTileLink = startPage.select(".panel.linkownia.pracownik.klient > a").first(); if (null == studentTileLink) { - throw new NotLoggedInErrorException("You are probably not logged in. Force login"); + throw new VulcanException("Na pewno używasz konta z dostępem do Witryny ucznia i rodzica?"); } String snpPageUrl = studentTileLink.attr("href"); @@ -84,7 +84,7 @@ public class StudentAndParent implements SnP { String[] path = snpPageUrl.split(client.getHost())[1].split("/"); if (5 != path.length) { - throw new NotLoggedInErrorException("You are probably not logged in"); + throw new NotLoggedInErrorException("You are probably not logged in " + snpPageUrl); } return path[2]; diff --git a/api/src/main/java/io/github/wulkanowy/api/login/Login.java b/api/src/main/java/io/github/wulkanowy/api/login/Login.java index a734501e..04e1efc1 100644 --- a/api/src/main/java/io/github/wulkanowy/api/login/Login.java +++ b/api/src/main/java/io/github/wulkanowy/api/login/Login.java @@ -9,6 +9,7 @@ import org.jsoup.select.Elements; import java.io.IOException; import io.github.wulkanowy.api.Client; +import io.github.wulkanowy.api.NotLoggedInErrorException; import io.github.wulkanowy.api.VulcanException; public class Login { @@ -27,6 +28,10 @@ public class Login { public String login(String email, String password, String symbol) throws VulcanException, IOException { Document certDoc = sendCredentials(email, password); + if ("Błąd".equals(certDoc.title())) { + throw new NotLoggedInErrorException(certDoc.selectFirst("body").text()); + } + return sendCertificate(certDoc, symbol); } diff --git a/api/src/test/java/io/github/wulkanowy/api/ClientTest.java b/api/src/test/java/io/github/wulkanowy/api/ClientTest.java index 38f85617..50724875 100644 --- a/api/src/test/java/io/github/wulkanowy/api/ClientTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/ClientTest.java @@ -25,7 +25,7 @@ public class ClientTest { Document doc = Jsoup.parse(getFixtureAsString("login/Logowanie-success.html")); - Assert.assertEquals(doc, client.checkForErrors(doc)); + Assert.assertEquals(doc, client.checkForErrors(doc, 200)); } @Test(expected = VulcanOfflineException.class) @@ -34,7 +34,7 @@ public class ClientTest { Document doc = Jsoup.parse(getFixtureAsString("login/PrzerwaTechniczna.html")); - client.checkForErrors(doc); + client.checkForErrors(doc, 200); } @Test(expected = NotLoggedInErrorException.class) @@ -43,7 +43,7 @@ public class ClientTest { Document doc = Jsoup.parse(getFixtureAsString("login/Logowanie-notLoggedIn.html")); - client.checkForErrors(doc); + client.checkForErrors(doc, 200); } @Test diff --git a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java index 2b3d7250..387d18f5 100644 --- a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java @@ -53,7 +53,7 @@ public class StudentAndParentTest { snp.getSnpHomePageUrl()); } - @Test(expected = NotLoggedInErrorException.class) + @Test(expected = VulcanException.class) public void getSnpPageUrlWithWrongPage() throws Exception { Document wrongPageDocument = Jsoup.parse( FixtureHelper.getAsString(getClass().getResourceAsStream("OcenyWszystkie-semester.html")) From ef648c7f8b881eacf999588809c4d43aaf5db697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Thu, 24 May 2018 22:25:24 +0200 Subject: [PATCH 20/41] Clear db before register (#121) --- .../io/github/wulkanowy/data/sync/AccountSync.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java index a79540a6..27b497c7 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java @@ -2,6 +2,8 @@ package io.github.wulkanowy.data.sync; import android.content.Context; +import org.greenrobot.greendao.database.Database; + import java.io.IOException; import java.util.List; @@ -11,6 +13,7 @@ import javax.inject.Singleton; import io.github.wulkanowy.api.Vulcan; import io.github.wulkanowy.api.VulcanException; import io.github.wulkanowy.data.db.dao.entities.Account; +import io.github.wulkanowy.data.db.dao.entities.DaoMaster; import io.github.wulkanowy.data.db.dao.entities.DaoSession; import io.github.wulkanowy.data.db.dao.entities.Diary; import io.github.wulkanowy.data.db.dao.entities.DiaryDao; @@ -49,6 +52,8 @@ public class AccountSync { public void registerUser(String email, String password, String symbol) throws VulcanException, IOException, CryptoException { + clearUserData(); + vulcan.setCredentials(email, password, symbol, null, null, null); daoSession.getDatabase().beginTransaction(); @@ -152,4 +157,11 @@ public class AccountSync { diary.getValue() ); } + + private void clearUserData() { + Database database = daoSession.getDatabase(); + DaoMaster.dropAllTables(database, true); + DaoMaster.createAllTables(database, true); + sharedPref.setCurrentUserId(0); + } } From 34205e4a8b6b3d06da601e0ca094182151c1f501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Fri, 25 May 2018 11:49:53 +0200 Subject: [PATCH 21/41] Fix autofill on api lvl 26 (#122) --- app/src/main/res/layout/activity_login.xml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index ec3872da..4a6f08b2 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -61,13 +61,13 @@ android:id="@+id/login_activity_email_text_input" android:layout_width="match_parent" android:layout_height="wrap_content" + android:hint="@string/prompt_email" android:layout_marginBottom="12dp"> @@ -76,6 +76,7 @@ From ffe8511e3fb12e5c881bd5de72147bd93d441edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Fri, 25 May 2018 16:35:12 +0200 Subject: [PATCH 22/41] Add some fabric answers (#120) --- .../io/github/wulkanowy/WulkanowyApp.java | 10 ++++--- .../wulkanowy/data/db/dao/DbContract.java | 3 +++ .../wulkanowy/data/db/dao/DbRepository.java | 10 +++++-- .../wulkanowy/ui/login/LoginPresenter.java | 3 +++ .../attendance/AttendanceTabPresenter.java | 3 +++ .../ui/main/exams/ExamsTabPresenter.java | 3 +++ .../ui/main/grades/GradesPresenter.java | 13 +++++++-- .../main/timetable/TimetableTabPresenter.java | 4 ++- .../github/wulkanowy/utils/FabricUtils.java | 27 +++++++++++++++++++ build.gradle | 6 ++--- 10 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java index e4fd7ca9..2ecc5109 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java @@ -3,6 +3,7 @@ package io.github.wulkanowy; import android.app.Application; import com.crashlytics.android.Crashlytics; +import com.crashlytics.android.answers.Answers; import com.crashlytics.android.core.CrashlyticsCore; import com.jakewharton.threetenabp.AndroidThreeTen; @@ -61,9 +62,12 @@ public class WulkanowyApp extends Application { private void initializeFabric() { Fabric.with(new Fabric.Builder(this) - .kits(new Crashlytics.Builder() - .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) - .build()) + .kits( + new Crashlytics.Builder() + .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) + .build(), + new Answers() + ) .debuggable(BuildConfig.DEBUG) .build()); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java index 38115cc4..34541d3e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java @@ -4,6 +4,7 @@ import java.util.List; import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.db.dao.entities.Subject; +import io.github.wulkanowy.data.db.dao.entities.Symbol; import io.github.wulkanowy.data.db.dao.entities.Week; public interface DbContract { @@ -20,6 +21,8 @@ public interface DbContract { long getCurrentSymbolId(); + Symbol getCurrentSymbol(); + long getCurrentDiaryId(); long getSemesterId(int name); diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java index 6757c48e..43eee87e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java @@ -12,6 +12,7 @@ import io.github.wulkanowy.data.db.dao.entities.Semester; import io.github.wulkanowy.data.db.dao.entities.SemesterDao; import io.github.wulkanowy.data.db.dao.entities.StudentDao; import io.github.wulkanowy.data.db.dao.entities.Subject; +import io.github.wulkanowy.data.db.dao.entities.Symbol; import io.github.wulkanowy.data.db.dao.entities.SymbolDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; @@ -57,10 +58,15 @@ public class DbRepository implements DbContract { } @Override - public long getCurrentSymbolId() { + public Symbol getCurrentSymbol() { return daoSession.getSymbolDao().queryBuilder().where( SymbolDao.Properties.UserId.eq(sharedPref.getCurrentUserId()) - ).unique().getId(); + ).unique(); + } + + @Override + public long getCurrentSymbolId() { + return getCurrentSymbol().getId(); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java index 3140ad78..e5b37a6e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java @@ -11,6 +11,7 @@ import io.github.wulkanowy.api.login.BadCredentialsException; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.ui.base.BasePresenter; import io.github.wulkanowy.utils.AppConstant; +import io.github.wulkanowy.utils.FabricUtils; public class LoginPresenter extends BasePresenter implements LoginContract.Presenter { @@ -84,6 +85,7 @@ public class LoginPresenter extends BasePresenter @Override public void onEndAsync(boolean success, Exception exception) { if (success) { + FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol()); getView().openMainActivity(); return; } else if (exception instanceof BadCredentialsException) { @@ -93,6 +95,7 @@ public class LoginPresenter extends BasePresenter getView().setErrorSymbolRequired(); getView().showSoftInput(); } else { + FabricUtils.logRegister(false, symbol); getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java index 47927feb..72cab5d3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java @@ -10,6 +10,7 @@ import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; import io.github.wulkanowy.data.db.dao.entities.Day; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.ui.base.BasePresenter; +import io.github.wulkanowy.utils.FabricUtils; import io.github.wulkanowy.utils.async.AbstractTask; import io.github.wulkanowy.utils.async.AsyncListeners; @@ -88,6 +89,8 @@ public class AttendanceTabPresenter extends BasePresenter getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); } getView().hideRefreshingBar(); + + FabricUtils.logRefresh("Exams", result, date); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java index 0927d145..1e99bbde 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java @@ -1,5 +1,8 @@ package io.github.wulkanowy.ui.main.grades; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.CustomEvent; + import java.util.ArrayList; import java.util.List; @@ -10,6 +13,7 @@ import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.db.dao.entities.Subject; import io.github.wulkanowy.ui.base.BasePresenter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.utils.FabricUtils; import io.github.wulkanowy.utils.async.AbstractTask; import io.github.wulkanowy.utils.async.AsyncListeners; @@ -59,6 +63,9 @@ public class GradesPresenter extends BasePresenter getView().setCurrentSemester(which); reloadGrades(); + + Answers.getInstance().logCustom(new CustomEvent("Semester change") + .putCustomAttribute("Name", semesterName)); } private void reloadGrades() { @@ -100,8 +107,8 @@ public class GradesPresenter extends BasePresenter } @Override - public void onEndRefreshAsync(boolean success, Exception exception) { - if (success) { + public void onEndRefreshAsync(boolean result, Exception exception) { + if (result) { reloadGrades(); int numberOfNewGrades = getRepository().getDbRepo().getNewGrades(semesterName).size(); @@ -115,6 +122,8 @@ public class GradesPresenter extends BasePresenter getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); } getView().hideRefreshingBar(); + + FabricUtils.logRefresh("Grades", result, null); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java index ca582726..ef41c4c7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java @@ -1,6 +1,5 @@ package io.github.wulkanowy.ui.main.timetable; - import java.util.ArrayList; import java.util.List; @@ -11,6 +10,7 @@ import io.github.wulkanowy.data.db.dao.entities.Day; import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.ui.base.BasePresenter; +import io.github.wulkanowy.utils.FabricUtils; import io.github.wulkanowy.utils.async.AbstractTask; import io.github.wulkanowy.utils.async.AsyncListeners; @@ -91,6 +91,8 @@ public class TimetableTabPresenter extends BasePresenter Date: Fri, 25 May 2018 19:10:34 +0200 Subject: [PATCH 23/41] Stop refreshing while semester switching window open (#123) --- .../ui/main/grades/GradesContract.java | 2 ++ .../ui/main/grades/GradesFragment.java | 1 + .../ui/main/grades/GradesPresenter.java | 21 +++++++++++++------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java index a48b340d..07ca0d73 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java @@ -40,5 +40,7 @@ public interface GradesContract { void onStart(View view, OnFragmentIsReadyListener listener); void onSemesterChange(int which); + + void onSemesterSwitchActive(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java index 32c1f3d3..5a31736b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java @@ -80,6 +80,7 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_filter) { + presenter.onSemesterSwitchActive(); CharSequence[] items = new CharSequence[]{ getResources().getString(R.string.semester_text, 1), getResources().getString(R.string.semester_text, 2), diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java index 1e99bbde..493cc545 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.ui.main.grades; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; +import org.threeten.bp.LocalDate; + import java.util.ArrayList; import java.util.List; @@ -57,11 +59,15 @@ public class GradesPresenter extends BasePresenter } } + @Override + public void onSemesterSwitchActive() { + cancelAsyncTasks(); + } + @Override public void onSemesterChange(int which) { semesterName = which + 1; getView().setCurrentSemester(which); - reloadGrades(); Answers.getInstance().logCustom(new CustomEvent("Semester change") @@ -123,7 +129,7 @@ public class GradesPresenter extends BasePresenter } getView().hideRefreshingBar(); - FabricUtils.logRefresh("Grades", result, null); + FabricUtils.logRefresh("Grades", result, LocalDate.now().toString()); } @Override @@ -165,10 +171,7 @@ public class GradesPresenter extends BasePresenter listener.onFragmentIsReady(); } - @Override - public void onDestroy() { - isFirstSight = false; - + private void cancelAsyncTasks() { if (refreshTask != null) { refreshTask.cancel(true); refreshTask = null; @@ -177,6 +180,12 @@ public class GradesPresenter extends BasePresenter loadingTask.cancel(true); loadingTask = null; } + } + + @Override + public void onDestroy() { + isFirstSight = false; + cancelAsyncTasks(); super.onDestroy(); } } From 74c0dda999488fdcbc0f4cc133e81161f3de2adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Fri, 25 May 2018 20:14:16 +0200 Subject: [PATCH 24/41] Fix lesson description from warning (#124) --- .../io/github/wulkanowy/api/timetable/Timetable.java | 4 +++- .../github/wulkanowy/api/timetable/TimetableTest.java | 1 + .../wulkanowy/api/timetable/PlanLekcji-full.html | 11 ++++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 3aaebf6b..1373aee9 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -122,7 +122,9 @@ public class Timetable { Elements warn = e.select(".uwaga-panel"); if (!warn.isEmpty()) { - e.select(".x-treelabel-rlz").last().text("(" + warn.text() + ")"); + e.select("span").last() + .addClass("x-treelabel-rlz") + .text(warn.text()); e.remove(1); } } diff --git a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java index b517436b..1383b830 100644 --- a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java @@ -156,6 +156,7 @@ public class TimetableTest extends StudentAndParentTestCase { Assert.assertEquals("poprzednio: Wychowanie fizyczne", full.getWeekTable().getDay(4).getLesson(2).getDescription()); Assert.assertEquals("egzamin", full.getWeekTable().getDay(3).getLesson(0).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription()); + Assert.assertEquals("opis w uwadze bez klasy w spanie", full.getWeekTable().getDay(4).getLesson(4).getDescription()); Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getDescription()); } diff --git a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html index 14026d8f..c6ade3a5 100644 --- a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html +++ b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html @@ -319,7 +319,16 @@
- + +
+ Język polski + + 16 + (oddział nieobecny) +
+ +
opis w uwadze bez klasy w spanie
+ 5 From b59008a90f8dd31d8503fb017fc41f8ee4e45116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Fri, 25 May 2018 20:33:45 +0200 Subject: [PATCH 25/41] Version 0.4.4 --- app/build.gradle | 6 +++--- app/src/main/play/pl-PL/whatsnew | 9 +++++---- build.gradle | 4 +++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8a831d4f..35559640 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ buildscript { classpath "org.greenrobot:greendao-gradle-plugin:$greenDaoGradle" classpath "io.fabric.tools:gradle:$fabricGradle" classpath "com.google.gms:oss-licenses:0.9.2" - classpath 'com.github.triplet.gradle:play-publisher:1.2.0' + classpath "com.github.triplet.gradle:play-publisher:$playPublisher" } } @@ -41,8 +41,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 26 - versionCode 11 - versionName "0.4.3" + versionCode 12 + versionName "0.4.4" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true playAccountConfig = playAccountConfigs.defaultAccountConfig diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index 8bce40fa..dd43c504 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,4 +1,5 @@ -Wersja 0.4.3: -- naprawiono błąd z pokazywaniem usuniętych lekcji w planie -- naprawiono drobne błędy z wyrównaniem tekstu na starszych urządzeniach -- poprawiono synchronizację w tle spowodowaną błędem w komunikacji z serwerem +Wersja 0.4.4: +- naprawiono błędy w synchronizacji planu lekcji +- naprawiono błędy podczas pierwszego logowania +- naprawiono błąd podczas zmiany semestru +- kolejny raz poprawiono synchronizację w tle diff --git a/build.gradle b/build.gradle index 3be2d2d4..0f974657 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,9 @@ ext { fabricGradle = "1.25.4" crashlyticsSdk = "2.9.3" - crashlyticsAnswers = "1.4.1" + crashlyticsAnswers = "1.4.2" + + playPublisher = "1.2.2" } allprojects { From 3f1fff6d96fbdf6e156b49e33b88075bba21629e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 26 May 2018 20:44:06 +0200 Subject: [PATCH 26/41] Implementation of a new Dagger injection (#103) --- .../io/github/wulkanowy/WulkanowyApp.java | 23 ++-- .../wulkanowy/data/db/dao/DbHelper.java | 5 +- .../db/resources/ResourcesRepository.java | 3 +- .../data/db/shared/SharedPrefRepository.java | 5 +- .../wulkanowy/data/sync/AccountSync.java | 3 +- .../io/github/wulkanowy/di/AppComponent.java | 20 ++++ .../io/github/wulkanowy/di/AppModule.java | 78 ++++++++++++ .../io/github/wulkanowy/di/BuilderModule.java | 39 ++++++ .../di/annotations/ActivityContext.java | 11 -- .../di/annotations/ApplicationContext.java | 11 -- .../di/annotations/SharedPreferencesInfo.java | 11 -- .../di/component/ActivityComponent.java | 19 --- .../di/component/ApplicationComponent.java | 32 ----- .../di/component/FragmentComponent.java | 31 ----- .../wulkanowy/di/modules/ActivityModule.java | 64 ---------- .../di/modules/ApplicationModule.java | 111 ------------------ .../wulkanowy/di/modules/FragmentModule.java | 103 ---------------- .../{annotations => scopes}/PerActivity.java | 2 +- .../PerChildFragment.java} | 8 +- .../{annotations => scopes}/PerFragment.java | 2 +- .../wulkanowy/services/jobs/SyncJob.java | 4 +- .../widgets/TimetableWidgetServices.java | 10 +- .../wulkanowy/ui/base/BaseActivity.java | 72 +++++------- .../wulkanowy/ui/base/BaseContract.java | 15 +-- .../wulkanowy/ui/base/BaseFragment.java | 100 ++++------------ .../wulkanowy/ui/base/BasePresenter.java | 6 +- .../wulkanowy/ui/login/LoginActivity.java | 29 ++--- .../wulkanowy/ui/login/LoginContract.java | 5 - .../wulkanowy/ui/login/LoginModule.java | 13 ++ .../wulkanowy/ui/login/LoginPresenter.java | 8 +- .../wulkanowy/ui/main/MainActivity.java | 18 ++- .../wulkanowy/ui/main/MainContract.java | 6 +- .../github/wulkanowy/ui/main/MainModule.java | 50 ++++++++ .../wulkanowy/ui/main/MainPresenter.java | 10 +- .../main/attendance/AttendanceContract.java | 6 +- .../main/attendance/AttendanceFragment.java | 29 ++--- .../ui/main/attendance/AttendanceModule.java | 32 +++++ .../main/attendance/AttendancePresenter.java | 13 +- .../{ => tab}/AttendanceHeaderItem.java | 2 +- .../{ => tab}/AttendanceSubItem.java | 3 +- .../{ => tab}/AttendanceTabContract.java | 2 +- .../{ => tab}/AttendanceTabFragment.java | 39 ++---- .../attendance/tab/AttendanceTabModule.java | 21 ++++ .../{ => tab}/AttendanceTabPresenter.java | 17 +-- .../ui/main/exams/ExamsContract.java | 6 +- .../ui/main/exams/ExamsFragment.java | 26 ++-- .../wulkanowy/ui/main/exams/ExamsModule.java | 32 +++++ .../ui/main/exams/ExamsPresenter.java | 12 +- .../main/exams/{ => tab}/ExamsHeaderItem.java | 4 +- .../ui/main/exams/{ => tab}/ExamsSubItem.java | 3 +- .../exams/{ => tab}/ExamsTabContract.java | 4 +- .../exams/{ => tab}/ExamsTabFragment.java | 35 ++---- .../ui/main/exams/tab/ExamsTabModule.java | 21 ++++ .../exams/{ => tab}/ExamsTabPresenter.java | 18 +-- .../ui/main/grades/GradesContract.java | 5 +- .../ui/main/grades/GradesFragment.java | 30 ++--- .../ui/main/grades/GradesModule.java | 18 +++ .../ui/main/grades/GradesPresenter.java | 14 ++- .../ui/main/timetable/TimetableContract.java | 6 +- .../ui/main/timetable/TimetableFragment.java | 27 ++--- .../ui/main/timetable/TimetableModule.java | 32 +++++ .../ui/main/timetable/TimetablePresenter.java | 12 +- .../{ => tab}/TimetableHeaderItem.java | 2 +- .../timetable/{ => tab}/TimetableSubItem.java | 3 +- .../{ => tab}/TimetableTabContract.java | 2 +- .../{ => tab}/TimetableTabFragment.java | 36 ++---- .../timetable/tab/TimetableTabModule.java | 21 ++++ .../{ => tab}/TimetableTabPresenter.java | 17 +-- .../wulkanowy/ui/splash/SplashActivity.java | 10 +- .../wulkanowy/ui/splash/SplashContract.java | 3 - .../wulkanowy/ui/splash/SplashModule.java | 13 ++ .../wulkanowy/ui/splash/SplashPresenter.java | 4 +- .../ui/widgets/TimetableWidgetFactory.java | 17 +-- .../ui/widgets/TimetableWidgetProvider.java | 5 +- 74 files changed, 678 insertions(+), 851 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/di/AppComponent.java create mode 100644 app/src/main/java/io/github/wulkanowy/di/AppModule.java create mode 100644 app/src/main/java/io/github/wulkanowy/di/BuilderModule.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/annotations/ActivityContext.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/annotations/ApplicationContext.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/annotations/SharedPreferencesInfo.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/component/ActivityComponent.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/component/ApplicationComponent.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/modules/ActivityModule.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java rename app/src/main/java/io/github/wulkanowy/di/{annotations => scopes}/PerActivity.java (81%) rename app/src/main/java/io/github/wulkanowy/di/{annotations/DatabaseInfo.java => scopes/PerChildFragment.java} (51%) rename app/src/main/java/io/github/wulkanowy/di/{annotations => scopes}/PerFragment.java (81%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/login/LoginModule.java create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/MainModule.java create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceHeaderItem.java (99%) rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceSubItem.java (96%) rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceTabContract.java (92%) rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceTabFragment.java (76%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceTabPresenter.java (92%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsHeaderItem.java (96%) rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsSubItem.java (96%) rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsTabContract.java (83%) rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsTabFragment.java (74%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsTabPresenter.java (90%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableHeaderItem.java (98%) rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableSubItem.java (97%) rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableTabContract.java (92%) rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableTabFragment.java (78%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableTabPresenter.java (92%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/splash/SplashModule.java diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java index 2ecc5109..5b68abbf 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java @@ -1,7 +1,5 @@ package io.github.wulkanowy; -import android.app.Application; - import com.crashlytics.android.Crashlytics; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.core.CrashlyticsCore; @@ -11,18 +9,16 @@ import org.greenrobot.greendao.query.QueryBuilder; import javax.inject.Inject; +import dagger.android.AndroidInjector; +import dagger.android.support.DaggerApplication; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.utils.Log; import io.fabric.sdk.android.Fabric; import io.github.wulkanowy.data.RepositoryContract; -import io.github.wulkanowy.di.component.ApplicationComponent; -import io.github.wulkanowy.di.component.DaggerApplicationComponent; -import io.github.wulkanowy.di.modules.ApplicationModule; +import io.github.wulkanowy.di.DaggerAppComponent; import io.github.wulkanowy.utils.LogUtils; -public class WulkanowyApp extends Application { - - protected ApplicationComponent applicationComponent; +public class WulkanowyApp extends DaggerApplication { @Inject RepositoryContract repository; @@ -32,12 +28,6 @@ public class WulkanowyApp extends Application { super.onCreate(); AndroidThreeTen.init(this); - applicationComponent = DaggerApplicationComponent - .builder() - .applicationModule(new ApplicationModule(this)) - .build(); - applicationComponent.inject(this); - if (BuildConfig.DEBUG) { enableDebugLog(); } @@ -72,7 +62,8 @@ public class WulkanowyApp extends Application { .build()); } - public ApplicationComponent getApplicationComponent() { - return applicationComponent; + @Override + protected AndroidInjector applicationInjector() { + return DaggerAppComponent.builder().create(this); } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java index 97bb7559..7ffcfe27 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java @@ -12,6 +12,7 @@ import java.util.Comparator; import java.util.List; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import io.github.wulkanowy.api.Vulcan; @@ -21,8 +22,6 @@ import io.github.wulkanowy.data.db.dao.migrations.Migration26; import io.github.wulkanowy.data.db.dao.migrations.Migration27; import io.github.wulkanowy.data.db.dao.migrations.Migration28; import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.di.annotations.ApplicationContext; -import io.github.wulkanowy.di.annotations.DatabaseInfo; import io.github.wulkanowy.utils.LogUtils; @Singleton @@ -33,7 +32,7 @@ public class DbHelper extends DaoMaster.OpenHelper { private final Vulcan vulcan; @Inject - DbHelper(@ApplicationContext Context context, @DatabaseInfo String dbName, + DbHelper(Context context, @Named("dbName") String dbName, SharedPrefContract sharedPref, Vulcan vulcan) { super(context, dbName); this.sharedPref = sharedPref; diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java index a430e335..81aeaee2 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java @@ -15,7 +15,6 @@ import javax.inject.Singleton; import io.github.wulkanowy.R; import io.github.wulkanowy.api.NotLoggedInErrorException; import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; -import io.github.wulkanowy.di.annotations.ApplicationContext; import io.github.wulkanowy.utils.AppConstant; import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; @@ -26,7 +25,7 @@ public class ResourcesRepository implements ResourcesContract { private Resources resources; @Inject - ResourcesRepository(@ApplicationContext Context context) { + ResourcesRepository(Context context) { resources = context.getResources(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java index bf46ce35..11f43ca3 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java @@ -6,10 +6,9 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; -import io.github.wulkanowy.di.annotations.ApplicationContext; -import io.github.wulkanowy.di.annotations.SharedPreferencesInfo; import io.github.wulkanowy.ui.main.settings.SettingsFragment; @Singleton @@ -24,7 +23,7 @@ public class SharedPrefRepository implements SharedPrefContract { private final SharedPreferences settingsSharedPref; @Inject - SharedPrefRepository(@ApplicationContext Context context, @SharedPreferencesInfo String sharedName) { + SharedPrefRepository(Context context, @Named("sharedPrefName") String sharedName) { appSharedPref = context.getSharedPreferences(sharedName, Context.MODE_PRIVATE); settingsSharedPref = PreferenceManager.getDefaultSharedPreferences(context); } diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java index 27b497c7..032e95e4 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java @@ -23,7 +23,6 @@ import io.github.wulkanowy.data.db.dao.entities.StudentDao; import io.github.wulkanowy.data.db.dao.entities.Symbol; import io.github.wulkanowy.data.db.dao.entities.SymbolDao; import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.di.annotations.ApplicationContext; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; @@ -42,7 +41,7 @@ public class AccountSync { @Inject AccountSync(DaoSession daoSession, SharedPrefContract sharedPref, - Vulcan vulcan, @ApplicationContext Context context) { + Vulcan vulcan, Context context) { this.daoSession = daoSession; this.sharedPref = sharedPref; this.vulcan = vulcan; diff --git a/app/src/main/java/io/github/wulkanowy/di/AppComponent.java b/app/src/main/java/io/github/wulkanowy/di/AppComponent.java new file mode 100644 index 00000000..92f5d9a1 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/di/AppComponent.java @@ -0,0 +1,20 @@ +package io.github.wulkanowy.di; + +import javax.inject.Singleton; + +import dagger.Component; +import dagger.android.AndroidInjector; +import dagger.android.support.AndroidSupportInjectionModule; +import io.github.wulkanowy.WulkanowyApp; + +@Singleton +@Component(modules = { + AndroidSupportInjectionModule.class, + AppModule.class, + BuilderModule.class +}) +public interface AppComponent extends AndroidInjector { + @Component.Builder + abstract class Builder extends AndroidInjector.Builder { + } +} diff --git a/app/src/main/java/io/github/wulkanowy/di/AppModule.java b/app/src/main/java/io/github/wulkanowy/di/AppModule.java new file mode 100644 index 00000000..d6d4dfa2 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/di/AppModule.java @@ -0,0 +1,78 @@ +package io.github.wulkanowy.di; + +import android.content.Context; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import io.github.wulkanowy.WulkanowyApp; +import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.data.Repository; +import io.github.wulkanowy.data.RepositoryContract; +import io.github.wulkanowy.data.db.dao.DbContract; +import io.github.wulkanowy.data.db.dao.DbHelper; +import io.github.wulkanowy.data.db.dao.DbRepository; +import io.github.wulkanowy.data.db.dao.entities.DaoMaster; +import io.github.wulkanowy.data.db.dao.entities.DaoSession; +import io.github.wulkanowy.data.db.resources.ResourcesContract; +import io.github.wulkanowy.data.db.resources.ResourcesRepository; +import io.github.wulkanowy.data.db.shared.SharedPrefContract; +import io.github.wulkanowy.data.db.shared.SharedPrefRepository; +import io.github.wulkanowy.data.sync.SyncContract; +import io.github.wulkanowy.data.sync.SyncRepository; +import io.github.wulkanowy.utils.AppConstant; + +@Module +public abstract class AppModule { + + @Binds + abstract Context provideContext(WulkanowyApp app); + + @Singleton + @Binds + abstract RepositoryContract provideRepository(Repository repository); + + @Singleton + @Binds + abstract DbContract provideDatabse(DbRepository dbRepository); + + @Singleton + @Binds + abstract SharedPrefContract provideSharedPref(SharedPrefRepository sharedPrefRepository); + + @Singleton + @Binds + abstract SyncContract provideSync(SyncRepository syncRepository); + + @Singleton + @Binds + abstract ResourcesContract provideResources(ResourcesRepository resourcesRepository); + + @Singleton + @Provides + static DaoSession provideDaoSession(DbHelper dbHelper) { + return new DaoMaster(dbHelper.getWritableDb()).newSession(); + } + + @Singleton + @Provides + static Vulcan provideVulcan() { + return new Vulcan(); + } + + @Provides + @Named("dbName") + static String provideDbName() { + return AppConstant.DATABASE_NAME; + } + + @Provides + @Named("sharedPrefName") + static String provideSharedPrefName() { + return AppConstant.SHARED_PREFERENCES_NAME; + } + +} diff --git a/app/src/main/java/io/github/wulkanowy/di/BuilderModule.java b/app/src/main/java/io/github/wulkanowy/di/BuilderModule.java new file mode 100644 index 00000000..74b77d52 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/di/BuilderModule.java @@ -0,0 +1,39 @@ +package io.github.wulkanowy.di; + +import dagger.Module; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerActivity; +import io.github.wulkanowy.services.jobs.SyncJob; +import io.github.wulkanowy.services.widgets.TimetableWidgetServices; +import io.github.wulkanowy.ui.login.LoginActivity; +import io.github.wulkanowy.ui.login.LoginModule; +import io.github.wulkanowy.ui.main.MainActivity; +import io.github.wulkanowy.ui.main.MainModule; +import io.github.wulkanowy.ui.splash.SplashActivity; +import io.github.wulkanowy.ui.splash.SplashModule; +import io.github.wulkanowy.ui.widgets.TimetableWidgetProvider; + +@Module +abstract class BuilderModule { + + @PerActivity + @ContributesAndroidInjector(modules = SplashModule.class) + abstract SplashActivity bindSplashActivity(); + + @PerActivity + @ContributesAndroidInjector(modules = LoginModule.class) + abstract LoginActivity bindLoginActivity(); + + @PerActivity + @ContributesAndroidInjector(modules = MainModule.class) + abstract MainActivity bindMainActivity(); + + @ContributesAndroidInjector + abstract SyncJob bindSyncJob(); + + @ContributesAndroidInjector + abstract TimetableWidgetServices bindTimetableWidgetServices(); + + @ContributesAndroidInjector + abstract TimetableWidgetProvider bindTimetableWidgetProvider(); +} diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/ActivityContext.java b/app/src/main/java/io/github/wulkanowy/di/annotations/ActivityContext.java deleted file mode 100644 index 2a74c32d..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/ActivityContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.wulkanowy.di.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface ActivityContext { -} diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/ApplicationContext.java b/app/src/main/java/io/github/wulkanowy/di/annotations/ApplicationContext.java deleted file mode 100644 index 04139d99..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/ApplicationContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.wulkanowy.di.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface ApplicationContext { -} diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/SharedPreferencesInfo.java b/app/src/main/java/io/github/wulkanowy/di/annotations/SharedPreferencesInfo.java deleted file mode 100644 index 919c77a0..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/SharedPreferencesInfo.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.wulkanowy.di.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface SharedPreferencesInfo { -} diff --git a/app/src/main/java/io/github/wulkanowy/di/component/ActivityComponent.java b/app/src/main/java/io/github/wulkanowy/di/component/ActivityComponent.java deleted file mode 100644 index 3365a317..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/component/ActivityComponent.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.wulkanowy.di.component; - -import dagger.Component; -import io.github.wulkanowy.di.annotations.PerActivity; -import io.github.wulkanowy.di.modules.ActivityModule; -import io.github.wulkanowy.ui.login.LoginActivity; -import io.github.wulkanowy.ui.main.MainActivity; -import io.github.wulkanowy.ui.splash.SplashActivity; - -@PerActivity -@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) -public interface ActivityComponent { - - void inject(SplashActivity splashActivity); - - void inject(LoginActivity loginActivity); - - void inject(MainActivity mainActivity); -} diff --git a/app/src/main/java/io/github/wulkanowy/di/component/ApplicationComponent.java b/app/src/main/java/io/github/wulkanowy/di/component/ApplicationComponent.java deleted file mode 100644 index d4bf7bb7..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/component/ApplicationComponent.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.wulkanowy.di.component; - -import android.content.Context; - -import javax.inject.Singleton; - -import dagger.Component; -import io.github.wulkanowy.WulkanowyApp; -import io.github.wulkanowy.data.RepositoryContract; -import io.github.wulkanowy.di.annotations.ApplicationContext; -import io.github.wulkanowy.di.modules.ApplicationModule; -import io.github.wulkanowy.services.jobs.SyncJob; -import io.github.wulkanowy.ui.widgets.TimetableWidgetFactory; -import io.github.wulkanowy.ui.widgets.TimetableWidgetProvider; - -@Singleton -@Component(modules = ApplicationModule.class) -public interface ApplicationComponent { - - @ApplicationContext - Context getContext(); - - RepositoryContract getRepository(); - - void inject(WulkanowyApp wulkanowyApp); - - void inject(SyncJob syncJob); - - void inject(TimetableWidgetFactory timetableWidgetFactory); - - void inject(TimetableWidgetProvider timetableWidgetProvider); -} diff --git a/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java b/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java deleted file mode 100644 index 9f56364c..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.wulkanowy.di.component; - -import dagger.Component; -import io.github.wulkanowy.di.annotations.PerFragment; -import io.github.wulkanowy.di.modules.FragmentModule; -import io.github.wulkanowy.ui.main.attendance.AttendanceFragment; -import io.github.wulkanowy.ui.main.attendance.AttendanceTabFragment; -import io.github.wulkanowy.ui.main.exams.ExamsFragment; -import io.github.wulkanowy.ui.main.exams.ExamsTabFragment; -import io.github.wulkanowy.ui.main.grades.GradesFragment; -import io.github.wulkanowy.ui.main.timetable.TimetableFragment; -import io.github.wulkanowy.ui.main.timetable.TimetableTabFragment; - -@PerFragment -@Component(dependencies = ApplicationComponent.class, modules = FragmentModule.class) -public interface FragmentComponent { - - void inject(GradesFragment gradesFragment); - - void inject(AttendanceFragment attendanceFragment); - - void inject(AttendanceTabFragment attendanceTabFragment); - - void inject(ExamsFragment examsFragment); - - void inject(ExamsTabFragment examsTabFragment); - - void inject(TimetableFragment timetableFragment); - - void inject(TimetableTabFragment timetableTabFragment); -} diff --git a/app/src/main/java/io/github/wulkanowy/di/modules/ActivityModule.java b/app/src/main/java/io/github/wulkanowy/di/modules/ActivityModule.java deleted file mode 100644 index cdffe73a..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/modules/ActivityModule.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.wulkanowy.di.modules; - - -import android.content.Context; -import android.support.v7.app.AppCompatActivity; - -import dagger.Module; -import dagger.Provides; -import io.github.wulkanowy.di.annotations.ActivityContext; -import io.github.wulkanowy.di.annotations.PerActivity; -import io.github.wulkanowy.ui.base.BasePagerAdapter; -import io.github.wulkanowy.ui.login.LoginContract; -import io.github.wulkanowy.ui.login.LoginPresenter; -import io.github.wulkanowy.ui.main.MainContract; -import io.github.wulkanowy.ui.main.MainPresenter; -import io.github.wulkanowy.ui.splash.SplashContract; -import io.github.wulkanowy.ui.splash.SplashPresenter; - -@Module -public class ActivityModule { - - private AppCompatActivity activity; - - public ActivityModule(AppCompatActivity activity) { - this.activity = activity; - } - - @ActivityContext - @Provides - Context provideContext() { - return activity; - } - - @Provides - AppCompatActivity provideActivity() { - return activity; - } - - @PerActivity - @Provides - SplashContract.Presenter provideSplashPresenter - (SplashPresenter splashPresenter) { - return splashPresenter; - } - - @PerActivity - @Provides - LoginContract.Presenter provideLoginPresenter - (LoginPresenter loginPresenter) { - return loginPresenter; - } - - @PerActivity - @Provides - MainContract.Presenter provideMainPresenter - (MainPresenter mainPresenter) { - return mainPresenter; - } - - @Provides - BasePagerAdapter provideMainPagerAdapter() { - return new BasePagerAdapter(activity.getSupportFragmentManager()); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java b/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java deleted file mode 100644 index 7c2b3984..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java +++ /dev/null @@ -1,111 +0,0 @@ -package io.github.wulkanowy.di.modules; - -import android.app.Application; -import android.content.Context; - -import com.firebase.jobdispatcher.FirebaseJobDispatcher; -import com.firebase.jobdispatcher.GooglePlayDriver; - -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; -import io.github.wulkanowy.api.Vulcan; -import io.github.wulkanowy.data.Repository; -import io.github.wulkanowy.data.RepositoryContract; -import io.github.wulkanowy.data.db.dao.DbContract; -import io.github.wulkanowy.data.db.dao.DbHelper; -import io.github.wulkanowy.data.db.dao.DbRepository; -import io.github.wulkanowy.data.db.dao.entities.DaoMaster; -import io.github.wulkanowy.data.db.dao.entities.DaoSession; -import io.github.wulkanowy.data.db.resources.ResourcesContract; -import io.github.wulkanowy.data.db.resources.ResourcesRepository; -import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.data.db.shared.SharedPrefRepository; -import io.github.wulkanowy.data.sync.SyncContract; -import io.github.wulkanowy.data.sync.SyncRepository; -import io.github.wulkanowy.di.annotations.ApplicationContext; -import io.github.wulkanowy.di.annotations.DatabaseInfo; -import io.github.wulkanowy.di.annotations.SharedPreferencesInfo; -import io.github.wulkanowy.utils.AppConstant; - -@Module -public class ApplicationModule { - - private final Application application; - - public ApplicationModule(Application application) { - this.application = application; - } - - @Provides - Application provideApplication() { - return application; - } - - @ApplicationContext - @Provides - Context provideAppContext() { - return application; - } - - @DatabaseInfo - @Provides - String provideDatabaseName() { - return AppConstant.DATABASE_NAME; - } - - @SharedPreferencesInfo - @Provides - String provideSharedPreferencesName() { - return AppConstant.SHARED_PREFERENCES_NAME; - } - - @Singleton - @Provides - DaoSession provideDaoSession(DbHelper dbHelper) { - return new DaoMaster(dbHelper.getWritableDb()).newSession(); - } - - @Singleton - @Provides - Vulcan provideVulcan() { - return new Vulcan(); - } - - @Singleton - @Provides - RepositoryContract provideRepository(Repository repository) { - return repository; - } - - @Singleton - @Provides - SharedPrefContract provideSharedPref(SharedPrefRepository sharedPrefRepository) { - return sharedPrefRepository; - } - - @Singleton - @Provides - ResourcesContract provideAppResources(ResourcesRepository resourcesRepository) { - return resourcesRepository; - } - - - @Singleton - @Provides - DbContract provideDatabase(DbRepository dbRepository) { - return dbRepository; - } - - @Singleton - @Provides - SyncContract provideSync(SyncRepository syncRepository) { - return syncRepository; - } - - @Provides - FirebaseJobDispatcher provideDispatcher() { - return new FirebaseJobDispatcher(new GooglePlayDriver(application)); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java b/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java deleted file mode 100644 index 005b7aa1..00000000 --- a/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java +++ /dev/null @@ -1,103 +0,0 @@ -package io.github.wulkanowy.di.modules; - -import android.support.v4.app.Fragment; - -import dagger.Module; -import dagger.Provides; -import eu.davidea.flexibleadapter.FlexibleAdapter; -import io.github.wulkanowy.di.annotations.PerFragment; -import io.github.wulkanowy.ui.base.BasePagerAdapter; -import io.github.wulkanowy.ui.main.attendance.AttendanceContract; -import io.github.wulkanowy.ui.main.attendance.AttendanceHeaderItem; -import io.github.wulkanowy.ui.main.attendance.AttendancePresenter; -import io.github.wulkanowy.ui.main.attendance.AttendanceTabContract; -import io.github.wulkanowy.ui.main.attendance.AttendanceTabPresenter; -import io.github.wulkanowy.ui.main.exams.ExamsContract; -import io.github.wulkanowy.ui.main.exams.ExamsPresenter; -import io.github.wulkanowy.ui.main.exams.ExamsSubItem; -import io.github.wulkanowy.ui.main.exams.ExamsTabContract; -import io.github.wulkanowy.ui.main.exams.ExamsTabPresenter; -import io.github.wulkanowy.ui.main.grades.GradeHeaderItem; -import io.github.wulkanowy.ui.main.grades.GradesContract; -import io.github.wulkanowy.ui.main.grades.GradesPresenter; -import io.github.wulkanowy.ui.main.timetable.TimetableContract; -import io.github.wulkanowy.ui.main.timetable.TimetableHeaderItem; -import io.github.wulkanowy.ui.main.timetable.TimetablePresenter; -import io.github.wulkanowy.ui.main.timetable.TimetableTabContract; -import io.github.wulkanowy.ui.main.timetable.TimetableTabPresenter; - -@Module -public class FragmentModule { - - private final Fragment fragment; - - public FragmentModule(Fragment fragment) { - this.fragment = fragment; - } - - @PerFragment - @Provides - GradesContract.Presenter provideGradesPresenter(GradesPresenter gradesPresenter) { - return gradesPresenter; - } - - @PerFragment - @Provides - AttendanceContract.Presenter provideAttendancePresenter(AttendancePresenter attendancePresenter) { - return attendancePresenter; - } - - @PerFragment - @Provides - ExamsContract.Presenter provideDashboardPresenter(ExamsPresenter examsPresenter) { - return examsPresenter; - } - - @PerFragment - @Provides - AttendanceTabContract.Presenter provideAttendanceTabPresenter(AttendanceTabPresenter timetableTabPresenter) { - return timetableTabPresenter; - } - - @Provides - BasePagerAdapter provideBasePagerAdapter() { - return new BasePagerAdapter(fragment.getChildFragmentManager()); - } - - @Provides - FlexibleAdapter provideAttendanceTabAdapter() { - return new FlexibleAdapter<>(null); - } - - @Provides - FlexibleAdapter provideTimetableTabAdapter() { - return new FlexibleAdapter<>(null); - } - - @Provides - FlexibleAdapter provideGradesAdapter() { - return new FlexibleAdapter<>(null); - } - - @Provides - FlexibleAdapter provideExamAdapter() { - return new FlexibleAdapter<>(null); - } - - @PerFragment - @Provides - TimetableContract.Presenter provideTimetablePresenter(TimetablePresenter timetablePresenter) { - return timetablePresenter; - } - - @PerFragment - @Provides - TimetableTabContract.Presenter provideTimetableTabPresenter(TimetableTabPresenter timetableTabPresenter) { - return timetableTabPresenter; - } - - @Provides - ExamsTabContract.Presenter provideExamsTabPresenter(ExamsTabPresenter examsTabPresenter) { - return examsTabPresenter; - } -} diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/PerActivity.java b/app/src/main/java/io/github/wulkanowy/di/scopes/PerActivity.java similarity index 81% rename from app/src/main/java/io/github/wulkanowy/di/annotations/PerActivity.java rename to app/src/main/java/io/github/wulkanowy/di/scopes/PerActivity.java index f103994a..c9fc8a5b 100644 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/PerActivity.java +++ b/app/src/main/java/io/github/wulkanowy/di/scopes/PerActivity.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.di.annotations; +package io.github.wulkanowy.di.scopes; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/DatabaseInfo.java b/app/src/main/java/io/github/wulkanowy/di/scopes/PerChildFragment.java similarity index 51% rename from app/src/main/java/io/github/wulkanowy/di/annotations/DatabaseInfo.java rename to app/src/main/java/io/github/wulkanowy/di/scopes/PerChildFragment.java index fabcefba..67a9f820 100644 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/DatabaseInfo.java +++ b/app/src/main/java/io/github/wulkanowy/di/scopes/PerChildFragment.java @@ -1,11 +1,11 @@ -package io.github.wulkanowy.di.annotations; +package io.github.wulkanowy.di.scopes; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import javax.inject.Qualifier; +import javax.inject.Scope; -@Qualifier +@Scope @Retention(RetentionPolicy.RUNTIME) -public @interface DatabaseInfo { +public @interface PerChildFragment { } diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/PerFragment.java b/app/src/main/java/io/github/wulkanowy/di/scopes/PerFragment.java similarity index 81% rename from app/src/main/java/io/github/wulkanowy/di/annotations/PerFragment.java rename to app/src/main/java/io/github/wulkanowy/di/scopes/PerFragment.java index 98f364f7..a4d37c38 100644 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/PerFragment.java +++ b/app/src/main/java/io/github/wulkanowy/di/scopes/PerFragment.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.di.annotations; +package io.github.wulkanowy.di.scopes; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java index ab79034f..432bdc23 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java @@ -20,8 +20,8 @@ import java.util.List; import javax.inject.Inject; +import dagger.android.AndroidInjection; import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.sync.NotRegisteredUserException; @@ -60,7 +60,7 @@ public class SyncJob extends SimpleJobService { @Override public void onCreate() { super.onCreate(); - ((WulkanowyApp) getApplication()).getApplicationComponent().inject(this); + AndroidInjection.inject(this); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetServices.java b/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetServices.java index 728cc805..f442542e 100644 --- a/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetServices.java +++ b/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetServices.java @@ -3,12 +3,20 @@ package io.github.wulkanowy.services.widgets; import android.content.Intent; import android.widget.RemoteViewsService; +import javax.inject.Inject; + +import dagger.android.AndroidInjection; +import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.ui.widgets.TimetableWidgetFactory; public class TimetableWidgetServices extends RemoteViewsService { + @Inject + RepositoryContract repository; + @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { - return new TimetableWidgetFactory(getApplicationContext()); + AndroidInjection.inject(this); + return new TimetableWidgetFactory(getApplicationContext(), repository); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.java b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.java index c5c66df0..50796816 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.java @@ -1,35 +1,51 @@ package io.github.wulkanowy.ui.base; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatDelegate; -import android.widget.Toast; +import android.view.View; +import butterknife.ButterKnife; import butterknife.Unbinder; +import dagger.android.support.DaggerAppCompatActivity; import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; -import io.github.wulkanowy.di.component.ActivityComponent; -import io.github.wulkanowy.di.component.DaggerActivityComponent; -import io.github.wulkanowy.di.modules.ActivityModule; import io.github.wulkanowy.utils.NetworkUtils; -public abstract class BaseActivity extends AppCompatActivity implements BaseContract.View { - - private ActivityComponent activityComponent; +public abstract class BaseActivity extends DaggerAppCompatActivity implements BaseContract.View { private Unbinder unbinder; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); + } - activityComponent = DaggerActivityComponent.builder() - .activityModule(new ActivityModule(this)) - .applicationComponent(((WulkanowyApp) getApplication()).getApplicationComponent()) - .build(); + protected void injectViews() { + unbinder = ButterKnife.bind(this); + } + + @Override + public void showMessage(@NonNull String text) { + if (getMessageView() != null) { + Snackbar.make(getMessageView(), text, Snackbar.LENGTH_LONG).show(); + } + } + + @Override + public void showNoNetworkMessage() { + showMessage(getString(R.string.noInternet_text)); + } + + @Override + public boolean isNetworkConnected() { + return NetworkUtils.isOnline(getApplicationContext()); + } + + protected View getMessageView() { + return null; } @Override @@ -39,32 +55,4 @@ public abstract class BaseActivity extends AppCompatActivity implements BaseCont unbinder.unbind(); } } - - @Override - public void onError(int resId) { - onError(getString(resId)); - } - - @Override - public void onError(String message) { - Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onNoNetworkError() { - onError(R.string.noInternet_text); - } - - @Override - public boolean isNetworkConnected() { - return NetworkUtils.isOnline(getApplicationContext()); - } - - public ActivityComponent getActivityComponent() { - return activityComponent; - } - - public void setButterKnife(Unbinder unbinder) { - this.unbinder = unbinder; - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseContract.java b/app/src/main/java/io/github/wulkanowy/ui/base/BaseContract.java index 2a4dc569..3bfa40d1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseContract.java @@ -1,27 +1,22 @@ package io.github.wulkanowy.ui.base; -import android.support.annotation.StringRes; - -import io.github.wulkanowy.di.annotations.PerActivity; +import android.support.annotation.NonNull; public interface BaseContract { interface View { - void onError(@StringRes int resId); + void showMessage(@NonNull String text); - void onError(String message); - - void onNoNetworkError(); + void showNoNetworkMessage(); boolean isNetworkConnected(); } - @PerActivity interface Presenter { - void onStart(V view); + void attachView(@NonNull V view); - void onDestroy(); + void detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.java b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.java index efb9d61a..e2a5a9e0 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.java @@ -1,56 +1,20 @@ package io.github.wulkanowy.ui.base; -import android.content.Context; -import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; +import android.support.annotation.StringRes; import android.view.View; +import butterknife.ButterKnife; import butterknife.Unbinder; -import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; -import io.github.wulkanowy.di.component.DaggerFragmentComponent; -import io.github.wulkanowy.di.component.FragmentComponent; -import io.github.wulkanowy.di.modules.FragmentModule; +import dagger.android.support.DaggerFragment; +import io.github.wulkanowy.utils.NetworkUtils; -public abstract class BaseFragment extends Fragment implements BaseContract.View { - - private BaseActivity activity; +public abstract class BaseFragment extends DaggerFragment implements BaseContract.View { private Unbinder unbinder; - private FragmentComponent fragmentComponent; - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof BaseActivity) { - activity = (BaseActivity) context; - } - - fragmentComponent = DaggerFragmentComponent.builder() - .fragmentModule(new FragmentModule(this)) - .applicationComponent(((WulkanowyApp) activity.getApplication()).getApplicationComponent()) - .build(); - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(false); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setUpOnViewCreated(view); - } - - @Override - public void onDetach() { - activity = null; - super.onDetach(); + protected void injectViews(@NonNull View view) { + unbinder = ButterKnife.bind(this, view); } @Override @@ -61,44 +25,32 @@ public abstract class BaseFragment extends Fragment implements BaseContract.View super.onDestroyView(); } - @Override - public void onError(int resId) { - onError(getString(resId)); - } - - @Override - public void onError(String message) { - if (activity != null) { - activity.onError(message); + public void setTitle(String title) { + if (getActivity() != null) { + getActivity().setTitle(title); } } @Override - public void onNoNetworkError() { - onError(R.string.noInternet_text); + public void showMessage(@NonNull String text) { + if (getActivity() != null) { + ((BaseActivity) getActivity()).showMessage(text); + } + } + + public void showMessage(@StringRes int stringId) { + showMessage(getString(stringId)); + } + + @Override + public void showNoNetworkMessage() { + if (getActivity() != null) { + ((BaseActivity) getActivity()).showNoNetworkMessage(); + } } @Override public boolean isNetworkConnected() { - return activity != null && activity.isNetworkConnected(); - } - - public void setButterKnife(Unbinder unbinder) { - this.unbinder = unbinder; - } - - public void setTitle(String title) { - if (activity != null) { - activity.setTitle(title); - } - } - - public FragmentComponent getFragmentComponent() { - return fragmentComponent; - } - - - protected void setUpOnViewCreated(View fragmentView) { - // do something on view created + return NetworkUtils.isOnline(getContext()); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.java b/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.java index 611b7a29..8f9b8af0 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.base; +import android.support.annotation.NonNull; + import javax.inject.Inject; import io.github.wulkanowy.data.RepositoryContract; @@ -16,12 +18,12 @@ public class BasePresenter implements BaseContract. } @Override - public void onStart(V view) { + public void attachView(@NonNull V view) { this.view = view; } @Override - public void onDestroy() { + public void detachView() { view = null; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java index 9d6e8b12..37f3e03e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java @@ -5,7 +5,7 @@ import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.design.widget.Snackbar; +import android.support.annotation.NonNull; import android.support.design.widget.TextInputLayout; import android.support.v7.app.ActionBar; import android.view.View; @@ -18,7 +18,6 @@ import android.widget.TextView; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnEditorAction; import io.github.wulkanowy.R; @@ -64,14 +63,10 @@ public class LoginActivity extends BaseActivity implements LoginContract.View { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); + injectViews(); - setButterKnife(ButterKnife.bind(this)); - getActivityComponent().inject(this); - - presenter.onStart(this); - + presenter.attachView(this); setUpOnCreate(); - } protected void setUpOnCreate() { @@ -165,12 +160,6 @@ public class LoginActivity extends BaseActivity implements LoginContract.View { KeyboardUtils.hideSoftInput(this); } - @Override - public void onError(String message) { - Snackbar.make(findViewById(R.id.login_activity_container), message, - Snackbar.LENGTH_LONG).show(); - } - @Override public void setStepOneLoginProgress() { onLoginProgressUpdate("1", getString(R.string.step_login)); @@ -222,13 +211,19 @@ public class LoginActivity extends BaseActivity implements LoginContract.View { } } + @NonNull @Override - public void onDestroy() { - super.onDestroy(); - presenter.onDestroy(); + protected View getMessageView() { + return findViewById(R.id.login_activity_container); } private void onLoginProgressUpdate(String step, String message) { loginProgressText.setText(String.format("%1$s/2 - %2$s...", step, message)); } + + @Override + public void onDestroy() { + presenter.detachView(); + super.onDestroy(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java index 570e1b26..10f27f03 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java @@ -1,7 +1,5 @@ package io.github.wulkanowy.ui.login; -import io.github.wulkanowy.data.RepositoryContract; -import io.github.wulkanowy.di.annotations.PerActivity; import io.github.wulkanowy.ui.base.BaseContract; public interface LoginContract { @@ -37,7 +35,6 @@ public interface LoginContract { } - @PerActivity interface Presenter extends BaseContract.Presenter { void attemptLogin(String email, String password, String symbol); @@ -51,7 +48,5 @@ public interface LoginContract { void onEndAsync(boolean success, Exception exception); void onCanceledAsync(); - - RepositoryContract getRepository(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginModule.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginModule.java new file mode 100644 index 00000000..0cb26c49 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginModule.java @@ -0,0 +1,13 @@ +package io.github.wulkanowy.ui.login; + +import dagger.Binds; +import dagger.Module; +import io.github.wulkanowy.di.scopes.PerActivity; + +@Module +public abstract class LoginModule { + + @PerActivity + @Binds + abstract LoginContract.Presenter provideLoginPresenter(LoginPresenter loginPresenter); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java index e5b37a6e..fb63e6af 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java @@ -47,7 +47,7 @@ public class LoginPresenter extends BasePresenter loginAsync.execute(); } else { - getView().onNoNetworkError(); + getView().showNoNetworkMessage(); } getView().hideSoftInput(); @@ -96,7 +96,7 @@ public class LoginPresenter extends BasePresenter getView().showSoftInput(); } else { FabricUtils.logRegister(false, symbol); - getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); + getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } getView().showActionBar(true); @@ -160,11 +160,11 @@ public class LoginPresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { if (loginAsync != null) { loginAsync.cancel(true); loginAsync = null; } - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java index 6b7d07cf..f00f57c2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.view.View; @@ -13,9 +14,9 @@ import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem; import com.aurelhubert.ahbottomnavigation.AHBottomNavigationViewPager; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.ui.base.BaseActivity; @@ -40,6 +41,7 @@ public class MainActivity extends BaseActivity implements MainContract.View, @BindView(R.id.main_activity_progress_bar) View progressBar; + @Named("Main") @Inject BasePagerAdapter pagerAdapter; @@ -55,11 +57,9 @@ public class MainActivity extends BaseActivity implements MainContract.View, super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); + injectViews(); - getActivityComponent().inject(this); - setButterKnife(ButterKnife.bind(this)); - - presenter.onStart(this, getIntent().getIntExtra(EXTRA_CARD_ID_KEY, -1)); + presenter.attachView(this, getIntent().getIntExtra(EXTRA_CARD_ID_KEY, -1)); } @Override @@ -146,9 +146,15 @@ public class MainActivity extends BaseActivity implements MainContract.View, SyncJob.start(getApplicationContext(), interval, useOnlyWifi); } + @NonNull + @Override + protected View getMessageView() { + return findViewById(R.id.main_activity_view_pager); + } + @Override protected void onDestroy() { + presenter.detachView(); super.onDestroy(); - presenter.onDestroy(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java index cc326654..cb4e29e4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.main; -import io.github.wulkanowy.di.annotations.PerActivity; +import android.support.annotation.NonNull; + import io.github.wulkanowy.ui.base.BaseContract; public interface MainContract { @@ -22,10 +23,9 @@ public interface MainContract { void startSyncService(int interval, boolean useOnlyWifi); } - @PerActivity interface Presenter extends BaseContract.Presenter { - void onStart(View view, int tabPositionIntent); + void attachView(@NonNull View view, int initTabId); void onTabSelected(int position, boolean wasSelected); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.java new file mode 100644 index 00000000..ff3fed67 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.java @@ -0,0 +1,50 @@ +package io.github.wulkanowy.ui.main; + +import javax.inject.Named; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerActivity; +import io.github.wulkanowy.di.scopes.PerFragment; +import io.github.wulkanowy.ui.base.BasePagerAdapter; +import io.github.wulkanowy.ui.main.attendance.AttendanceFragment; +import io.github.wulkanowy.ui.main.attendance.AttendanceModule; +import io.github.wulkanowy.ui.main.exams.ExamsFragment; +import io.github.wulkanowy.ui.main.exams.ExamsModule; +import io.github.wulkanowy.ui.main.grades.GradesFragment; +import io.github.wulkanowy.ui.main.grades.GradesModule; +import io.github.wulkanowy.ui.main.timetable.TimetableFragment; +import io.github.wulkanowy.ui.main.timetable.TimetableModule; + +@Module +public abstract class MainModule { + + @PerActivity + @Binds + abstract MainContract.Presenter provideMainPresenter(MainPresenter mainPresenter); + + @Named("Main") + @PerActivity + @Provides + static BasePagerAdapter provideAdapter(MainActivity activity) { + return new BasePagerAdapter(activity.getSupportFragmentManager()); + } + + @PerFragment + @ContributesAndroidInjector(modules = GradesModule.class) + abstract GradesFragment bindsGradesFragment(); + + @PerFragment + @ContributesAndroidInjector(modules = TimetableModule.class) + abstract TimetableFragment bindTimetableFragment(); + + @PerFragment + @ContributesAndroidInjector(modules = ExamsModule.class) + abstract ExamsFragment bindExamsFragment(); + + @PerFragment + @ContributesAndroidInjector(modules = AttendanceModule.class) + abstract AttendanceFragment bindAttendanceFramgnet(); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java index ba5e41d8..c6741c3e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java @@ -1,6 +1,8 @@ package io.github.wulkanowy.ui.main; +import android.support.annotation.NonNull; + import javax.inject.Inject; import io.github.wulkanowy.data.RepositoryContract; @@ -17,15 +19,15 @@ public class MainPresenter extends BasePresenter } @Override - public void onStart(MainContract.View view, int tabPositionIntent) { - super.onStart(view); + public void attachView(@NonNull MainContract.View view, int initTabId) { + super.attachView(view); getView().showProgressBar(true); getView().hideActionBar(); int tabPosition; - if (tabPositionIntent != -1) { - tabPosition = tabPositionIntent; + if (initTabId != -1) { + tabPosition = initTabId; } else { tabPosition = getRepository().getSharedRepo().getStartupTab(); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java index daee63d2..1ad66787 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.main.attendance; -import io.github.wulkanowy.di.annotations.PerActivity; +import android.support.annotation.NonNull; + import io.github.wulkanowy.ui.base.BaseContract; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; @@ -21,12 +22,11 @@ public interface AttendanceContract { void setThemeForTab(int position); } - @PerActivity interface Presenter extends BaseContract.Presenter { void onFragmentActivated(boolean isVisible); - void onStart(View view, OnFragmentIsReadyListener listener); + void attachView(@NonNull View view, OnFragmentIsReadyListener listener); void setRestoredPosition(int position); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java index e26c9fc7..732806db 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java @@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.main.attendance; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; @@ -11,14 +10,14 @@ import android.view.View; import android.view.ViewGroup; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.attendance.tab.AttendanceTabFragment; public class AttendanceFragment extends BaseFragment implements AttendanceContract.View { @@ -31,6 +30,7 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra TabLayout tabLayout; @Inject + @Named("Attendance") BasePagerAdapter pagerAdapter; @Inject @@ -41,18 +41,13 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_attendance, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - presenter.onStart(this, (OnFragmentIsReadyListener) getActivity()); + presenter.attachView(this, (OnFragmentIsReadyListener) getActivity()); - if (savedInstanceState != null) { - presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); - } + if (savedInstanceState != null) { + presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); } - return view; } @@ -93,14 +88,6 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra setTitle(getString(R.string.attendance_text)); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(CURRENT_ITEM_KEY, viewPager.getCurrentItem()); @@ -109,7 +96,7 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceModule.java new file mode 100644 index 00000000..8679cf10 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceModule.java @@ -0,0 +1,32 @@ +package io.github.wulkanowy.ui.main.attendance; + +import javax.inject.Named; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerChildFragment; +import io.github.wulkanowy.di.scopes.PerFragment; +import io.github.wulkanowy.ui.base.BasePagerAdapter; +import io.github.wulkanowy.ui.main.attendance.tab.AttendanceTabFragment; +import io.github.wulkanowy.ui.main.attendance.tab.AttendanceTabModule; + +@Module +public abstract class AttendanceModule { + + @PerFragment + @Binds + abstract AttendanceContract.Presenter provideAttendancePresenter(AttendancePresenter attendancePresenter); + + @PerFragment + @Named("Attendance") + @Provides + static BasePagerAdapter providePagerAdapter(AttendanceFragment fragment) { + return new BasePagerAdapter(fragment.getChildFragmentManager()); + } + + @PerChildFragment + @ContributesAndroidInjector(modules = AttendanceTabModule.class) + abstract AttendanceTabFragment bindAttendanceTabFragment(); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java index 55541ed2..9cfb1384 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.main.attendance; +import android.support.annotation.NonNull; + import java.util.ArrayList; import java.util.List; @@ -31,8 +33,8 @@ public class AttendancePresenter extends BasePresenter } @Override - public void onStart(AttendanceContract.View view, OnFragmentIsReadyListener listener) { - super.onStart(view); + public void attachView(@NonNull AttendanceContract.View view, OnFragmentIsReadyListener listener) { + super.attachView(view); this.listener = listener; if (getView().isMenuVisible()) { @@ -64,7 +66,7 @@ public class AttendancePresenter extends BasePresenter } @Override - public void onDoInBackgroundLoading() throws Exception { + public void onDoInBackgroundLoading() { for (String date : dates) { getView().setTabDataToAdapter(date); } @@ -92,14 +94,13 @@ public class AttendancePresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; if (loadingTask != null) { loadingTask.cancel(true); loadingTask = null; } - - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java similarity index 99% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java index b7e6aecd..1c55f40c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; import android.content.Context; import android.content.res.TypedArray; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java similarity index 96% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java index 440d878e..6b6246d2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; import android.content.Context; import android.support.v4.app.DialogFragment; @@ -20,6 +20,7 @@ import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.viewholders.FlexibleViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; +import io.github.wulkanowy.ui.main.attendance.AttendanceDialogFragment; class AttendanceSubItem extends AbstractSectionableItem { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java similarity index 92% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java index dcb16bf8..d7c45904 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; import java.util.List; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java similarity index 76% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java index e5e65bb9..7b5ad1ce 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java @@ -1,9 +1,8 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -15,11 +14,9 @@ import java.util.List; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; public class AttendanceTabFragment extends BaseFragment implements AttendanceTabContract.View, @@ -61,34 +58,28 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_attendance_tab, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - - if (getArguments() != null) { - presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); - } - - presenter.onStart(this); - presenter.onFragmentActivated(isFragmentVisible); + if (getArguments() != null) { + presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); } + + presenter.attachView(this); + presenter.onFragmentActivated(isFragmentVisible); return view; } @Override - protected void setUpOnViewCreated(View fragmentView) { + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { adapter.setAutoCollapseOnExpand(true); adapter.setAutoScrollOnExpand(true); adapter.expandItemsAtStartUp(); - recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); refreshLayout.setColorSchemeResources(android.R.color.black); refreshLayout.setOnRefreshListener(this); - } @Override @@ -112,7 +103,7 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab @Override public void onRefreshSuccess() { - onError(R.string.sync_completed); + showMessage(R.string.sync_completed); } @Override @@ -130,17 +121,9 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab noItemView.setVisibility(show ? View.VISIBLE : View.INVISIBLE); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java new file mode 100644 index 00000000..01bb9aa4 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.main.attendance.tab; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import io.github.wulkanowy.di.scopes.PerChildFragment; + +@Module +public abstract class AttendanceTabModule { + + @PerChildFragment + @Binds + abstract AttendanceTabContract.Presenter provideAttendanceTabPresenter(AttendanceTabPresenter attendanceTabPresenter); + + @PerChildFragment + @Provides + static FlexibleAdapter provideAdapter() { + return new FlexibleAdapter<>(null); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java similarity index 92% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java index 72cab5d3..787b6eb9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java @@ -1,4 +1,6 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; + +import android.support.annotation.NonNull; import java.util.ArrayList; import java.util.List; @@ -34,8 +36,9 @@ public class AttendanceTabPresenter extends BasePresenter { - void onStart(View view, OnFragmentIsReadyListener listener); + void attachView(@NonNull View view, OnFragmentIsReadyListener listener); void onFragmentActivated(boolean isVisible); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java index cab3b902..50325798 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java @@ -10,14 +10,15 @@ import android.view.View; import android.view.ViewGroup; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.exams.tab.ExamsTabFragment; public class ExamsFragment extends BaseFragment implements ExamsContract.View { @@ -30,6 +31,7 @@ public class ExamsFragment extends BaseFragment implements ExamsContract.View { TabLayout tabLayout; @Inject + @Named("Exams") BasePagerAdapter pagerAdapter; @Inject @@ -39,16 +41,12 @@ public class ExamsFragment extends BaseFragment implements ExamsContract.View { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_exams, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - presenter.onStart(this, (OnFragmentIsReadyListener) getActivity()); + presenter.attachView(this, (OnFragmentIsReadyListener) getActivity()); - if (savedInstanceState != null) { - presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); - } + if (savedInstanceState != null) { + presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); } return view; } @@ -61,14 +59,6 @@ public class ExamsFragment extends BaseFragment implements ExamsContract.View { } } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void setActivityTitle() { setTitle(getString(R.string.exams_text)); @@ -107,6 +97,6 @@ public class ExamsFragment extends BaseFragment implements ExamsContract.View { @Override public void onDestroyView() { super.onDestroyView(); - presenter.onDestroy(); + presenter.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsModule.java new file mode 100644 index 00000000..8d56cf23 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsModule.java @@ -0,0 +1,32 @@ +package io.github.wulkanowy.ui.main.exams; + +import javax.inject.Named; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerChildFragment; +import io.github.wulkanowy.di.scopes.PerFragment; +import io.github.wulkanowy.ui.base.BasePagerAdapter; +import io.github.wulkanowy.ui.main.exams.tab.ExamsTabFragment; +import io.github.wulkanowy.ui.main.exams.tab.ExamsTabModule; + +@Module +public abstract class ExamsModule { + + @PerFragment + @Binds + abstract ExamsContract.Presenter provideExamsPresneter(ExamsPresenter examsPresenter); + + @Named("Exams") + @PerFragment + @Provides + static BasePagerAdapter providePagerAdapter(ExamsFragment fragment) { + return new BasePagerAdapter(fragment.getChildFragmentManager()); + } + + @PerChildFragment + @ContributesAndroidInjector(modules = ExamsTabModule.class) + abstract ExamsTabFragment bindExamsTabFragment(); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsPresenter.java index 5f6cd4dc..a5bd1055 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsPresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.main.exams; +import android.support.annotation.NonNull; + import java.util.ArrayList; import java.util.List; @@ -31,8 +33,8 @@ public class ExamsPresenter extends BasePresenter } @Override - public void onStart(ExamsContract.View view, OnFragmentIsReadyListener listener) { - super.onStart(view); + public void attachView(@NonNull ExamsContract.View view, OnFragmentIsReadyListener listener) { + super.attachView(view); this.listener = listener; if (getView().isMenuVisible()) { @@ -69,7 +71,7 @@ public class ExamsPresenter extends BasePresenter } @Override - public void onDoInBackgroundLoading() throws Exception { + public void onDoInBackgroundLoading() { for (String date : dates) { getView().setTabDataToAdapter(date); } @@ -91,13 +93,13 @@ public class ExamsPresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; if (loadingTask != null) { loadingTask.cancel(true); loadingTask = null; } - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsHeaderItem.java similarity index 96% rename from app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsHeaderItem.java index 86070515..e1d71990 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsHeaderItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.exams; +package io.github.wulkanowy.ui.main.exams.tab; import android.view.View; import android.widget.TextView; @@ -22,7 +22,7 @@ public class ExamsHeaderItem extends AbstractHeaderItem { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabContract.java similarity index 83% rename from app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabContract.java rename to app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabContract.java index ec59628a..4e0785bb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabContract.java @@ -1,8 +1,7 @@ -package io.github.wulkanowy.ui.main.exams; +package io.github.wulkanowy.ui.main.exams.tab; import java.util.List; -import io.github.wulkanowy.di.annotations.PerFragment; import io.github.wulkanowy.ui.base.BaseContract; public interface ExamsTabContract { @@ -20,7 +19,6 @@ public interface ExamsTabContract { void updateAdapterList(List headerItems); } - @PerFragment interface Presenter extends BaseContract.Presenter { void onFragmentActivated(boolean isSelected); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabFragment.java similarity index 74% rename from app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java rename to app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabFragment.java index d41e34d2..1b6f361a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabFragment.java @@ -1,8 +1,7 @@ -package io.github.wulkanowy.ui.main.exams; +package io.github.wulkanowy.ui.main.exams.tab; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -14,11 +13,9 @@ import java.util.List; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.View, @@ -60,26 +57,21 @@ public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.V @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_exams_tab, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - - if (getArguments() != null) { - presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); - } - presenter.onStart(this); - presenter.onFragmentActivated(isFragmentVisible); + if (getArguments() != null) { + presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); } + presenter.attachView(this); + presenter.onFragmentActivated(isFragmentVisible); return view; } @Override - protected void setUpOnViewCreated(View fragmentView) { + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { adapter.setDisplayHeadersAtStartUp(true); - recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); refreshLayout.setColorSchemeResources(android.R.color.black); @@ -107,7 +99,7 @@ public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.V @Override public void onRefreshSuccess() { - onError(R.string.sync_completed); + showMessage(R.string.sync_completed); } @Override @@ -125,17 +117,10 @@ public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.V progressBar.setVisibility(show ? View.VISIBLE : View.INVISIBLE); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabModule.java new file mode 100644 index 00000000..fc9a7595 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabModule.java @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.main.exams.tab; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import io.github.wulkanowy.di.scopes.PerChildFragment; + +@Module +public abstract class ExamsTabModule { + + @PerChildFragment + @Binds + abstract ExamsTabContract.Presenter provideExamsTabPresenter(ExamsTabPresenter examsTabPresenter); + + @PerChildFragment + @Provides + static FlexibleAdapter provideAdapter() { + return new FlexibleAdapter<>(null); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java similarity index 90% rename from app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabPresenter.java rename to app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java index 5925b357..062c0fd8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java @@ -1,4 +1,6 @@ -package io.github.wulkanowy.ui.main.exams; +package io.github.wulkanowy.ui.main.exams.tab; + +import android.support.annotation.NonNull; import java.util.ArrayList; import java.util.List; @@ -29,13 +31,13 @@ public class ExamsTabPresenter extends BasePresenter private boolean isFirstSight = false; @Inject - public ExamsTabPresenter(RepositoryContract repository) { + ExamsTabPresenter(RepositoryContract repository) { super(repository); } @Override - public void onStart(ExamsTabContract.View view) { - super.onStart(view); + public void attachView(@NonNull ExamsTabContract.View view) { + super.attachView(view); getView().showProgressBar(true); getView().showNoItem(false); } @@ -65,7 +67,7 @@ public class ExamsTabPresenter extends BasePresenter refreshTask.setOnRefreshListener(this); refreshTask.execute(); } else { - getView().onNoNetworkError(); + getView().showNoNetworkMessage(); getView().hideRefreshingBar(); } } @@ -91,7 +93,7 @@ public class ExamsTabPresenter extends BasePresenter getView().onRefreshSuccess(); } else { - getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); + getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } getView().hideRefreshingBar(); @@ -157,9 +159,9 @@ public class ExamsTabPresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; cancelAsyncTasks(); - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java index 07ca0d73..5583f98c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java @@ -1,10 +1,10 @@ package io.github.wulkanowy.ui.main.grades; +import android.support.annotation.NonNull; import android.support.v4.widget.SwipeRefreshLayout; import java.util.List; -import io.github.wulkanowy.di.annotations.PerActivity; import io.github.wulkanowy.ui.base.BaseContract; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; @@ -30,14 +30,13 @@ public interface GradesContract { } - @PerActivity interface Presenter extends BaseContract.Presenter { void onFragmentVisible(boolean isVisible); void onRefresh(); - void onStart(View view, OnFragmentIsReadyListener listener); + void attachView(@NonNull View view, OnFragmentIsReadyListener listener); void onSemesterChange(int which); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java index 5a31736b..09c0a1bb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java @@ -4,7 +4,6 @@ import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AlertDialog; import android.support.v7.widget.RecyclerView; @@ -20,11 +19,9 @@ import java.util.List; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; @@ -55,14 +52,9 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_grades, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - presenter.onStart(this, (OnFragmentIsReadyListener) getActivity()); - } - + presenter.attachView(this, (OnFragmentIsReadyListener) getActivity()); return view; } @@ -102,14 +94,14 @@ public class GradesFragment extends BaseFragment implements GradesContract.View } @Override - protected void setUpOnViewCreated(View fragmentView) { + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { noItemView.setVisibility(View.GONE); adapter.setAutoCollapseOnExpand(true); adapter.setAutoScrollOnExpand(true); adapter.expandItemsAtStartUp(); - recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); refreshLayout.setColorSchemeResources(android.R.color.black); @@ -155,25 +147,17 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public void onRefreshSuccessNoGrade() { - onError(R.string.snackbar_no_grades); + showMessage(R.string.snackbar_no_grades); } @Override public void onRefreshSuccess(int number) { - onError(getString(R.string.snackbar_new_grade, number)); - } - - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } + showMessage(getString(R.string.snackbar_new_grade, number)); } @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java new file mode 100644 index 00000000..edf00d3b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java @@ -0,0 +1,18 @@ +package io.github.wulkanowy.ui.main.grades; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import eu.davidea.flexibleadapter.FlexibleAdapter; + +@Module +public abstract class GradesModule { + + @Binds + abstract GradesContract.Presenter provideGradesPresenter(GradesPresenter gradesPresenter); + + @Provides + static FlexibleAdapter provideGradesAdapter() { + return new FlexibleAdapter<>(null); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java index 493cc545..ee6e0cb3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.main.grades; +import android.support.annotation.NonNull; + import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; @@ -41,8 +43,8 @@ public class GradesPresenter extends BasePresenter } @Override - public void onStart(GradesContract.View view, OnFragmentIsReadyListener listener) { - super.onStart(view); + public void attachView(@NonNull GradesContract.View view, OnFragmentIsReadyListener listener) { + super.attachView(view); this.listener = listener; if (getView().isMenuVisible()) { @@ -94,7 +96,7 @@ public class GradesPresenter extends BasePresenter refreshTask.setOnRefreshListener(this); refreshTask.execute(); } else { - getView().onNoNetworkError(); + getView().showNoNetworkMessage(); getView().hideRefreshingBar(); } } @@ -125,7 +127,7 @@ public class GradesPresenter extends BasePresenter getView().onRefreshSuccess(numberOfNewGrades); } } else { - getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); + getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } getView().hideRefreshingBar(); @@ -183,9 +185,9 @@ public class GradesPresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; cancelAsyncTasks(); - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java index 57eca17e..8344ad76 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.main.timetable; -import io.github.wulkanowy.di.annotations.PerFragment; +import android.support.annotation.NonNull; + import io.github.wulkanowy.ui.base.BaseContract; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; @@ -21,12 +22,11 @@ public interface TimetableContract { void setThemeForTab(int position); } - @PerFragment interface Presenter extends BaseContract.Presenter { void onFragmentActivated(boolean isVisible); - void onStart(View view, OnFragmentIsReadyListener listener); + void attachView(@NonNull View view, OnFragmentIsReadyListener listener); void setRestoredPosition(int position); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java index 6c5fd501..24960bd3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java @@ -11,14 +11,14 @@ import android.view.View; import android.view.ViewGroup; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.timetable.tab.TimetableTabFragment; public class TimetableFragment extends BaseFragment implements TimetableContract.View { @@ -30,6 +30,7 @@ public class TimetableFragment extends BaseFragment implements TimetableContract @BindView(R.id.timetable_fragment_tab_layout) TabLayout tabLayout; + @Named("Timetable") @Inject BasePagerAdapter pagerAdapter; @@ -40,16 +41,12 @@ public class TimetableFragment extends BaseFragment implements TimetableContract @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_timetable, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - presenter.onStart(this, (OnFragmentIsReadyListener) getActivity()); + presenter.attachView(this, (OnFragmentIsReadyListener) getActivity()); - if (savedInstanceState != null) { - presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); - } + if (savedInstanceState != null) { + presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); } return view; } @@ -91,14 +88,6 @@ public class TimetableFragment extends BaseFragment implements TimetableContract setTitle(getString(R.string.timetable_text)); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(CURRENT_ITEM_KEY, viewPager.getCurrentItem()); @@ -107,7 +96,7 @@ public class TimetableFragment extends BaseFragment implements TimetableContract @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableModule.java new file mode 100644 index 00000000..9ad1ee60 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableModule.java @@ -0,0 +1,32 @@ +package io.github.wulkanowy.ui.main.timetable; + +import javax.inject.Named; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerChildFragment; +import io.github.wulkanowy.di.scopes.PerFragment; +import io.github.wulkanowy.ui.base.BasePagerAdapter; +import io.github.wulkanowy.ui.main.timetable.tab.TimetableTabFragment; +import io.github.wulkanowy.ui.main.timetable.tab.TimetableTabModule; + +@Module +public abstract class TimetableModule { + + @Named("Timetable") + @PerFragment + @Provides + static BasePagerAdapter providePagerAdapter(TimetableFragment fragment) { + return new BasePagerAdapter(fragment.getChildFragmentManager()); + } + + @PerFragment + @Binds + abstract TimetableContract.Presenter provideTimetablePresenter(TimetablePresenter timetablePresenter); + + @PerChildFragment + @ContributesAndroidInjector(modules = TimetableTabModule.class) + abstract TimetableTabFragment bindTimetableTabFragment(); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java index d9c9c9c6..8c9bfaba 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.main.timetable; +import android.support.annotation.NonNull; + import java.util.ArrayList; import java.util.List; @@ -31,8 +33,8 @@ public class TimetablePresenter extends BasePresenter } @Override - public void onStart(TimetableContract.View view, OnFragmentIsReadyListener listener) { - super.onStart(view); + public void attachView(@NonNull TimetableContract.View view, OnFragmentIsReadyListener listener) { + super.attachView(view); this.listener = listener; if (getView().isMenuVisible()) { @@ -64,7 +66,7 @@ public class TimetablePresenter extends BasePresenter } @Override - public void onDoInBackgroundLoading() throws Exception { + public void onDoInBackgroundLoading() { for (String date : dates) { getView().setTabDataToAdapter(date); } @@ -91,13 +93,13 @@ public class TimetablePresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; if (loadingTask != null) { loadingTask.cancel(true); loadingTask = null; } - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java similarity index 98% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java index b98636b1..7e932f78 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; import android.content.Context; import android.content.res.TypedArray; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java similarity index 97% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java index a3e84dfa..4d64b54b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; import android.content.Context; import android.graphics.Paint; @@ -21,6 +21,7 @@ import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.viewholders.FlexibleViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; +import io.github.wulkanowy.ui.main.timetable.TimetableDialogFragment; public class TimetableSubItem diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java similarity index 92% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabContract.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java index 0d6bdf2a..7eeb4b81 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; import java.util.List; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java similarity index 78% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabFragment.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java index 53d9a67b..6000cc6c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; import android.os.Bundle; import android.support.annotation.NonNull; @@ -16,11 +16,9 @@ import java.util.List; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; public class TimetableTabFragment extends BaseFragment implements TimetableTabContract.View, @@ -65,33 +63,27 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_timetable_tab, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - - if (getArguments() != null) { - presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); - } - presenter.onStart(this); - presenter.onFragmentActivated(isFragmentVisible); + if (getArguments() != null) { + presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); } + presenter.attachView(this); + presenter.onFragmentActivated(isFragmentVisible); return view; } @Override - protected void setUpOnViewCreated(View fragmentView) { + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { adapter.setAutoCollapseOnExpand(true); adapter.setAutoScrollOnExpand(true); adapter.expandItemsAtStartUp(); - recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); refreshLayout.setColorSchemeResources(android.R.color.black); refreshLayout.setOnRefreshListener(this); - } @Override @@ -120,7 +112,7 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo @Override public void onRefreshSuccess() { - onError(R.string.sync_completed); + showMessage(R.string.sync_completed); } @Override @@ -138,17 +130,9 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo noItemView.setVisibility(show ? View.VISIBLE : View.INVISIBLE); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java new file mode 100644 index 00000000..3e1645f3 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.main.timetable.tab; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import io.github.wulkanowy.di.scopes.PerChildFragment; + +@Module +public abstract class TimetableTabModule { + + @PerChildFragment + @Binds + abstract TimetableTabContract.Presenter provideTimetableTabPresneter(TimetableTabPresenter timetableTabPresenter); + + @PerChildFragment + @Provides + static FlexibleAdapter provideTimetableAdapter() { + return new FlexibleAdapter<>(null); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java similarity index 92% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java index ef41c4c7..51464b2e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java @@ -1,4 +1,7 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; + + +import android.support.annotation.NonNull; import java.util.ArrayList; import java.util.List; @@ -36,8 +39,8 @@ public class TimetableTabPresenter extends BasePresenter { } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashModule.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashModule.java new file mode 100644 index 00000000..838b411d --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashModule.java @@ -0,0 +1,13 @@ +package io.github.wulkanowy.ui.splash; + +import dagger.Binds; +import dagger.Module; +import io.github.wulkanowy.di.scopes.PerActivity; + +@Module +public abstract class SplashModule { + + @PerActivity + @Binds + abstract SplashContract.Presenter provideSplashPresenter(SplashPresenter splashPresenter); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java index 8d20226f..ff64b3ca 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java @@ -16,8 +16,8 @@ public class SplashPresenter extends BasePresenter } @Override - public void onStart(@NonNull SplashContract.View activity) { - super.onStart(activity); + public void attachView(@NonNull SplashContract.View view) { + super.attachView(view); getView().cancelNotifications(); if (getRepository().getSharedRepo().isUserLoggedIn()) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java index 78e80580..2a858b90 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java +++ b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java @@ -12,10 +12,7 @@ import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; - import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; import io.github.wulkanowy.data.db.dao.entities.Week; @@ -23,22 +20,17 @@ import io.github.wulkanowy.utils.TimeUtils; public class TimetableWidgetFactory implements RemoteViewsService.RemoteViewsFactory { - private Context context; + private final Context context; private List lessonList = new ArrayList<>(); - @Inject - RepositoryContract repository; + private final RepositoryContract repository; - public TimetableWidgetFactory(Context context) { + public TimetableWidgetFactory(Context context, RepositoryContract repository) { this.context = context; + this.repository = repository; } - private void inject() { - if (repository == null) { - ((WulkanowyApp) context).getApplicationComponent().inject(this); - } - } @Override public void onCreate() { @@ -47,7 +39,6 @@ public class TimetableWidgetFactory implements RemoteViewsService.RemoteViewsFac @Override public void onDataSetChanged() { - inject(); lessonList = new ArrayList<>(); if (repository.getSharedRepo().isUserLoggedIn()) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetProvider.java b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetProvider.java index d68c7e9a..84f618a6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetProvider.java +++ b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetProvider.java @@ -11,8 +11,8 @@ import android.widget.RemoteViews; import javax.inject.Inject; +import dagger.android.AndroidInjection; import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.services.widgets.TimetableWidgetServices; import io.github.wulkanowy.ui.main.MainActivity; @@ -26,7 +26,6 @@ public class TimetableWidgetProvider extends AppWidgetProvider { RepositoryContract repository; @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { inject(context); @@ -106,7 +105,7 @@ public class TimetableWidgetProvider extends AppWidgetProvider { private void inject(Context context) { if (repository == null) { - ((WulkanowyApp) context.getApplicationContext()).getApplicationComponent().inject(this); + AndroidInjection.inject(this, context); } } } From b4c765b482b1e401c1170ccb51cb241c1cb25a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 28 May 2018 11:29:43 +0200 Subject: [PATCH 27/41] [API] Fix timetable endpoint (#125) --- .../main/java/io/github/wulkanowy/api/timetable/Timetable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 1373aee9..4668149c 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -19,7 +19,7 @@ import io.github.wulkanowy.api.generic.Week; public class Timetable { - private static final String TIMETABLE_PAGE_URL = "Lekcja.mvc/PlanLekcji?data="; + private static final String TIMETABLE_PAGE_URL = "Lekcja.mvc/PlanZajec?data="; private SnP snp; From d4b172e022f50a4ca74615dd9e623733691f49e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 28 May 2018 11:32:39 +0200 Subject: [PATCH 28/41] Version 0.4.5 --- app/build.gradle | 4 ++-- app/src/main/play/pl-PL/whatsnew | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 35559640..50677a7a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,8 +41,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 26 - versionCode 12 - versionName "0.4.4" + versionCode 13 + versionName "0.4.5" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true playAccountConfig = playAccountConfigs.defaultAccountConfig diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index dd43c504..b24edfaa 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,5 +1,2 @@ -Wersja 0.4.4: -- naprawiono błędy w synchronizacji planu lekcji -- naprawiono błędy podczas pierwszego logowania -- naprawiono błąd podczas zmiany semestru -- kolejny raz poprawiono synchronizację w tle +Wersja 0.4.5: +- naprawiono logownie From 306092ce45f118fb32c3c2d6e4d284771eb7405c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Wed, 30 May 2018 11:57:29 +0200 Subject: [PATCH 29/41] Add mobile access API (#126) --- api/build.gradle | 29 +++++++++++ .../java/io/github/wulkanowy/api/Vulcan.java | 10 ++++ .../wulkanowy/api/mobile/RegisterDevice.kt | 33 +++++++++++++ .../wulkanowy/api/mobile/RegisteredDevices.kt | 48 +++++++++++++++++++ .../wulkanowy/api/mobile/RegisterDevice.kt | 17 +++++++ .../api/mobile/RegisteredDevicesListTest.kt | 37 ++++++++++++++ .../api/mobile/DostepMobilny-filled.html | 44 +++++++++++++++++ .../wulkanowy/api/mobile/Rejestruj.html | 26 ++++++++++ 8 files changed, 244 insertions(+) create mode 100644 api/src/main/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt create mode 100644 api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt create mode 100644 api/src/test/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt create mode 100644 api/src/test/java/io/github/wulkanowy/api/mobile/RegisteredDevicesListTest.kt create mode 100644 api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html create mode 100644 api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html diff --git a/api/build.gradle b/api/build.gradle index 001d2579..f247baf1 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'java-library' +apply plugin: 'kotlin' apply plugin: 'org.sonarqube' apply plugin: 'jacoco' apply plugin: 'com.jfrog.bintray' @@ -32,6 +33,8 @@ dependencies { implementation "org.apache.commons:commons-lang3:$apacheLang" implementation "com.google.code.gson:gson:$gson" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + testImplementation "junit:junit:$junit" testImplementation "org.mockito:mockito-core:$mockito" } @@ -115,3 +118,29 @@ artifacts { archives sourcesJar archives javadocJar } + +buildscript { + ext.kotlin_version = '1.2.41' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +repositories { + mavenCentral() +} + +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} + +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java index d90d3874..c8c4d2b0 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java +++ b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java @@ -8,6 +8,8 @@ import io.github.wulkanowy.api.exams.ExamsWeek; import io.github.wulkanowy.api.grades.GradesList; import io.github.wulkanowy.api.grades.SubjectsList; import io.github.wulkanowy.api.messages.Messages; +import io.github.wulkanowy.api.mobile.RegisterDevice; +import io.github.wulkanowy.api.mobile.RegisteredDevices; import io.github.wulkanowy.api.notes.AchievementsList; import io.github.wulkanowy.api.notes.NotesList; import io.github.wulkanowy.api.school.SchoolInfo; @@ -108,6 +110,14 @@ public class Vulcan { return new FamilyInformation(getStudentAndParent()); } + public RegisteredDevices getRegisteredDevices() throws VulcanException, IOException { + return new RegisteredDevices(getStudentAndParent()); + } + + public RegisterDevice getRegisterDevice() throws VulcanException, IOException { + return new RegisterDevice(getStudentAndParent()); + } + public Messages getMessages() throws VulcanException { return new Messages(getClient()); } diff --git a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt new file mode 100644 index 00000000..f0da01e9 --- /dev/null +++ b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt @@ -0,0 +1,33 @@ +package io.github.wulkanowy.api.mobile + +import io.github.wulkanowy.api.SnP +import org.jsoup.nodes.Element + +class RegisterDevice(private val snp: SnP) { + + companion object { + const val REGISTER_URL = "DostepMobilny.mvc/Rejestruj" + } + + data class Token( + val token: String, + val symbol: String, + val pin: String + ) + + fun getToken(): Token { + val form = snp.getSnPPageDocument(REGISTER_URL).selectFirst("#rejestracja-formularz") + + val fields = form.select(".blockElement") + + return Token( + getValue(fields[1]), + getValue(fields[2]), + getValue(fields[3]) + ) + } + + fun getValue(e: Element): String { + return e.text().split(":")[1].trim() + } +} diff --git a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt new file mode 100644 index 00000000..cd08a585 --- /dev/null +++ b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt @@ -0,0 +1,48 @@ +package io.github.wulkanowy.api.mobile + +import io.github.wulkanowy.api.SnP +import java.text.SimpleDateFormat +import java.util.* + +class RegisteredDevices(private val snp: SnP) { + + companion object { + const val DEVICES_LIST_URL = "DostepMobilny.mvc" + } + + data class Device( + val name: String, + val system: String, + val date: String, + val id: Int + ) + + fun getList(): List { + val items = snp.getSnPPageDocument(DEVICES_LIST_URL).select("table tbody tr") + val devices: MutableList = mutableListOf() + + for (item in items) { + val cells = item.select("td") + val system = cells[0].text().split("(").last().removeSuffix(")") + + devices.add(Device( + cells[0].text().replace(" ($system)", ""), + system, + formatDate(cells[1].text()), + cells[2].select("a").attr("href") + .split("/").last().toInt() + )) + } + + return devices + } + + // TODO: Move to date utils + private fun formatDate(date: String): String { + val sdf = SimpleDateFormat("dd.MM.yyyy 'godz:' HH:mm:ss", Locale.ROOT) + val d = sdf.parse(date) + sdf.applyPattern("yyyy-MM-dd HH:mm:ss") + + return sdf.format(d) + } +} diff --git a/api/src/test/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt b/api/src/test/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt new file mode 100644 index 00000000..f67310c8 --- /dev/null +++ b/api/src/test/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt @@ -0,0 +1,17 @@ +package io.github.wulkanowy.api.mobile + +import io.github.wulkanowy.api.StudentAndParentTestCase +import org.junit.Assert.assertEquals +import org.junit.Test + +class RegisterDeviceTest : StudentAndParentTestCase() { + + @Test + fun getTokenTest() { + val registration = RegisterDevice(getSnp("Rejestruj.html")) + + assertEquals("3S1A1B2C", registration.getToken().token) + assertEquals("Default", registration.getToken().symbol) + assertEquals("1234567", registration.getToken().pin) + } +} diff --git a/api/src/test/java/io/github/wulkanowy/api/mobile/RegisteredDevicesListTest.kt b/api/src/test/java/io/github/wulkanowy/api/mobile/RegisteredDevicesListTest.kt new file mode 100644 index 00000000..3cd8b97c --- /dev/null +++ b/api/src/test/java/io/github/wulkanowy/api/mobile/RegisteredDevicesListTest.kt @@ -0,0 +1,37 @@ +package io.github.wulkanowy.api.mobile + +import io.github.wulkanowy.api.StudentAndParentTestCase +import org.junit.Assert.assertEquals +import org.junit.Test + +class RegisteredDevicesListTest : StudentAndParentTestCase() { + + private val filled = RegisteredDevices(getSnp("DostepMobilny-filled.html")) + + @Test + fun getListTest() { + assertEquals(2, filled.getList().size) + } + + @Test + fun getNameTest() { + assertEquals("google Android SDK built for x86", filled.getList()[0].name) + assertEquals("google (Android SDK) built for x86", filled.getList()[1].name) + } + + @Test + fun getSystemTest() { + assertEquals("Android 8.1.0", filled.getList()[0].system) + assertEquals("Android 8.1.0", filled.getList()[1].system) + } + + @Test + fun getDateTest() { + assertEquals("2018-01-20 22:35:30", filled.getList()[0].date) + } + + @Test + fun getIdTest() { + assertEquals(321, filled.getList()[0].id) + } +} diff --git a/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html b/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html new file mode 100644 index 00000000..9fbfd403 --- /dev/null +++ b/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html @@ -0,0 +1,44 @@ + + + + + Witryna ucznia i rodzica – dostęp mobilny + + + +
+

Dostęp mobilny

+ +
+

Zarejestrowane urządzenia

+
+ + + + + + + + + + + + + + + + + + + + +
UrządzenieData rejestracji
google Android SDK built for x86 (Android 8.1.0)20.01.2018 godz: 22:35:30 + Wyrejestruj +
google (Android SDK) built for x86 (Android 8.1.0)20.01.2018 godz: 22:35:30 + Wyrejestruj +
+
+ +
wersja: 18.01.0001.27311
+ + diff --git a/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html b/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html new file mode 100644 index 00000000..15d08d07 --- /dev/null +++ b/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html @@ -0,0 +1,26 @@ + + + + + Witryna ucznia i rodzica – Rejestracja urządzenia mobilnego + + + +
+

Rejestracja urządzenia mobilnego

+
+ Za pomocą aplikacji "Dzienniczek+" zeskanuj kod QR. + Kod QR + Token: 3S1A1B2C + Symbol: Default + PIN: 1234567 +
+
+
wersja: 18.01.0001.27311
+ + From 228f680e5d461ddfca7bc336fabf00740a09c574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 31 May 2018 23:01:52 +0200 Subject: [PATCH 30/41] Hide empty fields in summary (#128) --- .../ui/main/grades/GradeHeaderItem.java | 111 +++++++++--------- 1 file changed, 53 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java index 5d0fd073..33e96189 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java @@ -118,57 +118,13 @@ public class GradeHeaderItem item.getFinalRating())); resetViews(); - toggleSummaryText(); toggleSubjectText(); + toggleSummary(); alertImage.setVisibility(isSubItemsReadAndSaveAlertView(subItems) ? View.INVISIBLE : View.VISIBLE); } - @Override - public void onClick(View view) { - super.onClick(view); - toggleSubjectText(); - toggleSummaryText(); - } - - private void toggleSummaryText() { - if (isSummaryToggleable()) { - if (isExpand()) { - AnimationUtils.slideDown(predictedText); - AnimationUtils.slideDown(finalText); - } else { - AnimationUtils.slideUp(predictedText); - AnimationUtils.slideUp(finalText); - } - } - } - - private void toggleSubjectText() { - if (isExpand()) { - subjectName.setMaxLines(3); - } else { - subjectName.setMaxLines(1); - } - } - - private void resetViews() { - subjectName.setMaxLines(1); - predictedText.setVisibility(View.GONE); - finalText.setVisibility(View.GONE); - } - - private boolean isSubItemsReadAndSaveAlertView(List subItems) { - boolean isRead = true; - - for (GradesSubItem gradesSubItem : subItems) { - isRead = gradesSubItem.getGrade().getRead(); - gradesSubItem.setSubjectAlertImage(alertImage); - } - - return isRead; - } - private String getGradesAverageString() { float average = GradeUtils.calculate(item.getGradeList()); @@ -179,26 +135,65 @@ public class GradeHeaderItem return resources.getString(R.string.info_average_grades, average); } + @Override + public void onClick(View view) { + super.onClick(view); + toggleSubjectText(); + toggleSummary(); + } + + private void resetViews() { + subjectName.setMaxLines(1); + setDefaultSummaryVisibility(predictedText, item.getPredictedRating()); + setDefaultSummaryVisibility(finalText, item.getFinalRating()); + } + + private void setDefaultSummaryVisibility(View view, String value) { + if (!"-".equals(value) && isShowSummary) { + view.setVisibility(View.VISIBLE); + } else { + view.setVisibility(View.GONE); + } + } + + private void toggleSubjectText() { + if (isExpand()) { + subjectName.setMaxLines(3); + } else { + subjectName.setMaxLines(1); + } + } + + private void toggleSummary() { + toggleSummaryView(predictedText, item.getPredictedRating(), isExpand()); + toggleSummaryView(finalText, item.getFinalRating(), isExpand()); + } + private boolean isExpand() { return adapter.isExpanded(getFlexibleAdapterPosition()); } - private boolean isSummaryToggleable() { - boolean isSummaryEmpty = true; - - if (!"-".equals(item.getPredictedRating()) || !"-".equals(item.getFinalRating())) { - isSummaryEmpty = false; + private void toggleSummaryView(View view, String value, boolean expand) { + if ("-".equals(value) || isShowSummary) { + return; } - if (isSummaryEmpty) { - return false; - } else if (isShowSummary) { - predictedText.setVisibility(View.VISIBLE); - finalText.setVisibility(View.VISIBLE); - - return false; + if (expand) { + AnimationUtils.slideDown(view); + } else { + AnimationUtils.slideUp(view); } - return true; + } + + private boolean isSubItemsReadAndSaveAlertView(List subItems) { + boolean isRead = true; + + for (GradesSubItem gradesSubItem : subItems) { + isRead = gradesSubItem.getGrade().getRead(); + gradesSubItem.setSubjectAlertImage(alertImage); + } + + return isRead; } } } From e2003e253821566632ff0b6fa03fe6d9c5046116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 31 May 2018 23:54:59 +0200 Subject: [PATCH 31/41] Expand current day on startup (#129) --- .../ui/main/timetable/TimetableFragment.java | 1 - .../timetable/tab/TimetableTabContract.java | 2 + .../timetable/tab/TimetableTabFragment.java | 7 +++- .../timetable/tab/TimetableTabPresenter.java | 24 +++++++---- .../io/github/wulkanowy/utils/TimeUtils.java | 9 +++++ .../github/wulkanowy/utils/TimeUtilsTest.java | 40 +++++++++++++++++++ 6 files changed, 74 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java index 24960bd3..db3cc83c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java @@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.main.timetable; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java index 7eeb4b81..254060a2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java @@ -10,6 +10,8 @@ public interface TimetableTabContract { void updateAdapterList(List headerItems); + void expandItem(int item); + void onRefreshSuccess(); void hideRefreshingBar(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java index 6000cc6c..e0a30e8d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java @@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.main.timetable.tab; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -91,6 +90,12 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo adapter.updateDataSet(headerItems); } + @Override + public void expandItem(int position) { + adapter.expand(adapter.getItem(position), true); + recyclerView.scrollToPosition(position); + } + @Override public void setMenuVisibility(boolean menuVisible) { super.setMenuVisibility(menuVisible); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java index 51464b2e..8841a750 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java @@ -1,8 +1,9 @@ package io.github.wulkanowy.ui.main.timetable.tab; - import android.support.annotation.NonNull; +import org.threeten.bp.LocalDate; + import java.util.ArrayList; import java.util.List; @@ -13,7 +14,9 @@ import io.github.wulkanowy.data.db.dao.entities.Day; import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.ui.base.BasePresenter; +import io.github.wulkanowy.utils.AppConstant; import io.github.wulkanowy.utils.FabricUtils; +import io.github.wulkanowy.utils.TimeUtils; import io.github.wulkanowy.utils.async.AbstractTask; import io.github.wulkanowy.utils.async.AsyncListeners; @@ -48,8 +51,6 @@ public class TimetableTabPresenter extends BasePresenter Date: Fri, 1 Jun 2018 12:52:03 +0200 Subject: [PATCH 32/41] Move ticks converter to api (#130) --- .../io/github/wulkanowy/api/DateTimeUtils.kt | 49 +++++++++++++++++ .../java/io/github/wulkanowy/api/SnP.java | 5 ++ .../wulkanowy/api/StudentAndParent.java | 5 ++ .../api/attendance/AttendanceTable.java | 26 ++++----- .../github/wulkanowy/api/exams/ExamsWeek.java | 20 +++---- .../io/github/wulkanowy/api/generic/Day.java | 3 +- .../wulkanowy/api/{ => generic}/Diary.java | 2 +- .../api/{ => generic}/ParamItem.java | 4 +- .../wulkanowy/api/{ => generic}/Semester.java | 2 +- .../wulkanowy/api/{ => generic}/Student.java | 2 +- .../wulkanowy/api/grades/GradesList.java | 34 +++--------- .../wulkanowy/api/notes/AchievementsList.java | 6 +-- .../github/wulkanowy/api/notes/NotesList.java | 10 ++-- .../wulkanowy/api/school/SchoolInfo.java | 2 +- .../wulkanowy/api/school/TeachersInfo.java | 2 +- .../wulkanowy/api/timetable/Timetable.java | 21 +++----- .../github/wulkanowy/api/DateTimeUtilsTest.kt | 53 ++++++++++++++++++ .../wulkanowy/api/StudentAndParentTest.java | 2 + .../api/StudentAndParentTestCase.java | 2 + .../wulkanowy/api/grades/GradesListTest.java | 18 +++---- .../wulkanowy/api/notes/NotesListTest.java | 4 +- .../data/db/dao/migrations/Migration23.java | 2 +- .../wulkanowy/data/sync/AttendanceSync.java | 12 ++--- .../github/wulkanowy/data/sync/ExamsSync.java | 13 ++--- .../wulkanowy/data/sync/TimetableSync.java | 12 ++--- .../wulkanowy/utils/DataObjectConverter.java | 12 ++--- .../io/github/wulkanowy/utils/TimeUtils.java | 33 ------------ .../github/wulkanowy/utils/TimeUtilsTest.java | 54 +------------------ 28 files changed, 195 insertions(+), 215 deletions(-) create mode 100644 api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt rename api/src/main/java/io/github/wulkanowy/api/{ => generic}/Diary.java (93%) rename api/src/main/java/io/github/wulkanowy/api/{ => generic}/ParamItem.java (67%) rename api/src/main/java/io/github/wulkanowy/api/{ => generic}/Semester.java (93%) rename api/src/main/java/io/github/wulkanowy/api/{ => generic}/Student.java (93%) create mode 100644 api/src/test/java/io/github/wulkanowy/api/DateTimeUtilsTest.kt diff --git a/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt new file mode 100644 index 00000000..bad4e97d --- /dev/null +++ b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt @@ -0,0 +1,49 @@ +package io.github.wulkanowy.api + +import java.text.SimpleDateFormat +import java.util.* + +const val LOG_DATE_PATTERN = "dd.MM.yyyy" +const val API_DATE_PATTERN = "yyyy-MM-dd" + +const val TICKS_AT_EPOCH = 621355968000000000L +const val TICKS_PER_MILLISECOND = 10000 + +fun getFormattedDate(date: String): String { + return getFormattedDate(date, API_DATE_PATTERN) +} + +fun getFormattedDate(date: String, format: String): String { + val sdf = SimpleDateFormat(LOG_DATE_PATTERN, Locale.ROOT) + val d = sdf.parse(date) + sdf.applyPattern(format) + + return sdf.format(d) +} + +fun getDateAsTick(dateString: String?): String { + if (dateString.isNullOrEmpty()) { + return "" + } + + return getDateAsTick(dateString as String, API_DATE_PATTERN).toString() +} + +fun getDateAsTick(dateString: String, dateFormat: String): Long { + val format = SimpleDateFormat(dateFormat, Locale.ROOT) + format.timeZone = TimeZone.getTimeZone("UTC") + val dateObject = format.parse(dateString) + + return getDateAsTick(dateObject) +} + +fun getDateAsTick(date: Date): Long { + val calendar = Calendar.getInstance() + calendar.time = date + + return calendar.timeInMillis * TICKS_PER_MILLISECOND + TICKS_AT_EPOCH +} + +fun getDate(netTicks: Long): Date { + return Date((netTicks - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND) +} diff --git a/api/src/main/java/io/github/wulkanowy/api/SnP.java b/api/src/main/java/io/github/wulkanowy/api/SnP.java index 7f074071..6747faf0 100644 --- a/api/src/main/java/io/github/wulkanowy/api/SnP.java +++ b/api/src/main/java/io/github/wulkanowy/api/SnP.java @@ -6,6 +6,11 @@ import org.jsoup.nodes.Element; import java.io.IOException; import java.util.List; +import io.github.wulkanowy.api.generic.Diary; +import io.github.wulkanowy.api.generic.ParamItem; +import io.github.wulkanowy.api.generic.Semester; +import io.github.wulkanowy.api.generic.Student; + public interface SnP { String getSchoolID(); diff --git a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java index 16ee002e..a4b8fefa 100644 --- a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java +++ b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java @@ -11,6 +11,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import io.github.wulkanowy.api.generic.Diary; +import io.github.wulkanowy.api.generic.ParamItem; +import io.github.wulkanowy.api.generic.Semester; +import io.github.wulkanowy.api.generic.Student; + public class StudentAndParent implements SnP { private static final String START_PAGE_URL = "{schema}://uonetplus.{host}/{symbol}/Start.mvc/Index"; diff --git a/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java b/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java index d81a30b2..7caa70d8 100644 --- a/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java +++ b/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java @@ -4,12 +4,8 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; -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 io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; @@ -17,6 +13,9 @@ import io.github.wulkanowy.api.generic.Day; import io.github.wulkanowy.api.generic.Lesson; import io.github.wulkanowy.api.generic.Week; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getDateAsTick; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; + public class AttendanceTable { private final static String ATTENDANCE_PAGE_URL = "Frekwencja.mvc?data="; @@ -27,13 +26,12 @@ public class AttendanceTable { this.snp = snp; } - public Week getWeekTable() throws IOException, ParseException, VulcanException { + public Week getWeekTable() throws IOException, VulcanException { return getWeekTable(""); } - public Week getWeekTable(String tick) throws IOException, ParseException, VulcanException { - Element table = snp.getSnPPageDocument(ATTENDANCE_PAGE_URL + tick) - + public Week getWeekTable(String date) throws IOException, VulcanException { + Element table = snp.getSnPPageDocument(ATTENDANCE_PAGE_URL + getDateAsTick(date)) .select(".mainContainer .presentData").first(); Elements headerCells = table.select("thead th"); @@ -42,14 +40,10 @@ public class AttendanceTable { for (int i = 1; i < headerCells.size(); i++) { String[] dayHeaderCell = headerCells.get(i).html().split("
"); - SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - Date d = sdf.parse(dayHeaderCell[1].trim()); - sdf.applyPattern("yyyy-MM-dd"); - - Day day = new Day(); - day.setDayName(dayHeaderCell[0]); - day.setDate(sdf.format(d)); - days.add(day); + days.add(new Day() + .setDayName(dayHeaderCell[0]) + .setDate(getFormattedDate(dayHeaderCell[1].trim())) + ); } Elements hoursInDays = table.select("tbody tr"); diff --git a/api/src/main/java/io/github/wulkanowy/api/exams/ExamsWeek.java b/api/src/main/java/io/github/wulkanowy/api/exams/ExamsWeek.java index c111ce84..391056ac 100644 --- a/api/src/main/java/io/github/wulkanowy/api/exams/ExamsWeek.java +++ b/api/src/main/java/io/github/wulkanowy/api/exams/ExamsWeek.java @@ -6,17 +6,16 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; -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 io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; import io.github.wulkanowy.api.generic.Week; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getDateAsTick; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; + public class ExamsWeek { private static final String EXAMS_PAGE_URL = "Sprawdziany.mvc/Terminarz?rodzajWidoku=2&data="; @@ -27,12 +26,12 @@ public class ExamsWeek { this.snp = snp; } - public Week getCurrent() throws IOException, VulcanException, ParseException { + public Week getCurrent() throws IOException, VulcanException { return getWeek("", true); } - public Week getWeek(String tick, final boolean onlyNotEmpty) throws IOException, VulcanException, ParseException { - Document examsPage = snp.getSnPPageDocument(EXAMS_PAGE_URL + tick); + public Week getWeek(String date, final boolean onlyNotEmpty) throws IOException, VulcanException { + Document examsPage = snp.getSnPPageDocument(EXAMS_PAGE_URL + getDateAsTick(date)); Elements examsDays = examsPage.select(".mainContainer > div:not(.navigation)"); List days = new ArrayList<>(); @@ -71,11 +70,4 @@ public class ExamsWeek { .first().text().split(" ")[1])) .setDays(days); } - - private String getFormattedDate(String date) throws ParseException { - SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - Date d = sdf.parse(date); - sdf.applyPattern("yyyy-MM-dd"); - return sdf.format(d); - } } diff --git a/api/src/main/java/io/github/wulkanowy/api/generic/Day.java b/api/src/main/java/io/github/wulkanowy/api/generic/Day.java index 5b9086a3..fbb5ee0a 100644 --- a/api/src/main/java/io/github/wulkanowy/api/generic/Day.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Day.java @@ -37,7 +37,8 @@ public class Day { return dayName; } - public void setDayName(String dayName) { + public Day setDayName(String dayName) { this.dayName = dayName; + return this; } } diff --git a/api/src/main/java/io/github/wulkanowy/api/Diary.java b/api/src/main/java/io/github/wulkanowy/api/generic/Diary.java similarity index 93% rename from api/src/main/java/io/github/wulkanowy/api/Diary.java rename to api/src/main/java/io/github/wulkanowy/api/generic/Diary.java index d7d09f9c..5c7c8593 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Diary.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Diary.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.api; +package io.github.wulkanowy.api.generic; public class Diary implements ParamItem { diff --git a/api/src/main/java/io/github/wulkanowy/api/ParamItem.java b/api/src/main/java/io/github/wulkanowy/api/generic/ParamItem.java similarity index 67% rename from api/src/main/java/io/github/wulkanowy/api/ParamItem.java rename to api/src/main/java/io/github/wulkanowy/api/generic/ParamItem.java index c830467a..e7edfbf4 100644 --- a/api/src/main/java/io/github/wulkanowy/api/ParamItem.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/ParamItem.java @@ -1,6 +1,6 @@ -package io.github.wulkanowy.api; +package io.github.wulkanowy.api.generic; -interface ParamItem { +public interface ParamItem { ParamItem setId(String id); diff --git a/api/src/main/java/io/github/wulkanowy/api/Semester.java b/api/src/main/java/io/github/wulkanowy/api/generic/Semester.java similarity index 93% rename from api/src/main/java/io/github/wulkanowy/api/Semester.java rename to api/src/main/java/io/github/wulkanowy/api/generic/Semester.java index 31230f01..db4a724d 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Semester.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Semester.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.api; +package io.github.wulkanowy.api.generic; public class Semester implements ParamItem { diff --git a/api/src/main/java/io/github/wulkanowy/api/Student.java b/api/src/main/java/io/github/wulkanowy/api/generic/Student.java similarity index 93% rename from api/src/main/java/io/github/wulkanowy/api/Student.java rename to api/src/main/java/io/github/wulkanowy/api/generic/Student.java index 8b22f1d8..4ed5dd37 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Student.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Student.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.api; +package io.github.wulkanowy.api.generic; public class Student implements ParamItem { diff --git a/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java b/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java index 936c1533..cb9fe465 100644 --- a/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java +++ b/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java @@ -5,42 +5,32 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; -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; import io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; + public class GradesList { private static final String GRADES_PAGE_URL = "Oceny/Wszystkie?details=2&okres="; private SnP snp; - private List grades = new ArrayList<>(); - public GradesList(SnP snp) { this.snp = snp; } - private String getGradesPageUrl() { - return GRADES_PAGE_URL; - } - - public List getAll() throws IOException, ParseException, VulcanException { - return getAll(""); - } - - public List getAll(String semester) throws IOException, ParseException, VulcanException { - Document gradesPage = snp.getSnPPageDocument(getGradesPageUrl() + semester); + public List getAll(String semester) throws IOException, VulcanException { + Document gradesPage = snp.getSnPPageDocument(GRADES_PAGE_URL + semester); Elements gradesRows = gradesPage.select(".ocenySzczegoly-table > tbody > tr"); + List grades = new ArrayList<>(); + for (Element row : gradesRows) { if ("Brak ocen".equals(row.select("td:nth-child(2)").text())) { continue; @@ -52,13 +42,13 @@ public class GradesList { return grades; } - private Grade getGrade(Element row) throws ParseException { + private Grade getGrade(Element row) { String descriptions = row.select("td:nth-child(3)").text(); String symbol = descriptions.split(", ")[0]; String description = descriptions.replaceFirst(Pattern.quote(symbol), "").replaceFirst(", ", ""); String color = getColor(row.select("td:nth-child(2) span.ocenaCzastkowa").attr("style")); - String date = formatDate(row.select("td:nth-child(5)").text()); + String date = getFormattedDate(row.select("td:nth-child(5)").text()); return new Grade() .setSubject(row.select("td:nth-child(1)").text()) @@ -82,12 +72,4 @@ public class GradesList { return color; } - - private String formatDate(String date) throws ParseException { - SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - Date d = sdf.parse(date); - sdf.applyPattern("yyyy-MM-dd"); - - return sdf.format(d); - } } diff --git a/api/src/main/java/io/github/wulkanowy/api/notes/AchievementsList.java b/api/src/main/java/io/github/wulkanowy/api/notes/AchievementsList.java index 11d01342..346df832 100644 --- a/api/src/main/java/io/github/wulkanowy/api/notes/AchievementsList.java +++ b/api/src/main/java/io/github/wulkanowy/api/notes/AchievementsList.java @@ -14,9 +14,7 @@ public class AchievementsList { private static final String NOTES_PAGE_URL = "UwagiOsiagniecia.mvc/Wszystkie"; - private SnP snp = null; - - private List achievements = new ArrayList<>(); + private SnP snp; public AchievementsList(SnP snp) { this.snp = snp; @@ -27,6 +25,8 @@ public class AchievementsList { .select(".mainContainer > div").get(1); Elements items = pageFragment.select("article"); + List achievements = new ArrayList<>(); + for (Element item : items) { achievements.add(item.text()); } diff --git a/api/src/main/java/io/github/wulkanowy/api/notes/NotesList.java b/api/src/main/java/io/github/wulkanowy/api/notes/NotesList.java index 0c8a30b6..54f57edf 100644 --- a/api/src/main/java/io/github/wulkanowy/api/notes/NotesList.java +++ b/api/src/main/java/io/github/wulkanowy/api/notes/NotesList.java @@ -10,13 +10,13 @@ import java.util.List; import io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; + public class NotesList { private static final String NOTES_PAGE_URL = "UwagiOsiagniecia.mvc/Wszystkie"; - private SnP snp = null; - - private List notes = new ArrayList<>(); + private SnP snp; public NotesList(SnP snp) { this.snp = snp; @@ -28,10 +28,12 @@ public class NotesList { Elements items = pageFragment.select("article"); Elements dates = pageFragment.select("h2"); + List notes = new ArrayList<>(); + int index = 0; for (Element item : items) { notes.add(new Note() - .setDate(dates.get(index++).text()) + .setDate(getFormattedDate(dates.get(index++).text())) .setTeacher(snp.getRowDataChildValue(item, 1)) .setCategory(snp.getRowDataChildValue(item, 2)) .setContent(snp.getRowDataChildValue(item, 3)) diff --git a/api/src/main/java/io/github/wulkanowy/api/school/SchoolInfo.java b/api/src/main/java/io/github/wulkanowy/api/school/SchoolInfo.java index 51a7278b..f0dcd43d 100644 --- a/api/src/main/java/io/github/wulkanowy/api/school/SchoolInfo.java +++ b/api/src/main/java/io/github/wulkanowy/api/school/SchoolInfo.java @@ -11,7 +11,7 @@ public class SchoolInfo { private static final String SCHOOL_PAGE_URL = "Szkola.mvc/Nauczyciele"; - private SnP snp = null; + private SnP snp; public SchoolInfo(SnP snp) { this.snp = snp; diff --git a/api/src/main/java/io/github/wulkanowy/api/school/TeachersInfo.java b/api/src/main/java/io/github/wulkanowy/api/school/TeachersInfo.java index bbf5f5d7..ec8429bd 100644 --- a/api/src/main/java/io/github/wulkanowy/api/school/TeachersInfo.java +++ b/api/src/main/java/io/github/wulkanowy/api/school/TeachersInfo.java @@ -15,7 +15,7 @@ public class TeachersInfo { private static final String SCHOOL_PAGE_URL = "Szkola.mvc/Nauczyciele"; - private SnP snp = null; + private SnP snp; public TeachersInfo(SnP snp) { this.snp = snp; diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 4668149c..8a2b9e14 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -5,18 +5,17 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; -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 io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; import io.github.wulkanowy.api.generic.Lesson; import io.github.wulkanowy.api.generic.Week; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getDateAsTick; + public class Timetable { private static final String TIMETABLE_PAGE_URL = "Lekcja.mvc/PlanZajec?data="; @@ -27,12 +26,12 @@ public class Timetable { this.snp = snp; } - public Week getWeekTable() throws IOException, ParseException, VulcanException { + public Week getWeekTable() throws IOException, VulcanException { return getWeekTable(""); } - public Week getWeekTable(final String tick) throws IOException, ParseException, VulcanException { - Element table = snp.getSnPPageDocument(TIMETABLE_PAGE_URL + tick) + public Week getWeekTable(final String date) throws IOException, VulcanException { + Element table = snp.getSnPPageDocument(TIMETABLE_PAGE_URL + getDateAsTick(date)) .select(".mainContainer .presentData").first(); List days = getDays(table.select("thead th")); @@ -44,19 +43,15 @@ public class Timetable { .setDays(days); } - private List getDays(Elements tableHeaderCells) throws ParseException { + private List getDays(Elements tableHeaderCells) { List days = new ArrayList<>(); for (int i = 2; i < 7; i++) { String[] dayHeaderCell = tableHeaderCells.get(i).html().split("
"); - SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - Date d = sdf.parse(dayHeaderCell[1].trim()); - sdf.applyPattern("yyyy-MM-dd"); - TimetableDay day = new TimetableDay(); day.setDayName(dayHeaderCell[0]); - day.setDate(sdf.format(d)); + day.setDate(getFormattedDate(dayHeaderCell[1].trim())); if (tableHeaderCells.get(i).hasClass("free-day")) { day.setFreeDay(true); diff --git a/api/src/test/java/io/github/wulkanowy/api/DateTimeUtilsTest.kt b/api/src/test/java/io/github/wulkanowy/api/DateTimeUtilsTest.kt new file mode 100644 index 00000000..1105b2a7 --- /dev/null +++ b/api/src/test/java/io/github/wulkanowy/api/DateTimeUtilsTest.kt @@ -0,0 +1,53 @@ +package io.github.wulkanowy.api + +import org.junit.Assert +import org.junit.Test +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.* + +class DateTimeUtilsTest { + + @Test + fun getTicksDateObjectTest() { + val format = SimpleDateFormat("dd.MM.yyyy", Locale.ROOT) + format.timeZone = TimeZone.getTimeZone("UTC") + val date = format.parse("31.07.2017") + + Assert.assertEquals(636370560000000000L, getDateAsTick(date)) + + val calendar = Calendar.getInstance() + calendar.time = date + calendar.add(Calendar.DAY_OF_YEAR, -14) + val dateTwoWeekBefore = calendar.time + + Assert.assertEquals(636358464000000000L, getDateAsTick(dateTwoWeekBefore)) + } + + @Test(expected = ParseException::class) + fun getTicsStringInvalidFormatTest() { + Assert.assertEquals(636370560000000000L, getDateAsTick("31.07.2017", "dd.MMM.yyyy")) + } + + @Test + fun getTicsStringFormatTest() { + Assert.assertEquals(636370560000000000L, getDateAsTick("31.07.2017", "dd.MM.yyyy")) + } + + @Test + fun getTicsStringTest() { + Assert.assertEquals("636370560000000000", getDateAsTick("2017-07-31")) + Assert.assertEquals("636334272000000000", getDateAsTick("2017-06-19")) + Assert.assertEquals("636189120000000000", getDateAsTick("2017-01-02")) + Assert.assertEquals("636080256000000000", getDateAsTick("2016-08-29")) + } + + @Test + fun getDateTest() { + val format = SimpleDateFormat("dd.MM.yyyy", Locale.ROOT) + format.timeZone = TimeZone.getTimeZone("UTC") + val date = format.parse("31.07.2017") + + Assert.assertEquals(date, getDate(636370560000000000L)) + } +} diff --git a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java index 387d18f5..1b6f7a91 100644 --- a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java @@ -11,6 +11,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import io.github.wulkanowy.api.generic.Semester; + public class StudentAndParentTest { private Client client; diff --git a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTestCase.java b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTestCase.java index 8d32291f..764e8009 100644 --- a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTestCase.java +++ b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTestCase.java @@ -5,6 +5,8 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.mockito.Mockito; +import io.github.wulkanowy.api.generic.Semester; + public abstract class StudentAndParentTestCase { protected StudentAndParent getSnp(String fixtureFileName) throws Exception { diff --git a/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java b/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java index 6eff84c9..deab7617 100644 --- a/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java @@ -19,12 +19,12 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getAllTest() throws Exception { - Assert.assertEquals(7, filled.getAll().size()); // 2 items are skipped + Assert.assertEquals(7, filled.getAll("").size()); // 2 items are skipped } @Test public void getSubjectTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("Zajęcia z wychowawcą", list.get(0).getSubject()); Assert.assertEquals("Język angielski", list.get(3).getSubject()); @@ -34,7 +34,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getValueTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("5", list.get(0).getValue()); Assert.assertEquals("5", list.get(3).getValue()); @@ -44,7 +44,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getColorTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("000000", list.get(0).getColor()); Assert.assertEquals("1289F7", list.get(3).getColor()); @@ -54,7 +54,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getSymbolTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("A1", list.get(0).getSymbol()); Assert.assertEquals("BW3", list.get(3).getSymbol()); @@ -65,7 +65,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getDescriptionTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("Dzień Kobiet w naszej klasie", list.get(0).getDescription()); Assert.assertEquals("Writing", list.get(3).getDescription()); @@ -76,7 +76,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getWeightTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("1,00", list.get(0).getWeight()); Assert.assertEquals("3,00", list.get(3).getWeight()); @@ -86,7 +86,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getDateTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("2017-03-21", list.get(0).getDate()); Assert.assertEquals("2017-06-02", list.get(3).getDate()); @@ -96,7 +96,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getTeacherTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("Patryk Maciejewski", list.get(0).getTeacher()); Assert.assertEquals("Oliwia Woźniak", list.get(3).getTeacher()); diff --git a/api/src/test/java/io/github/wulkanowy/api/notes/NotesListTest.java b/api/src/test/java/io/github/wulkanowy/api/notes/NotesListTest.java index d76c0648..304eb01a 100644 --- a/api/src/test/java/io/github/wulkanowy/api/notes/NotesListTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/notes/NotesListTest.java @@ -30,8 +30,8 @@ public class NotesListTest extends StudentAndParentTestCase { public void getDateTest() throws Exception { List filledList = filled.getAllNotes(); - Assert.assertEquals("06.06.2017", filledList.get(0).getDate()); - Assert.assertEquals("01.10.2016", filledList.get(2).getDate()); + Assert.assertEquals("2017-06-06", filledList.get(0).getDate()); + Assert.assertEquals("2016-10-01", filledList.get(2).getDate()); } @Test diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java index b32c6261..97b575a0 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java @@ -9,7 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import io.github.wulkanowy.api.Diary; +import io.github.wulkanowy.api.generic.Diary; import io.github.wulkanowy.api.Vulcan; import io.github.wulkanowy.data.db.dao.DbHelper; import io.github.wulkanowy.data.db.shared.SharedPrefContract; diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java index 59a6e1a3..9f379be6 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -20,7 +19,6 @@ import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.LogUtils; -import io.github.wulkanowy.utils.TimeUtils; @Singleton public class AttendanceSync { @@ -37,10 +35,10 @@ public class AttendanceSync { this.vulcan = vulcan; } - public void syncAttendance(long diaryId, String date) throws IOException, ParseException, VulcanException { + public void syncAttendance(long diaryId, String date) throws IOException, VulcanException { this.diaryId = diaryId; - io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(getNormalizedDate(date)); + io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(date); Week weekDb = getWeekFromDb(weekApi.getStartDayDate()); long weekId = updateWeekInDb(weekDb, weekApi); @@ -52,12 +50,8 @@ public class AttendanceSync { LogUtils.debug("Synchronization attendance lessons (amount = " + lessonList.size() + ")"); } - private String getNormalizedDate(String date) throws ParseException { - return null != date ? String.valueOf(TimeUtils.getNetTicks(date)) : ""; - } - private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) - throws IOException, ParseException, VulcanException { + throws IOException, VulcanException { return vulcan.getAttendanceTable().getWeekTable(date); } diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java index 53470882..85b4dac4 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -19,7 +18,6 @@ import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.LogUtils; -import io.github.wulkanowy.utils.TimeUtils; public class ExamsSync { @@ -35,11 +33,10 @@ public class ExamsSync { this.vulcan = vulcan; } - public void syncExams(long diaryId, String date) throws IOException, VulcanException, - ParseException { + public void syncExams(long diaryId, String date) throws IOException, VulcanException { this.diaryId = diaryId; - io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(getNormalizedDate(date)); + io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(date); Week weekDb = getWeekFromDb(weekApi.getStartDayDate()); long weekId = updateWeekInDb(weekDb, weekApi); @@ -59,7 +56,7 @@ public class ExamsSync { } private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) - throws VulcanException, IOException, ParseException { + throws VulcanException, IOException { return vulcan.getExamsList().getWeek(date, true); } @@ -77,10 +74,6 @@ public class ExamsSync { return daoSession.getWeekDao().insert(weekApiEntity); } - private String getNormalizedDate(String date) throws ParseException { - return null != date ? String.valueOf(TimeUtils.getNetTicks(date)) : ""; - } - private Day getDayFromDb(String date, long weekId) { return daoSession.getDayDao().queryBuilder().where( DayDao.Properties.WeekId.eq(weekId), diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java index 3fe22aff..309403c8 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java @@ -3,7 +3,6 @@ package io.github.wulkanowy.data.sync; import org.apache.commons.collections4.CollectionUtils; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -22,7 +21,6 @@ import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.LogUtils; -import io.github.wulkanowy.utils.TimeUtils; @Singleton public class TimetableSync { @@ -39,10 +37,10 @@ public class TimetableSync { this.vulcan = vulcan; } - public void syncTimetable(long diaryId, String date) throws IOException, ParseException, VulcanException { + public void syncTimetable(long diaryId, String date) throws IOException, VulcanException { this.diaryId = diaryId; - io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(getNormalizedDate(date)); + io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(date); Week weekDb = getWeekFromDb(weekApi.getStartDayDate()); long weekId = updateWeekInDb(weekDb, weekApi); @@ -54,12 +52,8 @@ public class TimetableSync { LogUtils.debug("Synchronization timetable lessons (amount = " + lessonList.size() + ")"); } - private String getNormalizedDate(String date) throws ParseException { - return null != date ? String.valueOf(TimeUtils.getNetTicks(date)) : ""; - } - private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) - throws IOException, ParseException, VulcanException { + throws IOException, VulcanException { return vulcan.getTimetable().getWeekTable(date); } diff --git a/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java b/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java index 3f733ad6..1747fc26 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java +++ b/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java @@ -21,10 +21,10 @@ public final class DataObjectConverter { throw new IllegalStateException("Utility class"); } - public static List studentsToStudentEntities(List students, Long symbolId) { + public static List studentsToStudentEntities(List students, Long symbolId) { List studentList = new ArrayList<>(); - for (io.github.wulkanowy.api.Student student : students) { + for (io.github.wulkanowy.api.generic.Student student : students) { studentList.add(new Student() .setName(student.getName()) .setCurrent(student.isCurrent()) @@ -36,10 +36,10 @@ public final class DataObjectConverter { return studentList; } - public static List diariesToDiaryEntities(List diaryList, Long studentId) { + public static List diariesToDiaryEntities(List diaryList, Long studentId) { List diaryEntityList = new ArrayList<>(); - for (io.github.wulkanowy.api.Diary diary : diaryList) { + for (io.github.wulkanowy.api.generic.Diary diary : diaryList) { diaryEntityList.add(new Diary() .setStudentId(studentId) .setValue(diary.getId()) @@ -50,10 +50,10 @@ public final class DataObjectConverter { return diaryEntityList; } - public static List semestersToSemesterEntities(List semesters, long diaryId) { + public static List semestersToSemesterEntities(List semesters, long diaryId) { List semesterList = new ArrayList<>(); - for (io.github.wulkanowy.api.Semester semester : semesters) { + for (io.github.wulkanowy.api.generic.Semester semester : semesters) { semesterList.add(new Semester() .setDiaryId(diaryId) .setName(semester.getName()) diff --git a/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.java b/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.java index eaed222e..a305bc6d 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.java +++ b/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.java @@ -4,54 +4,21 @@ import org.threeten.bp.DayOfWeek; import org.threeten.bp.LocalDate; import org.threeten.bp.format.DateTimeFormatter; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; import java.util.List; -import java.util.Locale; -import java.util.TimeZone; public final class TimeUtils { - private static final long TICKS_AT_EPOCH = 621355968000000000L; - - private static final long TICKS_PER_MILLISECOND = 10000; - private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(AppConstant.DATE_PATTERN); private TimeUtils() { throw new IllegalStateException("Utility class"); } - public static long getNetTicks(Date date) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - - return (calendar.getTimeInMillis() * TICKS_PER_MILLISECOND) + TICKS_AT_EPOCH; - } - - public static long getNetTicks(String dateString) throws ParseException { - return getNetTicks(dateString, AppConstant.DATE_PATTERN); - } - - public static long getNetTicks(String dateString, String dateFormat) throws ParseException { - SimpleDateFormat format = new SimpleDateFormat(dateFormat, Locale.ROOT); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - Date dateObject = format.parse(dateString); - - return getNetTicks(dateObject); - } - public static LocalDate getParsedDate(String dateString, String dateFormat) { return LocalDate.parse(dateString, DateTimeFormatter.ofPattern(dateFormat)); } - public static Date getDate(long netTicks) { - return new Date((netTicks - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND); - } - public static List getMondaysFromCurrentSchoolYear() { LocalDate startDate = LocalDate.of(getCurrentSchoolYear(), 9, 1); LocalDate endDate = LocalDate.of(getCurrentSchoolYear() + 1, 8, 31); diff --git a/app/src/test/java/io/github/wulkanowy/utils/TimeUtilsTest.java b/app/src/test/java/io/github/wulkanowy/utils/TimeUtilsTest.java index 41e60689..e216392e 100644 --- a/app/src/test/java/io/github/wulkanowy/utils/TimeUtilsTest.java +++ b/app/src/test/java/io/github/wulkanowy/utils/TimeUtilsTest.java @@ -4,62 +4,12 @@ import org.junit.Assert; import org.junit.Test; import org.threeten.bp.LocalDate; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - public class TimeUtilsTest { - @Test - public void getTicksDateObjectTest() throws Exception { - SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - Date date = format.parse("31.07.2017"); - - Assert.assertEquals(636370560000000000L, TimeUtils.getNetTicks(date)); - - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - calendar.add(Calendar.DAY_OF_YEAR, -14); - Date dateTwoWeekBefore = calendar.getTime(); - - Assert.assertEquals(636358464000000000L, TimeUtils.getNetTicks(dateTwoWeekBefore)); - } - - @Test(expected = ParseException.class) - public void getTicsStringInvalidFormatTest() throws Exception { - Assert.assertEquals(636370560000000000L, TimeUtils.getNetTicks("31.07.2017", "dd.MMM.yyyy")); - } - - @Test - public void getTicsStringFormatTest() throws Exception { - Assert.assertEquals(636370560000000000L, TimeUtils.getNetTicks("31.07.2017", "dd.MM.yyyy")); - } - - @Test - public void getTicsStringTest() throws Exception { - Assert.assertEquals(636370560000000000L, TimeUtils.getNetTicks("2017-07-31")); - Assert.assertEquals(636334272000000000L, TimeUtils.getNetTicks("2017-06-19")); - Assert.assertEquals(636189120000000000L, TimeUtils.getNetTicks("2017-01-02")); - Assert.assertEquals(636080256000000000L, TimeUtils.getNetTicks("2016-08-29")); - } - @Test public void getParsedDateTest() { - Assert.assertEquals(LocalDate.of(1970, 1, 1), TimeUtils.getParsedDate("1970-01-01", "yyyy-MM-dd")); - } - - @Test - public void getDateTest() throws Exception { - DateFormat format = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - Date date = format.parse("31.07.2017"); - - Assert.assertEquals(date, TimeUtils.getDate(636370560000000000L)); + Assert.assertEquals(LocalDate.of(1970, 1, 1), + TimeUtils.getParsedDate("1970-01-01", "yyyy-MM-dd")); } @Test From 0e16519baf03bcb6d49bbb54f9cbdba95e4f45ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 4 Jun 2018 21:47:46 +0200 Subject: [PATCH 33/41] Add a summary of grades (#127) --- ...eHeaderItem.java => AttendanceHeader.java} | 8 +- .../attendance/tab/AttendanceSubItem.java | 4 +- .../attendance/tab/AttendanceTabContract.java | 2 +- .../attendance/tab/AttendanceTabFragment.java | 4 +- .../attendance/tab/AttendanceTabModule.java | 2 +- .../tab/AttendanceTabPresenter.java | 4 +- ...{ExamsHeaderItem.java => ExamsHeader.java} | 6 +- .../ui/main/exams/tab/ExamsSubItem.java | 4 +- .../ui/main/exams/tab/ExamsTabPresenter.java | 2 +- .../ui/main/grades/GradesContract.java | 6 +- .../ui/main/grades/GradesDialogFragment.java | 2 +- .../ui/main/grades/GradesFragment.java | 92 ++++++--- ...GradeHeaderItem.java => GradesHeader.java} | 12 +- .../ui/main/grades/GradesModule.java | 7 +- .../ui/main/grades/GradesPresenter.java | 55 +++++- .../ui/main/grades/GradesSubItem.java | 6 +- .../ui/main/grades/GradesSummaryHeader.java | 87 ++++++++ .../ui/main/grades/GradesSummarySubItem.java | 83 ++++++++ ...leHeaderItem.java => TimetableHeader.java} | 8 +- .../main/timetable/tab/TimetableSubItem.java | 4 +- .../timetable/tab/TimetableTabContract.java | 2 +- .../timetable/tab/TimetableTabFragment.java | 4 +- .../timetable/tab/TimetableTabModule.java | 2 +- .../timetable/tab/TimetableTabPresenter.java | 4 +- .../io/github/wulkanowy/utils/GradeUtils.java | 121 +++++++++--- .../res/drawable/ic_action_menu_semester.xml | 10 + .../res/drawable/ic_action_menu_summary.xml | 13 ++ .../main/res/drawable/ic_exclamation_24dp.xml | 2 +- .../drawable/ic_filter_list_black_24dp.xml | 5 - app/src/main/res/layout/fragment_grades.xml | 187 ++++++++++++++---- .../{grade_dialog.xml => grades_dialog.xml} | 0 .../{grade_header.xml => grades_header.xml} | 4 +- .../{grade_subitem.xml => grades_subitem.xml} | 0 .../main/res/layout/grades_summary_header.xml | 34 ++++ .../res/layout/grades_summary_subitem.xml | 75 +++++++ app/src/main/res/menu/grades_action_menu.xml | 20 ++ app/src/main/res/menu/semester_switch.xml | 13 -- app/src/main/res/values-pl/strings.xml | 9 + app/src/main/res/values/strings.xml | 9 + .../wulkanowy/utils/GradeUtilsTest.java | 57 ++++-- 40 files changed, 791 insertions(+), 178 deletions(-) rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/{AttendanceHeaderItem.java => AttendanceHeader.java} (95%) rename app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/{ExamsHeaderItem.java => ExamsHeader.java} (92%) rename app/src/main/java/io/github/wulkanowy/ui/main/grades/{GradeHeaderItem.java => GradesHeader.java} (94%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummaryHeader.java create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummarySubItem.java rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/{TimetableHeaderItem.java => TimetableHeader.java} (95%) create mode 100644 app/src/main/res/drawable/ic_action_menu_semester.xml create mode 100644 app/src/main/res/drawable/ic_action_menu_summary.xml delete mode 100644 app/src/main/res/drawable/ic_filter_list_black_24dp.xml rename app/src/main/res/layout/{grade_dialog.xml => grades_dialog.xml} (100%) rename app/src/main/res/layout/{grade_header.xml => grades_header.xml} (97%) rename app/src/main/res/layout/{grade_subitem.xml => grades_subitem.xml} (100%) create mode 100644 app/src/main/res/layout/grades_summary_header.xml create mode 100644 app/src/main/res/layout/grades_summary_subitem.xml create mode 100644 app/src/main/res/menu/grades_action_menu.xml delete mode 100644 app/src/main/res/menu/semester_switch.xml diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeader.java similarity index 95% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeader.java index 1c55f40c..940d1fd2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeader.java @@ -24,12 +24,12 @@ import eu.davidea.viewholders.ExpandableViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.Day; -public class AttendanceHeaderItem - extends AbstractExpandableHeaderItem { +public class AttendanceHeader + extends AbstractExpandableHeaderItem { private Day day; - AttendanceHeaderItem(Day day) { + AttendanceHeader(Day day) { this.day = day; } @@ -39,7 +39,7 @@ public class AttendanceHeaderItem if (o == null || getClass() != o.getClass()) return false; - AttendanceHeaderItem that = (AttendanceHeaderItem) o; + AttendanceHeader that = (AttendanceHeader) o; return new EqualsBuilder() .append(day, that.day) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java index 6b6246d2..65c8329e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java @@ -23,11 +23,11 @@ import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; import io.github.wulkanowy.ui.main.attendance.AttendanceDialogFragment; class AttendanceSubItem - extends AbstractSectionableItem { + extends AbstractSectionableItem { private AttendanceLesson lesson; - AttendanceSubItem(AttendanceHeaderItem header, AttendanceLesson lesson) { + AttendanceSubItem(AttendanceHeader header, AttendanceLesson lesson) { super(header); this.lesson = lesson; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java index d7c45904..a83e67e8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java @@ -8,7 +8,7 @@ public interface AttendanceTabContract { interface View extends BaseContract.View { - void updateAdapterList(List headerItems); + void updateAdapterList(List headerItems); void onRefreshSuccess(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java index 7b5ad1ce..8de47469 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java @@ -40,7 +40,7 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab AttendanceTabContract.Presenter presenter; @Inject - FlexibleAdapter adapter; + FlexibleAdapter adapter; private boolean isFragmentVisible = false; @@ -83,7 +83,7 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab } @Override - public void updateAdapterList(List headerItems) { + public void updateAdapterList(List headerItems) { adapter.updateDataSet(headerItems); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java index 01bb9aa4..380a221f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java @@ -15,7 +15,7 @@ public abstract class AttendanceTabModule { @PerChildFragment @Provides - static FlexibleAdapter provideAdapter() { + static FlexibleAdapter provideAdapter() { return new FlexibleAdapter<>(null); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java index 787b6eb9..7d0c26e5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java @@ -24,7 +24,7 @@ public class AttendanceTabPresenter extends BasePresenter headerItems = new ArrayList<>(); + private List headerItems = new ArrayList<>(); private String date; @@ -115,7 +115,7 @@ public class AttendanceTabPresenter extends BasePresenter { +public class ExamsHeader extends AbstractHeaderItem { private Day day; - ExamsHeaderItem(Day day) { + ExamsHeader(Day day) { this.day = day; } @@ -32,7 +32,7 @@ public class ExamsHeaderItem extends AbstractHeaderItem { + extends AbstractSectionableItem { private Exam exam; - ExamsSubItem(ExamsHeaderItem header, Exam exam) { + ExamsSubItem(ExamsHeader header, Exam exam) { super(header); this.exam = exam; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java index 062c0fd8..b60a4607 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java @@ -116,7 +116,7 @@ public class ExamsTabPresenter extends BasePresenter for (Day day : dayList) { day.resetExams(); - ExamsHeaderItem headerItem = new ExamsHeaderItem(day); + ExamsHeader headerItem = new ExamsHeader(day); List examList = day.getExams(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java index 5583f98c..d2423ec8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java @@ -12,7 +12,9 @@ public interface GradesContract { interface View extends BaseContract.View, SwipeRefreshLayout.OnRefreshListener { - void updateAdapterList(List headerItems); + void updateAdapterList(List headerItems); + + void updateSummaryAdapterList(List summarySubItems); void showNoItem(boolean show); @@ -28,6 +30,8 @@ public interface GradesContract { boolean isMenuVisible(); + void setSummaryAverages(String calculatedValue, String predictedValue, String finalValue ); + } interface Presenter extends BaseContract.Presenter { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesDialogFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesDialogFragment.java index b8da5a96..17ebc6e6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesDialogFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesDialogFragment.java @@ -71,7 +71,7 @@ public class GradesDialogFragment extends DialogFragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.grade_dialog, container, false); + View view = inflater.inflate(R.layout.grades_dialog, container, false); ButterKnife.bind(this, view); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java index 09c0a1bb..0d43b683 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java @@ -13,6 +13,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import java.util.List; @@ -27,17 +28,38 @@ import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; public class GradesFragment extends BaseFragment implements GradesContract.View { + @BindView(R.id.grade_fragment_summary_container) + View summary; + + @BindView(R.id.grade_fragment_details_container) + View details; + @BindView(R.id.grade_fragment_recycler) RecyclerView recyclerView; + @BindView(R.id.grade_fragment_summary_recycler) + RecyclerView summaryRecyclerView; + @BindView(R.id.grade_fragment_no_item_container) View noItemView; @BindView(R.id.grade_fragment_swipe_refresh) SwipeRefreshLayout refreshLayout; + @BindView(R.id.grade_fragment_summary_predicted_average) + TextView predictedAverage; + + @BindView(R.id.grade_fragment_summary_calculated_average) + TextView calculatedAverage; + + @BindView(R.id.grade_fragment_summary_final_average) + TextView finalAverage; + @Inject - FlexibleAdapter adapter; + FlexibleAdapter adapter; + + @Inject + FlexibleAdapter summaryAdapter; @Inject GradesContract.Presenter presenter; @@ -66,43 +88,57 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.semester_switch, menu); + inflater.inflate(R.menu.grades_action_menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.action_filter) { - presenter.onSemesterSwitchActive(); - CharSequence[] items = new CharSequence[]{ - getResources().getString(R.string.semester_text, 1), - getResources().getString(R.string.semester_text, 2), - }; - new AlertDialog.Builder(getContext()) - .setTitle(R.string.switch_semester) - .setNegativeButton(R.string.cancel, null) - .setSingleChoiceItems(items, this.currentSemester, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - presenter.onSemesterChange(which); - dialog.cancel(); - } - }).show(); - return true; - } else { - return super.onOptionsItemSelected(item); + switch (item.getItemId()) { + case R.id.action_semester_switch: + presenter.onSemesterSwitchActive(); + CharSequence[] items = new CharSequence[]{ + getResources().getString(R.string.semester_text, 1), + getResources().getString(R.string.semester_text, 2), + }; + new AlertDialog.Builder(getContext()) + .setTitle(R.string.switch_semester) + .setNegativeButton(R.string.cancel, null) + .setSingleChoiceItems(items, this.currentSemester, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + presenter.onSemesterChange(which); + dialog.cancel(); + } + }).show(); + return true; + case R.id.action_summary_switch: + boolean isDetailsVisible = details.getVisibility() == View.VISIBLE; + + item.setTitle(isDetailsVisible ? R.string.action_title_details : R.string.action_title_summary); + details.setVisibility(isDetailsVisible ? View.INVISIBLE : View.VISIBLE); + summary.setVisibility(isDetailsVisible ? View.VISIBLE : View.INVISIBLE); + return true; + default: + return super.onOptionsItemSelected(item); } } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { noItemView.setVisibility(View.GONE); + summary.setVisibility(View.INVISIBLE); + details.setVisibility(View.VISIBLE); adapter.setAutoCollapseOnExpand(true); adapter.setAutoScrollOnExpand(true); adapter.expandItemsAtStartUp(); + summaryAdapter.setDisplayHeadersAtStartUp(true); recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); + summaryRecyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); + summaryRecyclerView.setAdapter(summaryAdapter); + summaryRecyclerView.setNestedScrollingEnabled(false); refreshLayout.setColorSchemeResources(android.R.color.black); refreshLayout.setOnRefreshListener(this); @@ -116,6 +152,13 @@ public class GradesFragment extends BaseFragment implements GradesContract.View } } + @Override + public void setSummaryAverages(String calculatedValue, String predictedValue, String finalValue) { + calculatedAverage.setText(calculatedValue); + predictedAverage.setText(predictedValue); + finalAverage.setText(finalValue); + } + @Override public void setActivityTitle() { setTitle(getString(R.string.grades_text)); @@ -141,10 +184,15 @@ public class GradesFragment extends BaseFragment implements GradesContract.View } @Override - public void updateAdapterList(List headerItems) { + public void updateAdapterList(List headerItems) { adapter.updateDataSet(headerItems); } + @Override + public void updateSummaryAdapterList(List summarySubItems) { + summaryAdapter.updateDataSet(summarySubItems); + } + @Override public void onRefreshSuccessNoGrade() { showMessage(R.string.snackbar_no_grades); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesHeader.java similarity index 94% rename from app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesHeader.java index 33e96189..c39fcc4d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesHeader.java @@ -20,14 +20,14 @@ import io.github.wulkanowy.data.db.dao.entities.Subject; import io.github.wulkanowy.utils.AnimationUtils; import io.github.wulkanowy.utils.GradeUtils; -public class GradeHeaderItem - extends AbstractExpandableHeaderItem { +public class GradesHeader + extends AbstractExpandableHeaderItem { private Subject subject; private final boolean isShowSummary; - GradeHeaderItem(Subject subject, boolean isShowSummary) { + GradesHeader(Subject subject, boolean isShowSummary) { this.subject = subject; this.isShowSummary = isShowSummary; } @@ -38,7 +38,7 @@ public class GradeHeaderItem if (o == null || getClass() != o.getClass()) return false; - GradeHeaderItem that = (GradeHeaderItem) o; + GradesHeader that = (GradesHeader) o; return new EqualsBuilder() .append(subject, that.subject) @@ -54,7 +54,7 @@ public class GradeHeaderItem @Override public int getLayoutRes() { - return R.layout.grade_header; + return R.layout.grades_header; } @Override @@ -126,7 +126,7 @@ public class GradeHeaderItem } private String getGradesAverageString() { - float average = GradeUtils.calculate(item.getGradeList()); + float average = GradeUtils.calculateWeightedAverage(item.getGradeList()); if (average < 0) { return resources.getString(R.string.info_no_average); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java index edf00d3b..25eeef48 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java @@ -12,7 +12,12 @@ public abstract class GradesModule { abstract GradesContract.Presenter provideGradesPresenter(GradesPresenter gradesPresenter); @Provides - static FlexibleAdapter provideGradesAdapter() { + static FlexibleAdapter provideGradesAdapter() { + return new FlexibleAdapter<>(null); + } + + @Provides + static FlexibleAdapter provideGradesSummaryAdapter() { return new FlexibleAdapter<>(null); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java index ee6e0cb3..0f4d363c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java @@ -9,6 +9,7 @@ import org.threeten.bp.LocalDate; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import javax.inject.Inject; @@ -18,6 +19,7 @@ import io.github.wulkanowy.data.db.dao.entities.Subject; import io.github.wulkanowy.ui.base.BasePresenter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; import io.github.wulkanowy.utils.FabricUtils; +import io.github.wulkanowy.utils.GradeUtils; import io.github.wulkanowy.utils.async.AbstractTask; import io.github.wulkanowy.utils.async.AsyncListeners; @@ -31,12 +33,20 @@ public class GradesPresenter extends BasePresenter private OnFragmentIsReadyListener listener; - private List headerItems = new ArrayList<>(); + private List headerItems = new ArrayList<>(); + + private List summarySubItems = new ArrayList<>(); private boolean isFirstSight = false; private int semesterName; + private float finalAverage; + + private float predictedAverage; + + private float calculatedAverage; + @Inject GradesPresenter(RepositoryContract repository) { super(repository); @@ -56,7 +66,6 @@ public class GradesPresenter extends BasePresenter if (!isFirstSight) { isFirstSight = true; - reloadGrades(); } } @@ -76,12 +85,6 @@ public class GradesPresenter extends BasePresenter .putCustomAttribute("Name", semesterName)); } - private void reloadGrades() { - loadingTask = new AbstractTask(); - loadingTask.setOnFirstLoadingListener(this); - loadingTask.execute(); - } - @Override public void onFragmentVisible(boolean isVisible) { if (isVisible) { @@ -140,13 +143,17 @@ public class GradesPresenter extends BasePresenter boolean isShowSummary = getRepository().getSharedRepo().isShowGradesSummary(); headerItems = new ArrayList<>(); + summarySubItems = new ArrayList<>(); for (Subject subject : subjectList) { subject.resetGradeList(); List gradeList = subject.getGradeList(); + GradesSummaryHeader summaryHeader = new GradesSummaryHeader(subject, GradeUtils.calculateWeightedAverage(gradeList)); + summarySubItems.add(new GradesSummarySubItem(summaryHeader, subject)); + if (!gradeList.isEmpty()) { - GradeHeaderItem headerItem = new GradeHeaderItem(subject, isShowSummary); + GradesHeader headerItem = new GradesHeader(subject, isShowSummary); List subItems = new ArrayList<>(); @@ -159,6 +166,10 @@ public class GradesPresenter extends BasePresenter headerItems.add(headerItem); } } + + finalAverage = GradeUtils.calculateSubjectsAverage(subjectList, false); + predictedAverage = GradeUtils.calculateSubjectsAverage(subjectList, true); + calculatedAverage = GradeUtils.calculateDetailedSubjectsAverage(subjectList); } @Override @@ -170,9 +181,35 @@ public class GradesPresenter extends BasePresenter public void onEndLoadingAsync(boolean result, Exception exception) { getView().showNoItem(headerItems.isEmpty()); getView().updateAdapterList(headerItems); + + setSummaryAverages(); + getView().updateSummaryAdapterList(summarySubItems); + listener.onFragmentIsReady(); } + private void setSummaryAverages() { + getView().setSummaryAverages( + getFormattedAverage(calculatedAverage), + getFormattedAverage(predictedAverage), + getFormattedAverage(finalAverage) + ); + } + + private String getFormattedAverage(float average) { + if (-1.0f == average) { + return "-- --"; + } + + return String.format(Locale.FRANCE, "%.2f", average); + } + + private void reloadGrades() { + loadingTask = new AbstractTask(); + loadingTask.setOnFirstLoadingListener(this); + loadingTask.execute(); + } + private void cancelAsyncTasks() { if (refreshTask != null) { refreshTask.cancel(true); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSubItem.java index de9c54c6..82b338ae 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSubItem.java @@ -21,7 +21,7 @@ import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.utils.GradeUtils; public class GradesSubItem - extends AbstractSectionableItem { + extends AbstractSectionableItem { private Grade grade; @@ -29,7 +29,7 @@ public class GradesSubItem private View subjectAlertImage; - GradesSubItem(GradeHeaderItem header, Grade grade) { + GradesSubItem(GradesHeader header, Grade grade) { super(header); this.grade = grade; } @@ -64,7 +64,7 @@ public class GradesSubItem @Override public int getLayoutRes() { - return R.layout.grade_subitem; + return R.layout.grades_subitem; } @Override diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummaryHeader.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummaryHeader.java new file mode 100644 index 00000000..a06fa0d5 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummaryHeader.java @@ -0,0 +1,87 @@ +package io.github.wulkanowy.ui.main.grades; + +import android.view.View; +import android.widget.TextView; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.List; +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.items.AbstractHeaderItem; +import eu.davidea.flexibleadapter.items.IFlexible; +import eu.davidea.viewholders.FlexibleViewHolder; +import io.github.wulkanowy.R; +import io.github.wulkanowy.data.db.dao.entities.Subject; + +class GradesSummaryHeader extends AbstractHeaderItem { + + private Subject subject; + + private String average; + + GradesSummaryHeader(Subject subject, float average) { + this.subject = subject; + this.average = String.format(Locale.FRANCE, "%.2f", average); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + GradesSummaryHeader that = (GradesSummaryHeader) o; + + return new EqualsBuilder() + .append(subject, that.subject) + .append(average, that.average) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(subject) + .append(average) + .toHashCode(); + } + + @Override + public int getLayoutRes() { + return R.layout.grades_summary_header; + } + + @Override + public HeaderViewHolder createViewHolder(View view, FlexibleAdapter adapter) { + return new HeaderViewHolder(view, adapter); + } + + @Override + public void bindViewHolder(FlexibleAdapter adapter, HeaderViewHolder holder, int position, List payloads) { + holder.onBind(subject, average); + } + + static class HeaderViewHolder extends FlexibleViewHolder { + + @BindView(R.id.grades_summary_header_name) + TextView name; + + @BindView(R.id.grades_summary_header_average) + TextView average; + + HeaderViewHolder(View view, FlexibleAdapter adapter) { + super(view, adapter); + ButterKnife.bind(this, view); + } + + void onBind(Subject item, String value) { + name.setText(item.getName()); + average.setText("-1,00".equals(value) ? "" : value); + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummarySubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummarySubItem.java new file mode 100644 index 00000000..8ca9e484 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummarySubItem.java @@ -0,0 +1,83 @@ +package io.github.wulkanowy.ui.main.grades; + +import android.view.View; +import android.widget.TextView; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.items.AbstractSectionableItem; +import eu.davidea.flexibleadapter.items.IFlexible; +import eu.davidea.viewholders.FlexibleViewHolder; +import io.github.wulkanowy.R; +import io.github.wulkanowy.data.db.dao.entities.Subject; + +public class GradesSummarySubItem + extends AbstractSectionableItem { + + private Subject subject; + + public GradesSummarySubItem(GradesSummaryHeader header, Subject subject) { + super(header); + this.subject = subject; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + GradesSummarySubItem that = (GradesSummarySubItem) o; + + return new EqualsBuilder() + .append(subject, that.subject) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(subject) + .toHashCode(); + } + + @Override + public int getLayoutRes() { + return R.layout.grades_summary_subitem; + } + + @Override + public SubItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) { + return new SubItemViewHolder(view, adapter); + } + + @Override + public void bindViewHolder(FlexibleAdapter adapter, SubItemViewHolder holder, int position, List payloads) { + holder.onBind(subject); + } + + static class SubItemViewHolder extends FlexibleViewHolder { + + @BindView(R.id.grades_summary_subitem_final_grade) + TextView finalGrade; + + @BindView(R.id.grades_summary_subitem_predicted_grade) + TextView predictedGrade; + + SubItemViewHolder(View view, FlexibleAdapter adapter) { + super(view, adapter); + ButterKnife.bind(this, view); + } + + void onBind(Subject item) { + predictedGrade.setText(item.getPredictedRating()); + finalGrade.setText(item.getFinalRating()); + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java similarity index 95% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java index 7e932f78..93fab822 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java @@ -24,12 +24,12 @@ import eu.davidea.viewholders.ExpandableViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.Day; -public class TimetableHeaderItem - extends AbstractExpandableHeaderItem { +public class TimetableHeader + extends AbstractExpandableHeaderItem { private Day day; - TimetableHeaderItem(Day day) { + TimetableHeader(Day day) { this.day = day; } @@ -39,7 +39,7 @@ public class TimetableHeaderItem if (o == null || getClass() != o.getClass()) return false; - TimetableHeaderItem that = (TimetableHeaderItem) o; + TimetableHeader that = (TimetableHeader) o; return new EqualsBuilder() .append(day, that.day) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java index 4d64b54b..2bf47b33 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java @@ -25,11 +25,11 @@ import io.github.wulkanowy.ui.main.timetable.TimetableDialogFragment; public class TimetableSubItem - extends AbstractSectionableItem { + extends AbstractSectionableItem { private TimetableLesson lesson; - TimetableSubItem(TimetableHeaderItem header, TimetableLesson lesson) { + TimetableSubItem(TimetableHeader header, TimetableLesson lesson) { super(header); this.lesson = lesson; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java index 254060a2..0814ff3c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java @@ -8,7 +8,7 @@ public interface TimetableTabContract { interface View extends BaseContract.View { - void updateAdapterList(List headerItems); + void updateAdapterList(List headerItems); void expandItem(int item); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java index e0a30e8d..87db5195 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java @@ -44,7 +44,7 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo TimetableTabContract.Presenter presenter; @Inject - FlexibleAdapter adapter; + FlexibleAdapter adapter; private boolean isFragmentVisible = false; @@ -86,7 +86,7 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo } @Override - public void updateAdapterList(List headerItems) { + public void updateAdapterList(List headerItems) { adapter.updateDataSet(headerItems); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java index 3e1645f3..1afb055f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java @@ -15,7 +15,7 @@ public abstract class TimetableTabModule { @PerChildFragment @Provides - static FlexibleAdapter provideTimetableAdapter() { + static FlexibleAdapter provideTimetableAdapter() { return new FlexibleAdapter<>(null); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java index 8841a750..42f2424d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java @@ -28,7 +28,7 @@ public class TimetableTabPresenter extends BasePresenter headerItems = new ArrayList<>(); + private List headerItems = new ArrayList<>(); private String date; @@ -117,7 +117,7 @@ public class TimetableTabPresenter extends BasePresenter gradeList) { + public static float calculateWeightedAverage(List gradeList) { float counter = 0f; float denominator = 0f; for (Grade grade : gradeList) { - int integerWeight = getIntegerForWeightOfGrade(grade.getWeight()); - float floatValue = getMathematicalValueOfGrade(grade.getValue()); + int weight = getWeightValue(grade.getWeight()); + float value = getWeightedGradeValue(grade.getValue()); - if (floatValue != -1f) { - counter += floatValue * integerWeight; - denominator += integerWeight; + if (value != -1.0f) { + counter += value * weight; + denominator += weight; } } if (counter == 0f) { - return -1f; - } else { - return counter / denominator; + return -1.0f; } + return counter / denominator; } - private static float getMathematicalValueOfGrade(String valueOfGrade) { - if (valueOfGrade.matches("[-|+|=]{0,2}[0-6]") - || valueOfGrade.matches("[0-6][-|+|=]{0,2}")) { - if (valueOfGrade.matches("[-][0-6]") - || valueOfGrade.matches("[0-6][-]")) { - String replacedValue = valueOfGrade.replaceAll("[-]", ""); - return Float.valueOf(replacedValue) - 0.33f; - } else if (valueOfGrade.matches("[+][0-6]") - || valueOfGrade.matches("[0-6][+]")) { - String replacedValue = valueOfGrade.replaceAll("[+]", ""); - return Float.valueOf((replacedValue)) + 0.33f; - } else if (valueOfGrade.matches("[-|=]{1,2}[0-6]") - || valueOfGrade.matches("[0-6][-|=]{1,2}")) { - String replacedValue = valueOfGrade.replaceAll("[-|=]{1,2}", ""); - return Float.valueOf((replacedValue)) - 0.5f; - } else { - return Float.valueOf(valueOfGrade); - } - } else { - return -1; - } + public static float calculateSubjectsAverage(List subjectList, boolean usePredicted) { + return calculateSubjectsAverage(subjectList, usePredicted, false); } - private static int getIntegerForWeightOfGrade(String weightOfGrade) { - return Integer.valueOf(weightOfGrade.substring(0, weightOfGrade.length() - 3)); + public static float calculateDetailedSubjectsAverage(List subjectList) { + return calculateSubjectsAverage(subjectList, false, true); } public static int getValueColor(String value) { @@ -93,4 +74,80 @@ public final class GradeUtils { return R.color.default_grade; } } + + private static float calculateSubjectsAverage(List subjectList, boolean usePredicted, boolean useSubjectsAverages) { + float counter = 0f; + float denominator = 0f; + + for (Subject subject : subjectList) { + float value; + + if (useSubjectsAverages) { + value = calculateWeightedAverage(subject.getGradeList()); + } else { + value = getGradeValue(usePredicted ? subject.getPredictedRating() : subject.getFinalRating()); + } + + if (value != -1.0f) { + counter += Math.round(value); + denominator++; + } + } + + if (counter == 0) { + return -1.0f; + } + + return counter / denominator; + } + + private static float getGradeValue(String grade) { + if (validGradePattern.matcher(grade).matches()) { + return getWeightedGradeValue(grade); + } + + return getVerbalGradeValue(grade); + } + + private static float getVerbalGradeValue(String grade) { + switch (grade) { + case "celujący": + return 6f; + case "bardzo dobry": + return 5f; + case "dobry": + return 4f; + case "dostateczny": + return 3f; + case "dopuszczający": + return 2f; + case "niedostateczny": + return 1f; + default: + return -1f; + } + } + + private static float getWeightedGradeValue(String value) { + if (validGradePattern.matcher(value).matches()) { + if (value.matches("[-][0-6]") || value.matches("[0-6][-]")) { + String replacedValue = value.replaceAll("[-]", ""); + return Float.valueOf(replacedValue) - 0.33f; + } else if (value.matches("[+][0-6]") || value.matches("[0-6][+]")) { + String replacedValue = value.replaceAll("[+]", ""); + return Float.valueOf((replacedValue)) + 0.33f; + } else if (value.matches("[-|=]{1,2}[0-6]") || value.matches("[0-6][-|=]{1,2}")) { + String replacedValue = value.replaceAll("[-|=]{1,2}", ""); + return Float.valueOf((replacedValue)) - 0.5f; + } else { + return Float.valueOf(value); + } + } else { + return -1; + } + } + + private static int getWeightValue(String weightOfGrade) { + return Integer.valueOf(weightOfGrade.substring(0, weightOfGrade.length() - 3)); + } } diff --git a/app/src/main/res/drawable/ic_action_menu_semester.xml b/app/src/main/res/drawable/ic_action_menu_semester.xml new file mode 100644 index 00000000..b7acb9df --- /dev/null +++ b/app/src/main/res/drawable/ic_action_menu_semester.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_action_menu_summary.xml b/app/src/main/res/drawable/ic_action_menu_summary.xml new file mode 100644 index 00000000..1b2a93b8 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_menu_summary.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_exclamation_24dp.xml b/app/src/main/res/drawable/ic_exclamation_24dp.xml index 4d3c91cf..14950458 100644 --- a/app/src/main/res/drawable/ic_exclamation_24dp.xml +++ b/app/src/main/res/drawable/ic_exclamation_24dp.xml @@ -1,4 +1,4 @@ - + - - diff --git a/app/src/main/res/layout/fragment_grades.xml b/app/src/main/res/layout/fragment_grades.xml index f00b3108..f0642987 100644 --- a/app/src/main/res/layout/fragment_grades.xml +++ b/app/src/main/res/layout/fragment_grades.xml @@ -6,45 +6,166 @@ android:layout_height="match_parent" tools:context="io.github.wulkanowy.ui.main.grades.GradesFragment"> - - - - - - - - + android:layout_height="match_parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/app/src/main/res/layout/grade_dialog.xml b/app/src/main/res/layout/grades_dialog.xml similarity index 100% rename from app/src/main/res/layout/grade_dialog.xml rename to app/src/main/res/layout/grades_dialog.xml diff --git a/app/src/main/res/layout/grade_header.xml b/app/src/main/res/layout/grades_header.xml similarity index 97% rename from app/src/main/res/layout/grade_header.xml rename to app/src/main/res/layout/grades_header.xml index 032ad675..41b98076 100644 --- a/app/src/main/res/layout/grade_header.xml +++ b/app/src/main/res/layout/grades_header.xml @@ -51,6 +51,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/grade_header_average_text" + android:layout_marginEnd="10dp" + android:layout_marginRight="10dp" android:layout_marginTop="5dp" android:text="@string/info_grades_predicted_rating" android:textColor="@color/secondary_text" @@ -61,8 +63,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/grade_header_average_text" - android:layout_marginLeft="10dp" - android:layout_marginStart="10dp" android:layout_marginTop="5dp" android:layout_toEndOf="@+id/grade_header_predicted_rating_text" android:layout_toRightOf="@+id/grade_header_predicted_rating_text" diff --git a/app/src/main/res/layout/grade_subitem.xml b/app/src/main/res/layout/grades_subitem.xml similarity index 100% rename from app/src/main/res/layout/grade_subitem.xml rename to app/src/main/res/layout/grades_subitem.xml diff --git a/app/src/main/res/layout/grades_summary_header.xml b/app/src/main/res/layout/grades_summary_header.xml new file mode 100644 index 00000000..3055721f --- /dev/null +++ b/app/src/main/res/layout/grades_summary_header.xml @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/grades_summary_subitem.xml b/app/src/main/res/layout/grades_summary_subitem.xml new file mode 100644 index 00000000..c7715092 --- /dev/null +++ b/app/src/main/res/layout/grades_summary_subitem.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/grades_action_menu.xml b/app/src/main/res/menu/grades_action_menu.xml new file mode 100644 index 00000000..0533ae39 --- /dev/null +++ b/app/src/main/res/menu/grades_action_menu.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/app/src/main/res/menu/semester_switch.xml b/app/src/main/res/menu/semester_switch.xml deleted file mode 100644 index 6f8a027e..00000000 --- a/app/src/main/res/menu/semester_switch.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index aeb828d1..715e8ada 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -81,6 +81,9 @@ Brak lekcji w tym tygodniu Sala %s + Przewidywana + Końcowa + %d ocena %d oceny @@ -154,4 +157,10 @@ Brak sprawdzianów w tym tygodniu Typ Data wpisu + + Obliczona średnia + Szacowana średnia + Końcowa średnia + Podsumowanie + Szczegóły diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ffea541..d7cf1806 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -80,6 +80,9 @@ Final: %1$s No lesson in this week + Predicted + Final + Room %s @@ -149,4 +152,10 @@ No exams in this week Type Date of entry + + Calculated average + Predicted average + Final average + Summary + Details diff --git a/app/src/test/java/io/github/wulkanowy/utils/GradeUtilsTest.java b/app/src/test/java/io/github/wulkanowy/utils/GradeUtilsTest.java index 92a0b42c..1a5f9e4a 100644 --- a/app/src/test/java/io/github/wulkanowy/utils/GradeUtilsTest.java +++ b/app/src/test/java/io/github/wulkanowy/utils/GradeUtilsTest.java @@ -1,6 +1,5 @@ package io.github.wulkanowy.utils; -import org.junit.Assert; import org.junit.Test; import java.util.ArrayList; @@ -8,11 +7,14 @@ import java.util.List; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.Grade; +import io.github.wulkanowy.data.db.dao.entities.Subject; + +import static org.junit.Assert.assertEquals; public class GradeUtilsTest { @Test - public void averageTest() { + public void weightedAverageTest() { List gradeList = new ArrayList<>(); gradeList.add(new Grade().setValue("np.").setWeight("1,00")); gradeList.add(new Grade().setValue("-5").setWeight("10,00")); @@ -29,31 +31,48 @@ public class GradeUtilsTest { gradeList1.add(new Grade().setValue("5+").setWeight("10,00")); gradeList1.add(new Grade().setValue("5").setWeight("10,00")); - Assert.assertEquals(4.8f, GradeUtils.calculate(gradeList), 0.0f); - Assert.assertEquals(4.8f, GradeUtils.calculate(gradeList1), 0.0f); + assertEquals(4.8f, GradeUtils.calculateWeightedAverage(gradeList), 0.0f); + assertEquals(4.8f, GradeUtils.calculateWeightedAverage(gradeList1), 0.0f); } @Test - public void errorAverageTest() { + public void subjectsAverageTest() { + List subjectList = new ArrayList<>(); + subjectList.add(new Subject().setPredictedRating("2").setFinalRating("3")); + subjectList.add(new Subject().setPredictedRating("niedostateczny").setFinalRating("dopuszczający")); + subjectList.add(new Subject().setPredictedRating("dostateczny").setFinalRating("dobry")); + subjectList.add(new Subject().setPredictedRating("bardzo dobry").setFinalRating("celujący")); + subjectList.add(new Subject().setPredictedRating("2/3").setFinalRating("-4")); + + assertEquals(3.8f, GradeUtils.calculateSubjectsAverage(subjectList, false), 0.0f); + assertEquals(2.75f, GradeUtils.calculateSubjectsAverage(subjectList, true), 0.0f); + } + + @Test + public void abnormalAverageTest() { List gradeList = new ArrayList<>(); gradeList.add(new Grade().setValue("np.").setWeight("1,00")); - Assert.assertEquals(-1f, GradeUtils.calculate(gradeList), 0.0f); + List subjectList = new ArrayList<>(); + subjectList.add(new Subject().setFinalRating("nieklasyfikowany")); + + assertEquals(-1f, GradeUtils.calculateWeightedAverage(gradeList), 0.0f); + assertEquals(-1f, GradeUtils.calculateSubjectsAverage(subjectList, false), 0.0f); } @Test - public void getValueColor() { - Assert.assertEquals(R.color.six_grade, GradeUtils.getValueColor("-6")); - Assert.assertEquals(R.color.five_grade, GradeUtils.getValueColor("--5")); - Assert.assertEquals(R.color.four_grade, GradeUtils.getValueColor("=4")); - Assert.assertEquals(R.color.three_grade, GradeUtils.getValueColor("3-")); - Assert.assertEquals(R.color.two_grade, GradeUtils.getValueColor("2--")); - Assert.assertEquals(R.color.two_grade, GradeUtils.getValueColor("2=")); - Assert.assertEquals(R.color.one_grade, GradeUtils.getValueColor("1+")); - Assert.assertEquals(R.color.one_grade, GradeUtils.getValueColor("+1")); - Assert.assertEquals(R.color.default_grade, GradeUtils.getValueColor("6 (.XI)")); - Assert.assertEquals(R.color.default_grade, GradeUtils.getValueColor("Np")); - Assert.assertEquals(R.color.default_grade, GradeUtils.getValueColor("7")); - Assert.assertEquals(R.color.default_grade, GradeUtils.getValueColor("")); + public void getValueColorTest() { + assertEquals(R.color.six_grade, GradeUtils.getValueColor("-6")); + assertEquals(R.color.five_grade, GradeUtils.getValueColor("--5")); + assertEquals(R.color.four_grade, GradeUtils.getValueColor("=4")); + assertEquals(R.color.three_grade, GradeUtils.getValueColor("3-")); + assertEquals(R.color.two_grade, GradeUtils.getValueColor("2--")); + assertEquals(R.color.two_grade, GradeUtils.getValueColor("2=")); + assertEquals(R.color.one_grade, GradeUtils.getValueColor("1+")); + assertEquals(R.color.one_grade, GradeUtils.getValueColor("+1")); + assertEquals(R.color.default_grade, GradeUtils.getValueColor("6 (.XI)")); + assertEquals(R.color.default_grade, GradeUtils.getValueColor("Np")); + assertEquals(R.color.default_grade, GradeUtils.getValueColor("7")); + assertEquals(R.color.default_grade, GradeUtils.getValueColor("")); } } From a06d11412786cf34a8b78e9f2897cee1f50cbe6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Wed, 6 Jun 2018 19:38:54 +0200 Subject: [PATCH 34/41] Add logger (#131) --- api/build.gradle | 1 + .../java/io/github/wulkanowy/api/Client.java | 38 +++++++++++---- .../io/github/wulkanowy/api/DateTimeUtils.kt | 8 +++- .../wulkanowy/api/StudentAndParent.java | 26 +++++++--- .../java/io/github/wulkanowy/api/Vulcan.java | 9 +++- .../wulkanowy/api/mobile/RegisteredDevices.kt | 14 +----- .../wulkanowy/api/StudentAndParentTest.java | 6 +-- ...Parent.html => WitrynaUczniaIRodzica.html} | 0 app/build.gradle | 3 ++ .../io/github/wulkanowy/WulkanowyApp.java | 13 +++-- .../wulkanowy/data/db/dao/DbHelper.java | 12 ++--- .../data/db/dao/migrations/Migration23.java | 2 +- .../db/resources/ResourcesRepository.java | 7 +-- .../wulkanowy/data/sync/AccountSync.java | 17 +++---- .../wulkanowy/data/sync/AttendanceSync.java | 4 +- .../github/wulkanowy/data/sync/ExamsSync.java | 4 +- .../github/wulkanowy/data/sync/GradeSync.java | 9 ++-- .../wulkanowy/data/sync/SubjectSync.java | 4 +- .../wulkanowy/data/sync/SyncRepository.java | 21 ++++----- .../wulkanowy/data/sync/TimetableSync.java | 4 +- .../wulkanowy/services/jobs/SyncJob.java | 13 +++-- .../wulkanowy/ui/login/LoginPresenter.java | 4 +- .../ui/main/exams/ExamsFragment.java | 2 - .../wulkanowy/ui/splash/SplashActivity.java | 1 - .../github/wulkanowy/utils/FabricUtils.java | 16 +++++-- .../io/github/wulkanowy/utils/LogUtils.java | 26 ---------- .../github/wulkanowy/utils/LoggerUtils.java | 47 +++++++++++++++++++ .../wulkanowy/utils/async/AbstractTask.java | 8 ++-- .../wulkanowy/utils/security/Scrambler.java | 4 +- .../data/db/dao/entities/GradeTest.java | 2 - build.gradle | 4 ++ 31 files changed, 201 insertions(+), 128 deletions(-) rename api/src/test/resources/io/github/wulkanowy/api/{StudentAndParent.html => WitrynaUczniaIRodzica.html} (100%) delete mode 100644 app/src/main/java/io/github/wulkanowy/utils/LogUtils.java create mode 100644 app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java diff --git a/api/build.gradle b/api/build.gradle index f247baf1..1f7cf197 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -32,6 +32,7 @@ dependencies { implementation "org.jsoup:jsoup:$jsoup" implementation "org.apache.commons:commons-lang3:$apacheLang" implementation "com.google.code.gson:gson:$gson" + implementation "org.slf4j:slf4j-api:$slf4jApi" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index 277b8039..869ed65e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.api; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Date; @@ -27,6 +29,8 @@ public class Client { private Cookies cookies = new Cookies(); + private static final Logger logger = LoggerFactory.getLogger(Client.class); + Client(String email, String password, String symbol) { this.email = email; this.password = password; @@ -59,9 +63,13 @@ public class Client { } this.symbol = new Login(this).login(email, password, symbol); + logger.info("Login successful on {} at {}", getHost(), new Date()); } private boolean isLoggedIn() { + logger.debug("Last success request: {}", lastSuccessRequest); + logger.debug("Cookies: {}", getCookies().size()); + return getCookies().size() > 0 && lastSuccessRequest != null && 5 > TimeUnit.MILLISECONDS.toMinutes(new Date().getTime() - lastSuccessRequest.getTime()); @@ -75,10 +83,6 @@ public class Client { this.symbol = symbol; } - public void addCookies(Map items) { - cookies.addItems(items); - } - private Map getCookies() { return cookies.getItems(); } @@ -111,7 +115,11 @@ public class Client { this.cookies.addItems(cookies); } - Connection.Response response = Jsoup.connect(getFilledUrl(url)) + url = getFilledUrl(url); + + logger.debug("GET {}", url); + + Connection.Response response = Jsoup.connect(url) .followRedirects(true) .cookies(getCookies()) .execute(); @@ -128,7 +136,11 @@ public class Client { } public synchronized Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException { - Connection connection = Jsoup.connect(getFilledUrl(url)); + url = getFilledUrl(url); + + logger.debug("POST {}", url); + + Connection connection = Jsoup.connect(url); for (String[] data : params) { connection.data(data[0], data[1]); @@ -150,7 +162,11 @@ public class Client { public String getJsonStringByUrl(String url) throws IOException, VulcanException { login(); - Connection.Response response = Jsoup.connect(getFilledUrl(url)) + url = getFilledUrl(url); + + logger.debug("GET {}", url); + + Connection.Response response = Jsoup.connect(url) .followRedirects(true) .ignoreContentType(true) .cookies(getCookies()) @@ -164,7 +180,11 @@ public class Client { public String postJsonStringByUrl(String url, String[][] params) throws IOException, VulcanException { login(); - Connection connection = Jsoup.connect(getFilledUrl(url)); + url = getFilledUrl(url); + + logger.debug("POST {}", url); + + Connection connection = Jsoup.connect(url); for (String[] data : params) { connection.data(data[0], data[1]); @@ -196,7 +216,7 @@ public class Client { } if ("Błąd strony".equals(title)) { - throw new NotLoggedInErrorException(title + " " + doc.selectFirst("p, body") + ", status: " + code); + throw new NotLoggedInErrorException(title + " " + doc.selectFirst("body") + ", status: " + code); } return doc; diff --git a/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt index bad4e97d..3b620db5 100644 --- a/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt +++ b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt @@ -14,9 +14,13 @@ fun getFormattedDate(date: String): String { } fun getFormattedDate(date: String, format: String): String { - val sdf = SimpleDateFormat(LOG_DATE_PATTERN, Locale.ROOT) + return getFormattedDate(date, LOG_DATE_PATTERN, format) +} + +fun getFormattedDate(date: String, fromFormat: String, toFormat: String): String { + val sdf = SimpleDateFormat(fromFormat, Locale.ROOT) val d = sdf.parse(date) - sdf.applyPattern(format) + sdf.applyPattern(toFormat) return sdf.format(d) } diff --git a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java index a4b8fefa..03a7b0e5 100644 --- a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java +++ b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.api; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URL; @@ -32,6 +34,8 @@ public class StudentAndParent implements SnP { private String diaryID; + private static final Logger logger = LoggerFactory.getLogger(StudentAndParent.class); + StudentAndParent(Client client, String schoolID, String studentID, String diaryID) { this.client = client; this.schoolID = schoolID; @@ -43,6 +47,11 @@ public class StudentAndParent implements SnP { if (null == getStudentID() || "".equals(getStudentID())) { Document doc = client.getPageByUrl(getSnpHomePageUrl()); + if (doc.select("#idSection").isEmpty()) { + logger.error("Expected SnP page, got page with title: {} {}", doc.title(), doc.selectFirst("body")); + throw new VulcanException("Nieznany błąd podczas pobierania danych. Strona: " + doc.title()); + } + Student student = getCurrent(getStudents(doc)); studentID = student.getId(); @@ -72,24 +81,27 @@ public class StudentAndParent implements SnP { // get url to uonetplus-opiekun.fakelog.cf Document startPage = client.getPageByUrl(START_PAGE_URL); - Element studentTileLink = startPage.select(".panel.linkownia.pracownik.klient > a").first(); + Elements studentTileLink = startPage.select(".panel.linkownia.pracownik.klient > a"); - if (null == studentTileLink) { + logger.debug("studentTileLink: {}", studentTileLink.size()); + + if (studentTileLink.isEmpty()) { throw new VulcanException("Na pewno używasz konta z dostępem do Witryny ucznia i rodzica?"); } - String snpPageUrl = studentTileLink.attr("href"); + String snpPageUrl = studentTileLink.last().attr("href"); this.schoolID = getExtractedIdFromUrl(snpPageUrl); return snpPageUrl; } - String getExtractedIdFromUrl(String snpPageUrl) throws NotLoggedInErrorException { + String getExtractedIdFromUrl(String snpPageUrl) throws VulcanException { String[] path = snpPageUrl.split(client.getHost())[1].split("/"); if (5 != path.length) { - throw new NotLoggedInErrorException("You are probably not logged in " + snpPageUrl); + logger.error("Expected snp url, got {}", snpPageUrl); + throw new VulcanException("Na pewno używasz konta z dostępem do Witryny ucznia i rodzica?"); } return path[2]; @@ -107,12 +119,12 @@ public class StudentAndParent implements SnP { Map cookies = new HashMap<>(); cookies.put("idBiezacyDziennik", diaryID); cookies.put("idBiezacyUczen", studentID); - client.addCookies(cookies); Document doc = client.getPageByUrl(getBaseUrl() + url, true, cookies); if (!doc.title().startsWith("Witryna ucznia i rodzica")) { - throw new VulcanException("Expected SnP page, got page with title: " + doc.title()); + logger.error("Expected SnP page, got page with title: {} {}", doc.title(), doc.selectFirst("body")); + throw new VulcanException("Nieznany błąd podczas pobierania danych. Strona: " + doc.title()); } if (doc.title().endsWith("Strona główna")) { diff --git a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java index c8c4d2b0..2b4d1205 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java +++ b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java @@ -1,5 +1,8 @@ package io.github.wulkanowy.api; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import io.github.wulkanowy.api.attendance.AttendanceStatistics; @@ -30,17 +33,21 @@ public class Vulcan { private String diaryId; + private static final Logger logger = LoggerFactory.getLogger(Vulcan.class); + public void setCredentials(String email, String password, String symbol, String schoolId, String studentId, String diaryId) { this.schoolId = schoolId; this.studentId = studentId; this.diaryId = diaryId; client = new Client(email, password, symbol); + + logger.debug("Client created with symbol " + symbol); } public Client getClient() throws NotLoggedInErrorException { if (null == client) { - throw new NotLoggedInErrorException("Use setCredentials() method first"); + throw new NotLoggedInErrorException("Vulcan must be initialized by calling setCredentials() prior to fetch data"); } return client; diff --git a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt index cd08a585..d622b4de 100644 --- a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt +++ b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt @@ -1,8 +1,7 @@ package io.github.wulkanowy.api.mobile import io.github.wulkanowy.api.SnP -import java.text.SimpleDateFormat -import java.util.* +import io.github.wulkanowy.api.getFormattedDate class RegisteredDevices(private val snp: SnP) { @@ -28,7 +27,7 @@ class RegisteredDevices(private val snp: SnP) { devices.add(Device( cells[0].text().replace(" ($system)", ""), system, - formatDate(cells[1].text()), + getFormattedDate(cells[1].text(), "dd.MM.yyyy 'godz:' HH:mm:ss", "yyyy-MM-dd HH:mm:ss"), cells[2].select("a").attr("href") .split("/").last().toInt() )) @@ -36,13 +35,4 @@ class RegisteredDevices(private val snp: SnP) { return devices } - - // TODO: Move to date utils - private fun formatDate(date: String): String { - val sdf = SimpleDateFormat("dd.MM.yyyy 'godz:' HH:mm:ss", Locale.ROOT) - val d = sdf.parse(date) - sdf.applyPattern("yyyy-MM-dd HH:mm:ss") - - return sdf.format(d) - } } diff --git a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java index 1b6f7a91..ba0c8f7f 100644 --- a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java @@ -83,7 +83,7 @@ public class StudentAndParentTest { snp.getExtractedIdFromUrl("https://uonetplus-opiekun.vulcan.net.pl/demoupowiat/demo12345/Start/Index/")); } - @Test(expected = NotLoggedInErrorException.class) + @Test(expected = VulcanException.class) public void getExtractedIDNotLoggedTest() throws Exception { Mockito.when(client.getHost()).thenReturn("vulcan.net.pl"); StudentAndParent snp = new StudentAndParent(client, "symbol", null, null); @@ -131,8 +131,8 @@ public class StudentAndParentTest { @Test public void getDiariesAndStudentTest() throws IOException, VulcanException { - Document snpHome = Jsoup.parse(FixtureHelper.getAsString( - getClass().getResourceAsStream("StudentAndParent.html"))); + String input = FixtureHelper.getAsString(getClass().getResourceAsStream("WitrynaUczniaIRodzica.html")); + Document snpHome = Jsoup.parse(input); client = Mockito.mock(Client.class); Mockito.when(client.getPageByUrl(Mockito.anyString())).thenReturn(snpHome); diff --git a/api/src/test/resources/io/github/wulkanowy/api/StudentAndParent.html b/api/src/test/resources/io/github/wulkanowy/api/WitrynaUczniaIRodzica.html similarity index 100% rename from api/src/test/resources/io/github/wulkanowy/api/StudentAndParent.html rename to api/src/test/resources/io/github/wulkanowy/api/WitrynaUczniaIRodzica.html diff --git a/app/build.gradle b/app/build.gradle index 50677a7a..aefebcfb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -118,6 +118,9 @@ dependencies { implementation "com.jakewharton.threetenabp:threetenabp:$threeTenABP" implementation "com.google.android.gms:play-services-oss-licenses:$ossLicenses" + implementation "com.jakewharton.timber:timber:$timber" + implementation "at.favre.lib:slf4j-timber:$slf4jTimber" + implementation("com.crashlytics.sdk.android:crashlytics:$crashlyticsSdk@aar") { transitive = true } diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java index 5b68abbf..d3570512 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java @@ -12,11 +12,12 @@ import javax.inject.Inject; import dagger.android.AndroidInjector; import dagger.android.support.DaggerApplication; import eu.davidea.flexibleadapter.FlexibleAdapter; -import eu.davidea.flexibleadapter.utils.Log; import io.fabric.sdk.android.Fabric; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.di.DaggerAppComponent; -import io.github.wulkanowy.utils.LogUtils; +import io.github.wulkanowy.utils.FabricUtils; +import io.github.wulkanowy.utils.LoggerUtils; +import timber.log.Timber; public class WulkanowyApp extends DaggerApplication { @@ -39,15 +40,18 @@ public class WulkanowyApp extends DaggerApplication { if (repository.getSharedRepo().isUserLoggedIn()) { try { repository.getSyncRepo().initLastUser(); + FabricUtils.logLogin("Open app", true); } catch (Exception e) { - LogUtils.error("An error occurred when the application was started", e); + FabricUtils.logLogin("Open app", false); + Timber.e(e, "An error occurred when the application was started"); } } } private void enableDebugLog() { QueryBuilder.LOG_VALUES = true; - FlexibleAdapter.enableLogs(Log.Level.DEBUG); + FlexibleAdapter.enableLogs(eu.davidea.flexibleadapter.utils.Log.Level.DEBUG); + Timber.plant(new LoggerUtils.DebugLogTree()); } private void initializeFabric() { @@ -60,6 +64,7 @@ public class WulkanowyApp extends DaggerApplication { ) .debuggable(BuildConfig.DEBUG) .build()); + Timber.plant(new LoggerUtils.CrashlyticsTree()); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java index 7ffcfe27..904fa343 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java @@ -22,7 +22,7 @@ import io.github.wulkanowy.data.db.dao.migrations.Migration26; import io.github.wulkanowy.data.db.dao.migrations.Migration27; import io.github.wulkanowy.data.db.dao.migrations.Migration28; import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class DbHelper extends DaoMaster.OpenHelper { @@ -41,7 +41,7 @@ public class DbHelper extends DaoMaster.OpenHelper { @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - LogUtils.info("Cleaning user data oldVersion=" + oldVersion + " newVersion=" + newVersion); + Timber.i("Cleaning user data oldVersion=%s newVersion=%s", oldVersion, newVersion); Database database = new StandardDatabase(db); recreateDatabase(database); } @@ -54,11 +54,11 @@ public class DbHelper extends DaoMaster.OpenHelper { for (Migration migration : migrations) { if (oldVersion < migration.getVersion()) { try { - LogUtils.info("Applying migration to db schema v" + migration.getVersion() + "..."); + Timber.i("Applying migration to db schema v%s...", migration.getVersion()); migration.runMigration(db, sharedPref, vulcan); - LogUtils.info("Migration " + migration.getVersion() + " complete"); + Timber.i("Migration %s complete", migration.getVersion()); } catch (Exception e) { - e.printStackTrace(); + Timber.e(e, "Failed to apply migration"); recreateDatabase(db); break; } @@ -67,7 +67,7 @@ public class DbHelper extends DaoMaster.OpenHelper { } private void recreateDatabase(Database db) { - LogUtils.info("Database is recreating..."); + Timber.i("Database is recreating..."); sharedPref.setCurrentUserId(0); DaoMaster.dropAllTables(db, true); onCreate(db); diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java index 97b575a0..b2a41ad1 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java @@ -9,8 +9,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import io.github.wulkanowy.api.generic.Diary; import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.api.generic.Diary; import io.github.wulkanowy.data.db.dao.DbHelper; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.utils.security.Scrambler; diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java index 81aeaee2..f8a1baaa 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java @@ -3,8 +3,6 @@ package io.github.wulkanowy.data.db.resources; import android.content.Context; import android.content.res.Resources; -import com.crashlytics.android.Crashlytics; - import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; @@ -16,8 +14,8 @@ import io.github.wulkanowy.R; import io.github.wulkanowy.api.NotLoggedInErrorException; import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; import io.github.wulkanowy.utils.AppConstant; -import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; +import timber.log.Timber; @Singleton public class ResourcesRepository implements ResourcesContract { @@ -41,8 +39,7 @@ public class ResourcesRepository implements ResourcesContract { @Override public String getErrorLoginMessage(Exception exception) { - LogUtils.error(AppConstant.APP_NAME + " encountered a error", exception); - Crashlytics.logException(exception); + Timber.e(exception,"%s encountered a error", AppConstant.APP_NAME); if (exception instanceof CryptoException) { return resources.getString(R.string.encrypt_failed_text); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java index 032e95e4..b9f72cb2 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java @@ -24,9 +24,9 @@ import io.github.wulkanowy.data.db.dao.entities.Symbol; import io.github.wulkanowy.data.db.dao.entities.SymbolDao; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; import io.github.wulkanowy.utils.security.Scrambler; +import timber.log.Timber; @Singleton public class AccountSync { @@ -73,7 +73,7 @@ public class AccountSync { } private Account insertAccount(String email, String password) throws CryptoException { - LogUtils.debug("Register account: " + email); + Timber.d("Register account"); Account account = new Account() .setEmail(email) .setPassword(Scrambler.encrypt(email, password, context)); @@ -82,10 +82,11 @@ public class AccountSync { } private Symbol insertSymbol(Account account) throws VulcanException, IOException { - LogUtils.debug("Register symbol: " + vulcan.getSymbol()); + String schoolId = vulcan.getStudentAndParent().getSchoolID(); + Timber.d("Register symbol %s", vulcan.getSymbol()); Symbol symbol = new Symbol() .setUserId(account.getId()) - .setSchoolId(vulcan.getStudentAndParent().getSchoolID()) + .setSchoolId(schoolId) .setSymbol(vulcan.getSymbol()); daoSession.getSymbolDao().insert(symbol); @@ -97,7 +98,7 @@ public class AccountSync { vulcan.getStudentAndParent().getStudents(), symbol.getId() ); - LogUtils.debug("Register students: " + studentList.size()); + Timber.d("Register students %s", studentList.size()); daoSession.getStudentDao().insertInTx(studentList); } @@ -108,7 +109,7 @@ public class AccountSync { StudentDao.Properties.SymbolId.eq(symbolEntity.getId()), StudentDao.Properties.Current.eq(true) ).unique().getId()); - LogUtils.debug("Register diaries: " + diaryList.size()); + Timber.d("Register diaries %s", diaryList.size()); daoSession.getDiaryDao().insertInTx(diaryList); } @@ -118,7 +119,7 @@ public class AccountSync { daoSession.getDiaryDao().queryBuilder().where( DiaryDao.Properties.Current.eq(true) ).unique().getId()); - LogUtils.debug("Register semesters: " + semesterList.size()); + Timber.d("Register semesters %s", semesterList.size()); daoSession.getSemesterDao().insertInTx(semesterList); } @@ -130,7 +131,7 @@ public class AccountSync { throw new NotRegisteredUserException("Can't find user id in SharedPreferences"); } - LogUtils.debug("Initialization current user id=" + userId); + Timber.d("Init current user (%s)", userId); Account account = daoSession.getAccountDao().load(userId); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java index 9f379be6..18769418 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java @@ -18,7 +18,7 @@ import io.github.wulkanowy.data.db.dao.entities.DayDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class AttendanceSync { @@ -47,7 +47,7 @@ public class AttendanceSync { daoSession.getAttendanceLessonDao().saveInTx(lessonList); - LogUtils.debug("Synchronization attendance lessons (amount = " + lessonList.size() + ")"); + Timber.d("Attendance synchronization complete (%s)", lessonList.size()); } private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java index 85b4dac4..db473092 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java @@ -17,7 +17,7 @@ import io.github.wulkanowy.data.db.dao.entities.ExamDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public class ExamsSync { @@ -45,7 +45,7 @@ public class ExamsSync { daoSession.getExamDao().saveInTx(examList); - LogUtils.debug("Synchronization exams (amount = " + examList.size() + ")"); + Timber.d("Exams synchronization complete (%s)", examList.size()); } private Week getWeekFromDb(String date) { diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java index 0b70695d..59a71845 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -16,7 +15,7 @@ import io.github.wulkanowy.data.db.dao.entities.Semester; import io.github.wulkanowy.data.db.dao.entities.SubjectDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.EntitiesCompare; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class GradeSync { @@ -33,7 +32,7 @@ public class GradeSync { this.vulcan = vulcan; } - public void sync(long semesterId) throws IOException, VulcanException, ParseException { + public void sync(long semesterId) throws IOException, VulcanException { this.semesterId = semesterId; Semester semester = daoSession.getSemesterDao().load(semesterId); @@ -44,7 +43,7 @@ public class GradeSync { daoSession.getGradeDao().deleteInTx(semester.getGradeList()); daoSession.getGradeDao().insertInTx(lastList); - LogUtils.debug("Synchronization grades (amount = " + lastList.size() + ")"); + Timber.d("Grades synchronization complete (%s)", lastList.size()); } private void resetSemesterRelations(Semester semester) { @@ -64,7 +63,7 @@ public class GradeSync { return updatedList; } - private List getComparedList(Semester semester) throws IOException, VulcanException, ParseException { + private List getComparedList(Semester semester) throws IOException, VulcanException { List gradesFromNet = DataObjectConverter.gradesToGradeEntities( vulcan.getGradesList().getAll(semester.getValue()), semesterId); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java index 163a6234..1d0300d6 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java @@ -13,7 +13,7 @@ import io.github.wulkanowy.data.db.dao.entities.DaoSession; import io.github.wulkanowy.data.db.dao.entities.Semester; import io.github.wulkanowy.data.db.dao.entities.Subject; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class SubjectSync { @@ -40,7 +40,7 @@ public class SubjectSync { daoSession.getSubjectDao().deleteInTx(getSubjectsFromDb()); daoSession.getSubjectDao().insertInTx(lastList); - LogUtils.debug("Synchronization subjects (amount = " + lastList.size() + ")"); + Timber.d("Subjects synchronization complete (%s)", lastList.size()); } private List getSubjectsFromNet(Semester semester) throws VulcanException, IOException { diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java b/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java index 6a1e4dc1..05dd14fd 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import javax.inject.Inject; import javax.inject.Singleton; @@ -47,17 +46,17 @@ public class SyncRepository implements SyncContract { } @Override - public void initLastUser() throws IOException, CryptoException { + public void initLastUser() throws CryptoException { accountSync.initLastUser(); } @Override - public void syncGrades(int semesterName) throws VulcanException, IOException, ParseException { + public void syncGrades(int semesterName) throws VulcanException, IOException { gradeSync.sync(semesterName); } @Override - public void syncGrades() throws VulcanException, IOException, ParseException { + public void syncGrades() throws VulcanException, IOException { gradeSync.sync(database.getCurrentSemesterId()); } @@ -72,12 +71,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncAttendance() throws ParseException, IOException, VulcanException { + public void syncAttendance() throws IOException, VulcanException { attendanceSync.syncAttendance(database.getCurrentDiaryId(), null); } @Override - public void syncAttendance(long diaryId, String date) throws ParseException, IOException, VulcanException { + public void syncAttendance(long diaryId, String date) throws IOException, VulcanException { if (diaryId != 0) { attendanceSync.syncAttendance(diaryId, date); } else { @@ -86,12 +85,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncTimetable() throws VulcanException, IOException, ParseException { + public void syncTimetable() throws VulcanException, IOException { timetableSync.syncTimetable(database.getCurrentDiaryId(), null); } @Override - public void syncTimetable(long diaryId, String date) throws VulcanException, IOException, ParseException { + public void syncTimetable(long diaryId, String date) throws VulcanException, IOException { if (diaryId != 0) { timetableSync.syncTimetable(diaryId, date); } else { @@ -100,12 +99,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncExams() throws VulcanException, IOException, ParseException { + public void syncExams() throws VulcanException, IOException { examsSync.syncExams(database.getCurrentDiaryId(), null); } @Override - public void syncExams(long diaryId, String date) throws VulcanException, IOException, ParseException { + public void syncExams(long diaryId, String date) throws VulcanException, IOException { if (diaryId != 0) { examsSync.syncExams(diaryId, date); } else { @@ -114,7 +113,7 @@ public class SyncRepository implements SyncContract { } @Override - public void syncAll() throws VulcanException, IOException, ParseException { + public void syncAll() throws VulcanException, IOException { syncSubjects(); syncGrades(); syncAttendance(); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java index 309403c8..1ea2fa48 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java @@ -20,7 +20,7 @@ import io.github.wulkanowy.data.db.dao.entities.TimetableLessonDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class TimetableSync { @@ -49,7 +49,7 @@ public class TimetableSync { daoSession.getTimetableLessonDao().saveInTx(lessonList); - LogUtils.debug("Synchronization timetable lessons (amount = " + lessonList.size() + ")"); + Timber.d("Timetable synchronization complete (%s)", lessonList.size()); } private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java index 432bdc23..b2136391 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java @@ -4,7 +4,6 @@ import android.app.PendingIntent; import android.content.Context; import android.support.v4.app.NotificationCompat; -import com.crashlytics.android.Crashlytics; import com.firebase.jobdispatcher.Constraint; import com.firebase.jobdispatcher.FirebaseJobDispatcher; import com.firebase.jobdispatcher.GooglePlayDriver; @@ -27,7 +26,8 @@ import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.sync.NotRegisteredUserException; import io.github.wulkanowy.services.notifies.GradeNotify; import io.github.wulkanowy.ui.main.MainActivity; -import io.github.wulkanowy.utils.LogUtils; +import io.github.wulkanowy.utils.FabricUtils; +import timber.log.Timber; public class SyncJob extends SimpleJobService { @@ -74,13 +74,18 @@ public class SyncJob extends SimpleJobService { if (!gradeList.isEmpty() && repository.getSharedRepo().isNotifyEnable()) { showNotification(); } + + FabricUtils.logLogin("Background", true); + return JobService.RESULT_SUCCESS; } catch (NotRegisteredUserException e) { logError(e); stop(getApplicationContext()); + return JobService.RESULT_FAIL_NORETRY; } catch (Exception e) { logError(e); + return JobService.RESULT_FAIL_RETRY; } } @@ -122,7 +127,7 @@ public class SyncJob extends SimpleJobService { } private void logError(Exception e) { - Crashlytics.logException(e); - LogUtils.error("During background synchronization an error occurred", e); + FabricUtils.logLogin("Background", false); + Timber.e(e, "During background synchronization an error occurred"); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java index fb63e6af..3ae1ce9e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java @@ -85,7 +85,7 @@ public class LoginPresenter extends BasePresenter @Override public void onEndAsync(boolean success, Exception exception) { if (success) { - FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol()); + FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol(), "Success"); getView().openMainActivity(); return; } else if (exception instanceof BadCredentialsException) { @@ -95,7 +95,7 @@ public class LoginPresenter extends BasePresenter getView().setErrorSymbolRequired(); getView().showSoftInput(); } else { - FabricUtils.logRegister(false, symbol); + FabricUtils.logRegister(false, symbol, exception.getMessage()); getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java index 50325798..05557b81 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java @@ -2,7 +2,6 @@ package io.github.wulkanowy.ui.main.exams; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; @@ -13,7 +12,6 @@ import javax.inject.Inject; import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java index b90f396c..5e4dfec1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java @@ -4,7 +4,6 @@ import android.os.Bundle; import javax.inject.Inject; -import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.services.notifies.NotificationService; import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.login.LoginActivity; diff --git a/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java b/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java index 38811534..69897caa 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java +++ b/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java @@ -2,6 +2,7 @@ package io.github.wulkanowy.utils; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; +import com.crashlytics.android.answers.LoginEvent; import com.crashlytics.android.answers.SignUpEvent; public final class FabricUtils { @@ -10,17 +11,26 @@ public final class FabricUtils { throw new IllegalStateException("Utility class"); } - public static void logRegister(boolean result, String symbol) { + public static void logLogin(String method, boolean result) { + Answers.getInstance().logLogin(new LoginEvent() + .putMethod(method) + .putSuccess(result) + ); + } + + public static void logRegister(boolean result, String symbol, String message) { Answers.getInstance().logSignUp(new SignUpEvent() .putMethod("Login activity") .putSuccess(result) - .putCustomAttribute("symbol", symbol)); + .putCustomAttribute("symbol", symbol) + .putCustomAttribute("message", message) + ); } public static void logRefresh(String name, boolean result, String date) { Answers.getInstance().logCustom( new CustomEvent(name + " refresh") - .putCustomAttribute("Success", result ? 1 : 0) + .putCustomAttribute("Success", result ? "true" : "false") .putCustomAttribute("Date", date) ); } diff --git a/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java b/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java deleted file mode 100644 index f59bbf64..00000000 --- a/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.wulkanowy.utils; - -import android.util.Log; - -public final class LogUtils { - - private LogUtils() { - throw new IllegalStateException("Utility class"); - } - - public static void debug(String message) { - Log.d(AppConstant.APP_NAME, message); - } - - public static void error(String message, Throwable throwable) { - Log.e(AppConstant.APP_NAME, message, throwable); - } - - public static void error(String message) { - Log.e(AppConstant.APP_NAME, message); - } - - public static void info(String message) { - Log.i(AppConstant.APP_NAME, message); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java new file mode 100644 index 00000000..6e6c701b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java @@ -0,0 +1,47 @@ +package io.github.wulkanowy.utils; + +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; + +import com.crashlytics.android.Crashlytics; + +import timber.log.Timber; + +public final class LoggerUtils { + + public static class CrashlyticsTree extends Timber.Tree { + + @Override + protected void log(int priority, @Nullable String tag, @Nullable String message, @Nullable Throwable t) { + Crashlytics.setInt("priority", priority); + Crashlytics.setString("tag", tag); + + if (t == null) { + Crashlytics.log(message); + } else { + Crashlytics.setString("message", message); + Crashlytics.logException(t); + } + } + } + + public static class DebugLogTree extends Timber.DebugTree { + + @Override + protected void log(int priority, String tag, @NonNull String message, Throwable t) { + if ("HUAWEI".equals(Build.MANUFACTURER) || "samsung".equals(Build.MANUFACTURER)) { + if (priority == Log.VERBOSE || priority == Log.DEBUG || priority == Log.INFO) { + priority = Log.ERROR; + } + } + super.log(priority, AppConstant.APP_NAME, message, t); + } + + @Override + protected String createStackElementTag(@NonNull StackTraceElement element) { + return super.createStackElementTag(element) + " - " + element.getLineNumber(); + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java b/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java index 5106d641..44721416 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java +++ b/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java @@ -2,7 +2,7 @@ package io.github.wulkanowy.utils.async; import android.os.AsyncTask; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public class AbstractTask extends AsyncTask { @@ -28,7 +28,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onDoInBackgroundRefresh(); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } return true; } catch (Exception e) { @@ -45,7 +45,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onCanceledRefreshAsync(); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } } @@ -57,7 +57,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onEndRefreshAsync(result, exception); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } } } diff --git a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java index dc0c409a..8e425a89 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java +++ b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java @@ -26,7 +26,7 @@ import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.security.auth.x500.X500Principal; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public final class Scrambler { @@ -111,7 +111,7 @@ public final class Scrambler { throw new CryptoException("GenerateNewKey - String is empty"); } - LogUtils.debug("Key pair are create"); + Timber.d("Key pair are create"); } diff --git a/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java b/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java index 580ffdf5..f47e75e2 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java +++ b/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java @@ -3,8 +3,6 @@ package io.github.wulkanowy.data.db.dao.entities; import org.junit.Assert; import org.junit.Test; -import io.github.wulkanowy.R; - public class GradeTest { @Test diff --git a/build.gradle b/build.gradle index 0f974657..6af8545e 100644 --- a/build.gradle +++ b/build.gradle @@ -50,6 +50,10 @@ ext { gson = "2.8.5" ossLicenses = "15.0.1" + slf4jApi = "1.7.25" + slf4jTimber = "1.0.1" + timber = "4.7.0" + debugDb = "1.0.3" sqlcipher = "3.5.9" From 8d014ab7e92eb1ccd0fd020c24aaefb2f29c568a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82?= Date: Thu, 7 Jun 2018 08:13:49 +0200 Subject: [PATCH 35/41] Fix displaying the replacements in widget (#134) --- .../wulkanowy/ui/widgets/TimetableWidgetFactory.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java index 2a858b90..395e1c07 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java +++ b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java @@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.widgets; import android.content.Context; import android.content.Intent; +import android.graphics.Paint; import android.view.View; import android.widget.AdapterView; import android.widget.RemoteViews; @@ -75,13 +76,21 @@ public class TimetableWidgetFactory implements RemoteViewsService.RemoteViewsFac views.setTextViewText(R.id.timetable_widget_item_room, getRoomText(position)); if (!getDescriptionText(position).isEmpty()) { + views.setViewVisibility(R.id.timetable_widget_item_description, View.VISIBLE); views.setTextViewText(R.id.timetable_widget_item_description, getDescriptionText(position)); } else { views.setViewVisibility(R.id.timetable_widget_item_description, View.GONE); } - views.setOnClickFillInIntent(R.id.timetable_widget_item_container, new Intent()); + if (lessonList.get(position).getMovedOrCanceled()) { + views.setInt(R.id.timetable_widget_item_subject, "setPaintFlags", + Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); + } else { + views.setInt(R.id.timetable_widget_item_subject, "setPaintFlags", + Paint.ANTI_ALIAS_FLAG); + } + views.setOnClickFillInIntent(R.id.timetable_widget_item_container, new Intent()); return views; } From 81d177c2709c138c0cf4adcb08a524ec7b0063a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 9 Jun 2018 00:59:39 +0200 Subject: [PATCH 36/41] Hide actionbar on scroll (#135) --- .../wulkanowy/ui/main/MainActivity.java | 7 +- .../ui/main/settings/AboutScreen.java | 67 ------------------- .../ui/main/settings/SettingsFragment.java | 66 ++++++++++++------ app/src/main/res/layout/activity_main.xml | 49 ++++++-------- app/src/main/res/xml/preferences.xml | 45 +++++-------- build.gradle | 6 +- 6 files changed, 93 insertions(+), 147 deletions(-) delete mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/settings/AboutScreen.java diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java index f00f57c2..3fc03fca 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.view.View; @@ -41,6 +42,9 @@ public class MainActivity extends BaseActivity implements MainContract.View, @BindView(R.id.main_activity_progress_bar) View progressBar; + @BindView(R.id.main_activity_appbar) + AppBarLayout appBar; + @Named("Main") @Inject BasePagerAdapter pagerAdapter; @@ -56,7 +60,7 @@ public class MainActivity extends BaseActivity implements MainContract.View, public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); + setSupportActionBar((Toolbar) findViewById(R.id.main_activity_toolbar)); injectViews(); presenter.attachView(this, getIntent().getIntExtra(EXTRA_CARD_ID_KEY, -1)); @@ -88,6 +92,7 @@ public class MainActivity extends BaseActivity implements MainContract.View, @Override public boolean onTabSelected(int position, boolean wasSelected) { presenter.onTabSelected(position, wasSelected); + appBar.setExpanded(true, true); return true; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/settings/AboutScreen.java b/app/src/main/java/io/github/wulkanowy/ui/main/settings/AboutScreen.java deleted file mode 100644 index fe677de4..00000000 --- a/app/src/main/java/io/github/wulkanowy/ui/main/settings/AboutScreen.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.wulkanowy.ui.main.settings; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.preference.Preference; -import android.widget.Toast; - -import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; - -import io.github.wulkanowy.BuildConfig; -import io.github.wulkanowy.R; -import io.github.wulkanowy.utils.AppConstant; - -public class AboutScreen extends SettingsFragment { - - public static final String SHARED_KEY_ABOUT_VERSION = "about_version"; - - public static final String SHARED_KEY_ABOUT_LICENSES = "about_osl"; - - public static final String SHARED_KEY_ABOUT_REPO = "about_repo"; - - private Preference.OnPreferenceClickListener onProgrammerListener = new Preference.OnPreferenceClickListener() { - private int clicks = 0; - - @Override - public boolean onPreferenceClick(Preference preference) { - Toast.makeText(getActivity(), getVersionToast(clicks++), Toast.LENGTH_SHORT).show(); - return true; - } - - private int getVersionToast(int click) { - if (0 == click) { - return R.string.about_programmer_step1; - } - - if (1 == click) { - return R.string.about_programmer_step2; - } - - if (9 > click) { - return R.string.about_programmer_step3; - } - - return R.string.about_programmer; - } - }; - - public AboutScreen() { - // silence is golden - } - - @Override - public void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - findPreference(SHARED_KEY_ABOUT_VERSION).setSummary(BuildConfig.VERSION_NAME); - findPreference(SHARED_KEY_ABOUT_VERSION).setOnPreferenceClickListener(onProgrammerListener); - findPreference(SHARED_KEY_ABOUT_REPO).setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(AppConstant.REPO_URL))); - findPreference(SHARED_KEY_ABOUT_LICENSES).setIntent(new Intent(getActivity(), OssLicensesMenuActivity.class) - .putExtra("title", getString(R.string.pref_about_osl))); - } - - @Override - public void onCreatePreferences(Bundle bundle, String rootKey) { - setPreferencesFromResource(R.xml.preferences, rootKey); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java index e08a4902..661706c0 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java @@ -1,18 +1,23 @@ package io.github.wulkanowy.ui.main.settings; +import android.content.Intent; import android.content.SharedPreferences; +import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; +import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; -import android.support.v7.preference.PreferenceScreen; +import android.widget.Toast; +import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; + +import io.github.wulkanowy.BuildConfig; import io.github.wulkanowy.R; import io.github.wulkanowy.services.jobs.SyncJob; +import io.github.wulkanowy.utils.AppConstant; public class SettingsFragment extends PreferenceFragmentCompat - implements SharedPreferences.OnSharedPreferenceChangeListener, - PreferenceFragmentCompat.OnPreferenceStartScreenCallback{ + implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String SHARED_KEY_START_TAB = "startup_tab"; @@ -28,6 +33,38 @@ public class SettingsFragment extends PreferenceFragmentCompat public static final String SHARED_KEY_SERVICES_MOBILE_DISABLED = "services_disable_mobile"; + public static final String SHARED_KEY_ABOUT_VERSION = "about_version"; + + public static final String SHARED_KEY_ABOUT_LICENSES = "about_osl"; + + public static final String SHARED_KEY_ABOUT_REPO = "about_repo"; + + private Preference.OnPreferenceClickListener onProgrammerListener = new Preference.OnPreferenceClickListener() { + private int clicks = 0; + + @Override + public boolean onPreferenceClick(Preference preference) { + Toast.makeText(getActivity(), getVersionToast(clicks++), Toast.LENGTH_SHORT).show(); + return true; + } + + private int getVersionToast(int click) { + if (0 == click) { + return R.string.about_programmer_step1; + } + + if (1 == click) { + return R.string.about_programmer_step2; + } + + if (9 > click) { + return R.string.about_programmer_step3; + } + + return R.string.about_programmer; + } + }; + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); @@ -36,6 +73,12 @@ public class SettingsFragment extends PreferenceFragmentCompat @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + findPreference(SHARED_KEY_ABOUT_VERSION).setSummary(BuildConfig.VERSION_NAME); + findPreference(SHARED_KEY_ABOUT_VERSION).setOnPreferenceClickListener(onProgrammerListener); + findPreference(SHARED_KEY_ABOUT_REPO).setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(AppConstant.REPO_URL))); + findPreference(SHARED_KEY_ABOUT_LICENSES).setIntent(new Intent(getActivity(), OssLicensesMenuActivity.class) + .putExtra("title", getString(R.string.pref_about_osl))); } @Override @@ -43,21 +86,6 @@ public class SettingsFragment extends PreferenceFragmentCompat return this; } - @Override - public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, - PreferenceScreen preferenceScreen) { - FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction(); - AboutScreen fragment = new AboutScreen(); - Bundle args = new Bundle(); - args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.getKey()); - fragment.setArguments(args); - ft.add(R.id.main_activity_container, fragment, preferenceScreen.getKey()); - ft.addToBackStack(preferenceScreen.getKey()); - ft.commit(); - - return true; - } - @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(SHARED_KEY_SERVICES_ENABLE) || key.equals(SHARED_KEY_SERVICES_INTERVAL) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index f9201ad4..3f8473d8 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,37 +1,28 @@ - - - - - - + android:baselineAligned="false" + android:weightSum="1"> + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1"> + + + + + + android:layout_marginBottom="@dimen/bottom_navigation_height" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> - - + \ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index a2b1b368..300bc0f3 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -11,13 +11,13 @@ + android:summary="@string/required_restart" + android:title="@string/pref_grades_summary_line_show" /> + android:summary="@string/required_restart" + android:title="@string/pref_attendance_present_show" /> + android:title="@string/pref_services_mobile_data" /> - - - - - - - - - - + + + + diff --git a/build.gradle b/build.gradle index 6af8545e..760fb09f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ buildscript { repositories { - jcenter() mavenCentral() google() + jcenter() maven { url "https://plugins.gradle.org/m2/" } } dependencies { - classpath 'com.android.tools.build:gradle:3.1.2' + classpath 'com.android.tools.build:gradle:3.1.3' classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.0' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' @@ -70,9 +70,9 @@ ext { allprojects { repositories { - jcenter() mavenCentral() google() + jcenter() maven { url "https://jitpack.io" } } } From 7b7be1eef12c7ada1a4efebef24465201105c31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 10 Jun 2018 19:46:34 +0200 Subject: [PATCH 37/41] API fixes (#136) --- .../java/io/github/wulkanowy/api/Client.java | 7 +++++- .../io/github/wulkanowy/api/login/Login.java | 9 +++++++- .../wulkanowy/api/timetable/Timetable.java | 22 +++++++++++++++++-- .../api/timetable/TimetableTest.java | 1 + .../api/timetable/PlanLekcji-full.html | 15 ++++++++++++- 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index 869ed65e..8bbae7ca 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -62,6 +62,7 @@ public class Client { return; } + clearCookies(); this.symbol = new Login(this).login(email, password, symbol); logger.info("Login successful on {} at {}", getHost(), new Date()); } @@ -87,6 +88,10 @@ public class Client { return cookies.getItems(); } + public void clearCookies() { + cookies = new Cookies(); + } + String getHost() { return host; } @@ -216,7 +221,7 @@ public class Client { } if ("Błąd strony".equals(title)) { - throw new NotLoggedInErrorException(title + " " + doc.selectFirst("body") + ", status: " + code); + throw new NotLoggedInErrorException(title + " " + doc.body() + ", status: " + code); } return doc; diff --git a/api/src/main/java/io/github/wulkanowy/api/login/Login.java b/api/src/main/java/io/github/wulkanowy/api/login/Login.java index 04e1efc1..f6d4cd11 100644 --- a/api/src/main/java/io/github/wulkanowy/api/login/Login.java +++ b/api/src/main/java/io/github/wulkanowy/api/login/Login.java @@ -5,6 +5,8 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.parser.Parser; import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -21,6 +23,8 @@ public class Login { private Client client; + private static final Logger logger = LoggerFactory.getLogger(Login.class); + public Login(Client client) { this.client = client; } @@ -29,7 +33,8 @@ public class Login { Document certDoc = sendCredentials(email, password); if ("Błąd".equals(certDoc.title())) { - throw new NotLoggedInErrorException(certDoc.selectFirst("body").text()); + client.clearCookies(); + throw new NotLoggedInErrorException(certDoc.body().text()); } return sendCertificate(certDoc, symbol); @@ -88,6 +93,7 @@ public class Login { String title = targetDoc.title(); if ("Working...".equals(title)) { // on adfs login + logger.info("ADFS login"); title = sendCertData(targetDoc).title(); } @@ -96,6 +102,7 @@ public class Login { } if (!"Uonet+".equals(title)) { + logger.debug("Login failed. Body: {}", targetDoc.body()); throw new LoginErrorException("Expected page title `UONET+`, got " + title); } diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 8a2b9e14..95c40167 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.api.timetable; import org.apache.commons.lang3.StringUtils; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; @@ -13,8 +15,8 @@ import io.github.wulkanowy.api.VulcanException; import io.github.wulkanowy.api.generic.Lesson; import io.github.wulkanowy.api.generic.Week; -import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; import static io.github.wulkanowy.api.DateTimeUtilsKt.getDateAsTick; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; public class Timetable { @@ -22,6 +24,8 @@ public class Timetable { private SnP snp; + private static final Logger logger = LoggerFactory.getLogger(Timetable.class); + public Timetable(SnP snp) { this.snp = snp; } @@ -45,8 +49,13 @@ public class Timetable { private List getDays(Elements tableHeaderCells) { List days = new ArrayList<>(); + int numberOfDays = tableHeaderCells.size(); - for (int i = 2; i < 7; i++) { + if (numberOfDays > 7) { + logger.info("Number of days: {}", numberOfDays); + } + + for (int i = 2; i < numberOfDays; i++) { String[] dayHeaderCell = tableHeaderCells.get(i).html().split("
"); TimetableDay day = new TimetableDay(); @@ -127,6 +136,11 @@ public class Timetable { private void addLessonInfoFromElement(Lesson lesson, Element e) { Elements spans = e.select("span"); + if (spans.isEmpty()) { + logger.warn("Lesson span is empty"); + return; + } + addTypeInfo(lesson, spans); addNormalLessonInfo(lesson, spans); addChangesInfo(lesson, spans); @@ -213,6 +227,10 @@ public class Timetable { } private String[] getLessonAndGroupInfoFromSpan(Element span) { + if (!span.text().contains("[")) { + return new String[] {span.text(), ""}; + } + String[] subjectNameArray = span.text().split(" "); String groupName = subjectNameArray[subjectNameArray.length - 1]; diff --git a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java index 1383b830..7b3cce6e 100644 --- a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java @@ -156,6 +156,7 @@ public class TimetableTest extends StudentAndParentTestCase { Assert.assertEquals("poprzednio: Wychowanie fizyczne", full.getWeekTable().getDay(4).getLesson(2).getDescription()); Assert.assertEquals("egzamin", full.getWeekTable().getDay(3).getLesson(0).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription()); + Assert.assertEquals("poprzednio: Zajęcia z wychowawcą", full.getWeekTable().getDay(4).getLesson(5).getDescription()); Assert.assertEquals("opis w uwadze bez klasy w spanie", full.getWeekTable().getDay(4).getLesson(4).getDescription()); Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getDescription()); } diff --git a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html index c6ade3a5..c3dbfebe 100644 --- a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html +++ b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html @@ -364,7 +364,20 @@ - + +
+ Tworzenie i administrowanie bazami danych [zaw2] + + + +
+
+ Zajęcia z wychowawcą + Małgorzata Kowal + 43 + (zmiana organizacji zajęć) +
+ 6 From 072c504d2b70bcd642d3db05a3891d4bbc0b8d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Wed, 13 Jun 2018 03:07:34 +0200 Subject: [PATCH 38/41] Clean data user on bad user credentials (#138) --- .../java/io/github/wulkanowy/data/Repository.java | 6 ++++++ .../io/github/wulkanowy/data/RepositoryContract.java | 2 ++ .../io/github/wulkanowy/data/db/dao/DbContract.java | 2 ++ .../io/github/wulkanowy/data/db/dao/DbRepository.java | 11 +++++++++++ .../wulkanowy/data/db/shared/SharedPrefContract.java | 2 ++ .../data/db/shared/SharedPrefRepository.java | 6 ++++++ .../io/github/wulkanowy/services/jobs/SyncJob.java | 7 +++++++ 7 files changed, 36 insertions(+) diff --git a/app/src/main/java/io/github/wulkanowy/data/Repository.java b/app/src/main/java/io/github/wulkanowy/data/Repository.java index 1516c027..ac6a8b42 100644 --- a/app/src/main/java/io/github/wulkanowy/data/Repository.java +++ b/app/src/main/java/io/github/wulkanowy/data/Repository.java @@ -47,4 +47,10 @@ public class Repository implements RepositoryContract { public SyncContract getSyncRepo() { return synchronization; } + + @Override + public void cleanAllData() { + sharedPref.cleanSharedPref(); + database.recreateDatabase(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java b/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java index ffcfb046..e4dbd26b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java @@ -17,4 +17,6 @@ public interface RepositoryContract { DbContract getDbRepo(); SyncContract getSyncRepo(); + + void cleanAllData(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java index 34541d3e..f32884f5 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java @@ -30,4 +30,6 @@ public interface DbContract { long getCurrentSemesterId(); int getCurrentSemesterName(); + + void recreateDatabase(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java index 43eee87e..2c92c55d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java @@ -1,9 +1,12 @@ package io.github.wulkanowy.data.db.dao; +import org.greenrobot.greendao.database.Database; + import java.util.List; import javax.inject.Inject; +import io.github.wulkanowy.data.db.dao.entities.DaoMaster; import io.github.wulkanowy.data.db.dao.entities.DaoSession; import io.github.wulkanowy.data.db.dao.entities.DiaryDao; import io.github.wulkanowy.data.db.dao.entities.Grade; @@ -109,4 +112,12 @@ public class DbRepository implements DbContract { SemesterDao.Properties.Current.eq(true) ).unique(); } + + @Override + public void recreateDatabase() { + Database database = daoSession.getDatabase(); + + DaoMaster.dropAllTables(database, true); + DaoMaster.createAllTables(database, true); + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefContract.java b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefContract.java index b9d3fd14..61795f64 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefContract.java @@ -28,4 +28,6 @@ public interface SharedPrefContract { boolean isServicesEnable(); boolean isNotifyEnable(); + + void cleanSharedPref(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java index 11f43ca3..ca6624a8 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java @@ -88,4 +88,10 @@ public class SharedPrefRepository implements SharedPrefContract { public boolean isMobileDisable() { return settingsSharedPref.getBoolean(SettingsFragment.SHARED_KEY_SERVICES_MOBILE_DISABLED, false); } + + @Override + public void cleanSharedPref() { + appSharedPref.edit().clear().apply(); + settingsSharedPref.edit().clear().apply(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java index b2136391..d0fc73d6 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java @@ -21,6 +21,7 @@ import javax.inject.Inject; import dagger.android.AndroidInjection; import io.github.wulkanowy.R; +import io.github.wulkanowy.api.login.BadCredentialsException; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.sync.NotRegisteredUserException; @@ -82,6 +83,12 @@ public class SyncJob extends SimpleJobService { logError(e); stop(getApplicationContext()); + return JobService.RESULT_FAIL_NORETRY; + } catch (BadCredentialsException e) { + logError(e); + repository.cleanAllData(); + stop(getApplicationContext()); + return JobService.RESULT_FAIL_NORETRY; } catch (Exception e) { logError(e); From b63e28f9a928bd939010f3b034f2a46b1d9b034a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Wed, 13 Jun 2018 18:53:42 +0200 Subject: [PATCH 39/41] Separate synchronization from login (#137) --- .../wulkanowy/ui/login/LoginActivity.java | 7 ++++ .../wulkanowy/ui/login/LoginContract.java | 4 +- .../wulkanowy/ui/login/LoginPresenter.java | 38 +++++++++++-------- .../github/wulkanowy/ui/login/LoginTask.java | 21 +++++++--- app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 6 files changed, 51 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java index 37f3e03e..a0960af2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java @@ -14,6 +14,7 @@ import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import javax.inject.Inject; @@ -217,6 +218,12 @@ public class LoginActivity extends BaseActivity implements LoginContract.View { return findViewById(R.id.login_activity_container); } + + @Override + public void onSyncFailed() { + Toast.makeText(getApplicationContext(), R.string.login_sync_error, Toast.LENGTH_LONG).show(); + } + private void onLoginProgressUpdate(String step, String message) { loginProgressText.setText(String.format("%1$s/2 - %2$s...", step, message)); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java index 10f27f03..96bb49d6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java @@ -33,6 +33,8 @@ public interface LoginContract { void showActionBar(boolean show); + void onSyncFailed(); + } interface Presenter extends BaseContract.Presenter { @@ -45,7 +47,7 @@ public interface LoginContract { void onLoginProgress(int step); - void onEndAsync(boolean success, Exception exception); + void onEndAsync(int success, Exception exception); void onCanceledAsync(); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java index 3ae1ce9e..d8461bf3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java @@ -83,22 +83,30 @@ public class LoginPresenter extends BasePresenter } @Override - public void onEndAsync(boolean success, Exception exception) { - if (success) { - FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol(), "Success"); - getView().openMainActivity(); - return; - } else if (exception instanceof BadCredentialsException) { - getView().setErrorPassIncorrect(); - getView().showSoftInput(); - } else if (exception instanceof AccountPermissionException) { - getView().setErrorSymbolRequired(); - getView().showSoftInput(); - } else { - FabricUtils.logRegister(false, symbol, exception.getMessage()); - getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); + public void onEndAsync(int success, Exception exception) { + switch (success) { + case LoginTask.LOGIN_AND_SYNC_SUCCESS: + FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol(), "Success"); + getView().openMainActivity(); + return; + case LoginTask.SYNC_FAILED: + FabricUtils.logRegister(true, symbol, exception.getMessage()); + getView().onSyncFailed(); + getView().openMainActivity(); + return; + case LoginTask.LOGIN_FAILED: + if (exception instanceof BadCredentialsException) { + getView().setErrorPassIncorrect(); + getView().showSoftInput(); + } else if (exception instanceof AccountPermissionException) { + getView().setErrorSymbolRequired(); + getView().showSoftInput(); + } else { + FabricUtils.logRegister(false, symbol, exception.getMessage()); + getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); + } + break; } - getView().showActionBar(true); getView().showLoginProgress(false); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java index b22194da..2938a836 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java @@ -2,7 +2,13 @@ package io.github.wulkanowy.ui.login; import android.os.AsyncTask; -public class LoginTask extends AsyncTask { +public class LoginTask extends AsyncTask { + + public final static int LOGIN_AND_SYNC_SUCCESS = 1; + + public final static int LOGIN_FAILED = -1; + + public final static int SYNC_FAILED = 2; private LoginContract.Presenter presenter; @@ -18,18 +24,23 @@ public class LoginTask extends AsyncTask { } @Override - protected Boolean doInBackground(Void... params) { + protected Integer doInBackground(Void... params) { try { publishProgress(1); presenter.onDoInBackground(1); + } catch (Exception e) { + exception = e; + return LOGIN_FAILED; + } + try { publishProgress(2); presenter.onDoInBackground(2); } catch (Exception e) { exception = e; - return false; + return SYNC_FAILED; } - return true; + return LOGIN_AND_SYNC_SUCCESS; } @Override @@ -38,7 +49,7 @@ public class LoginTask extends AsyncTask { } @Override - protected void onPostExecute(Boolean success) { + protected void onPostExecute(Integer success) { presenter.onEndAsync(success, exception); } diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 715e8ada..af4fdf16 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -163,4 +163,5 @@ Końcowa średnia Podsumowanie Szczegóły + Podczas synchronizacji wystąpił błąd diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d7cf1806..1dce9f0a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -158,4 +158,5 @@ Final average Summary Details + An error has occurred during synchronization From 11578aa735f74c3ee12327a6621c7c904640f099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 14 Jun 2018 11:40:46 +0200 Subject: [PATCH 40/41] Add dark theme (#133) --- app/src/main/AndroidManifest.xml | 9 ++-- .../data/db/shared/SharedPrefContract.java | 2 + .../data/db/shared/SharedPrefRepository.java | 5 ++ .../wulkanowy/ui/base/BaseActivity.java | 1 + .../wulkanowy/ui/main/MainActivity.java | 11 ++-- .../attendance/AttendanceDialogFragment.java | 2 +- .../main/attendance/tab/AttendanceHeader.java | 20 ++------ .../ui/main/grades/GradesFragment.java | 2 + .../ui/main/settings/SettingsFragment.java | 50 +++++++++++++++++-- .../main/timetable/tab/TimetableHeader.java | 19 ++----- .../wulkanowy/ui/splash/SplashActivity.java | 5 ++ .../wulkanowy/ui/splash/SplashContract.java | 2 + .../wulkanowy/ui/splash/SplashPresenter.java | 1 + .../github/wulkanowy/utils/CommonUtils.java | 14 ++++++ app/src/main/res/drawable-night/ic_border.xml | 9 ++++ app/src/main/res/drawable/ic_border.xml | 2 +- .../res/drawable/ic_menu_attendance_24dp.xml | 4 +- .../main/res/drawable/ic_menu_exams_24dp.xml | 2 +- .../main/res/drawable/ic_menu_grade_26dp.xml | 4 +- .../main/res/drawable/ic_menu_other_24dp.xml | 4 +- .../res/drawable/ic_menu_timetable_24dp.xml | 4 +- app/src/main/res/drawable/ic_wrench_24dp.xml | 12 ----- app/src/main/res/layout/attendance_dialog.xml | 1 + app/src/main/res/layout/attendance_header.xml | 6 +-- .../main/res/layout/attendance_subitem.xml | 3 +- app/src/main/res/layout/current_week_tab.xml | 4 +- app/src/main/res/layout/exams_dialog.xml | 1 + app/src/main/res/layout/exams_header.xml | 4 +- app/src/main/res/layout/exams_subitem.xml | 2 +- .../res/layout/fragment_attendance_tab.xml | 8 +-- .../main/res/layout/fragment_exams_tab.xml | 6 +-- app/src/main/res/layout/fragment_grades.xml | 6 +-- .../res/layout/fragment_timetable_tab.xml | 6 +-- app/src/main/res/layout/grades_dialog.xml | 1 + app/src/main/res/layout/grades_header.xml | 8 +-- .../main/res/layout/grades_summary_header.xml | 2 +- app/src/main/res/layout/timetable_dialog.xml | 5 +- app/src/main/res/layout/timetable_header.xml | 6 +-- app/src/main/res/layout/timetable_subitem.xml | 7 ++- app/src/main/res/layout/timetable_widget.xml | 2 +- app/src/main/res/values-night/styles.xml | 17 +++++++ .../main/res/values-pl/prefernces_array.xml | 8 ++- app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values/attrs.xml | 4 ++ app/src/main/res/values/colors.xml | 7 ++- app/src/main/res/values/prefernces_array.xml | 16 +++++- app/src/main/res/values/strings.xml | 2 + app/src/main/res/values/styles.xml | 5 +- app/src/main/res/xml/preferences.xml | 7 +++ 49 files changed, 221 insertions(+), 108 deletions(-) create mode 100644 app/src/main/res/drawable-night/ic_border.xml delete mode 100644 app/src/main/res/drawable/ic_wrench_24dp.xml create mode 100644 app/src/main/res/values-night/styles.xml create mode 100644 app/src/main/res/values/attrs.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 24b5e188..dd982626 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,6 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" - android:supportsRtl="true" android:theme="@style/WulkanowyTheme"> + /> + android:theme="@style/WulkanowyTheme.DarkActionBar" /> + android:theme="@style/WulkanowyTheme.DarkActionBar" /> { @@ -86,15 +86,6 @@ public class AttendanceHeader @BindView(R.id.attendance_header_free_name) TextView freeName; - @BindColor(R.color.secondary_text) - int secondaryColor; - - @BindColor(R.color.free_day) - int backgroundFreeDay; - - @BindColor(android.R.color.black) - int black; - private Context context; HeaderViewHolder(View view, FlexibleAdapter adapter) { @@ -117,16 +108,15 @@ public class AttendanceHeader setInactiveHeader(item.getAttendanceLessons().isEmpty()); } - private void setInactiveHeader(boolean inactive) { ((FrameLayout) getContentView()).setForeground(inactive ? null : getSelectableDrawable()); - dayName.setTextColor(inactive ? secondaryColor : black); + dayName.setTextColor(CommonUtils.getThemeAttrColor(context, + inactive ? android.R.attr.textColorSecondary : android.R.attr.textColorPrimary)); if (inactive) { - getContentView().setBackgroundColor(backgroundFreeDay); + getContentView().setBackgroundColor(CommonUtils.getThemeAttrColor(context, R.attr.colorControlHighlight)); } else { - getContentView().setBackgroundDrawable(context.getResources() - .getDrawable(R.drawable.ic_border)); + getContentView().setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_border)); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java index 0d43b683..ca1b949c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java @@ -88,7 +88,9 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.clear(); inflater.inflate(R.menu.grades_action_menu, menu); + super.onCreateOptionsMenu(menu, inflater); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java index 661706c0..8bd93024 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java @@ -5,6 +5,7 @@ import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v7.app.AppCompatDelegate; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; import android.widget.Toast; @@ -14,6 +15,7 @@ import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; import io.github.wulkanowy.BuildConfig; import io.github.wulkanowy.R; import io.github.wulkanowy.services.jobs.SyncJob; +import io.github.wulkanowy.ui.main.MainActivity; import io.github.wulkanowy.utils.AppConstant; public class SettingsFragment extends PreferenceFragmentCompat @@ -25,6 +27,8 @@ public class SettingsFragment extends PreferenceFragmentCompat public static final String SHARED_KEY_ATTENDANCE_PRESENT = "attendance_present"; + public static final String SHARED_KEY_THEME = "theme"; + public static final String SHARED_KEY_SERVICES_ENABLE = "services_enable"; public static final String SHARED_KEY_NOTIFY_ENABLE = "notify_enable"; @@ -39,6 +43,10 @@ public class SettingsFragment extends PreferenceFragmentCompat public static final String SHARED_KEY_ABOUT_REPO = "about_repo"; + private boolean isStarted; + + private boolean isVisible; + private Preference.OnPreferenceClickListener onProgrammerListener = new Preference.OnPreferenceClickListener() { private int clicks = 0; @@ -93,6 +101,20 @@ public class SettingsFragment extends PreferenceFragmentCompat launchServices(sharedPreferences.getBoolean(SHARED_KEY_SERVICES_ENABLE, true), sharedPreferences); } + + if (key.equals(SHARED_KEY_THEME)) { + setCurrentTheme(sharedPreferences); + } + } + + private void setCurrentTheme(SharedPreferences sharedPreferences) { + AppCompatDelegate.setDefaultNightMode(Integer.parseInt(sharedPreferences.getString(SHARED_KEY_THEME, "1"))); + getActivity().finish(); + startActivity(MainActivity + .getStartIntent(getContext()) + .putExtra(MainActivity.EXTRA_CARD_ID_KEY, 4) + ); + getActivity().overridePendingTransition(0, 0); } private void launchServices(boolean start, SharedPreferences sharedPref) { @@ -107,11 +129,25 @@ public class SettingsFragment extends PreferenceFragmentCompat } } + private void setTitle() { + getActivity().setTitle(R.string.settings_text); + } + @Override - public void setMenuVisibility(boolean menuVisible) { - super.setMenuVisibility(menuVisible); - if (menuVisible) { - getActivity().setTitle(R.string.settings_text); + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + isVisible = isVisibleToUser; + if (isVisible && isStarted) { + setTitle(); + } + } + + @Override + public void onStart() { + super.onStart(); + isStarted = true; + if (isVisible) { + setTitle(); } } @@ -128,4 +164,10 @@ public class SettingsFragment extends PreferenceFragmentCompat getPreferenceScreen().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); } + + @Override + public void onStop() { + super.onStop(); + isStarted = false; + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java index 93fab822..cb877387 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java @@ -14,7 +14,6 @@ import org.apache.commons.lang3.builder.HashCodeBuilder; import java.util.List; -import butterknife.BindColor; import butterknife.BindView; import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; @@ -23,6 +22,7 @@ import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.viewholders.ExpandableViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.Day; +import io.github.wulkanowy.utils.CommonUtils; public class TimetableHeader extends AbstractExpandableHeaderItem { @@ -83,15 +83,6 @@ public class TimetableHeader @BindView(R.id.timetable_header_free_name) TextView freeName; - @BindColor(R.color.secondary_text) - int secondaryColor; - - @BindColor(R.color.free_day) - int backgroundFreeDay; - - @BindColor(android.R.color.black) - int black; - private Context context; HeaderViewHolder(View view, FlexibleAdapter adapter) { @@ -112,13 +103,13 @@ public class TimetableHeader private void setInactiveHeader(boolean inactive) { ((FrameLayout) getContentView()).setForeground(inactive ? null : getSelectableDrawable()); - dayName.setTextColor(inactive ? secondaryColor : black); + dayName.setTextColor(CommonUtils.getThemeAttrColor(context, + inactive ? android.R.attr.textColorSecondary : android.R.attr.textColorPrimary)); if (inactive) { - getContentView().setBackgroundColor(backgroundFreeDay); + getContentView().setBackgroundColor(CommonUtils.getThemeAttrColor(context, R.attr.colorControlHighlight)); } else { - getContentView().setBackgroundDrawable(context.getResources() - .getDrawable(R.drawable.ic_border)); + getContentView().setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_border)); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java index 5e4dfec1..21ce8ba5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.splash; import android.os.Bundle; +import android.support.v7.app.AppCompatDelegate; import javax.inject.Inject; @@ -38,6 +39,10 @@ public class SplashActivity extends BaseActivity implements SplashContract.View finish(); } + public void setCurrentThemeMode(int mode) { + AppCompatDelegate.setDefaultNightMode(mode); + } + @Override public void cancelNotifications() { new NotificationService(getApplicationContext()).cancelAll(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java index 1a186eca..a1c5ad72 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java @@ -11,6 +11,8 @@ public interface SplashContract { void openMainActivity(); void cancelNotifications(); + + void setCurrentThemeMode(int mode); } interface Presenter extends BaseContract.Presenter { diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java index ff64b3ca..69423348 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java @@ -18,6 +18,7 @@ public class SplashPresenter extends BasePresenter @Override public void attachView(@NonNull SplashContract.View view) { super.attachView(view); + getView().setCurrentThemeMode(getRepository().getSharedRepo().getCurrentTheme()); getView().cancelNotifications(); if (getRepository().getSharedRepo().isUserLoggedIn()) { diff --git a/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java b/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java index 8ec73faf..9c7b35fb 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java +++ b/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java @@ -1,7 +1,11 @@ package io.github.wulkanowy.utils; import android.app.Activity; +import android.content.Context; +import android.content.res.TypedArray; import android.net.Uri; +import android.support.annotation.AttrRes; +import android.support.annotation.ColorInt; import android.support.customtabs.CustomTabsIntent; import io.github.wulkanowy.R; @@ -37,4 +41,14 @@ public final class CommonUtils { return R.string.noColor_text; } } + + @ColorInt + public static int getThemeAttrColor(Context context, @AttrRes int colorAttr) { + final TypedArray array = context.obtainStyledAttributes(null, new int[]{colorAttr}); + try { + return array.getColor(0, 0); + } finally { + array.recycle(); + } + } } diff --git a/app/src/main/res/drawable-night/ic_border.xml b/app/src/main/res/drawable-night/ic_border.xml new file mode 100644 index 00000000..ca44eb29 --- /dev/null +++ b/app/src/main/res/drawable-night/ic_border.xml @@ -0,0 +1,9 @@ + + + + diff --git a/app/src/main/res/drawable/ic_border.xml b/app/src/main/res/drawable/ic_border.xml index dc33b8aa..f46b3ad7 100644 --- a/app/src/main/res/drawable/ic_border.xml +++ b/app/src/main/res/drawable/ic_border.xml @@ -6,4 +6,4 @@ android:centerColor="@android:color/transparent" android:centerX="0.01" android:startColor="#60606060" /> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_menu_attendance_24dp.xml b/app/src/main/res/drawable/ic_menu_attendance_24dp.xml index fdef7322..c0df16d6 100644 --- a/app/src/main/res/drawable/ic_menu_attendance_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_attendance_24dp.xml @@ -5,8 +5,8 @@ android:viewportHeight="24" android:viewportWidth="24"> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_menu_exams_24dp.xml b/app/src/main/res/drawable/ic_menu_exams_24dp.xml index 66294598..13179b7c 100644 --- a/app/src/main/res/drawable/ic_menu_exams_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_exams_24dp.xml @@ -4,7 +4,7 @@ android:viewportHeight="24" android:viewportWidth="24"> diff --git a/app/src/main/res/drawable/ic_menu_grade_26dp.xml b/app/src/main/res/drawable/ic_menu_grade_26dp.xml index 61506dad..3866cd3c 100644 --- a/app/src/main/res/drawable/ic_menu_grade_26dp.xml +++ b/app/src/main/res/drawable/ic_menu_grade_26dp.xml @@ -4,8 +4,8 @@ android:viewportHeight="26" android:viewportWidth="26"> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_menu_other_24dp.xml b/app/src/main/res/drawable/ic_menu_other_24dp.xml index 9fed586b..a0774724 100644 --- a/app/src/main/res/drawable/ic_menu_other_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_other_24dp.xml @@ -5,7 +5,7 @@ android:viewportHeight="24" android:viewportWidth="24"> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_menu_timetable_24dp.xml b/app/src/main/res/drawable/ic_menu_timetable_24dp.xml index a689dc06..63880977 100644 --- a/app/src/main/res/drawable/ic_menu_timetable_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_timetable_24dp.xml @@ -5,7 +5,7 @@ android:viewportHeight="24" android:viewportWidth="24"> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_wrench_24dp.xml b/app/src/main/res/drawable/ic_wrench_24dp.xml deleted file mode 100644 index 8f3a86fa..00000000 --- a/app/src/main/res/drawable/ic_wrench_24dp.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/attendance_dialog.xml b/app/src/main/res/layout/attendance_dialog.xml index 916c993c..4b0f1ff9 100644 --- a/app/src/main/res/layout/attendance_dialog.xml +++ b/app/src/main/res/layout/attendance_dialog.xml @@ -144,6 +144,7 @@ android:background="?attr/selectableItemBackground" android:focusable="true" android:text="@string/generic_dialog_close" + android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/attendance_header.xml b/app/src/main/res/layout/attendance_header.xml index 61dac631..350b2452 100644 --- a/app/src/main/res/layout/attendance_header.xml +++ b/app/src/main/res/layout/attendance_header.xml @@ -39,7 +39,7 @@ android:layout_marginTop="5dp" android:maxLines="1" android:text="@string/app_name" - android:textColor="@color/secondary_text" + android:textColor="?android:attr/android:textColorSecondary" android:textSize="14sp" /> - \ No newline at end of file + android:textColor="?attr/colorPrimary" + android:textSize="14sp" /> diff --git a/app/src/main/res/layout/exams_dialog.xml b/app/src/main/res/layout/exams_dialog.xml index 47fd7bb7..72d4b8dd 100644 --- a/app/src/main/res/layout/exams_dialog.xml +++ b/app/src/main/res/layout/exams_dialog.xml @@ -169,6 +169,7 @@ android:background="?attr/selectableItemBackground" android:focusable="true" android:text="@string/generic_dialog_close" + android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/exams_header.xml b/app/src/main/res/layout/exams_header.xml index 3895ae2e..7f7bf65f 100644 --- a/app/src/main/res/layout/exams_header.xml +++ b/app/src/main/res/layout/exams_header.xml @@ -2,7 +2,7 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/exams_subitem.xml b/app/src/main/res/layout/exams_subitem.xml index 52386de4..3f50f07c 100644 --- a/app/src/main/res/layout/exams_subitem.xml +++ b/app/src/main/res/layout/exams_subitem.xml @@ -53,4 +53,4 @@ android:text="@string/app_name" android:textSize="13sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_attendance_tab.xml b/app/src/main/res/layout/fragment_attendance_tab.xml index f98e7280..4dc450b5 100644 --- a/app/src/main/res/layout/fragment_attendance_tab.xml +++ b/app/src/main/res/layout/fragment_attendance_tab.xml @@ -1,6 +1,6 @@ - @@ -43,8 +43,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="46dp" - android:text="@string/attendance_no_entries" android:gravity="center" + android:text="@string/attendance_no_entries" android:textSize="20sp" /> diff --git a/app/src/main/res/layout/fragment_exams_tab.xml b/app/src/main/res/layout/fragment_exams_tab.xml index e446b2fb..433f5b1c 100644 --- a/app/src/main/res/layout/fragment_exams_tab.xml +++ b/app/src/main/res/layout/fragment_exams_tab.xml @@ -25,7 +25,7 @@ android:layout_height="match_parent" android:gravity="center"> - - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_grades.xml b/app/src/main/res/layout/fragment_grades.xml index f0642987..1f177a60 100644 --- a/app/src/main/res/layout/fragment_grades.xml +++ b/app/src/main/res/layout/fragment_grades.xml @@ -144,7 +144,7 @@ android:layout_height="match_parent" android:gravity="center"> - - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_timetable_tab.xml b/app/src/main/res/layout/fragment_timetable_tab.xml index 47aa5101..612b5df8 100644 --- a/app/src/main/res/layout/fragment_timetable_tab.xml +++ b/app/src/main/res/layout/fragment_timetable_tab.xml @@ -25,7 +25,7 @@ android:layout_height="match_parent" android:gravity="center"> - diff --git a/app/src/main/res/layout/grades_dialog.xml b/app/src/main/res/layout/grades_dialog.xml index 048f1e1b..c5cf073e 100644 --- a/app/src/main/res/layout/grades_dialog.xml +++ b/app/src/main/res/layout/grades_dialog.xml @@ -177,6 +177,7 @@ android:background="?attr/selectableItemBackground" android:focusable="true" android:text="@string/generic_dialog_close" + android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/grades_header.xml b/app/src/main/res/layout/grades_header.xml index 41b98076..b819dd54 100644 --- a/app/src/main/res/layout/grades_header.xml +++ b/app/src/main/res/layout/grades_header.xml @@ -29,7 +29,7 @@ android:layout_below="@+id/grade_header_subject_text" android:layout_marginTop="5dp" android:text="@string/app_name" - android:textColor="@color/secondary_text" + android:textColor="?android:attr/android:textColorSecondary" android:textSize="12sp" /> @@ -192,6 +192,7 @@ android:background="?attr/selectableItemBackground" android:focusable="true" android:text="@string/generic_dialog_close" + android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/timetable_header.xml b/app/src/main/res/layout/timetable_header.xml index 1e8ecec8..53ea8ce4 100644 --- a/app/src/main/res/layout/timetable_header.xml +++ b/app/src/main/res/layout/timetable_header.xml @@ -39,7 +39,7 @@ android:layout_marginTop="5dp" android:maxLines="1" android:text="@string/app_name" - android:textColor="@color/secondary_text" + android:textColor="?android:attr/android:textColorSecondary" android:textSize="14sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_subitem.xml b/app/src/main/res/layout/timetable_subitem.xml index 86b173b4..3c3cdc42 100644 --- a/app/src/main/res/layout/timetable_subitem.xml +++ b/app/src/main/res/layout/timetable_subitem.xml @@ -13,7 +13,6 @@ android:foreground="?attr/selectableItemBackgroundBorderless" card_view:cardElevation="0dp"> - @@ -92,4 +91,4 @@ tool:ignore="contentDescription"/> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_widget.xml b/app/src/main/res/layout/timetable_widget.xml index c2f146ae..acf8d238 100644 --- a/app/src/main/res/layout/timetable_widget.xml +++ b/app/src/main/res/layout/timetable_widget.xml @@ -72,4 +72,4 @@ android:text="@string/widget_timetable_no_lesson" android:textColor="@android:color/black" android:textSize="20sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..d0b4f53f --- /dev/null +++ b/app/src/main/res/values-night/styles.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/app/src/main/res/values-pl/prefernces_array.xml b/app/src/main/res/values-pl/prefernces_array.xml index 4e66a373..3731be40 100644 --- a/app/src/main/res/values-pl/prefernces_array.xml +++ b/app/src/main/res/values-pl/prefernces_array.xml @@ -9,4 +9,10 @@ 12 godzin 24 godzin - \ No newline at end of file + + Wyłączony + Włączony + Automatyczny + Używaj ustawień systemowych + + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index af4fdf16..1af99630 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -129,6 +129,7 @@ Pokazuj podsumowanie w ocenach Pokazuj obecność we frekwencji Wymagany restart + Ciemny motyw (Beta) Powiadomienia Pokazuj powiadomienia diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 00000000..3593e29e --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 90f8c15e..68145e05 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -10,8 +10,11 @@ #FFE68C #CE9AD2 #d32f2f + #cdcdcd + #4c4c4c #333 - #cdcdcd - #eee + + #303030 + #ffffff diff --git a/app/src/main/res/values/prefernces_array.xml b/app/src/main/res/values/prefernces_array.xml index 346b57c3..59f4fffe 100644 --- a/app/src/main/res/values/prefernces_array.xml +++ b/app/src/main/res/values/prefernces_array.xml @@ -12,6 +12,20 @@ 2 3 + + + Off + On + Auto + Follow system settings + + + 1 + 2 + 0 + -1 + + 10 minutes 30 minutes @@ -30,4 +44,4 @@ 720 1440 - \ 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 1dce9f0a..21e63f5f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -125,6 +125,8 @@ Show present in attendance Required restart + Dark theme (Beta) + Notifications Show the notifications diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index d72afb53..1eb55f9d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,6 +1,6 @@ - -