1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-09-20 01:29:09 -05:00

Add timetable to Wulkanowy (#38)

* Add timetable entities, synchronization and UI
* Add better code hub config
* Update SDK tools
* Change activity to ui

* [API] fix lesson room, when division into groups
* [API] Rewrite lesson parser
* [API] Add support for new lesson type
* [API] Fix for substitutions in the timetable
This commit is contained in:
Rafał Borcz 2017-12-11 19:45:28 +01:00 committed by Mikołaj Pich
parent 647ed08460
commit c111e43f18
77 changed files with 3125 additions and 471 deletions

5
.bettercodehub.yml Normal file
View File

@ -0,0 +1,5 @@
exclude:
- /app/src/main/java/io/github/wulkanowy/dao/entities/.*
component_depth: 1
languages:
- java

View File

@ -4,8 +4,9 @@ apply plugin: 'jacoco'
apply plugin: 'com.jfrog.bintray' apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.github.dcendents.android-maven'
sourceCompatibility = "1.7" compileJava.options.encoding = "UTF-8"
targetCompatibility = "1.7" compileTestJava.options.encoding = "UTF-8"
ext { ext {
PUBLISH_GROUP_ID = GROUP_ID PUBLISH_GROUP_ID = GROUP_ID

View File

@ -9,6 +9,8 @@ public class Day {
private String date = ""; private String date = "";
private String dayName = "";
private boolean isFreeDay = false; private boolean isFreeDay = false;
private String freeDayName = ""; private String freeDayName = "";
@ -35,6 +37,15 @@ public class Day {
return this; return this;
} }
public String getDayName() {
return dayName;
}
public Day setDayName(String dayName) {
this.dayName = dayName;
return this;
}
public boolean isFreeDay() { public boolean isFreeDay() {
return isFreeDay; return isFreeDay;
} }

View File

@ -10,6 +10,8 @@ public class Lesson {
public static final String CLASS_NEW_MOVED_IN_OR_CHANGED = "x-treelabel-zas"; public static final String CLASS_NEW_MOVED_IN_OR_CHANGED = "x-treelabel-zas";
private String number = "";
private String subject = ""; private String subject = "";
private String teacher = ""; private String teacher = "";
@ -24,6 +26,8 @@ public class Lesson {
private String endTime = ""; private String endTime = "";
private String date = "";
private boolean isEmpty = false; private boolean isEmpty = false;
private boolean isDivisionIntoGroups = false; private boolean isDivisionIntoGroups = false;
@ -36,6 +40,15 @@ public class Lesson {
private boolean isNewMovedInOrChanged = false; private boolean isNewMovedInOrChanged = false;
public String getNumber() {
return number;
}
public Lesson setNumber(String number) {
this.number = number;
return this;
}
public String getSubject() { public String getSubject() {
return subject; return subject;
} }
@ -99,6 +112,15 @@ public class Lesson {
return this; return this;
} }
public String getDate() {
return date;
}
public Lesson setDate(String date) {
this.date = date;
return this;
}
public boolean isEmpty() { public boolean isEmpty() {
return isEmpty; return isEmpty;
} }

View File

@ -5,8 +5,12 @@ import org.jsoup.nodes.Element;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale;
import io.github.wulkanowy.api.StudentAndParent; import io.github.wulkanowy.api.StudentAndParent;
@ -20,125 +24,178 @@ public class Timetable {
this.snp = snp; this.snp = snp;
} }
public Week getWeekTable() throws IOException { public Week getWeekTable() throws IOException, ParseException {
return getWeekTable(""); return getWeekTable("");
} }
public Week getWeekTable(String tick) throws IOException { public Week getWeekTable(final String tick) throws IOException, ParseException {
Element table = snp.getSnPPageDocument(TIMETABLE_PAGE_URL + tick) Element table = snp.getSnPPageDocument(TIMETABLE_PAGE_URL + tick)
.select(".mainContainer .presentData").first(); .select(".mainContainer .presentData").first();
Elements tableHeaderCells = table.select("thead th"); List<Day> days = getDays(table.select("thead th"));
setLessonToDays(table, days);
return new Week()
.setStartDayDate(days.get(0).getDate())
.setDays(days);
}
private List<Day> getDays(Elements tableHeaderCells) throws ParseException {
List<Day> days = new ArrayList<>(); List<Day> days = new ArrayList<>();
for (int i = 2; i < 7; i++) { for (int i = 2; i < 7; i++) {
String[] dayHeaderCell = tableHeaderCells.get(i).html().split("<br>"); String[] dayHeaderCell = tableHeaderCells.get(i).html().split("<br>");
boolean isFreeDay = tableHeaderCells.get(i).hasClass("free-day");
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 day = new Day();
day.setDate(dayHeaderCell[1]); day.setDayName(dayHeaderCell[0]);
day.setDate(sdf.format(d));
if (isFreeDay) { if (tableHeaderCells.get(i).hasClass("free-day")) {
day.setFreeDay(isFreeDay); day.setFreeDay(true);
day.setFreeDayName(dayHeaderCell[2]); day.setFreeDayName(dayHeaderCell[2]);
} }
days.add(day); days.add(day);
} }
Elements hoursInDays = table.select("tbody tr"); return days;
}
// fill days in week with lessons private void setLessonToDays(Element table, List<Day> days) {
for (Element row : hoursInDays) { for (Element row : table.select("tbody tr")) {
Elements hours = row.select("td"); Elements hours = row.select("td");
// fill hours in day // fill hours in day
for (int i = 2; i < hours.size(); i++) { for (int i = 2; i < hours.size(); i++) {
Lesson lesson = new Lesson(); Lesson lesson = new Lesson();
Elements e = hours.get(i).select("div");
switch (e.size()) {
case 1:
lesson = getLessonFromElement(e.first());
break;
case 3:
lesson = getLessonFromElement(e.get(1));
break;
default:
lesson.setEmpty(true);
break;
}
String[] startEndEnd = hours.get(1).text().split(" "); String[] startEndEnd = hours.get(1).text().split(" ");
lesson.setStartTime(startEndEnd[0]); lesson.setStartTime(startEndEnd[0]);
lesson.setEndTime(startEndEnd[1]); lesson.setEndTime(startEndEnd[1]);
lesson.setDate(days.get(i - 2).getDate());
lesson.setNumber(hours.get(0).text());
addLessonDetails(lesson, hours.get(i).select("div"));
days.get(i - 2).setLesson(lesson); days.get(i - 2).setLesson(lesson);
} }
} }
Element startDayCellHeader = tableHeaderCells.get(2);
String[] dayDescription = startDayCellHeader.html().split("<br>");
return new Week()
.setStartDayDate(dayDescription[1])
.setDays(days);
} }
private Lesson getLessonFromElement(Element e) { private void addLessonDetails(Lesson lesson, Elements e) {
Lesson lesson = new Lesson(); switch (e.size()) {
case 1:
addLessonInfoFromElement(lesson, e.first());
break;
case 2:
addLessonInfoFromElement(lesson, e.last());
break;
case 3:
addLessonInfoFromElement(lesson, e.get(1));
break;
default:
lesson.setEmpty(true);
break;
}
}
private void addLessonInfoFromElement(Lesson lesson, Element e) {
Elements spans = e.select("span"); Elements spans = e.select("span");
lesson.setSubject(spans.get(0).text()); addTypeInfo(lesson, spans);
lesson.setTeacher(spans.get(1).text()); addNormalLessonInfo(lesson, spans);
lesson.setRoom(spans.get(2).text()); addChangesInfo(lesson, spans);
addGroupLessonInfo(lesson, spans);
// okienko dla uczniów
if (5 == spans.size()) {
lesson.setTeacher(spans.get(2).text());
lesson.setRoom(spans.get(3).text());
}
addGroupDivisionInfo(lesson, spans);
adTypeInfo(lesson, spans);
addDescriptionInfo(lesson, spans);
return lesson;
} }
private void addGroupDivisionInfo(Lesson lesson, Elements e) { private void addTypeInfo(Lesson lesson, Elements spans) {
if ((4 == e.size() && (e.first().attr("class").equals("")) || if (spans.first().hasClass(Lesson.CLASS_PLANNING)) {
(5 == e.size() && e.first().hasClass(Lesson.CLASS_NEW_MOVED_IN_OR_CHANGED)))) {
lesson.setDivisionIntoGroups(true);
String[] subjectNameArray = lesson.getSubject().split(" ");
String groupName = subjectNameArray[subjectNameArray.length - 1];
lesson.setSubject(lesson.getSubject().replace(" " + groupName, ""));
lesson.setGroupName(StringUtils.substringBetween(groupName, "[", "]"));
lesson.setTeacher(e.get(2).text());
lesson.setRoom(e.get(3).text());
}
}
private void adTypeInfo(Lesson lesson, Elements e) {
if (e.first().hasClass(Lesson.CLASS_MOVED_OR_CANCELED)) {
lesson.setMovedOrCanceled(true);
} else if (e.first().hasClass(Lesson.CLASS_NEW_MOVED_IN_OR_CHANGED)) {
lesson.setNewMovedInOrChanged(true);
} else if (e.first().hasClass(Lesson.CLASS_PLANNING)) {
lesson.setPlanning(true); lesson.setPlanning(true);
} }
if (e.last().hasClass(Lesson.CLASS_REALIZED) if (spans.first().hasClass(Lesson.CLASS_MOVED_OR_CANCELED)) {
|| e.first().attr("class").equals("")) { lesson.setMovedOrCanceled(true);
}
if (spans.first().hasClass(Lesson.CLASS_NEW_MOVED_IN_OR_CHANGED)) {
lesson.setNewMovedInOrChanged(true);
}
if (spans.last().hasClass(Lesson.CLASS_REALIZED) || "".equals(spans.first().attr("class"))) {
lesson.setRealized(true); lesson.setRealized(true);
} }
} }
private void addDescriptionInfo(Lesson lesson, Elements e) { private void addNormalLessonInfo(Lesson lesson, Elements spans) {
if ((4 == e.size() || 5 == e.size()) if (3 == spans.size()) {
&& (e.first().hasClass(Lesson.CLASS_MOVED_OR_CANCELED) lesson.setSubject(spans.get(0).text());
|| e.first().hasClass(Lesson.CLASS_NEW_MOVED_IN_OR_CHANGED))) { lesson.setTeacher(spans.get(1).text());
lesson.setDescription(StringUtils.substringBetween(e.last().text(), "(", ")")); lesson.setRoom(spans.get(2).text());
} }
} }
private void addChangesInfo(Lesson lesson, Elements spans) {
if (!spans.last().hasClass(Lesson.CLASS_REALIZED)) {
return;
}
if (7 == spans.size()) {
lesson.setSubject(spans.get(3).text());
lesson.setTeacher(spans.get(4).text());
lesson.setRoom(spans.get(5).text());
lesson.setMovedOrCanceled(false);
lesson.setNewMovedInOrChanged(true);
lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")")
+ " (poprzednio: " + spans.get(0).text() + ")");
} else if (9 == spans.size()) {
String[] subjectAndGroupInfo = getLessonAndGroupInfoFromSpan(spans.get(4));
lesson.setSubject(subjectAndGroupInfo[0]);
lesson.setGroupName(subjectAndGroupInfo[1]);
lesson.setTeacher(spans.get(6).text());
lesson.setRoom(spans.get(7).text());
lesson.setMovedOrCanceled(false);
lesson.setNewMovedInOrChanged(true);
lesson.setDivisionIntoGroups(true);
lesson.setDescription(StringUtils.substringBetween(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(), "(", ")"));
}
}
private void addGroupLessonInfo(Lesson lesson, Elements spans) {
if (4 == spans.size() && !spans.last().hasClass(Lesson.CLASS_REALIZED)) {
lesson.setRoom(spans.last().text());
}
if ((4 == spans.size() && !spans.last().hasClass(Lesson.CLASS_REALIZED) || 5 == spans.size())) {
String[] subjectAndGroupInfo = getLessonAndGroupInfoFromSpan(spans.get(0));
lesson.setSubject(subjectAndGroupInfo[0]);
lesson.setGroupName(subjectAndGroupInfo[1]);
lesson.setTeacher(spans.get(2).text());
lesson.setDivisionIntoGroups(true);
}
if (5 == spans.size()) {
lesson.setRoom(spans.get(3).text());
}
}
private String[] getLessonAndGroupInfoFromSpan(Element span) {
String[] subjectNameArray = span.text().split(" ");
String groupName = subjectNameArray[subjectNameArray.length - 1];
return new String[]{
span.text().replace(" " + groupName, ""),
StringUtils.substringBetween(groupName, "[", "]")
};
}
} }

View File

@ -32,20 +32,29 @@ public class TimetableTest extends StudentAndParentTestCase {
@Test @Test
public void getStartDayDateTest() throws Exception { public void getStartDayDateTest() throws Exception {
Assert.assertEquals("19.06.2017", std.getWeekTable().getStartDayDate()); Assert.assertEquals("2017-06-19", std.getWeekTable().getStartDayDate());
Assert.assertEquals("19.06.2017", full.getWeekTable().getStartDayDate()); Assert.assertEquals("2017-06-19", full.getWeekTable().getStartDayDate());
Assert.assertEquals("31.07.2017", holidays.getWeekTable().getStartDayDate()); Assert.assertEquals("2017-07-31", holidays.getWeekTable().getStartDayDate());
} }
// Day // Day
@Test
public void getDayNameTest() throws Exception {
Assert.assertEquals("poniedziałek", std.getWeekTable().getDay(0).getDayName());
Assert.assertEquals("piątek", std.getWeekTable().getDay(4).getDayName());
Assert.assertEquals("wtorek", full.getWeekTable().getDay(1).getDayName());
Assert.assertEquals("czwartek", full.getWeekTable().getDay(3).getDayName());
Assert.assertEquals("środa", holidays.getWeekTable().getDay(2).getDayName());
}
@Test @Test
public void getDayDateTest() throws Exception { public void getDayDateTest() throws Exception {
Assert.assertEquals("19.06.2017", std.getWeekTable().getDay(0).getDate()); Assert.assertEquals("2017-06-19", std.getWeekTable().getDay(0).getDate());
Assert.assertEquals("23.06.2017", std.getWeekTable().getDay(4).getDate()); Assert.assertEquals("2017-06-23", std.getWeekTable().getDay(4).getDate());
Assert.assertEquals("20.06.2017", full.getWeekTable().getDay(1).getDate()); Assert.assertEquals("2017-06-20", full.getWeekTable().getDay(1).getDate());
Assert.assertEquals("22.06.2017", full.getWeekTable().getDay(3).getDate()); Assert.assertEquals("2017-06-22", full.getWeekTable().getDay(3).getDate());
Assert.assertEquals("02.08.2017", holidays.getWeekTable().getDay(2).getDate()); Assert.assertEquals("2017-08-02", holidays.getWeekTable().getDay(2).getDate());
} }
@Test @Test
@ -72,12 +81,26 @@ public class TimetableTest extends StudentAndParentTestCase {
// Lesson // Lesson
@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());
}
@Test @Test
public void getLessonSubjectTest() throws Exception { public void getLessonSubjectTest() throws Exception {
Assert.assertEquals("Historia", std.getWeekTable().getDay(0).getLesson(1).getSubject()); Assert.assertEquals("Historia", std.getWeekTable().getDay(0).getLesson(1).getSubject());
Assert.assertEquals("Zajęcia techniczne", std.getWeekTable().getDay(2).getLesson(4).getSubject()); 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("Język angielski", full.getWeekTable().getDay(0).getLesson(1).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()); Assert.assertEquals("Uroczyste zakończenie roku szkolnego", full.getWeekTable().getDay(4).getLesson(0).getSubject());
Assert.assertEquals("Fizyka", full.getWeekTable().getDay(0).getLesson(0).getSubject());
Assert.assertEquals("Metodologia programowania", full.getWeekTable().getDay(1).getLesson(0).getSubject());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getSubject()); Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getSubject());
} }
@ -87,6 +110,8 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertEquals("Chlebowski Stanisław", std.getWeekTable().getDay(2).getLesson(4).getTeacher()); Assert.assertEquals("Chlebowski Stanisław", std.getWeekTable().getDay(2).getLesson(4).getTeacher());
Assert.assertEquals("Kobczyk Iwona", full.getWeekTable().getDay(0).getLesson(1).getTeacher()); Assert.assertEquals("Kobczyk Iwona", full.getWeekTable().getDay(0).getLesson(1).getTeacher());
Assert.assertEquals("Bączek Grzegorz", full.getWeekTable().getDay(0).getLesson(7).getTeacher()); Assert.assertEquals("Bączek Grzegorz", full.getWeekTable().getDay(0).getLesson(7).getTeacher());
Assert.assertEquals("Nowak Jadwiga", full.getWeekTable().getDay(2).getLesson(0).getTeacher());
Assert.assertEquals("Nowicka Irena", full.getWeekTable().getDay(3).getLesson(1).getTeacher());
Assert.assertEquals("Baran Małgorzata", full.getWeekTable().getDay(4).getLesson(0).getTeacher()); Assert.assertEquals("Baran Małgorzata", full.getWeekTable().getDay(4).getLesson(0).getTeacher());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getTeacher()); Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getTeacher());
} }
@ -95,7 +120,11 @@ public class TimetableTest extends StudentAndParentTestCase {
public void getLessonRoomTest() throws Exception { public void getLessonRoomTest() throws Exception {
Assert.assertEquals("", std.getWeekTable().getDay(3).getLesson(3).getRoom()); Assert.assertEquals("", std.getWeekTable().getDay(3).getLesson(3).getRoom());
Assert.assertEquals("33", full.getWeekTable().getDay(0).getLesson(7).getRoom()); Assert.assertEquals("33", full.getWeekTable().getDay(0).getLesson(7).getRoom());
Assert.assertEquals("19", full.getWeekTable().getDay(0).getLesson(0).getRoom());
Assert.assertEquals("32", full.getWeekTable().getDay(1).getLesson(0).getRoom());
Assert.assertEquals("32", full.getWeekTable().getDay(1).getLesson(8).getRoom()); Assert.assertEquals("32", full.getWeekTable().getDay(1).getLesson(8).getRoom());
Assert.assertEquals("32", full.getWeekTable().getDay(2).getLesson(8).getRoom());
Assert.assertEquals("G4", full.getWeekTable().getDay(3).getLesson(1).getRoom());
Assert.assertEquals("37", full.getWeekTable().getDay(4).getLesson(0).getRoom()); Assert.assertEquals("37", full.getWeekTable().getDay(4).getLesson(0).getRoom());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getRoom()); Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getRoom());
} }
@ -103,9 +132,12 @@ public class TimetableTest extends StudentAndParentTestCase {
@Test @Test
public void getLessonDescriptionTest() throws Exception { public void getLessonDescriptionTest() throws Exception {
Assert.assertEquals("", std.getWeekTable().getDay(3).getLesson(3).getDescription()); Assert.assertEquals("", std.getWeekTable().getDay(3).getLesson(3).getDescription());
Assert.assertEquals("przeniesiona z lekcji 7, 01.12.2017", full.getWeekTable().getDay(1).getLesson(1).getDescription());
Assert.assertEquals("okienko dla uczniów", full.getWeekTable().getDay(0).getLesson(7).getDescription()); Assert.assertEquals("okienko dla uczniów", full.getWeekTable().getDay(0).getLesson(7).getDescription());
Assert.assertEquals("przeniesiona z lekcji 7, 20.06.2017", full.getWeekTable().getDay(1).getLesson(2).getDescription()); Assert.assertEquals("przeniesiona z lekcji 7, 20.06.2017", full.getWeekTable().getDay(1).getLesson(2).getDescription());
Assert.assertEquals("przeniesiona z lekcji 4, 20.06.2017", full.getWeekTable().getDay(1).getLesson(3).getDescription()); Assert.assertEquals("przeniesiona z lekcji 4, 20.06.2017", full.getWeekTable().getDay(1).getLesson(3).getDescription());
Assert.assertEquals("zastępstwo (poprzednio: Religia)", full.getWeekTable().getDay(2).getLesson(0).getDescription());
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(0).getDescription());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getDescription()); Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getDescription());
} }
@ -115,7 +147,9 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertEquals("CH", std.getWeekTable().getDay(0).getLesson(2).getGroupName()); Assert.assertEquals("CH", std.getWeekTable().getDay(0).getLesson(2).getGroupName());
Assert.assertEquals("JNPW", std.getWeekTable().getDay(4).getLesson(0).getGroupName()); Assert.assertEquals("JNPW", std.getWeekTable().getDay(4).getLesson(0).getGroupName());
Assert.assertEquals("", full.getWeekTable().getDay(0).getLesson(7).getGroupName()); Assert.assertEquals("", full.getWeekTable().getDay(0).getLesson(7).getGroupName());
Assert.assertEquals("zaw2", full.getWeekTable().getDay(1).getLesson(0).getGroupName());
Assert.assertEquals("wf2", full.getWeekTable().getDay(1).getLesson(3).getGroupName()); Assert.assertEquals("wf2", full.getWeekTable().getDay(1).getLesson(3).getGroupName());
Assert.assertEquals("zaw1", full.getWeekTable().getDay(3).getLesson(1).getGroupName());
Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getGroupName()); Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getGroupName());
} }
@ -141,6 +175,7 @@ public class TimetableTest extends StudentAndParentTestCase {
public void getLessonIsEmptyTest() throws Exception { public void getLessonIsEmptyTest() throws Exception {
Assert.assertFalse(std.getWeekTable().getDay(1).getLesson(4).isEmpty()); Assert.assertFalse(std.getWeekTable().getDay(1).getLesson(4).isEmpty());
Assert.assertTrue(std.getWeekTable().getDay(3).getLesson(7).isEmpty()); Assert.assertTrue(std.getWeekTable().getDay(3).getLesson(7).isEmpty());
Assert.assertFalse(full.getWeekTable().getDay(1).getLesson(1).isEmpty());
Assert.assertFalse(full.getWeekTable().getDay(1).getLesson(2).isEmpty()); Assert.assertFalse(full.getWeekTable().getDay(1).getLesson(2).isEmpty());
Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(7).isEmpty()); Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(7).isEmpty());
Assert.assertTrue(full.getWeekTable().getDay(2).getLesson(9).isEmpty()); Assert.assertTrue(full.getWeekTable().getDay(2).getLesson(9).isEmpty());
@ -154,6 +189,7 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertTrue(std.getWeekTable().getDay(4).getLesson(0).isDivisionIntoGroups()); Assert.assertTrue(std.getWeekTable().getDay(4).getLesson(0).isDivisionIntoGroups());
Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(7).isDivisionIntoGroups()); Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(7).isDivisionIntoGroups());
Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(3).isDivisionIntoGroups()); Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(3).isDivisionIntoGroups());
Assert.assertTrue(full.getWeekTable().getDay(3).getLesson(1).isDivisionIntoGroups());
Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isDivisionIntoGroups()); Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isDivisionIntoGroups());
} }
@ -161,7 +197,7 @@ public class TimetableTest extends StudentAndParentTestCase {
public void getLessonIsPlanningTest() throws Exception { public void getLessonIsPlanningTest() throws Exception {
Assert.assertFalse(std.getWeekTable().getDay(4).getLesson(4).isPlanning()); Assert.assertFalse(std.getWeekTable().getDay(4).getLesson(4).isPlanning());
Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(1).isPlanning()); Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(1).isPlanning());
Assert.assertFalse(full.getWeekTable().getDay(1).getLesson(3).isPlanning()); Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(3).isPlanning());
Assert.assertTrue(full.getWeekTable().getDay(4).getLesson(0).isPlanning()); Assert.assertTrue(full.getWeekTable().getDay(4).getLesson(0).isPlanning());
Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isPlanning()); Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isPlanning());
} }
@ -190,6 +226,7 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(1).isNewMovedInOrChanged()); Assert.assertFalse(full.getWeekTable().getDay(0).getLesson(1).isNewMovedInOrChanged());
Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(2).isNewMovedInOrChanged()); Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(2).isNewMovedInOrChanged());
Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(3).isNewMovedInOrChanged()); Assert.assertTrue(full.getWeekTable().getDay(1).getLesson(3).isNewMovedInOrChanged());
Assert.assertTrue(full.getWeekTable().getDay(3).getLesson(1).isNewMovedInOrChanged());
Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isNewMovedInOrChanged()); Assert.assertFalse(holidays.getWeekTable().getDay(3).getLesson(3).isNewMovedInOrChanged());
} }
} }

View File

@ -24,9 +24,34 @@
<tr> <tr>
<td>0</td> <td>0</td>
<td>07:10 07:55</td> <td>07:10 07:55</td>
<td></td> <td>
<td></td> <div>
<td></td> <span class="x-treelabel-ppl x-treelabel-inv">Fizyka [zaw2]</span>
<span class="x-treelabel-ppl x-treelabel-inv"></span>
<span class="x-treelabel-ppl x-treelabel-inv">Bączek Grzegorz</span>
<span class="x-treelabel-ppl x-treelabel-inv">19</span>
<span class="x-treelabel-rlz">(uczniowie zwolnieni do domu)</span>
</div>
</td>
<td>
<div>
<span class="x-treelabel-ppl">Metodologia programowania [zaw2]</span>
<span class="x-treelabel-ppl"></span>
<span class="x-treelabel-ppl"></span>
<span class="x-treelabel-ppl">32</span>
</div>
</td>
<td>
<div>
<span class="x-treelabel-inv">Religia</span>
<span class="x-treelabel-inv">Cyranka Krystian</span>
<span class="x-treelabel-inv">3</span>
<span class="x-treelabel-ppl x-treelabel-zas">Wychowanie do życia w rodzinie</span>
<span class="x-treelabel-ppl x-treelabel-zas">Nowak Jadwiga</span>
<span class="x-treelabel-ppl x-treelabel-zas">3</span>
<span class="x-treelabel-rlz">(zastępstwo)</span>
</div>
</td>
<td></td> <td></td>
<td> <td>
<div> <div>
@ -47,7 +72,22 @@
<span></span> <span></span>
</div> </div>
</td> </td>
<td></td> <td>
<div>
<span class="x-treelabel-ppl x-treelabel-inv">Metodologia programowania [zaw2]</span>
<span class="x-treelabel-ppl x-treelabel-inv"></span>
<span class="x-treelabel-ppl x-treelabel-inv">Baran Małgorzata</span>
<span class="x-treelabel-ppl x-treelabel-inv">36</span>
<span class="x-treelabel-rlz">(zmiana organizacji zajęć)</span>
</div>
<div>
<span class="x-treelabel-ppl x-treelabel-zas">Wychowanie fizyczne [zaw2]</span>
<span class="x-treelabel-ppl x-treelabel-zas"></span>
<span class="x-treelabel-ppl x-treelabel-zas"></span>
<span class="x-treelabel-ppl x-treelabel-zas">G3</span>
<span class="x-treelabel-rlz">(przeniesiona z lekcji 7, 01.12.2017)</span>
</div>
</td>
<td> <td>
<div> <div>
<span>Użytkowanie urządzeń peryferyjnych komputera [zaw2]</span> <span>Użytkowanie urządzeń peryferyjnych komputera [zaw2]</span>
@ -56,7 +96,19 @@
<span></span> <span></span>
</div> </div>
</td> </td>
<td></td> <td>
<div>
<span class="x-treelabel-inv">Wychowanie fizyczne [zaw1]</span>
<span class="x-treelabel-inv"></span>
<span class="x-treelabel-inv">Jarocki Krzysztof</span>
<span class="x-treelabel-inv">G4</span>
<span class="x-treelabel-ppl x-treelabel-zas">Wychowanie fizyczne [zaw1]</span>
<span class="x-treelabel-ppl x-treelabel-zas"></span>
<span class="x-treelabel-ppl x-treelabel-zas">Nowicka Irena</span>
<span class="x-treelabel-ppl x-treelabel-zas">G4</span>
<span class="x-treelabel-rlz">(zastępstwo)</span>
</div>
</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>

View File

@ -5,7 +5,7 @@ apply from: '../android-sonarqube.gradle'
android { android {
compileSdkVersion 27 compileSdkVersion 27
buildToolsVersion "27.0.1" buildToolsVersion "27.0.2"
defaultConfig { defaultConfig {
applicationId "io.github.wulkanowy" applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
@ -31,7 +31,7 @@ android {
unitTests.all { unitTests.all {
testLogging { testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError" events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false} outputs.upToDateWhen { false }
showStandardStreams = true showStandardStreams = true
} }
} }
@ -39,25 +39,28 @@ android {
} }
greendao { greendao {
schemaVersion 14 schemaVersion 19
generateTests = true generateTests = true
} }
dependencies { dependencies {
implementation project(":api") implementation project(':api')
implementation 'com.android.support:appcompat-v7:27.0.1' implementation 'com.android.support:appcompat-v7:27.0.2'
implementation 'com.android.support.constraint:constraint-layout:1.0.2' implementation 'com.android.support:design:27.0.2'
implementation 'com.android.support:design:27.0.1' implementation 'com.android.support:support-v4:27.0.2'
implementation 'com.android.support:support-vector-drawable:27.0.1' implementation 'com.android.support:recyclerview-v7:27.0.2'
implementation 'com.android.support:support-v4:27.0.1' implementation 'com.android.support:cardview-v7:27.0.2'
implementation 'com.android.support:recyclerview-v7:27.0.1' implementation 'com.android.support:customtabs:27.0.2'
implementation 'com.android.support:cardview-v7:27.0.1' implementation 'com.firebase:firebase-jobdispatcher:0.8.5'
implementation 'com.android.support:customtabs:27.0.1'
implementation 'com.firebase:firebase-jobdispatcher:0.8.4'
implementation 'com.thoughtbot:expandablerecyclerview:1.3' implementation 'com.thoughtbot:expandablerecyclerview:1.3'
implementation 'org.apache.commons:commons-lang3:3.6' implementation 'org.apache.commons:commons-lang3:3.6'
implementation 'eu.davidea:flexible-adapter:5.0.0-rc3'
implementation 'org.apache.commons:commons-collections4:4.1' implementation 'org.apache.commons:commons-collections4:4.1'
implementation 'org.greenrobot:greendao:3.2.2' implementation 'org.greenrobot:greendao:3.2.2'
implementation 'com.jakewharton:butterknife:8.8.1'
implementation 'joda-time:joda-time:2.9.9'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
debugImplementation 'com.amitshekhar.android:debug-db:1.0.1' debugImplementation 'com.amitshekhar.android:debug-db:1.0.1'
debugImplementation 'net.zetetic:android-database-sqlcipher:3.5.7@aar' debugImplementation 'net.zetetic:android-database-sqlcipher:3.5.7@aar'
@ -65,12 +68,6 @@ dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.11.0' testImplementation 'org.mockito:mockito-core:2.11.0'
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestImplementation 'com.android.support:support-annotations:27.0.1'
androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test:rules:1.0.1'
androidTestImplementation 'org.hamcrest:hamcrest-library:1.3'
androidTestImplementation 'org.mockito:mockito-android:2.11.0' androidTestImplementation 'org.mockito:mockito-android:2.11.0'
} }

View File

@ -0,0 +1,19 @@
package io.github.wulkanowy.dao.entities;
import org.greenrobot.greendao.test.AbstractDaoTestLongPk;
public class DayTest extends AbstractDaoTestLongPk<DayDao, Day> {
public DayTest() {
super(DayDao.class);
}
@Override
protected Day createEntity(Long key) {
Day entity = new Day();
entity.setId(key);
entity.setIsFreeDay(false);
return entity;
}
}

View File

@ -0,0 +1,24 @@
package io.github.wulkanowy.dao.entities;
import org.greenrobot.greendao.test.AbstractDaoTestLongPk;
public class LessonTest extends AbstractDaoTestLongPk<LessonDao, Lesson> {
public LessonTest() {
super(LessonDao.class);
}
@Override
protected Lesson createEntity(Long key) {
Lesson entity = new Lesson();
entity.setId(key);
entity.setIsEmpty(false);
entity.setIsDivisionIntoGroups(false);
entity.setIsPlanning(false);
entity.setIsRealized(false);
entity.setIsMovedOrCanceled(false);
entity.setIsNewMovedInOrChanged(false);
return entity;
}
}

View File

@ -0,0 +1,21 @@
package io.github.wulkanowy.dao.entities;
import org.greenrobot.greendao.test.AbstractDaoTestLongPk;
import io.github.wulkanowy.dao.entities.Week;
import io.github.wulkanowy.dao.entities.WeekDao;
public class WeekTest extends AbstractDaoTestLongPk<WeekDao, Week> {
public WeekTest() {
super(WeekDao.class);
}
@Override
protected Week createEntity(Long key) {
Week entity = new Week();
entity.setId(key);
return entity;
}
}

View File

@ -6,18 +6,26 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import java.io.IOException;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class VulcanSynchronizationTest { public class VulcanSynchronizationTest {
@Test @Test(expected = IOException.class)
public void syncNoLoginSessionSubjectTest() { public void syncNoLoginSessionSubjectTest() throws IOException {
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession()); VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession());
Assert.assertFalse(vulcanSynchronization.syncSubjectsAndGrades()); vulcanSynchronization.syncSubjectsAndGrades();
} }
@Test @Test(expected = IOException.class)
public void syncNoLoginSessionGradeTest() { public void syncNoLoginSessionGradeTest() throws IOException {
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession()); VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession());
Assert.assertFalse(vulcanSynchronization.syncGrades()); vulcanSynchronization.syncGrades();
}
@Test(expected = IOException.class)
public void syncNoLoginSessionTimetableTest() throws IOException {
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession());
vulcanSynchronization.syncTimetable();
} }
} }

View File

@ -0,0 +1,103 @@
package io.github.wulkanowy.services.synchronization;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.greenrobot.greendao.database.Database;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.timetable.Day;
import io.github.wulkanowy.api.timetable.Lesson;
import io.github.wulkanowy.api.timetable.Timetable;
import io.github.wulkanowy.api.timetable.Week;
import io.github.wulkanowy.dao.entities.Account;
import io.github.wulkanowy.dao.entities.DaoMaster;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.synchronisation.TimetableSynchronization;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@RunWith(AndroidJUnit4.class)
public class TimetableSynchronizationTest {
private static DaoSession daoSession;
@BeforeClass
public static void setUpClass() {
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(InstrumentationRegistry.getTargetContext(), "wulkanowyTest-database");
Database database = devOpenHelper.getWritableDb();
daoSession = new DaoMaster(database).newSession();
}
@Test
public void syncTimetableEmptyDatabaseTest() throws Exception {
Long userId = daoSession.getAccountDao().insert(new Account().setEmail("TEST@TEST"));
List<Day> dayList = new ArrayList<>();
dayList.add(new Day()
.setDate("20.12.2012")
.setLesson(new Lesson().setSubject("Matematyka").setRoom("20")));
Week week = new Week().setDays(dayList);
List<Day> nextDayList = new ArrayList<>();
dayList.add(new Day()
.setDate("24.11.2013")
.setLesson(new Lesson().setSubject("Matematyka").setRoom("22")));
Week nextWeek = new Week().setDays(nextDayList);
Timetable timetable = mock(Timetable.class);
doReturn(week).when(timetable).getWeekTable();
doReturn(nextWeek).when(timetable).getWeekTable(anyString());
Vulcan vulcan = mock(Vulcan.class);
doReturn(timetable).when(vulcan).getTimetable();
LoginSession loginSession = mock(LoginSession.class);
doReturn(vulcan).when(loginSession).getVulcan();
doReturn(daoSession).when(loginSession).getDaoSession();
doReturn(userId).when(loginSession).getUserId();
TimetableSynchronization timetableSynchronization = new TimetableSynchronization();
timetableSynchronization.sync(loginSession, null);
List<io.github.wulkanowy.dao.entities.Day> dayEntityList = daoSession.getDayDao().loadAll();
List<io.github.wulkanowy.dao.entities.Lesson> lessonEntityList = dayEntityList.get(0).getLessons();
Assert.assertNotNull(dayEntityList.get(0));
Assert.assertEquals(userId, dayEntityList.get(0).getUserId());
Assert.assertEquals(1L, lessonEntityList.get(0).getDayId().longValue());
Assert.assertEquals("Matematyka", lessonEntityList.get(0).getSubject());
Assert.assertEquals("20", lessonEntityList.get(0).getRoom());
Assert.assertEquals("20.12.2012", dayEntityList.get(0).getDate());
}
@Before
public void setUp() {
daoSession.getAccountDao().deleteAll();
daoSession.getDayDao().deleteAll();
daoSession.getLessonDao().deleteAll();
daoSession.clear();
}
@AfterClass
public static void cleanUp() {
daoSession.getAccountDao().deleteAll();
daoSession.getDayDao().deleteAll();
daoSession.getLessonDao().deleteAll();
daoSession.clear();
}
}

View File

@ -11,7 +11,7 @@
<uses-sdk tools:overrideLibrary="com.thoughtbot.expandablerecyclerview" /> <uses-sdk tools:overrideLibrary="com.thoughtbot.expandablerecyclerview" />
<application <application
android:name=".activity.WulkanowyApp" android:name=".ui.WulkanowyApp"
android:allowBackup="false" android:allowBackup="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
@ -19,7 +19,7 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/WulkanowyTheme"> android:theme="@style/WulkanowyTheme">
<activity <activity
android:name=".activity.splash.SplashActivity" android:name=".ui.splash.SplashActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:noHistory="true" android:noHistory="true"
android:theme="@style/WulkanowyTheme.noActionBar"> android:theme="@style/WulkanowyTheme.noActionBar">
@ -30,17 +30,17 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".activity.login.LoginActivity" android:name=".ui.login.LoginActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/title_activity_login" android:label="@string/title_activity_login"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".activity.dashboard.DashboardActivity" android:name=".ui.main.DashboardActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/activity_dashboard_text" /> android:label="@string/activity_dashboard_text" />
<service <service
android:name=".services.jobs.GradeJob$GradeService" android:name=".services.jobs.FullSyncJob$SyncService"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" /> <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />

View File

@ -1,19 +0,0 @@
package io.github.wulkanowy.activity.dashboard.lessonplan;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import io.github.wulkanowy.R;
public class LessonPlanFragment extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_lessonplan, container, false);
}
}

View File

@ -9,7 +9,10 @@ import org.greenrobot.greendao.annotation.ToMany;
import java.util.List; import java.util.List;
@Entity(nameInDb = "Accounts") @Entity(
nameInDb = "Accounts",
active = true
)
public class Account { public class Account {
@Id(autoincrement = true) @Id(autoincrement = true)
@ -36,6 +39,9 @@ public class Account {
@ToMany(referencedJoinProperty = "userId") @ToMany(referencedJoinProperty = "userId")
private List<Grade> gradeList; private List<Grade> gradeList;
@ToMany(referencedJoinProperty = "userId")
private List<Day> dayList;
/** /**
* Used to resolve relations * Used to resolve relations
*/ */
@ -50,7 +56,7 @@ public class Account {
@Generated(hash = 735765217) @Generated(hash = 735765217)
public Account(Long id, String name, String email, String password, String symbol, public Account(Long id, String name, String email, String password, String symbol,
String snpId) { String snpId) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.email = email; this.email = email;
@ -213,6 +219,36 @@ public class Account {
myDao.update(this); myDao.update(this);
} }
/**
* 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 = 300459794)
public List<Day> getDayList() {
if (dayList == null) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
DayDao targetDao = daoSession.getDayDao();
List<Day> dayListNew = targetDao._queryAccount_DayList(id);
synchronized (this) {
if (dayList == null) {
dayList = dayListNew;
}
}
}
return dayList;
}
/**
* Resets a to-many relationship, making the next get call to query for a fresh result.
*/
@Generated(hash = 1010399236)
public synchronized void resetDayList() {
dayList = null;
}
/** called by internal mechanisms, do not call yourself. */ /** called by internal mechanisms, do not call yourself. */
@Generated(hash = 1812283172) @Generated(hash = 1812283172)
public void __setDaoSession(DaoSession daoSession) { public void __setDaoSession(DaoSession daoSession) {

View File

@ -0,0 +1,214 @@
package io.github.wulkanowy.dao.entities;
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 org.greenrobot.greendao.annotation.ToMany;
import java.util.List;
@Entity(
nameInDb = "Days",
active = true,
indexes ={@Index(value = "userId,weekId,date", unique = true)}
)
public class Day {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "USER_ID")
private Long userId;
@Property(nameInDb = "WEEK_ID")
private Long weekId;
@Property(nameInDb = "DATE")
private String date = "";
@Property(nameInDb = "DAY_NAME")
private String dayName = "";
@Property(nameInDb = "IS_FREE_DAY")
private boolean isFreeDay = false;
@Property(nameInDb = "FREE_DAY_NAME")
private String freeDayName = "";
@ToMany(referencedJoinProperty = "dayId")
private List<Lesson> lessons;
/**
* Used to resolve relations
*/
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/**
* Used for active entity operations.
*/
@Generated(hash = 312167767)
private transient DayDao myDao;
@Generated(hash = 723729681)
public Day(Long id, Long userId, Long weekId, String date, String dayName,
boolean isFreeDay, String freeDayName) {
this.id = id;
this.userId = userId;
this.weekId = weekId;
this.date = date;
this.dayName = dayName;
this.isFreeDay = isFreeDay;
this.freeDayName = freeDayName;
}
@Generated(hash = 866989762)
public Day() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public Long getWeekId() {
return weekId;
}
public Day setWeekId(Long weekId) {
this.weekId = weekId;
return this;
}
public Day setUserId(Long userId) {
this.userId = userId;
return this;
}
public String getDate() {
return date;
}
public Day setDate(String date) {
this.date = date;
return this;
}
public String getDayName() {
return dayName;
}
public Day setDayName(String dayName) {
this.dayName = dayName;
return this;
}
public boolean isFreeDay() {
return isFreeDay;
}
public Day setFreeDay(boolean freeDay) {
isFreeDay = freeDay;
return this;
}
public String getFreeDayName() {
return freeDayName;
}
public Day setFreeDayName(String freeDayName) {
this.freeDayName = freeDayName;
return this;
}
public boolean getIsFreeDay() {
return this.isFreeDay;
}
public void setIsFreeDay(boolean isFreeDay) {
this.isFreeDay = isFreeDay;
}
/**
* 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 = 1552857303)
public List<Lesson> getLessons() {
if (lessons == null) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
LessonDao targetDao = daoSession.getLessonDao();
List<Lesson> lessonsNew = targetDao._queryDay_Lessons(id);
synchronized (this) {
if (lessons == null) {
lessons = lessonsNew;
}
}
}
return lessons;
}
/**
* Resets a to-many relationship, making the next get call to query for a fresh result.
*/
@Generated(hash = 1769801440)
public synchronized void resetLessons() {
lessons = null;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** 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;
}
}

View File

@ -0,0 +1,349 @@
package io.github.wulkanowy.dao.entities;
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;
@Entity(
nameInDb = "Lessons",
active = true,
indexes ={@Index(value = "dayId,date,startTime,endTime", unique = true)}
)
public class Lesson {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "DAY_ID")
private Long dayId;
@Property(nameInDb = "NUMBER_OF_LESSON")
private String number;
@Property(nameInDb = "SUBJECT_NAME")
private String subject = "";
@Property(nameInDb = "TEACHER")
private String teacher = "";
@Property(nameInDb = "ROOM")
private String room = "";
@Property(nameInDb = "DESCRIPTION")
private String description = "";
@Property(nameInDb = "GROUP_NAME")
private String groupName = "";
@Property(nameInDb = "START_TIME")
private String startTime = "";
@Property(nameInDb = "END_TIME")
private String endTime = "";
@Property(nameInDb = "DATE")
private String date = "";
@Property(nameInDb = "IS_EMPTY")
private boolean isEmpty = false;
@Property(nameInDb = "IS_DIVISION_INTO_GROUP")
private boolean isDivisionIntoGroups = false;
@Property(nameInDb = "IS_PLANNING")
private boolean isPlanning = false;
@Property(nameInDb = "IS_REALIZED")
private boolean isRealized = false;
@Property(nameInDb = "IS_MOVED_CANCELED")
private boolean isMovedOrCanceled = false;
@Property(nameInDb = "IS_NEW_MOVED_IN_CANCELED")
private boolean isNewMovedInOrChanged = false;
/**
* Used to resolve relations
*/
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/**
* Used for active entity operations.
*/
@Generated(hash = 610143130)
private transient LessonDao myDao;
@Generated(hash = 140778287)
public Lesson(Long id, Long dayId, String number, String subject, String teacher, String room,
String description, String groupName, String startTime, String endTime, String date,
boolean isEmpty, boolean isDivisionIntoGroups, boolean isPlanning, boolean isRealized,
boolean isMovedOrCanceled, boolean isNewMovedInOrChanged) {
this.id = id;
this.dayId = dayId;
this.number = number;
this.subject = subject;
this.teacher = teacher;
this.room = room;
this.description = description;
this.groupName = groupName;
this.startTime = startTime;
this.endTime = endTime;
this.date = date;
this.isEmpty = isEmpty;
this.isDivisionIntoGroups = isDivisionIntoGroups;
this.isPlanning = isPlanning;
this.isRealized = isRealized;
this.isMovedOrCanceled = isMovedOrCanceled;
this.isNewMovedInOrChanged = isNewMovedInOrChanged;
}
@Generated(hash = 1669664117)
public Lesson() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public Long getDayId() {
return this.dayId;
}
public void setDayId(Long dayId) {
this.dayId = dayId;
}
public String getNumber() {
return number;
}
public Lesson setNumber(String number) {
this.number = number;
return this;
}
public String getSubject() {
return subject;
}
public Lesson setSubject(String subject) {
this.subject = subject;
return this;
}
public String getTeacher() {
return teacher;
}
public Lesson setTeacher(String teacher) {
this.teacher = teacher;
return this;
}
public String getRoom() {
return room;
}
public Lesson setRoom(String room) {
this.room = room;
return this;
}
public String getDescription() {
return description;
}
public Lesson setDescription(String description) {
this.description = description;
return this;
}
public String getGroupName() {
return groupName;
}
public Lesson setGroupName(String groupName) {
this.groupName = groupName;
return this;
}
public String getStartTime() {
return startTime;
}
public Lesson setStartTime(String startTime) {
this.startTime = startTime;
return this;
}
public String getEndTime() {
return endTime;
}
public Lesson setEndTime(String endTime) {
this.endTime = endTime;
return this;
}
public String getDate() {
return date;
}
public Lesson setDate(String date) {
this.date = date;
return this;
}
public boolean isEmpty() {
return isEmpty;
}
public Lesson setEmpty(boolean empty) {
isEmpty = empty;
return this;
}
public boolean isDivisionIntoGroups() {
return isDivisionIntoGroups;
}
public Lesson setDivisionIntoGroups(boolean divisionIntoGroups) {
isDivisionIntoGroups = divisionIntoGroups;
return this;
}
public boolean isPlanning() {
return isPlanning;
}
public Lesson setPlanning(boolean planning) {
isPlanning = planning;
return this;
}
public boolean isRealized() {
return isRealized;
}
public Lesson setRealized(boolean realized) {
isRealized = realized;
return this;
}
public boolean isMovedOrCanceled() {
return isMovedOrCanceled;
}
public Lesson setMovedOrCanceled(boolean movedOrCanceled) {
isMovedOrCanceled = movedOrCanceled;
return this;
}
public boolean isNewMovedInOrChanged() {
return isNewMovedInOrChanged;
}
public Lesson setNewMovedInOrChanged(boolean newMovedInOrChanged) {
isNewMovedInOrChanged = newMovedInOrChanged;
return this;
}
public boolean getIsEmpty() {
return this.isEmpty;
}
public void setIsEmpty(boolean isEmpty) {
this.isEmpty = isEmpty;
}
public boolean getIsDivisionIntoGroups() {
return this.isDivisionIntoGroups;
}
public void setIsDivisionIntoGroups(boolean isDivisionIntoGroups) {
this.isDivisionIntoGroups = isDivisionIntoGroups;
}
public boolean getIsPlanning() {
return this.isPlanning;
}
public void setIsPlanning(boolean isPlanning) {
this.isPlanning = isPlanning;
}
public boolean getIsRealized() {
return this.isRealized;
}
public void setIsRealized(boolean isRealized) {
this.isRealized = isRealized;
}
public boolean getIsMovedOrCanceled() {
return this.isMovedOrCanceled;
}
public void setIsMovedOrCanceled(boolean isMovedOrCanceled) {
this.isMovedOrCanceled = isMovedOrCanceled;
}
public boolean getIsNewMovedInOrChanged() {
return this.isNewMovedInOrChanged;
}
public void setIsNewMovedInOrChanged(boolean isNewMovedInOrChanged) {
this.isNewMovedInOrChanged = isNewMovedInOrChanged;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 2078826279)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getLessonDao() : null;
}
}

View File

@ -9,7 +9,10 @@ import org.greenrobot.greendao.annotation.ToMany;
import java.util.List; import java.util.List;
@Entity(nameInDb = "Subjects") @Entity(
nameInDb = "Subjects",
active = true
)
public class Subject { public class Subject {
@Id(autoincrement = true) @Id(autoincrement = true)

View File

@ -0,0 +1,148 @@
package io.github.wulkanowy.dao.entities;
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 org.greenrobot.greendao.annotation.ToMany;
import java.util.List;
@Entity(
nameInDb = "Weeks",
active = true,
indexes ={@Index(value = "userId,startDayDate", unique = true)}
)
public class Week {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "USER_ID")
private Long userId;
@Property(nameInDb = "START_DATE")
private String startDayDate = "";
@ToMany(referencedJoinProperty = "weekId")
private List<Day> dayList;
/** Used to resolve relations */
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/** Used for active entity operations. */
@Generated(hash = 1019310398)
private transient WeekDao myDao;
@Generated(hash = 36829814)
public Week(Long id, Long userId, String startDayDate) {
this.id = id;
this.userId = userId;
this.startDayDate = startDayDate;
}
@Generated(hash = 2135529658)
public Week() {
}
public Long getId() {
return id;
}
public Week setId(Long id) {
this.id = id;
return this;
}
public Long getUserId() {
return userId;
}
public Week setUserId(Long userId) {
this.userId = userId;
return this;
}
public String getStartDayDate() {
return startDayDate;
}
public Week setStartDayDate(String startDayDate) {
this.startDayDate = startDayDate;
return this;
}
/**
* 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 = 1562119145)
public List<Day> getDayList() {
if (dayList == null) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
DayDao targetDao = daoSession.getDayDao();
List<Day> dayListNew = targetDao._queryWeek_DayList(id);
synchronized (this) {
if (dayList == null) {
dayList = dayListNew;
}
}
}
return dayList;
}
/** Resets a to-many relationship, making the next get call to query for a fresh result. */
@Generated(hash = 1010399236)
public synchronized void resetDayList() {
dayList = null;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/** called by internal mechanisms, do not call yourself. */
@Generated(hash = 665278367)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getWeekDao() : null;
}
}

View File

@ -15,7 +15,7 @@ public class Safety extends Scrambler {
generateNewKey(email, context); generateNewKey(email, context);
return encryptString(email, plainText); return encryptString(email, plainText);
} else { } else {
if (!RootUtilities.isRooted()) { if (RootUtilities.isRooted()) {
return new String(Base64.encode(plainText.getBytes(), Base64.DEFAULT)); return new String(Base64.encode(plainText.getBytes(), Base64.DEFAULT));
} else { } else {
throw new UnsupportedOperationException("Stored data in this devices isn't safe because android is rooted"); throw new UnsupportedOperationException("Stored data in this devices isn't safe because android is rooted");

View File

@ -29,11 +29,10 @@ import javax.security.auth.x500.X500Principal;
public class Scrambler { public class Scrambler {
public static final String DEBUG_TAG = "WulkanowySecurity";
private static final String ANDROID_KEYSTORE = "AndroidKeyStore"; private static final String ANDROID_KEYSTORE = "AndroidKeyStore";
public static final String DEBUG_TAG = "WulkanowySecurity";
private KeyStore keyStore; private KeyStore keyStore;
protected void loadKeyStore() throws CryptoException { protected void loadKeyStore() throws CryptoException {
@ -48,6 +47,7 @@ public class Scrambler {
} }
@SuppressWarnings("deprecation")
@TargetApi(18) @TargetApi(18)
protected void generateNewKey(String alias, Context context) throws CryptoException { protected void generateNewKey(String alias, Context context) throws CryptoException {
@ -116,9 +116,9 @@ public class Scrambler {
cipherOutputStream.write(text.getBytes("UTF-8")); cipherOutputStream.write(text.getBytes("UTF-8"));
cipherOutputStream.close(); cipherOutputStream.close();
byte[] vals = outputStream.toByteArray(); byte[] values = outputStream.toByteArray();
return Base64.encodeToString(vals, Base64.DEFAULT); return Base64.encodeToString(values, Base64.DEFAULT);
} catch (Exception e) { } catch (Exception e) {
Log.e(DEBUG_TAG, e.getMessage()); Log.e(DEBUG_TAG, e.getMessage());

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.services; package io.github.wulkanowy.services;
import android.content.Context; import android.content.Context;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import java.io.IOException; import java.io.IOException;
@ -19,6 +20,7 @@ import io.github.wulkanowy.services.synchronisation.CurrentAccountLogin;
import io.github.wulkanowy.services.synchronisation.FirstAccountLogin; import io.github.wulkanowy.services.synchronisation.FirstAccountLogin;
import io.github.wulkanowy.services.synchronisation.GradesSynchronisation; import io.github.wulkanowy.services.synchronisation.GradesSynchronisation;
import io.github.wulkanowy.services.synchronisation.SubjectsSynchronisation; import io.github.wulkanowy.services.synchronisation.SubjectsSynchronisation;
import io.github.wulkanowy.services.synchronisation.TimetableSynchronization;
public class VulcanSynchronization { public class VulcanSynchronization {
@ -32,6 +34,10 @@ public class VulcanSynchronization {
this.loginSession = loginSession; this.loginSession = loginSession;
} }
public VulcanSynchronization() {
this.loginSession = new LoginSession();
}
public void firstLoginConnectStep(String email, String password, String symbol) public void firstLoginConnectStep(String email, String password, String symbol)
throws BadCredentialsException, IOException { throws BadCredentialsException, IOException {
firstAccountLogin = new FirstAccountLogin(new Login(new Cookies()), new Vulcan(), email, password, symbol); firstAccountLogin = new FirstAccountLogin(new Login(new Cookies()), new Vulcan(), email, password, symbol);
@ -48,44 +54,71 @@ public class VulcanSynchronization {
} }
} }
public void loginCurrentUser(Context context, DaoSession daoSession, Vulcan vulcan) public VulcanSynchronization loginCurrentUser(Context context, DaoSession daoSession) throws CryptoException,
throws CryptoException, BadCredentialsException, AccountPermissionException, LoginErrorException, IOException { BadCredentialsException, AccountPermissionException, LoginErrorException, IOException {
CurrentAccountLogin currentAccountLogin = new CurrentAccountLogin(context, daoSession, vulcan); return loginCurrentUser(context, daoSession, new Vulcan());
loginSession = currentAccountLogin.loginCurrentUser();
} }
public boolean syncGrades() { public VulcanSynchronization loginCurrentUser(Context context, DaoSession daoSession, Vulcan vulcan)
throws CryptoException, BadCredentialsException, AccountPermissionException,
LoginErrorException, IOException {
CurrentAccountLogin currentAccountLogin = new CurrentAccountLogin(context, daoSession, vulcan);
loginSession = currentAccountLogin.loginCurrentUser();
return this;
}
public void syncAll() throws IOException {
syncSubjectsAndGrades();
syncTimetable();
}
public void syncGrades() throws IOException {
if (loginSession != null) { if (loginSession != null) {
GradesSynchronisation gradesSynchronisation = new GradesSynchronisation(); GradesSynchronisation gradesSynchronisation = new GradesSynchronisation();
try { try {
gradesSynchronisation.sync(loginSession); gradesSynchronisation.sync(loginSession);
return true;
} catch (Exception e) { } catch (Exception e) {
Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of grades failed", e); Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of grades failed", e);
return false; throw new IOException(e.getCause());
} }
} else { } else {
Log.e(VulcanJobHelper.DEBUG_TAG, "Before synchronization, should login user to log", Log.e(VulcanJobHelper.DEBUG_TAG, "Before synchronization, should login user to log",
new UnsupportedOperationException()); new UnsupportedOperationException());
return false;
} }
} }
public boolean syncSubjectsAndGrades() { public void syncSubjectsAndGrades() throws IOException {
if (loginSession != null) { if (loginSession != null) {
SubjectsSynchronisation subjectsSynchronisation = new SubjectsSynchronisation(); SubjectsSynchronisation subjectsSynchronisation = new SubjectsSynchronisation();
try { try {
subjectsSynchronisation.sync(loginSession); subjectsSynchronisation.sync(loginSession);
syncGrades(); syncGrades();
return true;
} catch (Exception e) { } catch (Exception e) {
Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of subjects failed", e); Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of subjects failed", e);
return false; throw new IOException(e.getCause());
}
} else {
Log.e(VulcanJobHelper.DEBUG_TAG, "Before synchronization, should login user to log",
new UnsupportedOperationException());
}
}
public void syncTimetable() throws IOException {
syncTimetable(null);
}
public void syncTimetable(@Nullable String date) throws IOException {
if (loginSession != null) {
TimetableSynchronization timetableSynchronization = new TimetableSynchronization();
try {
timetableSynchronization.sync(loginSession, date);
} catch (Exception e) {
Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronization of timetable failed", e);
throw new IOException(e.getCause());
} }
} else { } else {
Log.e(VulcanJobHelper.DEBUG_TAG, "Before synchronization, should login user to log", Log.e(VulcanJobHelper.DEBUG_TAG, "Before synchronization, should login user to log",
new UnsupportedOperationException()); new UnsupportedOperationException());
return false;
} }
} }
} }

View File

@ -11,59 +11,49 @@ import com.firebase.jobdispatcher.Lifetime;
import com.firebase.jobdispatcher.RetryStrategy; import com.firebase.jobdispatcher.RetryStrategy;
import com.firebase.jobdispatcher.Trigger; import com.firebase.jobdispatcher.Trigger;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.WulkanowyApp;
import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.DatabaseAccess; import io.github.wulkanowy.dao.DatabaseAccess;
import io.github.wulkanowy.dao.entities.DaoSession; import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.dao.entities.Grade; import io.github.wulkanowy.dao.entities.Grade;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization; import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.services.notifications.NotificationHelper; import io.github.wulkanowy.services.notifications.NotificationBuilder;
import io.github.wulkanowy.ui.WulkanowyApp;
import io.github.wulkanowy.ui.main.DashboardActivity;
public class GradeJob extends VulcanJobHelper { public class FullSyncJob extends VulcanJobHelper<FullSyncJob> {
private static final String UNIQUE_TAG = "GradesSync34512"; private static final String UNIQUE_TAG = "FullSync";
private static final int DEFAULT_INTERVAL_START = 60 * 50; private static final int DEFAULT_INTERVAL_START = 60 * 50;
private static final int DEFAULT_INTERVAL_END = DEFAULT_INTERVAL_START + (60 * 10); private static final int DEFAULT_INTERVAL_END = DEFAULT_INTERVAL_START + (60 * 40);
@Override @Override
protected Job createJob(FirebaseJobDispatcher dispatcher) { protected Job createJob(FirebaseJobDispatcher dispatcher) {
return dispatcher.newJobBuilder() return dispatcher.newJobBuilder()
.setLifetime(Lifetime.FOREVER) .setLifetime(Lifetime.FOREVER)
.setService(GradeService.class) .setService(SyncService.class)
.setTag(UNIQUE_TAG) .setTag(UNIQUE_TAG)
.setRecurring(true) .setRecurring(true)
.setTrigger(Trigger.executionWindow(DEFAULT_INTERVAL_START, DEFAULT_INTERVAL_END)) .setTrigger(Trigger.executionWindow(DEFAULT_INTERVAL_START, DEFAULT_INTERVAL_END))
.setConstraints(Constraint.ON_ANY_NETWORK) .setConstraints(Constraint.ON_ANY_NETWORK)
.setReplaceCurrent(true) .setReplaceCurrent(false)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.build(); .build();
} }
public static class GradeService extends VulcanService { public static class SyncService extends VulcanService {
@Override @Override
public void workToBePerformed() throws CryptoException, BadCredentialsException, public void workToBePerformed() throws Exception {
NotLoggedInErrorException, AccountPermissionException, IOException {
DaoSession daoSession = ((WulkanowyApp) getApplication()).getDaoSession(); DaoSession daoSession = ((WulkanowyApp) getApplication()).getDaoSession();
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession()); VulcanSynchronization synchronization = new VulcanSynchronization()
vulcanSynchronization.loginCurrentUser(getApplicationContext(), daoSession, new Vulcan()); .loginCurrentUser(getApplicationContext(), daoSession);
vulcanSynchronization.syncGrades(); synchronization.syncAll();
List<Grade> newGradeList = new DatabaseAccess().getNewGrades(daoSession); List<Grade> newGradeList = new DatabaseAccess().getNewGrades(daoSession);
if (newGradeList.size() == 1) { if (newGradeList.size() == 1) {
@ -81,10 +71,10 @@ public class GradeJob extends VulcanJobHelper {
PendingIntent pendingIntent = PendingIntent PendingIntent pendingIntent = PendingIntent
.getActivity(getApplicationContext(), 0, intent, 0); .getActivity(getApplicationContext(), 0, intent, 0);
NotificationHelper notificationHelper = new NotificationHelper(getApplicationContext()); NotificationBuilder notificationBuilder = new NotificationBuilder(getApplicationContext());
NotificationCompat.Builder builder = notificationHelper NotificationCompat.Builder builder = notificationBuilder
.getNotifications(title, bodyText, pendingIntent); .getNotifications(title, bodyText, pendingIntent);
notificationHelper.getManager().notify(new Random().nextInt(10000), builder.build()); notificationBuilder.getManager().notify(new Random().nextInt(10000), builder.build());
} }
} }
} }

View File

@ -1,58 +0,0 @@
package io.github.wulkanowy.services.jobs;
import com.firebase.jobdispatcher.Constraint;
import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.Job;
import com.firebase.jobdispatcher.Lifetime;
import com.firebase.jobdispatcher.RetryStrategy;
import com.firebase.jobdispatcher.Trigger;
import java.io.IOException;
import io.github.wulkanowy.activity.WulkanowyApp;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization;
public class SubjectJob extends VulcanJobHelper {
private static final String UNIQUE_TAG = "SubjectsSync34512";
private static final int DEFAULT_INTERVAL_START = 0;
private static final int DEFAULT_INTERVAL_END = DEFAULT_INTERVAL_START + 10;
@Override
protected Job createJob(FirebaseJobDispatcher dispatcher) {
return dispatcher.newJobBuilder()
.setLifetime(Lifetime.UNTIL_NEXT_BOOT)
.setService(SubjectService.class)
.setTag(UNIQUE_TAG)
.setRecurring(false)
.setTrigger(Trigger.executionWindow(DEFAULT_INTERVAL_START, DEFAULT_INTERVAL_END))
.setConstraints(Constraint.ON_ANY_NETWORK)
.setReplaceCurrent(true)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.build();
}
private class SubjectService extends VulcanService {
@Override
public void workToBePerformed() throws CryptoException, BadCredentialsException,
NotLoggedInErrorException, AccountPermissionException, IOException {
DaoSession daoSession = ((WulkanowyApp) getApplication()).getDaoSession();
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession());
vulcanSynchronization.loginCurrentUser(getApplicationContext(), daoSession, new Vulcan());
vulcanSynchronization.syncSubjectsAndGrades();
}
}
}

View File

@ -2,20 +2,23 @@ package io.github.wulkanowy.services.jobs;
import android.content.Context; import android.content.Context;
import android.util.Log;
import com.firebase.jobdispatcher.FirebaseJobDispatcher; import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.GooglePlayDriver; import com.firebase.jobdispatcher.GooglePlayDriver;
import com.firebase.jobdispatcher.Job; import com.firebase.jobdispatcher.Job;
public abstract class VulcanJobHelper { public abstract class VulcanJobHelper<T extends VulcanJobHelper> {
public static final String DEBUG_TAG = "SynchronizationService"; public static final String DEBUG_TAG = "SynchronizationService";
public void scheduledJob(Context context) { @SuppressWarnings("unchecked")
public final T scheduledJob(Context context) {
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context)); FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
dispatcher.mustSchedule(createJob(dispatcher)); dispatcher.mustSchedule(createJob(dispatcher));
Log.i(DEBUG_TAG, "Wulkanowy Job is initiation: " + this.toString());
return (T) this;
} }
protected abstract Job createJob(FirebaseJobDispatcher dispatcher); protected abstract Job createJob(FirebaseJobDispatcher dispatcher);
} }

View File

@ -6,14 +6,8 @@ import android.util.Log;
import com.firebase.jobdispatcher.JobParameters; import com.firebase.jobdispatcher.JobParameters;
import com.firebase.jobdispatcher.JobService; import com.firebase.jobdispatcher.JobService;
import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.security.CryptoException;
public abstract class VulcanService extends JobService { public abstract class VulcanService extends JobService {
private SyncTask syncTask; private SyncTask syncTask;
@ -35,8 +29,7 @@ public abstract class VulcanService extends JobService {
return true; return true;
} }
public abstract void workToBePerformed() throws CryptoException, BadCredentialsException, public abstract void workToBePerformed() throws Exception;
NotLoggedInErrorException, AccountPermissionException, IOException;
private static class SyncTask extends AsyncTask<Void, Void, Void> { private static class SyncTask extends AsyncTask<Void, Void, Void> {

View File

@ -13,15 +13,15 @@ import android.support.v4.app.NotificationCompat;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
public class NotificationHelper extends ContextWrapper { public class NotificationBuilder extends ContextWrapper {
private NotificationManager manager;
public static final String CHANNEL_ID = "Wulkanowy_New_Grade_Channel"; public static final String CHANNEL_ID = "Wulkanowy_New_Grade_Channel";
public static final String CHANNEL_NAME = "New Grade Channel"; public static final String CHANNEL_NAME = "New Grade Channel";
public NotificationHelper(Context context) { private NotificationManager manager;
public NotificationBuilder(Context context) {
super(context); super(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannel(); createChannel();

View File

@ -44,7 +44,7 @@ public class FirstAccountLogin {
} }
public LoginSession login(Context context, DaoSession daoSession, String certificate) public LoginSession login(Context context, DaoSession daoSession, String certificate)
throws NotLoggedInErrorException, AccountPermissionException, IOException, CryptoException{ throws NotLoggedInErrorException, AccountPermissionException, IOException, CryptoException {
long userId; long userId;

View File

@ -0,0 +1,117 @@
package io.github.wulkanowy.services.synchronisation;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import org.greenrobot.greendao.query.Query;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.api.timetable.Day;
import io.github.wulkanowy.api.timetable.Week;
import io.github.wulkanowy.dao.entities.DayDao;
import io.github.wulkanowy.dao.entities.Lesson;
import io.github.wulkanowy.dao.entities.LessonDao;
import io.github.wulkanowy.dao.entities.WeekDao;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.jobs.VulcanJobHelper;
import io.github.wulkanowy.utilities.ConversionVulcanObject;
import io.github.wulkanowy.utilities.TimeUtilities;
public class TimetableSynchronization {
public void sync(@NonNull LoginSession loginSession, @Nullable String dateOfMonday) throws NotLoggedInErrorException,
IOException, ParseException {
DayDao dayDao = loginSession.getDaoSession().getDayDao();
LessonDao lessonDao = loginSession.getDaoSession().getLessonDao();
WeekDao weekDao = loginSession.getDaoSession().getWeekDao();
Long weekId;
Week week = dateOfMonday == null ? loginSession.getVulcan().getTimetable().getWeekTable()
: loginSession.getVulcan().getTimetable()
.getWeekTable(String.valueOf(TimeUtilities.getNetTicks(dateOfMonday, "yyyy-MM-dd")));
Query<io.github.wulkanowy.dao.entities.Week> weekQuery = weekDao.queryBuilder()
.where(WeekDao.Properties.UserId.eq(loginSession.getUserId()), WeekDao.Properties.StartDayDate.eq(week.getStartDayDate())).build();
io.github.wulkanowy.dao.entities.Week week1 = weekQuery.unique();
if (week1 != null) {
weekId = week1.getId();
} else {
weekId = weekDao.insert(ConversionVulcanObject.weekToWeekEntitie(week).setUserId(loginSession.getUserId()));
}
List<Day> dayList = week.getDays();
dayDao.saveInTx(getPreparedDaysList(dayList, loginSession.getUserId(), weekId, dayDao));
Log.d(VulcanJobHelper.DEBUG_TAG, "Synchronization days (amount = " + dayList.size() + ")");
List<Lesson> lessonList = new ArrayList<>();
lessonList.addAll(getPreparedLessonsList(dayList, dayDao, lessonDao));
lessonDao.saveInTx(lessonList);
Log.d(VulcanJobHelper.DEBUG_TAG, "Synchronization lessons (amount = " + lessonList.size() + ")");
}
private List<Lesson> getPreparedLessonsList(List<Day> dayList, DayDao dayDao, LessonDao lessonDao) {
List<Lesson> allLessonsList = new ArrayList<>();
for (Day day : dayList) {
Query<io.github.wulkanowy.dao.entities.Day> dayQuery = dayDao.queryBuilder()
.where(DayDao.Properties.Date.eq(day.getDate()))
.build();
List<Lesson> lessonEntityList = ConversionVulcanObject.lessonsToLessonsEntities(day.getLessons());
List<Lesson> updatedLessonEntityList = new ArrayList<>();
for (Lesson lesson : lessonEntityList) {
Query<Lesson> lessonQuery = lessonDao.queryBuilder().where(LessonDao.Properties.DayId.eq(dayQuery.uniqueOrThrow().getId()), LessonDao.Properties.Date.eq(lesson.getDate()),
LessonDao.Properties.StartTime.eq(lesson.getStartTime()), LessonDao.Properties.EndTime.eq(lesson.getEndTime())).build();
Lesson lesson1 = lessonQuery.unique();
if (lesson1 != null) {
lesson.setId(lesson1.getId());
}
lesson.setDayId(dayQuery.uniqueOrThrow().getId());
if (!"".equals(lesson.getSubject())) {
updatedLessonEntityList.add(lesson);
}
}
allLessonsList.addAll(updatedLessonEntityList);
}
return allLessonsList;
}
private List<io.github.wulkanowy.dao.entities.Day> getPreparedDaysList(List<Day> dayList, long userId, long weekId, DayDao dayDao) {
List<io.github.wulkanowy.dao.entities.Day> updatedDayList = new ArrayList<>();
List<io.github.wulkanowy.dao.entities.Day> dayEntityList = ConversionVulcanObject
.daysToDaysEntities(dayList);
for (io.github.wulkanowy.dao.entities.Day day : dayEntityList) {
Query<io.github.wulkanowy.dao.entities.Day> dayQuery = dayDao.queryBuilder().where(DayDao.Properties.UserId.eq(userId), DayDao.Properties.WeekId.eq(weekId), DayDao.Properties.Date.eq(day.getDate())).build();
io.github.wulkanowy.dao.entities.Day day1 = dayQuery.unique();
if (day1 != null) {
day.setId(day1.getId());
}
day.setUserId(userId);
day.setWeekId(weekId);
updatedDayList.add(day);
}
return updatedDayList;
}
}

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity; package io.github.wulkanowy.ui;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
@ -7,17 +7,22 @@ import android.content.SharedPreferences;
import org.greenrobot.greendao.database.Database; import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.query.QueryBuilder; import org.greenrobot.greendao.query.QueryBuilder;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.utils.Log;
import io.github.wulkanowy.dao.entities.DaoMaster; import io.github.wulkanowy.dao.entities.DaoMaster;
import io.github.wulkanowy.dao.entities.DaoSession; import io.github.wulkanowy.dao.entities.DaoSession;
public class WulkanowyApp extends Application { public class WulkanowyApp extends Application {
public static final String DEBUG_TAG = "WulaknowyActivity";
private DaoSession daoSession; private DaoSession daoSession;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
enableDebugLog();
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, "wulkanowy-database"); DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, "wulkanowy-database");
Database database = devOpenHelper.getWritableDb(); Database database = devOpenHelper.getWritableDb();
@ -34,7 +39,11 @@ public class WulkanowyApp extends Application {
editor.apply(); editor.apply();
} }
}
private void enableDebugLog() {
QueryBuilder.LOG_VALUES = true; QueryBuilder.LOG_VALUES = true;
FlexibleAdapter.enableLogs(Log.Level.DEBUG);
} }
public DaoSession getDaoSession() { public DaoSession getDaoSession() {

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.login; package io.github.wulkanowy.ui.login;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.login; package io.github.wulkanowy.ui.login;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
@ -17,10 +17,10 @@ import android.widget.TextView;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.WulkanowyApp;
import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.api.login.AccountPermissionException; import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException; import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException; import io.github.wulkanowy.api.login.NotLoggedInErrorException;
@ -28,7 +28,9 @@ import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException; import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession; import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization; import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.services.jobs.GradeJob; import io.github.wulkanowy.services.jobs.FullSyncJob;
import io.github.wulkanowy.ui.WulkanowyApp;
import io.github.wulkanowy.ui.main.DashboardActivity;
import io.github.wulkanowy.utilities.ConnectionUtilities; import io.github.wulkanowy.utilities.ConnectionUtilities;
/** /**
@ -78,7 +80,7 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
vulcanSynchronization.firstLoginSignInStep(activity.get(), daoSession); vulcanSynchronization.firstLoginSignInStep(activity.get(), daoSession);
publishProgress("3", activity.get().getResources().getString(R.string.step_synchronization)); publishProgress("3", activity.get().getResources().getString(R.string.step_synchronization));
vulcanSynchronization.syncSubjectsAndGrades(); vulcanSynchronization.syncAll();
} catch (BadCredentialsException e) { } catch (BadCredentialsException e) {
return R.string.login_bad_credentials_text; return R.string.login_bad_credentials_text;
@ -86,14 +88,17 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
return R.string.error_bad_account_permission; return R.string.error_bad_account_permission;
} catch (CryptoException e) { } catch (CryptoException e) {
return R.string.encrypt_failed_text; return R.string.encrypt_failed_text;
} catch (UnknownHostException e) {
return R.string.noInternet_text;
} catch (SocketTimeoutException e) {
return R.string.generic_timeout_error;
} catch (NotLoggedInErrorException | IOException e) { } catch (NotLoggedInErrorException | IOException e) {
return R.string.login_denied_text; return R.string.login_denied_text;
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
return -1; return -1;
} }
GradeJob gradeJob = new GradeJob(); new FullSyncJob().scheduledJob(activity.get());
gradeJob.scheduledJob(activity.get());
return R.string.login_accepted_text; return R.string.login_accepted_text;
@ -145,12 +150,12 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
.setIcon(android.R.drawable.ic_dialog_alert) .setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.alert_dialog_blocked_app) .setTitle(R.string.alert_dialog_blocked_app)
.setMessage(R.string.alert_dialog_blocked_app_message) .setMessage(R.string.alert_dialog_blocked_app_message)
.setPositiveButton(R.string.dialog_close, new DialogInterface.OnClickListener() { .setPositiveButton(R.string.generic_dialog_close, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialogInterface, int i) { public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss(); dialogInterface.dismiss();
} }
}); });
alertDialog.show(); alertDialog.show();
break; break;

View File

@ -0,0 +1,189 @@
package io.github.wulkanowy.ui.main;
import android.app.Activity;
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.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem;
import io.github.wulkanowy.R;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.ui.WulkanowyApp;
import io.github.wulkanowy.utilities.ConnectionUtilities;
public abstract class AbstractFragment<T extends AbstractExpandableHeaderItem> extends Fragment
implements AsyncResponse<T> {
private FlexibleAdapter<T> flexibleAdapter;
private List<T> itemList = new ArrayList<>();
private WeakReference<Activity> activityWeakReference;
private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView recyclerViewLayout;
private DaoSession daoSession;
private long userId;
public AbstractFragment() {
//empty constructor for fragments
}
public long getUserId() {
return userId;
}
public SwipeRefreshLayout getRefreshLayoutView() {
return swipeRefreshLayout;
}
public DaoSession getDaoSession() {
return daoSession;
}
public Activity getActivityWeakReference() {
return activityWeakReference.get();
}
public abstract int getLayoutId();
public abstract int getRecyclerViewId();
public abstract int getLoadingBarId();
public abstract int getRefreshLayoutId();
public abstract List<T> getItems() throws Exception;
public abstract void onRefresh() throws Exception;
public abstract void onPostRefresh(int stringResult);
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(getLayoutId(), container, false);
recyclerViewLayout = view.findViewById(getRecyclerViewId());
swipeRefreshLayout = view.findViewById(getRefreshLayoutId());
setUpRefreshLayout(swipeRefreshLayout);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity() != null && getView() != null) {
activityWeakReference = new WeakReference<Activity>(getActivity());
daoSession = ((WulkanowyApp) getActivity().getApplication()).getDaoSession();
userId = getActivity().getSharedPreferences("LoginData", Context.MODE_PRIVATE)
.getLong("userId", 0);
if (itemList != null)
if (itemList.isEmpty()) {
flexibleAdapter = getFlexibleAdapter(itemList);
setAdapterOnRecyclerView(recyclerViewLayout);
if (getUserVisibleHint()) {
new DatabaseQueryTask(this).execute();
}
} else {
setAdapterOnRecyclerView(recyclerViewLayout);
setLoadingBarInvisible(getView());
}
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isResumed() && isVisibleToUser && flexibleAdapter.getItemCount() == 0) {
new DatabaseQueryTask(this).execute();
}
}
@Override
public void onQuarryProcessFinish(@NonNull List<T> resultItemList) {
itemList = resultItemList;
flexibleAdapter = getFlexibleAdapter(itemList);
setAdapterOnRecyclerView(recyclerViewLayout);
if (getView() != null) {
setLoadingBarInvisible(getView());
}
}
@Override
public void onRefreshProcessFinish(@Nullable List<T> resultItemList, int stringEventId) {
if (resultItemList != null) {
itemList = resultItemList;
updateDataInRecyclerView();
}
onPostRefresh(stringEventId);
getRefreshLayoutView().setRefreshing(false);
}
@NonNull
protected FlexibleAdapter<T> getFlexibleAdapter(@NonNull List<T> itemList) {
return new FlexibleAdapter<>(itemList)
.setAutoCollapseOnExpand(true)
.setAutoScrollOnExpand(true)
.expandItemsAtStartUp();
}
@NonNull
private SwipeRefreshLayout.OnRefreshListener getDefaultRefreshListener() {
return new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
if (ConnectionUtilities.isOnline(getContext())) {
new RefreshTask(AbstractFragment.this).execute();
} else {
Toast.makeText(getContext(), R.string.noInternet_text, Toast.LENGTH_SHORT).show();
swipeRefreshLayout.setRefreshing(false);
}
}
};
}
private void updateDataInRecyclerView() {
flexibleAdapter.updateDataSet(itemList);
setAdapterOnRecyclerView(recyclerViewLayout);
}
protected void setUpRefreshLayout(@NonNull SwipeRefreshLayout swipeRefreshLayout) {
swipeRefreshLayout.setColorSchemeResources(android.R.color.black);
swipeRefreshLayout.setOnRefreshListener(getDefaultRefreshListener());
}
protected final void setLoadingBarInvisible(@NonNull View mainView) {
mainView.findViewById(getLoadingBarId()).setVisibility(View.INVISIBLE);
}
protected void setAdapterOnRecyclerView(@NonNull RecyclerView recyclerView) {
recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(getActivityWeakReference()));
recyclerView.setAdapter(flexibleAdapter);
}
}

View File

@ -0,0 +1,14 @@
package io.github.wulkanowy.ui.main;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.List;
import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem;
public interface AsyncResponse<T extends AbstractExpandableHeaderItem> {
void onQuarryProcessFinish(@NonNull List<T> resultItemList);
void onRefreshProcessFinish(@Nullable List<T> resultItemList, int stringErrorId);
}

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.dashboard; package io.github.wulkanowy.ui.main;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -9,10 +9,10 @@ import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem; import android.view.MenuItem;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.dashboard.attendance.AttendanceFragment; import io.github.wulkanowy.ui.main.attendance.AttendanceFragment;
import io.github.wulkanowy.activity.dashboard.board.BoardFragment; import io.github.wulkanowy.ui.main.board.BoardFragment;
import io.github.wulkanowy.activity.dashboard.grades.GradesFragment; import io.github.wulkanowy.ui.main.grades.GradesFragment;
import io.github.wulkanowy.activity.dashboard.lessonplan.LessonPlanFragment; import io.github.wulkanowy.ui.main.timetable.TimetableFragment;
public class DashboardActivity extends AppCompatActivity { public class DashboardActivity extends AppCompatActivity {
@ -24,7 +24,7 @@ public class DashboardActivity extends AppCompatActivity {
private BoardFragment boardFragment = new BoardFragment(); private BoardFragment boardFragment = new BoardFragment();
private LessonPlanFragment lessonPlanFragment = new LessonPlanFragment(); private TimetableFragment timetableFragment = new TimetableFragment();
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() { = new BottomNavigationView.OnNavigationItemSelectedListener() {
@ -44,7 +44,7 @@ public class DashboardActivity extends AppCompatActivity {
case R.id.navigation_lessonplan: case R.id.navigation_lessonplan:
setTitle(R.string.lessonplan_text); setTitle(R.string.lessonplan_text);
currentFragment = lessonPlanFragment; currentFragment = timetableFragment;
break; break;
case R.id.navigation_dashboard: case R.id.navigation_dashboard:
@ -74,7 +74,7 @@ public class DashboardActivity extends AppCompatActivity {
setTitle(savedInstanceState.getString("activityTitle")); setTitle(savedInstanceState.getString("activityTitle"));
} else { } else {
currentFragment = gradesFragment; currentFragment = gradesFragment;
setTitle(R.string.dashboard_text); setTitle(R.string.grades_text);
} }
int cardID = getIntent().getIntExtra("cardID", 0); int cardID = getIntent().getIntExtra("cardID", 0);

View File

@ -0,0 +1,30 @@
package io.github.wulkanowy.ui.main;
import android.os.AsyncTask;
import java.util.List;
public class DatabaseQueryTask extends AsyncTask<Void, Void, List<?>> {
private AbstractFragment abstractFragment;
public DatabaseQueryTask(AbstractFragment<?> abstractFragment) {
this.abstractFragment = abstractFragment;
}
@Override
protected List<?> doInBackground(Void... voids) {
try {
return abstractFragment.getItems();
} catch (Exception e) {
return null;
}
}
@SuppressWarnings("unchecked")
@Override
protected void onPostExecute(List<?> objects) {
super.onPostExecute(objects);
abstractFragment.onQuarryProcessFinish(objects);
}
}

View File

@ -0,0 +1,52 @@
package io.github.wulkanowy.ui.main;
import android.os.AsyncTask;
import android.util.Log;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.List;
import io.github.wulkanowy.R;
public class RefreshTask extends AsyncTask<Void, Void, List<?>> {
public static final String DEBUG_TAG = "RefreshTask";
private int stringEventId = 0;
private AbstractFragment abstractFragment;
public RefreshTask(AbstractFragment abstractFragment) {
this.abstractFragment = abstractFragment;
}
@Override
protected List<?> doInBackground(Void... voids) {
try {
abstractFragment.onRefresh();
return abstractFragment.getItems();
} catch (UnknownHostException e) {
stringEventId = R.string.noInternet_text;
Log.i(DEBUG_TAG, "Synchronization is failed because occur problem with internet",
new IOException());
return null;
} catch (SocketTimeoutException e) {
stringEventId = R.string.generic_timeout_error;
Log.i(DEBUG_TAG, "Too long wait for connection with internet", e);
return null;
} catch (Exception e) {
stringEventId = R.string.refresh_error_text;
Log.e(DEBUG_TAG, "There was a synchronization problem", e);
return null;
}
}
@SuppressWarnings("unchecked")
@Override
protected void onPostExecute(List<?> objects) {
super.onPostExecute(objects);
abstractFragment.onRefreshProcessFinish(objects, stringEventId);
}
}

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.dashboard.attendance; package io.github.wulkanowy.ui.main.attendance;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.dashboard.board; package io.github.wulkanowy.ui.main.board;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.dashboard.grades; package io.github.wulkanowy.ui.main.grades;
import android.app.Activity; import android.app.Activity;
@ -14,6 +14,7 @@ import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
import com.thoughtbot.expandablerecyclerview.viewholders.ChildViewHolder; import com.thoughtbot.expandablerecyclerview.viewholders.ChildViewHolder;
import com.thoughtbot.expandablerecyclerview.viewholders.GroupViewHolder; import com.thoughtbot.expandablerecyclerview.viewholders.GroupViewHolder;
import java.lang.ref.WeakReference;
import java.util.List; import java.util.List;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
@ -22,9 +23,9 @@ import io.github.wulkanowy.utilities.AverageCalculator;
public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.SubjectViewHolder, GradesAdapter.GradeViewHolder> { public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.SubjectViewHolder, GradesAdapter.GradeViewHolder> {
private Activity activity; private static int numberOfNotReadGrade;
private int numberOfNotReadGrade; private Activity activity;
public GradesAdapter(List<? extends ExpandableGroup> groups, Activity activity) { public GradesAdapter(List<? extends ExpandableGroup> groups, Activity activity) {
super(groups); super(groups);
@ -34,13 +35,13 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
@Override @Override
public SubjectViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) { public SubjectViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.subject_item, parent, false); View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.subject_item, parent, false);
return new SubjectViewHolder(view); return new SubjectViewHolder(view, activity);
} }
@Override @Override
public GradeViewHolder onCreateChildViewHolder(ViewGroup child, int viewType) { public GradeViewHolder onCreateChildViewHolder(ViewGroup child, int viewType) {
View view = LayoutInflater.from(child.getContext()).inflate(R.layout.grade_item, child, false); View view = LayoutInflater.from(child.getContext()).inflate(R.layout.grade_item, child, false);
return new GradeViewHolder(view); return new GradeViewHolder(view, activity);
} }
@Override @Override
@ -53,7 +54,9 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
holder.bind((Grade) group.getItems().get(childIndex)); holder.bind((Grade) group.getItems().get(childIndex));
} }
public class SubjectViewHolder extends GroupViewHolder { public static class SubjectViewHolder extends GroupViewHolder {
private WeakReference<Activity> activity;
private TextView subjectName; private TextView subjectName;
@ -63,16 +66,17 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
private ImageView subjectAlertNewGrades; private ImageView subjectAlertNewGrades;
public SubjectViewHolder(View itemView) { public SubjectViewHolder(View itemView, Activity activity) {
super(itemView); super(itemView);
this.activity = new WeakReference<>(activity);
subjectName = itemView.findViewById(R.id.subject_text); subjectName = itemView.findViewById(R.id.subject_text);
numberOfGrades = itemView.findViewById(R.id.subject_number_of_grades); numberOfGrades = itemView.findViewById(R.id.subject_number_of_grades);
subjectAlertNewGrades = itemView.findViewById(R.id.subject_new_grades_alert); subjectAlertNewGrades = itemView.findViewById(R.id.subject_new_grades_alert);
averageGrades = itemView.findViewById(R.id.subject_grades_average); averageGrades = itemView.findViewById(R.id.subject_grades_average);
subjectAlertNewGrades.setVisibility(View.INVISIBLE);
} }
@SuppressWarnings("unchecked")
public void bind(ExpandableGroup group) { public void bind(ExpandableGroup group) {
int volumeGrades = group.getItemCount(); int volumeGrades = group.getItemCount();
List<Grade> gradeList = group.getItems(); List<Grade> gradeList = group.getItems();
@ -83,20 +87,24 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
if (average < 0) { if (average < 0) {
averageGrades.setText(R.string.info_no_average); averageGrades.setText(R.string.info_no_average);
} else { } else {
averageGrades.setText(activity.getResources().getString(R.string.info_average_grades, average)); averageGrades.setText(activity.get().getResources().getString(R.string.info_average_grades, average));
} }
subjectName.setText(group.getTitle()); subjectName.setText(group.getTitle());
numberOfGrades.setText(activity.getResources().getQuantityString(R.plurals.numberOfGradesPlurals, volumeGrades, volumeGrades)); numberOfGrades.setText(activity.get().getResources().getQuantityString(R.plurals.numberOfGradesPlurals, volumeGrades, volumeGrades));
for (Grade grade : gradeList) { for (Grade grade : gradeList) {
if (!grade.getRead()) { if (!grade.getRead()) {
subjectAlertNewGrades.setVisibility(View.VISIBLE); subjectAlertNewGrades.setVisibility(View.VISIBLE);
} else {
subjectAlertNewGrades.setVisibility(View.INVISIBLE);
} }
} }
} }
} }
public class GradeViewHolder extends ChildViewHolder { public static class GradeViewHolder extends ChildViewHolder {
private WeakReference<Activity> activity;
private TextView gradeValue; private TextView gradeValue;
@ -110,9 +118,11 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
private Grade gradeItem; private Grade gradeItem;
public GradeViewHolder(View itemView) { public GradeViewHolder(View itemView, Activity activity) {
super(itemView); super(itemView);
this.itemView = itemView; this.itemView = itemView;
this.activity = new WeakReference<>(activity);
gradeValue = itemView.findViewById(R.id.grade_text); gradeValue = itemView.findViewById(R.id.grade_text);
descriptionGrade = itemView.findViewById(R.id.description_grade_text); descriptionGrade = itemView.findViewById(R.id.description_grade_text);
dateGrade = itemView.findViewById(R.id.grade_date_text); dateGrade = itemView.findViewById(R.id.grade_date_text);
@ -147,16 +157,18 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
public void onClick(View v) { public void onClick(View v) {
GradesDialogFragment gradesDialogFragment = GradesDialogFragment.newInstance(gradeItem); GradesDialogFragment gradesDialogFragment = GradesDialogFragment.newInstance(gradeItem);
gradesDialogFragment.setStyle(DialogFragment.STYLE_NO_TITLE, 0); gradesDialogFragment.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
gradesDialogFragment.show(activity.getFragmentManager(), gradeItem.toString()); gradesDialogFragment.show(activity.get().getFragmentManager(), gradeItem.toString());
if (!gradeItem.getRead()) { if (!gradeItem.getRead()) {
numberOfNotReadGrade--; numberOfNotReadGrade--;
} }
if (numberOfNotReadGrade == 0) { if (numberOfNotReadGrade == 0) {
View subjectView = activity.findViewById(R.id.subject_grade_recycler).findViewWithTag(gradeItem.getSubject()); View subjectView = activity.get().findViewById(R.id.subject_grade_recycler).findViewWithTag(gradeItem.getSubject());
View subjectAlertNewGrade = subjectView.findViewById(R.id.subject_new_grades_alert); if (subjectView != null) {
subjectAlertNewGrade.setVisibility(View.INVISIBLE); View subjectAlertNewGrade = subjectView.findViewById(R.id.subject_new_grades_alert);
subjectAlertNewGrade.setVisibility(View.INVISIBLE);
}
} }
gradeItem.setRead(true); gradeItem.setRead(true);

View File

@ -1,9 +1,11 @@
package io.github.wulkanowy.activity.dashboard.grades; package io.github.wulkanowy.ui.main.grades;
import android.app.Dialog; import android.app.Dialog;
import android.app.DialogFragment; import android.app.DialogFragment;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -17,21 +19,41 @@ public class GradesDialogFragment extends DialogFragment {
private Grade grade; private Grade grade;
public static final GradesDialogFragment newInstance(Grade grade) {
return new GradesDialogFragment().setGrade(grade);
}
public GradesDialogFragment() { public GradesDialogFragment() {
setRetainInstance(true); setRetainInstance(true);
} }
public GradesDialogFragment setGrade(Grade grade) { public static final GradesDialogFragment newInstance(Grade grade) {
return new GradesDialogFragment().setGrade(grade);
}
public static int colorHexToColorName(String hexColor) {
switch (hexColor) {
case "000000":
return R.string.color_black_text;
case "F04C4C":
return R.string.color_red_text;
case "20A4F7":
return R.string.color_blue_text;
case "6ECD07":
return R.string.color_green_text;
default:
return R.string.noColor_text;
}
}
private GradesDialogFragment setGrade(Grade grade) {
this.grade = grade; this.grade = grade;
return this; return this;
} }
@Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.grades_dialog, container, false); View view = inflater.inflate(R.layout.grades_dialog, container, false);
TextView gradeText = view.findViewById(R.id.dialog_grade_text); TextView gradeText = view.findViewById(R.id.dialog_grade_text);
@ -82,24 +104,4 @@ public class GradesDialogFragment extends DialogFragment {
} }
super.onDestroyView(); super.onDestroyView();
} }
public static int colorHexToColorName(String hexColor) {
switch (hexColor) {
case "000000":
return R.string.color_black_text;
case "F04C4C":
return R.string.color_red_text;
case "20A4F7":
return R.string.color_blue_text;
case "6ECD07":
return R.string.color_green_text;
default:
return R.string.noColor_text;
}
}
} }

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.dashboard.grades; package io.github.wulkanowy.ui.main.grades;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.WulkanowyApp;
import io.github.wulkanowy.api.Vulcan; import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.dao.DatabaseAccess; import io.github.wulkanowy.dao.DatabaseAccess;
import io.github.wulkanowy.dao.entities.Account; import io.github.wulkanowy.dao.entities.Account;
@ -32,6 +31,7 @@ import io.github.wulkanowy.dao.entities.Subject;
import io.github.wulkanowy.services.LoginSession; import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization; import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.services.jobs.VulcanJobHelper; import io.github.wulkanowy.services.jobs.VulcanJobHelper;
import io.github.wulkanowy.ui.WulkanowyApp;
import io.github.wulkanowy.utilities.ConnectionUtilities; import io.github.wulkanowy.utilities.ConnectionUtilities;
public class GradesFragment extends Fragment { public class GradesFragment extends Fragment {
@ -40,16 +40,42 @@ public class GradesFragment extends Fragment {
private static long userId; private static long userId;
public GradesFragment() {
//empty constructor for fragments
}
private static void createExpList(View mainView, Activity activity) {
RecyclerView recyclerView = mainView.findViewById(R.id.subject_grade_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
GradesAdapter gradesAdapter = new GradesAdapter(subjectWithGradesList, activity);
recyclerView.setAdapter(gradesAdapter);
}
private static void downloadGradesFormDatabase(DaoSession daoSession) {
subjectWithGradesList = new ArrayList<>();
AccountDao accountDao = daoSession.getAccountDao();
Account account = accountDao.load(userId);
for (Subject subject : account.getSubjectList()) {
List<Grade> gradeList = subject.getGradeList();
if (!gradeList.isEmpty()) {
SubjectWithGrades subjectWithGrades = new SubjectWithGrades(subject.getName(), gradeList);
subjectWithGradesList.add(subjectWithGrades);
}
}
}
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
DaoSession daoSession;
View view = inflater.inflate(R.layout.fragment_grades, container, false); View view = inflater.inflate(R.layout.fragment_grades, container, false);
view.findViewById(R.id.fragment_no_grades).setVisibility(View.GONE); view.findViewById(R.id.fragment_no_grades).setVisibility(View.GONE);
if (getActivity() != null) { if (getActivity() != null) {
daoSession = ((WulkanowyApp) getActivity().getApplication()).getDaoSession(); DaoSession daoSession = ((WulkanowyApp) getActivity().getApplication()).getDaoSession();
userId = getActivity().getSharedPreferences("LoginData", Context.MODE_PRIVATE) userId = getActivity().getSharedPreferences("LoginData", Context.MODE_PRIVATE)
.getLong("userId", 0); .getLong("userId", 0);
@ -89,30 +115,6 @@ public class GradesFragment extends Fragment {
}); });
} }
private static void createExpList(View mainView, Activity activity) {
RecyclerView recyclerView = mainView.findViewById(R.id.subject_grade_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
GradesAdapter gradesAdapter = new GradesAdapter(subjectWithGradesList, activity);
recyclerView.setAdapter(gradesAdapter);
}
private static void downloadGradesFormDatabase(DaoSession daoSession) {
subjectWithGradesList = new ArrayList<>();
AccountDao accountDao = daoSession.getAccountDao();
Account account = accountDao.load(userId);
for (Subject subject : account.getSubjectList()) {
List<Grade> gradeList = subject.getGradeList();
if (!gradeList.isEmpty()) {
SubjectWithGrades subjectWithGrades = new SubjectWithGrades(subject.getName(), gradeList);
subjectWithGradesList.add(subjectWithGrades);
}
}
}
private static class GenerateListTask extends AsyncTask<Void, Void, Void> { private static class GenerateListTask extends AsyncTask<Void, Void, Void> {
private WeakReference<View> mainView; private WeakReference<View> mainView;

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.dashboard.grades; package io.github.wulkanowy.ui.main.grades;
import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup; import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;

View File

@ -0,0 +1,100 @@
package io.github.wulkanowy.ui.main.timetable;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import org.apache.commons.lang3.StringUtils;
import io.github.wulkanowy.R;
import io.github.wulkanowy.dao.entities.Lesson;
public class TimetableDialogFragment extends DialogFragment {
private Lesson lesson;
public TimetableDialogFragment() {
//empty constructor for fragment
}
public static TimetableDialogFragment newInstance(Lesson lesson) {
return new TimetableDialogFragment().setLesson(lesson);
}
private TimetableDialogFragment setLesson(Lesson lesson) {
this.lesson = lesson;
return this;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.timetable_dialog, container, false);
setRetainInstance(true);
TextView lessonText = view.findViewById(R.id.timetable_dialog_lesson_value);
TextView teacherText = view.findViewById(R.id.timetable_dialog_teacher_value);
TextView groupText = view.findViewById(R.id.timetable_dialog_group_value);
TextView roomText = view.findViewById(R.id.timetable_dialog_room_value);
TextView timeText = view.findViewById(R.id.timetable_dialog_time_value);
TextView descriptionText = view.findViewById(R.id.timetable_dialog_description_value);
Button closeButton = view.findViewById(R.id.timetable_dialog_close);
if (!lesson.getSubject().isEmpty()) {
lessonText.setText(lesson.getSubject());
}
if (!lesson.getTeacher().isEmpty()) {
teacherText.setText(lesson.getTeacher());
} else {
teacherText.setVisibility(View.GONE);
view.findViewById(R.id.timetable_dialog_teacher).setVisibility(View.GONE);
}
if (!lesson.getGroupName().isEmpty()) {
groupText.setText(lesson.getGroupName());
} else {
groupText.setVisibility(View.GONE);
view.findViewById(R.id.timetable_dialog_group).setVisibility(View.GONE);
}
if (!lesson.getRoom().isEmpty()) {
roomText.setText(lesson.getRoom());
}
if (!lesson.getEndTime().isEmpty() && !lesson.getStartTime().isEmpty()) {
timeText.setText(String.format("%1$s - %2$s", lesson.getStartTime(), lesson.getEndTime()));
}
if (!lesson.getDescription().isEmpty()) {
descriptionText.setText(StringUtils.capitalize(lesson.getDescription()));
} else {
descriptionText.setVisibility(View.GONE);
view.findViewById(R.id.timetable_dialog_description).setVisibility(View.GONE);
}
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
return view;
}
@Override
public void onDestroyView() {
Dialog dialog = getDialog();
if (dialog != null && getRetainInstance()) {
dialog.setDismissMessage(null);
}
super.onDestroyView();
}
}

View File

@ -0,0 +1,121 @@
package io.github.wulkanowy.ui.main.timetable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import java.util.ArrayList;
import java.util.List;
import io.github.wulkanowy.R;
import io.github.wulkanowy.utilities.TimeUtilities;
public class TimetableFragment extends Fragment {
private final String DATE_PATTERN = "yyyy-MM-dd";
private List<String> dateStringList = new ArrayList<>();
private TimetablePagerAdapter pagerAdapter;
private ViewPager viewPager;
private TabLayout tabLayout;
public TimetableFragment() {
//empty constructor for fragment
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_timetable, container, false);
viewPager = view.findViewById(R.id.timetable_fragment_viewpager);
tabLayout = view.findViewById(R.id.timetable_fragment_tab);
new CreateTabTask(this).execute();
return view;
}
private TimetablePagerAdapter getPagerAdapter() {
TimetablePagerAdapter pagerAdapter = new TimetablePagerAdapter(getChildFragmentManager());
for (String date : dateStringList) {
pagerAdapter.addFragment(TimetableFragmentTab.newInstance(date), date);
}
return pagerAdapter;
}
private String getDateOfCurrentMonday() {
DateTime currentDate = new DateTime();
if (currentDate.getDayOfWeek() == DateTimeConstants.SATURDAY) {
currentDate = currentDate.plusDays(2);
} else if (currentDate.getDayOfWeek() == DateTimeConstants.SUNDAY) {
currentDate = currentDate.plusDays(1);
} else {
currentDate = currentDate.withDayOfWeek(DateTimeConstants.MONDAY);
}
return currentDate.toString(DATE_PATTERN);
}
private void setAdapterOnViewPager() {
viewPager.setAdapter(pagerAdapter);
viewPager.setCurrentItem(dateStringList.indexOf(getDateOfCurrentMonday()));
}
private void setDateStringList() {
if (dateStringList.isEmpty()) {
dateStringList = TimeUtilities.getMondaysFromCurrentSchoolYear(DATE_PATTERN);
}
}
private void setViewPagerOnTabLayout() {
tabLayout.setupWithViewPager(viewPager);
}
protected final void setLoadingBarInvisible() {
if (getView() != null) {
getView().findViewById(R.id.timetable_tab_progress_bar).setVisibility(View.GONE);
}
}
private static class CreateTabTask extends AsyncTask<Void, Void, Void> {
private TimetableFragment fragment;
public CreateTabTask(TimetableFragment fragment) {
this.fragment = fragment;
}
@Override
protected Void doInBackground(Void... voids) {
fragment.setDateStringList();
fragment.pagerAdapter = fragment.getPagerAdapter();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
fragment.setAdapterOnViewPager();
fragment.setViewPagerOnTabLayout();
fragment.setLoadingBarInvisible();
}
}
}

View File

@ -0,0 +1,161 @@
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.v7.widget.RecyclerView;
import org.joda.time.DateTime;
import org.joda.time.DateTimeComparator;
import org.joda.time.DateTimeConstants;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import io.github.wulkanowy.R;
import io.github.wulkanowy.dao.entities.Day;
import io.github.wulkanowy.dao.entities.Lesson;
import io.github.wulkanowy.dao.entities.Week;
import io.github.wulkanowy.dao.entities.WeekDao;
import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.ui.main.AbstractFragment;
public class TimetableFragmentTab extends AbstractFragment<TimetableHeaderItem> {
private final String DATE_PATTERN = "yyyy-MM-dd";
private int positionToScroll;
private String date;
public static TimetableFragmentTab newInstance(String date) {
TimetableFragmentTab fragmentTab = new TimetableFragmentTab();
Bundle argument = new Bundle();
argument.putString("date", date);
fragmentTab.setArguments(argument);
return fragmentTab;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
date = getArguments().getString("date");
}
}
@Override
public int getLayoutId() {
return R.layout.fragment_timetable_tab;
}
@Override
public int getRecyclerViewId() {
return R.id.timetable_recycler;
}
@Override
public int getRefreshLayoutId() {
return R.id.timetable_refresh_layout;
}
@Override
public int getLoadingBarId() {
return R.id.timetable_progress_bar;
}
@NonNull
@Override
public List<TimetableHeaderItem> getItems() throws Exception {
Week week = getWeek();
if (week == null) {
onRefresh();
return getItems();
}
List<Day> dayEntityList = week.getDayList();
List<TimetableHeaderItem> dayList = new ArrayList<>();
int iterator = -1;
for (Day day : dayEntityList) {
List<TimetableSubItem> timetableSubItems = new ArrayList<>();
TimetableHeaderItem headerItem = new TimetableHeaderItem(day);
for (Lesson lesson : day.getLessons()) {
TimetableSubItem subItem = new TimetableSubItem(headerItem, lesson, getFragmentManager());
timetableSubItems.add(subItem);
}
iterator++;
boolean isExpanded = getExpanded(day.getDate());
if (isExpanded) {
positionToScroll = iterator;
}
headerItem.setExpanded(isExpanded);
headerItem.setSubItems(timetableSubItems);
dayList.add(headerItem);
}
return dayList;
}
@Override
protected void setAdapterOnRecyclerView(@NonNull RecyclerView recyclerView) {
super.setAdapterOnRecyclerView(recyclerView);
recyclerView.scrollToPosition(positionToScroll);
}
@Override
public void onRefresh() throws Exception {
VulcanSynchronization synchronization = new VulcanSynchronization();
synchronization.loginCurrentUser(getContext(), getDaoSession());
synchronization.syncTimetable(date);
}
@Override
public void onPostRefresh(int stringResult) {
if (stringResult == 0) {
stringResult = R.string.timetable_refresh_success;
}
Snackbar.make(getActivityWeakReference().findViewById(R.id.fragment_container),
stringResult, Snackbar.LENGTH_SHORT).show();
}
private boolean getExpanded(String dayDate) {
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(DATE_PATTERN);
DateTime dayTime = dateTimeFormatter.parseDateTime(dayDate);
DateTime currentDate = new DateTime();
if (currentDate.getDayOfWeek() == DateTimeConstants.SATURDAY) {
currentDate = currentDate.plusDays(2);
} else if (currentDate.getDayOfWeek() == DateTimeConstants.SUNDAY) {
currentDate = currentDate.plusDays(1);
}
return DateTimeComparator.getDateOnlyInstance().compare(currentDate, dayTime) == 0;
}
private Week getWeek() {
if (date == null) {
LocalDate currentMonday = new LocalDate().withDayOfWeek(DateTimeConstants.MONDAY);
date = currentMonday.toString(DATE_PATTERN);
}
return getDaoSession().getWeekDao().queryBuilder()
.where(WeekDao.Properties.StartDayDate.eq(date),
WeekDao.Properties.UserId.eq(getUserId()))
.unique();
}
}

View File

@ -0,0 +1,86 @@
package io.github.wulkanowy.ui.main.timetable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem;
import eu.davidea.viewholders.ExpandableViewHolder;
import io.github.wulkanowy.R;
import io.github.wulkanowy.dao.entities.Day;
public class TimetableHeaderItem
extends AbstractExpandableHeaderItem<TimetableHeaderItem.HeaderViewHolder, TimetableSubItem> {
private Day day;
public TimetableHeaderItem(Day day) {
this.day = day;
}
@Override
public boolean equals(Object o) {
return this == o;
}
@Override
public int getLayoutRes() {
return R.layout.timetable_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.dayName.setText(StringUtils.capitalize(day.getDayName()));
holder.date.setText(day.getDate());
boolean alertActive = false;
for (TimetableSubItem subItem : getSubItems()) {
if (subItem.getLesson().getIsMovedOrCanceled() ||
subItem.getLesson().getIsNewMovedInOrChanged()) {
alertActive = true;
}
}
if (alertActive) {
holder.alert.setVisibility(View.VISIBLE);
} else {
holder.alert.setVisibility(View.GONE);
}
}
public static class HeaderViewHolder extends ExpandableViewHolder {
@BindView(R.id.timetable_header_dayName_text)
public TextView dayName;
@BindView(R.id.timetable_header_date_text)
public TextView date;
@BindView(R.id.timetable_header_alert_image)
public ImageView alert;
public HeaderViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
toggleExpansion();
}
});
ButterKnife.bind(this, view);
}
}
}

View File

@ -0,0 +1,48 @@
package io.github.wulkanowy.ui.main.timetable;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import java.util.ArrayList;
import java.util.List;
public class TimetablePagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>();
private List<String> titleList = new ArrayList<>();
public TimetablePagerAdapter(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment, String title) {
fragmentList.add(fragment);
titleList.add(title);
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return titleList.get(position);
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
// do nothing
}
}

View File

@ -0,0 +1,112 @@
package io.github.wulkanowy.ui.main.timetable;
import android.graphics.Paint;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractSectionableItem;
import eu.davidea.viewholders.FlexibleViewHolder;
import io.github.wulkanowy.R;
import io.github.wulkanowy.dao.entities.Lesson;
public class TimetableSubItem extends AbstractSectionableItem<TimetableSubItem.SubItemViewHolder, TimetableHeaderItem> {
private Lesson lesson;
private FragmentManager fragmentManager;
public TimetableSubItem(TimetableHeaderItem header, Lesson lesson, FragmentManager fragmentManager) {
super(header);
this.lesson = lesson;
this.fragmentManager = fragmentManager;
}
public Lesson getLesson() {
return lesson;
}
@Override
public boolean equals(Object o) {
return this == o;
}
@Override
public int getLayoutRes() {
return R.layout.timetable_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.lessonName.setText(lesson.getSubject());
holder.lessonTime.setText(String.format("%1$s - %2$s", lesson.getStartTime(), lesson.getEndTime()));
holder.numberOfLesson.setText(lesson.getNumber());
holder.room.setText(lesson.getRoom());
holder.setDialog(lesson, fragmentManager);
if (lesson.getIsMovedOrCanceled() || lesson.getIsNewMovedInOrChanged()) {
holder.change.setVisibility(View.VISIBLE);
} else {
holder.change.setVisibility(View.GONE);
}
if (lesson.getIsMovedOrCanceled()) {
holder.lessonName.setPaintFlags(holder.lessonName.getPaintFlags()
| Paint.STRIKE_THRU_TEXT_FLAG);
} else {
holder.lessonName.setPaintFlags(holder.lessonName.getPaintFlags()
& (~Paint.STRIKE_THRU_TEXT_FLAG));
}
if (!lesson.getRoom().isEmpty()) {
holder.room.setText(holder.getContentView().getContext().getString(R.string.timetable_subitem_room, lesson.getRoom()));
}
}
public static class SubItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.timetable_subItem_lesson_text)
public TextView lessonName;
@BindView(R.id.timetable_subItem_number_of_lesson)
public TextView numberOfLesson;
@BindView(R.id.timetable_subItem_time)
public TextView lessonTime;
@BindView(R.id.timetable_subItem_room)
public TextView room;
@BindView(R.id.timetable_subItem_change_image)
public ImageView change;
public SubItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
public void setDialog(final Lesson lesson, final FragmentManager fragmentManager) {
getContentView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
TimetableDialogFragment dialogFragment = TimetableDialogFragment.newInstance(lesson);
dialogFragment.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
dialogFragment.show(fragmentManager, lesson.toString());
}
});
}
}
}

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.splash; package io.github.wulkanowy.ui.splash;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -9,9 +9,9 @@ import android.widget.TextView;
import io.github.wulkanowy.BuildConfig; import io.github.wulkanowy.BuildConfig;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.dashboard.DashboardActivity; import io.github.wulkanowy.services.jobs.FullSyncJob;
import io.github.wulkanowy.activity.login.LoginActivity; import io.github.wulkanowy.ui.login.LoginActivity;
import io.github.wulkanowy.services.jobs.GradeJob; import io.github.wulkanowy.ui.main.DashboardActivity;
public class SplashActivity extends AppCompatActivity { public class SplashActivity extends AppCompatActivity {
@ -36,8 +36,7 @@ public class SplashActivity extends AppCompatActivity {
Intent intent = new Intent(this, LoginActivity.class); Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent); startActivity(intent);
} else { } else {
GradeJob gradesSync = new GradeJob(); new FullSyncJob().scheduledJob(getApplicationContext());
gradesSync.scheduledJob(this);
Intent intent = new Intent(this, DashboardActivity.class); Intent intent = new Intent(this, DashboardActivity.class);
startActivity(intent); startActivity(intent);

View File

@ -4,8 +4,11 @@ package io.github.wulkanowy.utilities;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import io.github.wulkanowy.dao.entities.Day;
import io.github.wulkanowy.dao.entities.Grade; import io.github.wulkanowy.dao.entities.Grade;
import io.github.wulkanowy.dao.entities.Lesson;
import io.github.wulkanowy.dao.entities.Subject; import io.github.wulkanowy.dao.entities.Subject;
import io.github.wulkanowy.dao.entities.Week;
public class ConversionVulcanObject { public class ConversionVulcanObject {
@ -48,4 +51,52 @@ public class ConversionVulcanObject {
} }
return gradeEntityList; return gradeEntityList;
} }
public static Week weekToWeekEntitie(io.github.wulkanowy.api.timetable.Week week) {
return new Week().setStartDayDate(week.getStartDayDate());
}
public static List<Day> daysToDaysEntities(List<io.github.wulkanowy.api.timetable.Day> dayList) {
List<Day> dayEntityList = new ArrayList<>();
for (io.github.wulkanowy.api.timetable.Day day : dayList) {
Day dayEntity = new Day()
.setDate(day.getDate())
.setDayName(day.getDayName())
.setFreeDay(day.isFreeDay())
.setFreeDayName(day.getFreeDayName());
dayEntityList.add(dayEntity);
}
return dayEntityList;
}
public static List<Lesson> lessonsToLessonsEntities(List<io.github.wulkanowy.api.timetable.Lesson> lessonList) {
List<Lesson> lessonEntityList = new ArrayList<>();
for (io.github.wulkanowy.api.timetable.Lesson lesson : lessonList) {
Lesson lessonEntity = new Lesson()
.setNumber(lesson.getNumber())
.setSubject(lesson.getSubject())
.setTeacher(lesson.getTeacher())
.setRoom(lesson.getRoom())
.setDescription(lesson.getDescription())
.setGroupName(lesson.getGroupName())
.setStartTime(lesson.getStartTime())
.setEndTime(lesson.getEndTime())
.setDate(lesson.getDate())
.setEmpty(lesson.isEmpty())
.setDivisionIntoGroups(lesson.isDivisionIntoGroups())
.setPlanning(lesson.isPlanning())
.setRealized(lesson.isRealized())
.setMovedOrCanceled(lesson.isMovedOrCanceled())
.setNewMovedInOrChanged(lesson.isNewMovedInOrChanged());
lessonEntityList.add(lessonEntity);
}
return lessonEntityList;
}
} }

View File

@ -1,42 +0,0 @@
package io.github.wulkanowy.utilities;
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 DateHelper {
private static final long TICKS_AT_EPOCH = 621355968000000000L;
private static final long TICKS_PER_MILLISECOND = 10000;
private DateHelper() {
throw new IllegalStateException("Utility class");
}
public static long getTicks(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return (calendar.getTimeInMillis() * TICKS_PER_MILLISECOND) + TICKS_AT_EPOCH;
}
public static long getTics(String dateString) throws ParseException {
return getTics(dateString, "dd.MM.yyyy");
}
public static long getTics(String dateString, String dateFormat) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat(dateFormat, Locale.ROOT);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date dateObject = format.parse(dateString);
return getTicks(dateObject);
}
public static Date getDate(long ticks) {
return new Date((ticks - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND);
}
}

View File

@ -21,7 +21,7 @@ public class RootUtilities {
if (file.exists()) { if (file.exists()) {
return true; return true;
} }
} catch (Exception e1) { } catch (Exception e) {
// ignore // ignore
} }
return canExecuteCommand("/system/xbin/which su") return canExecuteCommand("/system/xbin/which su")

View File

@ -0,0 +1,74 @@
package io.github.wulkanowy.utilities;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.LocalDate;
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 class TimeUtilities {
private static final long TICKS_AT_EPOCH = 621355968000000000L;
private static final long TICKS_PER_MILLISECOND = 10000;
private TimeUtilities() {
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, "dd.MM.yyyy");
}
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 Date getDate(long netTicks) {
return new Date((netTicks - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND);
}
public static List<String> getMondaysFromCurrentSchoolYear(String dateFormat) {
LocalDate startDate = new LocalDate(getCurrentSchoolYear(), 9, 1);
LocalDate endDate = new LocalDate(getCurrentSchoolYear() + 1, 8, 31);
List<String> dateList = new ArrayList<>();
LocalDate thisMonday = startDate.withDayOfWeek(DateTimeConstants.MONDAY);
if (startDate.isAfter(thisMonday)) {
startDate = thisMonday.plusWeeks(1);
} else {
startDate = thisMonday;
}
while (startDate.isBefore(endDate)) {
dateList.add(startDate.toString(dateFormat));
startDate = startDate.plusWeeks(1);
}
return dateList;
}
public static int getCurrentSchoolYear() {
DateTime dateTime = new DateTime();
return dateTime.getMonthOfYear() <= 8 ? dateTime.getYear() - 1 : dateTime.getYear();
}
}

View File

@ -0,0 +1,8 @@
<!-- drawable/exclamation.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="@color/colorPrimary" android:pathData="M11,4.5H13V15.5H11V4.5M13,17.5V19.5H11V17.5H13Z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="30dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"
android:fillColor="@color/colorPrimary"/>
</vector>

View File

@ -7,7 +7,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:weightSum="1" android:weightSum="1"
tools:context="io.github.wulkanowy.activity.dashboard.DashboardActivity"> tools:context="io.github.wulkanowy.ui.main.DashboardActivity">
<android.support.design.widget.CoordinatorLayout <android.support.design.widget.CoordinatorLayout
android:id="@+id/fragment_container" android:id="@+id/fragment_container"

View File

@ -7,7 +7,7 @@
android:paddingRight="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" android:paddingTop="@dimen/activity_vertical_margin"
android:id="@+id/coordinatorLayout" android:id="@+id/coordinatorLayout"
tools:context="io.github.wulkanowy.activity.login.LoginActivity" tools:context="io.github.wulkanowy.ui.login.LoginActivity"
> >
<!-- Login progress --> <!-- Login progress -->
@ -77,7 +77,6 @@
android:hint="@string/prompt_email" android:hint="@string/prompt_email"
android:inputType="textEmailAddress" android:inputType="textEmailAddress"
android:maxLines="1" android:maxLines="1"
android:importantForAutofill="noExcludeDescendants"
/> />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
@ -98,7 +97,6 @@
android:imeActionLabel="@string/action_sign_in" android:imeActionLabel="@string/action_sign_in"
android:imeOptions="actionDone" android:imeOptions="actionDone"
android:fontFamily="sans-serif" android:fontFamily="sans-serif"
android:importantForAutofill="noExcludeDescendants"
/> />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>

View File

@ -3,7 +3,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="io.github.wulkanowy.activity.dashboard.attendance.AttendanceFragment"> tools:context="io.github.wulkanowy.ui.main.attendance.AttendanceFragment">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -25,9 +25,10 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="46dp" android:layout_marginTop="47dp"
android:text="@string/activity_under_construction" android:text="@string/activity_under_construction"
android:textSize="17sp" android:textSize="17sp"
android:gravity="center"
android:textAlignment="center" android:textAlignment="center"
android:id="@+id/textView3" /> android:id="@+id/textView3" />
</RelativeLayout> </RelativeLayout>

View File

@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="io.github.wulkanowy.activity.dashboard.board.BoardFragment"> tools:context="io.github.wulkanowy.ui.main.board.BoardFragment">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -25,9 +25,10 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="46dp" android:layout_marginTop="47dp"
android:text="@string/activity_under_construction" android:text="@string/activity_under_construction"
android:textSize="17sp" android:textSize="17sp"
android:gravity="center"
android:textAlignment="center" android:textAlignment="center"
android:id="@+id/textView3" /> android:id="@+id/textView3" />
</RelativeLayout> </RelativeLayout>

View File

@ -4,7 +4,7 @@
android:id="@+id/coordinator_grade" android:id="@+id/coordinator_grade"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="io.github.wulkanowy.activity.dashboard.grades.GradesFragment"> tools:context="io.github.wulkanowy.ui.main.grades.GradesFragment">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -1,35 +0,0 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="io.github.wulkanowy.activity.dashboard.lessonplan.LessonPlanFragment">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:id="@+id/wrench_under_construction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView3"
android:layout_centerHorizontal="true"
android:layout_marginTop="45dp"
android:contentDescription="@string/activity_dashboard_text"
android:minHeight="100dp"
android:minWidth="100dp"
app:srcCompat="@drawable/ic_wrench_construction" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="46dp"
android:text="@string/activity_under_construction"
android:textSize="17sp"
android:textAlignment="center"
android:id="@+id/textView3" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,36 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true">
<RelativeLayout
android:id="@+id/timetable_tab_progress_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:id="@+id/timetable_fragment_tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMinWidth="125dp"
app:tabMode="scrollable"/>
<android.support.v4.view.ViewPager
android:id="@+id/timetable_fragment_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/timetable_fragment_tab" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,32 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator_grade"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="io.github.wulkanowy.ui.main.grades.GradesFragment">
<RelativeLayout
android:id="@+id/timetable_progress_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</RelativeLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/timetable_refresh_layout">
<android.support.v7.widget.RecyclerView
android:id="@+id/timetable_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,6 +1,7 @@
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tool="http://schemas.android.com/tools"
android:id="@+id/grade_cardview" android:id="@+id/grade_cardview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -45,7 +46,8 @@
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:text="@string/app_name" android:text="@string/app_name"
android:textSize="15sp" /> android:textSize="15sp"
tool:ignore="all"/>
<TextView <TextView
android:id="@+id/grade_date_text" android:id="@+id/grade_date_text"
@ -64,7 +66,8 @@
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
app:srcCompat="@drawable/subject_alert_circle" /> app:srcCompat="@drawable/subject_alert_circle"
tool:ignore="contentDescription"/>
</RelativeLayout> </RelativeLayout>
</android.support.v7.widget.CardView> </android.support.v7.widget.CardView>

View File

@ -8,7 +8,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="450dp" android:minHeight="450dp"
android:minWidth="325dp" android:minWidth="300dp"
android:orientation="vertical"> android:orientation="vertical">
@ -176,7 +176,7 @@
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:focusable="true" android:focusable="true"
android:text="@string/dialog_close" android:text="@string/generic_dialog_close"
android:textAllCaps="true" android:textAllCaps="true"
android:textSize="15sp" android:textSize="15sp"
/> />

View File

@ -2,6 +2,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:tool="http://schemas.android.com/tools"
android:background="@drawable/subject_border_1px" android:background="@drawable/subject_border_1px"
android:foreground="?attr/selectableItemBackgroundBorderless" android:foreground="?attr/selectableItemBackgroundBorderless"
android:padding="15dp"> android:padding="15dp">
@ -48,5 +49,6 @@
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
app:srcCompat="@drawable/subject_alert_circle" /> app:srcCompat="@drawable/subject_alert_circle"
tool:ignore="contentDescription"/>
</RelativeLayout> </RelativeLayout>

View File

@ -0,0 +1,200 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="300dp"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/timetable_dialog_relative_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:paddingEnd="20dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingStart="20dp"
android:paddingTop="10dp"
tools:ignore="UselessParent">
<TextView
android:id="@+id/timetable_dialog_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_gravity="start"
android:gravity="center_vertical"
android:maxLines="5"
android:minHeight="60dp"
android:minLines="2"
android:paddingTop="10dp"
android:text="@string/generic_dialog_details"
android:textIsSelectable="true"
android:textSize="20sp" />
<TextView
android:id="@+id/timetable_dialog_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_details"
android:layout_marginTop="10dp"
android:text="@string/timetable_dialog_description"
android:textColor="@color/colorPrimaryDark"
android:textSize="17sp" />
<TextView
android:id="@+id/timetable_dialog_description_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_description"
android:layout_marginTop="3dp"
android:text="@string/generic_app_no_data"
android:textColor="@color/colorPrimaryDark"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:id="@+id/timetable_dialog_lesson"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_description_value"
android:layout_marginTop="10dp"
android:text="@string/timetable_dialog_lesson"
android:textIsSelectable="true"
android:textSize="17sp" />
<TextView
android:id="@+id/timetable_dialog_lesson_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_lesson"
android:layout_marginTop="3dp"
android:text="@string/generic_app_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:id="@+id/timetable_dialog_teacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_lesson_value"
android:layout_marginTop="10dp"
android:text="@string/generic_dialog_teacher"
android:textSize="17sp" />
<TextView
android:id="@+id/timetable_dialog_teacher_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_teacher"
android:layout_marginTop="3dp"
android:text="@string/generic_app_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:id="@+id/timetable_dialog_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_teacher_value"
android:layout_marginTop="10dp"
android:text="@string/timetable_dialog_group"
android:textSize="17sp" />
<TextView
android:id="@+id/timetable_dialog_group_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_group"
android:layout_marginTop="3dp"
android:text="@string/generic_app_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:id="@+id/timetable_dialog_room"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_group_value"
android:layout_marginTop="10dp"
android:text="@string/timetable_dialog_room"
android:textSize="17sp" />
<TextView
android:id="@+id/timetable_dialog_room_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@id/timetable_dialog_room"
android:layout_marginTop="3dp"
android:text="@string/generic_app_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:id="@+id/timetable_dialog_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_room_value"
android:layout_marginTop="10dp"
android:text="@string/timetable_dialog_time"
android:textSize="17sp" />
<TextView
android:id="@+id/timetable_dialog_time_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_dialog_time"
android:layout_marginTop="3dp"
android:text="@string/generic_app_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<Button
android:id="@+id/timetable_dialog_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignTop="@+id/timetable_dialog_time_value"
android:layout_marginTop="25dp"
android:background="?attr/selectableItemBackground"
android:focusable="true"
android:text="@string/generic_dialog_close"
android:textAllCaps="true"
android:textSize="15sp" />
</RelativeLayout>
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,48 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/subject_border_1px"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:padding="15dp">
<TextView
android:id="@+id/timetable_header_dayName_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginEnd="15dp"
android:layout_marginRight="15dp"
android:layout_toLeftOf="@id/timetable_header_alert_image"
android:layout_toStartOf="@+id/timetable_header_alert_image"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/app_name"
android:textSize="19sp" />
<TextView
android:id="@+id/timetable_header_date_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/timetable_header_dayName_text"
android:layout_marginTop="5dp"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="#4C4C4C"
android:textSize="14sp" />
<ImageView
android:id="@+id/timetable_header_alert_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginTop="10dp"
app:srcCompat="@drawable/ic_generic_exclamation"
tools:ignore="contentDescription" />
</RelativeLayout>

View File

@ -0,0 +1,95 @@
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tool="http://schemas.android.com/tools"
android:id="@+id/timetable_subItem_cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="7dp"
android:layout_marginEnd="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginStart="5dp"
android:foreground="?attr/selectableItemBackgroundBorderless"
card_view:cardElevation="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="7dp"
android:layout_marginEnd="7dp"
android:layout_marginLeft="7dp"
android:layout_marginRight="7dp"
android:layout_marginStart="7dp"
android:layout_marginTop="7dp">
<TextView
android:id="@+id/timetable_subItem_number_of_lesson"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:gravity="center"
android:maxLength="1"
android:text="0"
android:textSize="32sp"
tool:ignore="all"/>
<TextView
android:id="@+id/timetable_subItem_lesson_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginEnd="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="40dp"
android:layout_marginStart="10dp"
android:layout_toEndOf="@+id/timetable_subItem_number_of_lesson"
android:layout_toRightOf="@+id/timetable_subItem_number_of_lesson"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/app_name"
android:textSize="17sp"
tool:ignore="all"/>
<TextView
android:id="@+id/timetable_subItem_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/timetable_subItem_number_of_lesson"
android:layout_alignLeft="@id/timetable_subItem_lesson_text"
android:layout_alignStart="@id/timetable_subItem_lesson_text"
android:maxLines="1"
android:text="@string/grades_text"
android:textColor="#4C4C4C"
android:textSize="12sp" />
<TextView
android:id="@+id/timetable_subItem_room"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/timetable_subItem_number_of_lesson"
android:layout_marginEnd="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="40dp"
android:layout_marginStart="10dp"
android:layout_toEndOf="@+id/timetable_subItem_time"
android:layout_toRightOf="@+id/timetable_subItem_time"
android:maxLines="1"
android:text="@string/grades_text"
android:textColor="#4C4C4C"
android:textSize="12sp"
tool:ignore="all"/>
<ImageView
android:id="@+id/timetable_subItem_change_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginTop="10dp"
app:srcCompat="@drawable/ic_timetable_swap"
tool:ignore="contentDescription"/>
</RelativeLayout>
</android.support.v7.widget.CardView>

View File

@ -51,13 +51,28 @@
<string name="dialog_teacher_text">Nauczyciel</string> <string name="dialog_teacher_text">Nauczyciel</string>
<string name="dialog_date_text">Data</string> <string name="dialog_date_text">Data</string>
<string name="dialog_color_text">Kolor</string> <string name="dialog_color_text">Kolor</string>
<string name="dialog_close">Zamknij</string>
<string name="timetable_dialog_lesson">Lekcja</string>
<string name="timetable_dialog_room">Sala</string>
<string name="timetable_dialog_group">Grupa</string>
<string name="timetable_dialog_time">Godziny</string>
<string name="timetable_dialog_description">Zmiany</string>
<string name="timetable_refresh_success">Poprawnie zsynchronizowano</string>
<string name="generic_dialog_details">Szczegóły</string>
<string name="generic_dialog_close">Zamknij</string>
<string name="generic_dialog_teacher">Nauczyciel</string>
<string name="generic_app_no_data">Brak danych</string>
<string name="generic_timeout_error">Zbyt długie oczekiwanie na połączenie</string>
<string name="snackbar_no_grades">Brak nowych ocen</string> <string name="snackbar_no_grades">Brak nowych ocen</string>
<string name="snackbar_new_grade">Ilość nowych ocen: %1$d</string> <string name="snackbar_new_grade">Ilość nowych ocen: %1$d</string>
<string name="info_average_grades">Średnia: %1$.2f</string> <string name="info_average_grades">Średnia: %1$.2f</string>
<string name="info_no_average">Brak średniej</string> <string name="info_no_average">Brak średniej</string>
<string name="timetable_subitem_room">Sala %s</string>
<plurals name="numberOfGradesPlurals"> <plurals name="numberOfGradesPlurals">
<item quantity="one">%d ocena</item> <item quantity="one">%d ocena</item>

View File

@ -51,7 +51,21 @@
<string name="dialog_teacher_text">Teacher</string> <string name="dialog_teacher_text">Teacher</string>
<string name="dialog_date_text">Date</string> <string name="dialog_date_text">Date</string>
<string name="dialog_color_text">Color</string> <string name="dialog_color_text">Color</string>
<string name="dialog_close">Close</string>
<string name="timetable_dialog_lesson">Lesson</string>
<string name="timetable_dialog_room">Room</string>
<string name="timetable_dialog_group">Group</string>
<string name="timetable_dialog_time">Times</string>
<string name="timetable_dialog_description">Changes</string>
<string name="timetable_refresh_success">Successful synchronisation</string>
<string name="generic_dialog_details">Details</string>
<string name="generic_dialog_close">Close</string>
<string name="generic_dialog_teacher">Teacher</string>
<string name="generic_app_no_data">No data</string>
<string name="generic_timeout_error">Too long wait for connection</string>
<string name="snackbar_no_grades">No new grades</string> <string name="snackbar_no_grades">No new grades</string>
<string name="snackbar_new_grade">Number of new grades: %1$d</string> <string name="snackbar_new_grade">Number of new grades: %1$d</string>
@ -59,6 +73,8 @@
<string name="info_average_grades">Average: %1$.2f</string> <string name="info_average_grades">Average: %1$.2f</string>
<string name="info_no_average">No average</string> <string name="info_no_average">No average</string>
<string name="timetable_subitem_room">Room %s</string>
<plurals name="numberOfGradesPlurals"> <plurals name="numberOfGradesPlurals">
<item quantity="one">%d grade</item> <item quantity="one">%d grade</item>
<item quantity="other">%d grades</item> <item quantity="other">%d grades</item>

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.dashboard.grades; package io.github.wulkanowy.ui.main.grades;
import org.junit.Assert; import org.junit.Assert;
@ -6,7 +6,7 @@ import org.junit.Test;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import static io.github.wulkanowy.activity.dashboard.grades.GradesDialogFragment.colorHexToColorName; import static io.github.wulkanowy.ui.main.grades.GradesDialogFragment.colorHexToColorName;
public class GradesDialogFragmentTest { public class GradesDialogFragmentTest {

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.activity.dashboard.grades; package io.github.wulkanowy.ui.main.grades;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;

View File

@ -8,6 +8,8 @@ import java.util.List;
import io.github.wulkanowy.api.grades.Grade; import io.github.wulkanowy.api.grades.Grade;
import io.github.wulkanowy.api.grades.Subject; import io.github.wulkanowy.api.grades.Subject;
import io.github.wulkanowy.api.timetable.Day;
import io.github.wulkanowy.api.timetable.Lesson;
public class ConversionVulcanObjectTest { public class ConversionVulcanObjectTest {
@ -42,4 +44,36 @@ public class ConversionVulcanObjectTest {
Assert.assertEquals(new ArrayList<>(), Assert.assertEquals(new ArrayList<>(),
ConversionVulcanObject.gradesToGradeEntities(new ArrayList<Grade>())); ConversionVulcanObject.gradesToGradeEntities(new ArrayList<Grade>()));
} }
@Test
public void dayConversionEmptyTest() {
Assert.assertEquals(new ArrayList<>(),
ConversionVulcanObject.daysToDaysEntities(new ArrayList<Day>()));
}
@Test
public void dayConversionTest() {
List<Day> dayList = new ArrayList<>();
dayList.add(new Day().setDate("20.12.2012"));
List<io.github.wulkanowy.dao.entities.Day> dayEntityList =
ConversionVulcanObject.daysToDaysEntities(dayList);
Assert.assertEquals("20.12.2012", dayEntityList.get(0).getDate());
}
@Test
public void lessonConversionEmptyTest() {
Assert.assertEquals(new ArrayList<>(),
ConversionVulcanObject.lessonsToLessonsEntities(new ArrayList<Lesson>()));
}
@Test
public void lessonConversionTest() {
List<Lesson> lessonList = new ArrayList<>();
lessonList.add(new Lesson().setRoom("20"));
List<io.github.wulkanowy.dao.entities.Lesson> lessonEntityList =
ConversionVulcanObject.lessonsToLessonsEntities(lessonList);
Assert.assertEquals("20", lessonEntityList.get(0).getRoom());
}
} }

View File

@ -11,7 +11,7 @@ import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
public class DateHelperTest { public class TimeUtilitiesTest {
@Test @Test
public void getTicksDateObjectTest() throws Exception { public void getTicksDateObjectTest() throws Exception {
@ -19,32 +19,32 @@ public class DateHelperTest {
format.setTimeZone(TimeZone.getTimeZone("UTC")); format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = format.parse("31.07.2017"); Date date = format.parse("31.07.2017");
Assert.assertEquals(636370560000000000L, DateHelper.getTicks(date)); Assert.assertEquals(636370560000000000L, TimeUtilities.getNetTicks(date));
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
calendar.setTime(date); calendar.setTime(date);
calendar.add(Calendar.DAY_OF_YEAR, -14); calendar.add(Calendar.DAY_OF_YEAR, -14);
Date dateTwoWeekBefore = calendar.getTime(); Date dateTwoWeekBefore = calendar.getTime();
Assert.assertEquals(636358464000000000L, DateHelper.getTicks(dateTwoWeekBefore)); Assert.assertEquals(636358464000000000L, TimeUtilities.getNetTicks(dateTwoWeekBefore));
} }
@Test(expected = ParseException.class) @Test(expected = ParseException.class)
public void getTicsStringInvalidFormatTest() throws Exception { public void getTicsStringInvalidFormatTest() throws Exception {
Assert.assertEquals(636370560000000000L, DateHelper.getTics("31.07.2017", "dd.MMM.yyyy")); Assert.assertEquals(636370560000000000L, TimeUtilities.getNetTicks("31.07.2017", "dd.MMM.yyyy"));
} }
@Test @Test
public void getTicsStringFormatTest() throws Exception { public void getTicsStringFormatTest() throws Exception {
Assert.assertEquals(636370560000000000L, DateHelper.getTics("31.07.2017", "dd.MM.yyyy")); Assert.assertEquals(636370560000000000L, TimeUtilities.getNetTicks("31.07.2017", "dd.MM.yyyy"));
} }
@Test @Test
public void getTicsStringTest() throws Exception { public void getTicsStringTest() throws Exception {
Assert.assertEquals(636370560000000000L, DateHelper.getTics("31.07.2017")); Assert.assertEquals(636370560000000000L, TimeUtilities.getNetTicks("31.07.2017"));
Assert.assertEquals(636334272000000000L, DateHelper.getTics("19.06.2017")); Assert.assertEquals(636334272000000000L, TimeUtilities.getNetTicks("19.06.2017"));
Assert.assertEquals(636189120000000000L, DateHelper.getTics("02.01.2017")); Assert.assertEquals(636189120000000000L, TimeUtilities.getNetTicks("02.01.2017"));
Assert.assertEquals(636080256000000000L, DateHelper.getTics("29.08.2016")); Assert.assertEquals(636080256000000000L, TimeUtilities.getNetTicks("29.08.2016"));
} }
@Test @Test
@ -53,6 +53,6 @@ public class DateHelperTest {
format.setTimeZone(TimeZone.getTimeZone("UTC")); format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = format.parse("31.07.2017"); Date date = format.parse("31.07.2017");
Assert.assertEquals(date, DateHelper.getDate(636370560000000000L)); Assert.assertEquals(date, TimeUtilities.getDate(636370560000000000L));
} }
} }