diff --git a/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java b/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java index 7c9fc27f5..677a6de02 100644 --- a/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java +++ b/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java @@ -4,8 +4,12 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; +import java.util.Locale; import io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.generic.Day; @@ -16,25 +20,34 @@ public class AttendanceTable { private SnP snp; - private String attendancePageUrl = "Frekwencja.mvc?data="; + private final static String ATTENDANCE_PAGE_URL = "Frekwencja.mvc?data="; public AttendanceTable(SnP snp) { this.snp = snp; } - public Week getWeekTable() throws IOException { + public Week getWeekTable() throws IOException, ParseException { return getWeekTable(""); } - public Week getWeekTable(String tick) throws IOException { - Element table = snp.getSnPPageDocument(attendancePageUrl + tick) + public Week getWeekTable(String tick) throws IOException, ParseException { + Element table = snp.getSnPPageDocument(ATTENDANCE_PAGE_URL + tick) .select(".mainContainer .presentData").first(); Elements headerCells = table.select("thead th"); List days = new ArrayList<>(); for (int i = 1; i < headerCells.size(); i++) { - days.add(new Day().setDate(headerCells.get(i).html().split("
")[1])); + String[] dayHeaderCell = headerCells.get(i).html().split("
"); + + SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); + Date d = sdf.parse(dayHeaderCell[1].trim()); + sdf.applyPattern("yyyy-MM-dd"); + + Day day = new Day(); + day.setDayName(dayHeaderCell[0]); + day.setDate(sdf.format(d)); + days.add(day); } Elements hoursInDays = table.select("tbody tr"); @@ -46,26 +59,29 @@ public class AttendanceTable { // fill hours in day int size = hours.size(); for (int i = 1; i < size; i++) { - days.get(i - 1).setLesson(getNewLesson(hours.get(i))); + Lesson lesson = new Lesson(); + lesson.setDate(days.get(i - 1).getDate()); + lesson.setNumber(hours.get(0).text()); + + addLessonDetails(lesson, hours.get(i)); + + days.get(i - 1).setLesson(lesson); } } - String[] dayDescription = headerCells.get(1).html().split("
"); - return new Week() - .setStartDayDate(dayDescription[1]) + .setStartDayDate(days.get(0).getDate()) .setDays(days); } - private Lesson getNewLesson(Element cell) { - Lesson lesson = new Lesson(); + private void addLessonDetails(Lesson lesson, Element cell) { lesson.setSubject(cell.select("span").text()); if (LessonTypes.CLASS_NOT_EXIST.equals(cell.attr("class"))) { lesson.setNotExist(true); lesson.setEmpty(true); - return lesson; + return; } switch (cell.select("div").attr("class")) { @@ -95,7 +111,5 @@ public class AttendanceTable { lesson.setEmpty(true); break; } - - return lesson; } } diff --git a/api/src/test/java/io/github/wulkanowy/api/attendance/AttendanceTableTest.java b/api/src/test/java/io/github/wulkanowy/api/attendance/AttendanceTableTest.java index 1420a4752..40ff4f065 100644 --- a/api/src/test/java/io/github/wulkanowy/api/attendance/AttendanceTableTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/attendance/AttendanceTableTest.java @@ -20,8 +20,8 @@ public class AttendanceTableTest extends StudentAndParentTestCase { @Test public void getWeekStartByDate() throws Exception { - Assert.assertEquals("31.08.2015", excellent.getWeekTable().getStartDayDate()); - Assert.assertEquals("05.09.2016", full.getWeekTable().getStartDayDate()); + Assert.assertEquals("2015-08-31", excellent.getWeekTable().getStartDayDate()); + Assert.assertEquals("2016-09-05", full.getWeekTable().getStartDayDate()); } @Test @@ -38,13 +38,13 @@ public class AttendanceTableTest extends StudentAndParentTestCase { @Test public void getDayDate() throws Exception { - Assert.assertEquals("31.08.2015", excellent.getWeekTable().getDay(0).getDate()); - Assert.assertEquals("02.09.2015", excellent.getWeekTable().getDay(2).getDate()); - Assert.assertEquals("04.09.2015", excellent.getWeekTable().getDay(4).getDate()); + Assert.assertEquals("2015-08-31", excellent.getWeekTable().getDay(0).getDate()); + Assert.assertEquals("2015-09-02", excellent.getWeekTable().getDay(2).getDate()); + Assert.assertEquals("2015-09-04", excellent.getWeekTable().getDay(4).getDate()); - Assert.assertEquals("05.09.2016", full.getWeekTable().getDay(0).getDate()); - Assert.assertEquals("07.09.2016", full.getWeekTable().getDay(2).getDate()); - Assert.assertEquals("09.09.2016", full.getWeekTable().getDay(4).getDate()); + Assert.assertEquals("2016-09-05", full.getWeekTable().getDay(0).getDate()); + Assert.assertEquals("2016-09-07", full.getWeekTable().getDay(2).getDate()); + Assert.assertEquals("2016-09-09", full.getWeekTable().getDay(4).getDate()); } @Test diff --git a/app/build.gradle b/app/build.gradle index d4374e2d1..4966d9f07 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,7 @@ android { } greendao { - schemaVersion 20 + schemaVersion 22 generateTests = true } diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/AttendanceLessonTest.java b/app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/AttendanceLessonTest.java new file mode 100644 index 000000000..492d642d1 --- /dev/null +++ b/app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/AttendanceLessonTest.java @@ -0,0 +1,28 @@ +package io.github.wulkanowy.data.db.dao.entities; + +import org.greenrobot.greendao.test.AbstractDaoTestLongPk; + +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLessonDao; + +public class AttendanceLessonTest extends AbstractDaoTestLongPk { + + public AttendanceLessonTest() { + super(AttendanceLessonDao.class); + } + + @Override + protected AttendanceLesson createEntity(Long key) { + AttendanceLesson entity = new AttendanceLesson(); + entity.setId(key); + entity.setIsPresence(false); + entity.setIsAbsenceUnexcused(false); + entity.setIsAbsenceExcused(false); + entity.setIsUnexcusedLateness(false); + entity.setIsAbsenceForSchoolReasons(false); + entity.setIsExcusedLateness(false); + entity.setIsExemption(false); + return entity; + } + +} diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/LessonTest.java b/app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/TimetableLessonTest.java similarity index 50% rename from app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/LessonTest.java rename to app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/TimetableLessonTest.java index c8690ff94..b215b6bef 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/LessonTest.java +++ b/app/src/androidTest/java/io/github/wulkanowy/data/db/dao/entities/TimetableLessonTest.java @@ -2,15 +2,18 @@ package io.github.wulkanowy.data.db.dao.entities; import org.greenrobot.greendao.test.AbstractDaoTestLongPk; -public class LessonTest extends AbstractDaoTestLongPk { +import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; +import io.github.wulkanowy.data.db.dao.entities.TimetableLessonDao; - public LessonTest() { - super(LessonDao.class); +public class TimetableLessonTest extends AbstractDaoTestLongPk { + + public TimetableLessonTest() { + super(TimetableLessonDao.class); } @Override - protected Lesson createEntity(Long key) { - Lesson entity = new Lesson(); + protected TimetableLesson createEntity(Long key) { + TimetableLesson entity = new TimetableLesson(); entity.setId(key); entity.setIsEmpty(false); entity.setIsDivisionIntoGroups(false); diff --git a/app/src/main/java/io/github/wulkanowy/data/Repository.java b/app/src/main/java/io/github/wulkanowy/data/Repository.java index 04460a07e..2637b08cb 100644 --- a/app/src/main/java/io/github/wulkanowy/data/Repository.java +++ b/app/src/main/java/io/github/wulkanowy/data/Repository.java @@ -1,6 +1,5 @@ package io.github.wulkanowy.data; - import java.io.IOException; import java.text.ParseException; import java.util.List; @@ -13,6 +12,7 @@ import io.github.wulkanowy.api.login.BadCredentialsException; import io.github.wulkanowy.api.login.NotLoggedInErrorException; import io.github.wulkanowy.api.login.VulcanOfflineException; import io.github.wulkanowy.data.db.dao.entities.Account; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; import io.github.wulkanowy.data.db.dao.entities.DaoSession; import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.db.dao.entities.GradeDao; @@ -21,6 +21,7 @@ import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.data.db.resources.ResourcesContract; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.data.sync.SyncContract; +import io.github.wulkanowy.data.sync.attendance.AttendanceSyncContract; import io.github.wulkanowy.data.sync.login.LoginSyncContract; import io.github.wulkanowy.data.sync.timetable.TimetableSyncContract; import io.github.wulkanowy.di.annotations.SyncGrades; @@ -38,6 +39,8 @@ public class Repository implements RepositoryContract { private final LoginSyncContract loginSync; + private final AttendanceSyncContract attendanceSync; + private final TimetableSyncContract timetableSync; private final SyncContract gradeSync; @@ -49,6 +52,7 @@ public class Repository implements RepositoryContract { ResourcesContract resources, DaoSession daoSession, LoginSyncContract loginSync, + AttendanceSyncContract attendanceSync, TimetableSyncContract timetableSync, @SyncGrades SyncContract gradeSync, @SyncSubjects SyncContract subjectSync) { @@ -56,6 +60,7 @@ public class Repository implements RepositoryContract { this.resources = resources; this.daoSession = daoSession; this.loginSync = loginSync; + this.attendanceSync = attendanceSync; this.timetableSync = timetableSync; this.gradeSync = gradeSync; this.subjectSync = subjectSync; @@ -81,6 +86,11 @@ public class Repository implements RepositoryContract { return resources.getErrorLoginMessage(e); } + @Override + public String getAttendanceLessonDescription(AttendanceLesson lesson) { + return resources.getAttendanceLessonDescription(lesson); + } + @Override public void loginUser(String email, String password, String symbol) throws NotLoggedInErrorException, AccountPermissionException, IOException, @@ -104,6 +114,16 @@ public class Repository implements RepositoryContract { subjectSync.sync(); } + @Override + public void syncAttendance() throws NotLoggedInErrorException, ParseException, IOException { + attendanceSync.syncAttendance(); + } + + @Override + public void syncAttendance(String date) throws NotLoggedInErrorException, ParseException, IOException { + attendanceSync.syncAttendance(date); + } + @Override public void syncTimetable() throws NotLoggedInErrorException, IOException, ParseException { timetableSync.syncTimetable(); @@ -118,6 +138,7 @@ public class Repository implements RepositoryContract { public void syncAll() throws NotLoggedInErrorException, IOException, ParseException { syncSubjects(); syncGrades(); + syncAttendance(); syncTimetable(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java b/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java index fcdf29ed8..90aaeef81 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java @@ -11,12 +11,13 @@ import io.github.wulkanowy.data.db.dao.entities.Account; import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.resources.ResourcesContract; +import io.github.wulkanowy.data.sync.attendance.AttendanceSyncContract; import io.github.wulkanowy.data.sync.login.LoginSyncContract; import io.github.wulkanowy.data.sync.timetable.TimetableSyncContract; @Singleton public interface RepositoryContract extends ResourcesContract, LoginSyncContract, - TimetableSyncContract { + AttendanceSyncContract, TimetableSyncContract { long getCurrentUserId(); diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/AttendanceLesson.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/AttendanceLesson.java new file mode 100644 index 000000000..9250518af --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/AttendanceLesson.java @@ -0,0 +1,254 @@ +package io.github.wulkanowy.data.db.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.Transient; + +import java.io.Serializable; + +@Entity( + nameInDb = "AttendanceLessons", + active = true, + indexes = {@Index(value = "dayId,date,number", unique = true)} +) +public class AttendanceLesson implements Serializable { + + @Id(autoincrement = true) + private Long id; + + @Property(nameInDb = "DAY_ID") + private Long dayId; + + @Property(nameInDb = "DATE") + private String date = ""; + + @Property(nameInDb = "NUMBER_OF_LESSON") + private int number = 0; + + @Property(nameInDb = "SUBJECT_NAME") + private String subject = ""; + + @Property(nameInDb = "IS_PRESENCE") + private boolean isPresence = false; + + @Property(nameInDb = "IS_ABSENCE_UNEXCUSED") + private boolean isAbsenceUnexcused = false; + + @Property(nameInDb = "IS_ABSENCE_EXCUSED") + private boolean isAbsenceExcused = false; + + @Property(nameInDb = "IS_UNEXCUSED_LATENESS") + private boolean isUnexcusedLateness = false; + + @Property(nameInDb = "IS_ABSENCE_FOR_SCHOOL_REASONS") + private boolean isAbsenceForSchoolReasons = false; + + @Property(nameInDb = "IS_EXCUSED_LATENESS") + private boolean isExcusedLateness = false; + + @Property(nameInDb = "IS_EXEMPTION") + private boolean isExemption = false; + + @Transient + private String description = ""; + + private static final long serialVersionUID = 42L; + + /** + * Used to resolve relations + */ + @Generated(hash = 2040040024) + private transient DaoSession daoSession; + + /** + * Used for active entity operations. + */ + @Generated(hash = 1936953859) + private transient AttendanceLessonDao myDao; + + @Generated(hash = 1428129046) + public AttendanceLesson(Long id, Long dayId, String date, int number, + String subject, boolean isPresence, boolean isAbsenceUnexcused, + boolean isAbsenceExcused, boolean isUnexcusedLateness, + boolean isAbsenceForSchoolReasons, boolean isExcusedLateness, + boolean isExemption) { + this.id = id; + this.dayId = dayId; + this.date = date; + this.number = number; + this.subject = subject; + this.isPresence = isPresence; + this.isAbsenceUnexcused = isAbsenceUnexcused; + this.isAbsenceExcused = isAbsenceExcused; + this.isUnexcusedLateness = isUnexcusedLateness; + this.isAbsenceForSchoolReasons = isAbsenceForSchoolReasons; + this.isExcusedLateness = isExcusedLateness; + this.isExemption = isExemption; + } + + @Generated(hash = 921806575) + public AttendanceLesson() { + } + + 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 getDate() { + return this.date; + } + + public AttendanceLesson setDate(String date) { + this.date = date; + return this; + } + + public int getNumber() { + return this.number; + } + + public AttendanceLesson setNumber(int number) { + this.number = number; + return this; + } + + public String getSubject() { + return this.subject; + } + + public AttendanceLesson setSubject(String subject) { + this.subject = subject; + return this; + } + + public boolean getIsPresence() { + return this.isPresence; + } + + public AttendanceLesson setIsPresence(boolean isPresence) { + this.isPresence = isPresence; + return this; + } + + public boolean getIsAbsenceUnexcused() { + return this.isAbsenceUnexcused; + } + + public AttendanceLesson setIsAbsenceUnexcused(boolean isAbsenceUnexcused) { + this.isAbsenceUnexcused = isAbsenceUnexcused; + return this; + } + + public boolean getIsAbsenceExcused() { + return this.isAbsenceExcused; + } + + public AttendanceLesson setIsAbsenceExcused(boolean isAbsenceExcused) { + this.isAbsenceExcused = isAbsenceExcused; + return this; + } + + public boolean getIsUnexcusedLateness() { + return this.isUnexcusedLateness; + } + + public AttendanceLesson setIsUnexcusedLateness(boolean isUnexcusedLateness) { + this.isUnexcusedLateness = isUnexcusedLateness; + return this; + } + + public boolean getIsAbsenceForSchoolReasons() { + return this.isAbsenceForSchoolReasons; + } + + public AttendanceLesson setIsAbsenceForSchoolReasons(boolean isAbsenceForSchoolReasons) { + this.isAbsenceForSchoolReasons = isAbsenceForSchoolReasons; + return this; + } + + public boolean getIsExcusedLateness() { + return this.isExcusedLateness; + } + + public AttendanceLesson setIsExcusedLateness(boolean isExcusedLateness) { + this.isExcusedLateness = isExcusedLateness; + return this; + } + + public boolean getIsExemption() { + return this.isExemption; + } + + public AttendanceLesson setIsExemption(boolean isExemption) { + this.isExemption = isExemption; + return this; + } + + public String getDescription() { + return description; + } + + public AttendanceLesson setDescription(String description) { + this.description = description; + return this; + } + + /** + * 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 = 1157101112) + public void __setDaoSession(DaoSession daoSession) { + this.daoSession = daoSession; + myDao = daoSession != null ? daoSession.getAttendanceLessonDao() : null; + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java index 99574e1db..fb3ce4143 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Day.java @@ -5,6 +5,7 @@ import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Index; +import org.greenrobot.greendao.annotation.OrderBy; import org.greenrobot.greendao.annotation.Property; import org.greenrobot.greendao.annotation.ToMany; @@ -13,7 +14,7 @@ import java.util.List; @Entity( nameInDb = "Days", active = true, - indexes ={@Index(value = "userId,weekId,date", unique = true)} + indexes = {@Index(value = "userId,weekId,date", unique = true)} ) public class Day { @@ -39,7 +40,11 @@ public class Day { private String freeDayName = ""; @ToMany(referencedJoinProperty = "dayId") - private List lessons; + private List timetableLessons; + + @ToMany(referencedJoinProperty = "dayId") + @OrderBy("number ASC") + private List attendanceLessons; /** * Used to resolve relations @@ -113,12 +118,12 @@ public class Day { return this; } - public boolean isFreeDay() { - return isFreeDay; + public boolean getIsFreeDay() { + return this.isFreeDay; } - public Day setFreeDay(boolean freeDay) { - isFreeDay = freeDay; + public Day setIsFreeDay(boolean isFreeDay) { + this.isFreeDay = isFreeDay; return this; } @@ -135,30 +140,58 @@ public class Day { * To-many relationship, resolved on first access (and after reset). * Changes to to-many relations are not persisted, make changes to the target entity. */ - @Generated(hash = 1552857303) - public List getLessons() { - if (lessons == null) { + @Generated(hash = 218588195) + public List getTimetableLessons() { + if (timetableLessons == null) { final DaoSession daoSession = this.daoSession; if (daoSession == null) { throw new DaoException("Entity is detached from DAO context"); } - LessonDao targetDao = daoSession.getLessonDao(); - List lessonsNew = targetDao._queryDay_Lessons(id); + TimetableLessonDao targetDao = daoSession.getTimetableLessonDao(); + List timetableLessonsNew = targetDao + ._queryDay_TimetableLessons(id); synchronized (this) { - if (lessons == null) { - lessons = lessonsNew; + if (timetableLessons == null) { + timetableLessons = timetableLessonsNew; } } } - return lessons; + return timetableLessons; + } + + /** Resets a to-many relationship, making the next get call to query for a fresh result. */ + @Generated(hash = 1687683740) + public synchronized void resetTimetableLessons() { + timetableLessons = null; } /** - * Resets a to-many relationship, making the next get call to query for a fresh result. + * 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 = 1769801440) - public synchronized void resetLessons() { - lessons = null; + @Generated(hash = 1166820581) + public List getAttendanceLessons() { + if (attendanceLessons == null) { + final DaoSession daoSession = this.daoSession; + if (daoSession == null) { + throw new DaoException("Entity is detached from DAO context"); + } + AttendanceLessonDao targetDao = daoSession.getAttendanceLessonDao(); + List attendanceLessonsNew = targetDao + ._queryDay_AttendanceLessons(id); + synchronized (this) { + if (attendanceLessons == null) { + attendanceLessons = attendanceLessonsNew; + } + } + } + return attendanceLessons; + } + + /** Resets a to-many relationship, making the next get call to query for a fresh result. */ + @Generated(hash = 1343075564) + public synchronized void resetAttendanceLessons() { + attendanceLessons = null; } /** @@ -197,14 +230,6 @@ public class Day { myDao.update(this); } - public boolean getIsFreeDay() { - return this.isFreeDay; - } - - public void setIsFreeDay(boolean isFreeDay) { - this.isFreeDay = isFreeDay; - } - /** called by internal mechanisms, do not call yourself. */ @Generated(hash = 1409317752) public void __setDaoSession(DaoSession daoSession) { diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Lesson.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/TimetableLesson.java similarity index 72% rename from app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Lesson.java rename to app/src/main/java/io/github/wulkanowy/data/db/dao/entities/TimetableLesson.java index db9be9445..390f679ef 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Lesson.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/TimetableLesson.java @@ -10,11 +10,11 @@ import org.greenrobot.greendao.annotation.Property; import java.io.Serializable; @Entity( - nameInDb = "Lessons", + nameInDb = "TimetableLessons", active = true, indexes = {@Index(value = "dayId,date,startTime,endTime", unique = true)} ) -public class Lesson implements Serializable { +public class TimetableLesson implements Serializable { @Id(autoincrement = true) private Long id; @@ -78,14 +78,15 @@ public class Lesson implements Serializable { /** * Used for active entity operations. */ - @Generated(hash = 610143130) - private transient LessonDao myDao; + @Generated(hash = 1119360138) + private transient TimetableLessonDao 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) { + @Generated(hash = 627457324) + public TimetableLesson(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; @@ -105,8 +106,8 @@ public class Lesson implements Serializable { this.isNewMovedInOrChanged = isNewMovedInOrChanged; } - @Generated(hash = 1669664117) - public Lesson() { + @Generated(hash = 1878030142) + public TimetableLesson() { } public Long getId() { @@ -126,186 +127,138 @@ public class Lesson implements Serializable { } public String getNumber() { - return number; + return this.number; } - public Lesson setNumber(String number) { + public TimetableLesson setNumber(String number) { this.number = number; return this; } public String getSubject() { - return subject; + return this.subject; } - public Lesson setSubject(String subject) { + public TimetableLesson setSubject(String subject) { this.subject = subject; return this; } public String getTeacher() { - return teacher; + return this.teacher; } - public Lesson setTeacher(String teacher) { + public TimetableLesson setTeacher(String teacher) { this.teacher = teacher; return this; } public String getRoom() { - return room; + return this.room; } - public Lesson setRoom(String room) { + public TimetableLesson setRoom(String room) { this.room = room; return this; } public String getDescription() { - return description; + return this.description; } - public Lesson setDescription(String description) { + public TimetableLesson setDescription(String description) { this.description = description; return this; } public String getGroupName() { - return groupName; + return this.groupName; } - public Lesson setGroupName(String groupName) { + public TimetableLesson setGroupName(String groupName) { this.groupName = groupName; return this; } public String getStartTime() { - return startTime; + return this.startTime; } - public Lesson setStartTime(String startTime) { + public TimetableLesson setStartTime(String startTime) { this.startTime = startTime; return this; } public String getEndTime() { - return endTime; + return this.endTime; } - public Lesson setEndTime(String endTime) { + public TimetableLesson setEndTime(String endTime) { this.endTime = endTime; return this; } public String getDate() { - return date; + return this.date; } - public Lesson setDate(String date) { + public TimetableLesson 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) { + public TimetableLesson setEmpty(boolean isEmpty) { this.isEmpty = isEmpty; + return this; } public boolean getIsDivisionIntoGroups() { return this.isDivisionIntoGroups; } - public void setIsDivisionIntoGroups(boolean isDivisionIntoGroups) { + public TimetableLesson setDivisionIntoGroups(boolean isDivisionIntoGroups) { this.isDivisionIntoGroups = isDivisionIntoGroups; + return this; } public boolean getIsPlanning() { return this.isPlanning; } - public void setIsPlanning(boolean isPlanning) { + public TimetableLesson setPlanning(boolean isPlanning) { this.isPlanning = isPlanning; + return this; } public boolean getIsRealized() { return this.isRealized; } - public void setIsRealized(boolean isRealized) { + public TimetableLesson setRealized(boolean isRealized) { this.isRealized = isRealized; + return this; } public boolean getIsMovedOrCanceled() { return this.isMovedOrCanceled; } - public void setIsMovedOrCanceled(boolean isMovedOrCanceled) { + public TimetableLesson setMovedOrCanceled(boolean isMovedOrCanceled) { this.isMovedOrCanceled = isMovedOrCanceled; + return this; } public boolean getIsNewMovedInOrChanged() { return this.isNewMovedInOrChanged; } - public void setIsNewMovedInOrChanged(boolean isNewMovedInOrChanged) { + public TimetableLesson setNewMovedInOrChanged(boolean isNewMovedInOrChanged) { this.isNewMovedInOrChanged = isNewMovedInOrChanged; + return this; } /** @@ -344,10 +297,34 @@ public class Lesson implements Serializable { myDao.update(this); } + public void setIsEmpty(boolean isEmpty) { + this.isEmpty = isEmpty; + } + + public void setIsDivisionIntoGroups(boolean isDivisionIntoGroups) { + this.isDivisionIntoGroups = isDivisionIntoGroups; + } + + public void setIsPlanning(boolean isPlanning) { + this.isPlanning = isPlanning; + } + + public void setIsRealized(boolean isRealized) { + this.isRealized = isRealized; + } + + public void setIsMovedOrCanceled(boolean isMovedOrCanceled) { + this.isMovedOrCanceled = isMovedOrCanceled; + } + + public void setIsNewMovedInOrChanged(boolean isNewMovedInOrChanged) { + this.isNewMovedInOrChanged = isNewMovedInOrChanged; + } + /** called by internal mechanisms, do not call yourself. */ - @Generated(hash = 2078826279) + @Generated(hash = 1885258429) public void __setDaoSession(DaoSession daoSession) { this.daoSession = daoSession; - myDao = daoSession != null ? daoSession.getLessonDao() : null; + myDao = daoSession != null ? daoSession.getTimetableLessonDao() : null; } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Week.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Week.java index c82f3277b..778f6ca3c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Week.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/entities/Week.java @@ -26,6 +26,12 @@ public class Week { @Property(nameInDb = "START_DATE") private String startDayDate = ""; + @Property(nameInDb = "IS_ATTENDANCE_SYNCED") + private boolean isAttendanceSynced = false; + + @Property(nameInDb = "IS_TIMETABLE_SYNCED") + private boolean isTimetableSynced = false; + @ToMany(referencedJoinProperty = "weekId") private List dayList; @@ -37,11 +43,14 @@ public class Week { @Generated(hash = 1019310398) private transient WeekDao myDao; - @Generated(hash = 36829814) - public Week(Long id, Long userId, String startDayDate) { + @Generated(hash = 1745118398) + public Week(Long id, Long userId, String startDayDate, boolean isAttendanceSynced, + boolean isTimetableSynced) { this.id = id; this.userId = userId; this.startDayDate = startDayDate; + this.isAttendanceSynced = isAttendanceSynced; + this.isTimetableSynced = isTimetableSynced; } @Generated(hash = 2135529658) @@ -75,6 +84,22 @@ public class Week { return this; } + public boolean getIsAttendanceSynced() { + return this.isAttendanceSynced; + } + + public void setIsAttendanceSynced(boolean isAttendanceSynced) { + this.isAttendanceSynced = isAttendanceSynced; + } + + public boolean getIsTimetableSynced() { + return this.isTimetableSynced; + } + + public void setIsTimetableSynced(boolean isTimetableSynced) { + this.isTimetableSynced = isTimetableSynced; + } + /** * To-many relationship, resolved on first access (and after reset). * Changes to to-many relations are not persisted, make changes to the target entity. diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/AppResources.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/AppResources.java index 8e7227d36..e9b854645 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/AppResources.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/AppResources.java @@ -13,6 +13,7 @@ import javax.inject.Singleton; import io.github.wulkanowy.R; import io.github.wulkanowy.api.login.NotLoggedInErrorException; import io.github.wulkanowy.api.login.VulcanOfflineException; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; import io.github.wulkanowy.di.annotations.ApplicationContext; import io.github.wulkanowy.utils.AppConstant; import io.github.wulkanowy.utils.LogUtils; @@ -56,4 +57,35 @@ public class AppResources implements ResourcesContract { return exception.getMessage(); } } + + @Override + public String getAttendanceLessonDescription(AttendanceLesson lesson) { + int id = R.string.attendance_present; + + if (lesson.getIsAbsenceForSchoolReasons()) { + id = R.string.attendance_absence_for_school_reasons; + } + + if (lesson.getIsAbsenceExcused()) { + id = R.string.attendance_absence_excused; + } + + if (lesson.getIsAbsenceUnexcused()) { + id = R.string.attendance_absence_unexcused; + } + + if (lesson.getIsExemption()) { + id = R.string.attendance_exemption; + } + + if (lesson.getIsExcusedLateness()) { + id = R.string.attendance_excused_lateness; + } + + if (lesson.getIsUnexcusedLateness()) { + id = R.string.attendance_unexcused_lateness; + } + + return resources.getString(id); + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesContract.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesContract.java index 3768ad2c6..0ef45a76d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesContract.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.data.db.resources; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; + public interface ResourcesContract { String[] getSymbolsKeysArray(); @@ -7,4 +9,6 @@ public interface ResourcesContract { String[] getSymbolsValuesArray(); String getErrorLoginMessage(Exception e); + + String getAttendanceLessonDescription(AttendanceLesson lesson); } diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/attendance/AttendanceSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/attendance/AttendanceSync.java new file mode 100644 index 000000000..19de88efa --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/sync/attendance/AttendanceSync.java @@ -0,0 +1,156 @@ +package io.github.wulkanowy.data.sync.attendance; + +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.api.generic.Lesson; +import io.github.wulkanowy.api.login.NotLoggedInErrorException; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLessonDao; +import io.github.wulkanowy.data.db.dao.entities.DaoSession; +import io.github.wulkanowy.data.db.dao.entities.Day; +import io.github.wulkanowy.data.db.dao.entities.DayDao; +import io.github.wulkanowy.data.db.dao.entities.Week; +import io.github.wulkanowy.data.db.dao.entities.WeekDao; +import io.github.wulkanowy.data.db.shared.SharedPrefContract; +import io.github.wulkanowy.utils.DataObjectConverter; +import io.github.wulkanowy.utils.LogUtils; +import io.github.wulkanowy.utils.TimeUtils; + +@Singleton +public class AttendanceSync implements AttendanceSyncContract { + + private final DaoSession daoSession; + + private final SharedPrefContract sharedPref; + + private final Vulcan vulcan; + + private long userId; + + @Inject + AttendanceSync(DaoSession daoSession, SharedPrefContract sharedPref, Vulcan vulcan) { + this.daoSession = daoSession; + this.sharedPref = sharedPref; + this.vulcan = vulcan; + } + + @Override + public void syncAttendance() throws IOException, NotLoggedInErrorException, ParseException { + syncAttendance(null); + } + + @Override + public void syncAttendance(String date) throws IOException, NotLoggedInErrorException, ParseException { + this.userId = sharedPref.getCurrentUserId(); + + io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(getNormalizedDate(date)); + Week weekDb = getWeekFromDb(weekApi.getStartDayDate()); + + long weekId = updateWeekInDb(weekDb, weekApi); + + List lessonList = updateDays(weekApi.getDays(), weekId); + + daoSession.getAttendanceLessonDao().saveInTx(lessonList); + + LogUtils.debug("Synchronization lessons (amount = " + lessonList.size() + ")"); + } + + private String getNormalizedDate(String date) throws ParseException { + return null != date ? String.valueOf(TimeUtils.getNetTicks(date)) : ""; + } + + private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) + throws IOException, NotLoggedInErrorException, ParseException { + return vulcan.getAttendanceTable().getWeekTable(date); + } + + private Week getWeekFromDb(String date) { + return daoSession.getWeekDao() + .queryBuilder() + .where(WeekDao.Properties.UserId.eq(userId), WeekDao.Properties.StartDayDate.eq(date)) + .unique(); + } + + private Long updateWeekInDb(Week dbWeekEntity, io.github.wulkanowy.api.generic.Week fromApi) { + if (dbWeekEntity != null) { + dbWeekEntity.setIsAttendanceSynced(true); + dbWeekEntity.update(); + + return dbWeekEntity.getId(); + } + + Week apiWeekEntity = DataObjectConverter.weekToWeekEntity(fromApi).setUserId(userId); + apiWeekEntity.setIsAttendanceSynced(true); + + return daoSession.getWeekDao().insert(apiWeekEntity); + } + + private List updateDays(List dayListFromApi, long weekId) { + List updatedLessonList = new ArrayList<>(); + + for (io.github.wulkanowy.api.generic.Day dayFromApi : dayListFromApi) { + + Day dbDayEntity = getDayFromDb(dayFromApi.getDate()); + + Day apiDayEntity = DataObjectConverter.dayToDayEntity(dayFromApi); + + long dayId = updateDay(dbDayEntity, apiDayEntity, weekId); + + updateLessons(dayFromApi.getLessons(), updatedLessonList, dayId); + } + + return updatedLessonList; + } + + private Day getDayFromDb(String date) { + return daoSession.getDayDao() + .queryBuilder() + .where(DayDao.Properties.UserId.eq(userId), DayDao.Properties.Date.eq(date)) + .unique(); + } + + private long updateDay(Day dbDayEntity, Day apiDayEntity, long weekId) { + if (null != dbDayEntity) { + return dbDayEntity.getId(); + } + + apiDayEntity.setUserId(userId); + apiDayEntity.setWeekId(weekId); + + return daoSession.getDayDao().insert(apiDayEntity); + } + + private void updateLessons(List lessons, List updatedLessons, long dayId) { + List lessonsFromApiEntities = DataObjectConverter + .lessonsToAttendanceLessonsEntities(lessons); + + for (AttendanceLesson apiLessonEntity : lessonsFromApiEntities) { + AttendanceLesson lessonFromDb = getLessonFromDb(apiLessonEntity, dayId); + + apiLessonEntity.setDayId(dayId); + + if (lessonFromDb != null) { + apiLessonEntity.setId(lessonFromDb.getId()); + } + + if (!"".equals(apiLessonEntity.getSubject())) { + updatedLessons.add(apiLessonEntity); + } + } + } + + private AttendanceLesson getLessonFromDb(AttendanceLesson apiEntity, long dayId) { + return daoSession.getAttendanceLessonDao().queryBuilder() + .where(AttendanceLessonDao.Properties.DayId.eq(dayId), + AttendanceLessonDao.Properties.Date.eq(apiEntity.getDate()), + AttendanceLessonDao.Properties.Number.eq(apiEntity.getNumber())) + .unique(); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/attendance/AttendanceSyncContract.java b/app/src/main/java/io/github/wulkanowy/data/sync/attendance/AttendanceSyncContract.java new file mode 100644 index 000000000..503086bab --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/sync/attendance/AttendanceSyncContract.java @@ -0,0 +1,13 @@ +package io.github.wulkanowy.data.sync.attendance; + +import java.io.IOException; +import java.text.ParseException; + +import io.github.wulkanowy.api.login.NotLoggedInErrorException; + +public interface AttendanceSyncContract { + + void syncAttendance(String date) throws NotLoggedInErrorException, IOException, ParseException; + + void syncAttendance() throws NotLoggedInErrorException, IOException, ParseException; +} diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/timetable/TimetableSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/timetable/TimetableSync.java index dcb048f1a..11819bed3 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/timetable/TimetableSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/timetable/TimetableSync.java @@ -9,12 +9,13 @@ import javax.inject.Inject; import javax.inject.Singleton; import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.api.generic.Lesson; import io.github.wulkanowy.api.login.NotLoggedInErrorException; import io.github.wulkanowy.data.db.dao.entities.DaoSession; import io.github.wulkanowy.data.db.dao.entities.Day; import io.github.wulkanowy.data.db.dao.entities.DayDao; -import io.github.wulkanowy.data.db.dao.entities.Lesson; -import io.github.wulkanowy.data.db.dao.entities.LessonDao; +import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; +import io.github.wulkanowy.data.db.dao.entities.TimetableLessonDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.data.db.shared.SharedPrefContract; @@ -27,9 +28,11 @@ public class TimetableSync implements TimetableSyncContract { private final DaoSession daoSession; + private final SharedPrefContract sharedPref; + private final Vulcan vulcan; - private final SharedPrefContract sharedPref; + private long userId; @Inject TimetableSync(DaoSession daoSession, SharedPrefContract sharedPref, Vulcan vulcan) { @@ -38,83 +41,122 @@ public class TimetableSync implements TimetableSyncContract { this.vulcan = vulcan; } - @Override - public void syncTimetable(String date) throws NotLoggedInErrorException, IOException, ParseException { - long userId = sharedPref.getCurrentUserId(); - - io.github.wulkanowy.api.generic.Week weekFromNet = - date == null ? vulcan.getTimetable().getWeekTable() - : vulcan.getTimetable().getWeekTable(String.valueOf(TimeUtils.getNetTicks(date))); - - Week weekFromDb = daoSession.getWeekDao().queryBuilder() - .where(WeekDao.Properties.UserId.eq(userId), - WeekDao.Properties.StartDayDate.eq(weekFromNet.getStartDayDate())) - .unique(); - - Long weekId; - - if (weekFromDb == null) { - Week weekFromNetEntity = DataObjectConverter.weekToWeekEntity(weekFromNet).setUserId(userId); - weekId = daoSession.getWeekDao().insert(weekFromNetEntity); - } else { - weekId = weekFromDb.getId(); - } - - List dayListFromNet = weekFromNet.getDays(); - - List updatedLessonList = new ArrayList<>(); - - for (io.github.wulkanowy.api.generic.Day dayFromNet : dayListFromNet) { - Day dayFromNetEntity = DataObjectConverter.dayToDayEntity(dayFromNet); - - Day dayFromDb = daoSession.getDayDao().queryBuilder() - .where(DayDao.Properties.UserId.eq(userId), - DayDao.Properties.WeekId.eq(weekId), - DayDao.Properties.Date.eq(dayFromNetEntity.getDate())) - .unique(); - - dayFromNetEntity.setUserId(userId); - dayFromNetEntity.setWeekId(weekId); - - Long dayId; - - if (dayFromDb != null) { - dayFromNetEntity.setId(dayFromDb.getId()); - daoSession.getDayDao().save(dayFromNetEntity); - dayId = dayFromNetEntity.getId(); - } else { - dayId = daoSession.getDayDao().insert(dayFromNetEntity); - } - - List lessonListFromNetEntities = DataObjectConverter - .lessonsToLessonsEntities(dayFromNet.getLessons()); - - for (Lesson lessonFromNetEntity : lessonListFromNetEntities) { - Lesson lessonFromDb = daoSession.getLessonDao().queryBuilder() - .where(LessonDao.Properties.DayId.eq(dayId), - LessonDao.Properties.Date.eq(lessonFromNetEntity.getDate()), - LessonDao.Properties.StartTime.eq(lessonFromNetEntity.getStartTime()), - LessonDao.Properties.EndTime.eq(lessonFromNetEntity.getEndTime())) - .unique(); - - if (lessonFromDb != null) { - lessonFromNetEntity.setId(lessonFromDb.getId()); - } - - lessonFromNetEntity.setDayId(dayFromNetEntity.getId()); - - if (!"".equals(lessonFromNetEntity.getSubject())) { - updatedLessonList.add(lessonFromNetEntity); - } - } - } - daoSession.getLessonDao().saveInTx(updatedLessonList); - - LogUtils.debug("Synchronization lessons (amount = " + updatedLessonList.size() + ")"); - } - @Override public void syncTimetable() throws NotLoggedInErrorException, IOException, ParseException { syncTimetable(null); } + + @Override + public void syncTimetable(String date) throws NotLoggedInErrorException, IOException, ParseException { + this.userId = sharedPref.getCurrentUserId(); + + io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(getNormalizedDate(date)); + Week weekDb = getWeekFromDb(weekApi.getStartDayDate()); + + long weekId = updateWeekInDb(weekDb, weekApi); + + List lessonList = updateDays(weekApi.getDays(), weekId); + + daoSession.getTimetableLessonDao().saveInTx(lessonList); + + LogUtils.debug("Synchronization lessons (amount = " + lessonList.size() + ")"); + } + + private String getNormalizedDate(String date) throws ParseException { + return null != date ? String.valueOf(TimeUtils.getNetTicks(date)) : ""; + } + + private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) + throws IOException, NotLoggedInErrorException, ParseException { + return vulcan.getTimetable().getWeekTable(date); + } + + private Week getWeekFromDb(String date) { + return daoSession.getWeekDao() + .queryBuilder() + .where(WeekDao.Properties.UserId.eq(userId), WeekDao.Properties.StartDayDate.eq(date)) + .unique(); + } + + private Long updateWeekInDb(Week dbEntity, io.github.wulkanowy.api.generic.Week fromApi) { + if (dbEntity != null) { + dbEntity.setIsTimetableSynced(true); + dbEntity.update(); + + return dbEntity.getId(); + } + + Week apiEntity = DataObjectConverter.weekToWeekEntity(fromApi).setUserId(userId); + apiEntity.setIsTimetableSynced(true); + + return daoSession.getWeekDao().insert(apiEntity); + } + + private List updateDays(List dayListFromApi, long weekId) { + List updatedLessonList = new ArrayList<>(); + + for (io.github.wulkanowy.api.generic.Day dayFromApi : dayListFromApi) { + + Day dbDayEntity = getDayFromDb(dayFromApi.getDate()); + + Day apiDayEntity = DataObjectConverter.dayToDayEntity(dayFromApi); + + long dayId = updateDay(dbDayEntity, apiDayEntity, weekId); + + updateLessons(dayFromApi.getLessons(), updatedLessonList, dayId); + } + + return updatedLessonList; + } + + private Day getDayFromDb(String date) { + return daoSession.getDayDao() + .queryBuilder() + .where(DayDao.Properties.UserId.eq(userId), DayDao.Properties.Date.eq(date)) + .unique(); + } + + private long updateDay(Day dayFromDb, Day apiDayEntity, long weekId) { + apiDayEntity.setUserId(userId); + apiDayEntity.setWeekId(weekId); + + if (null != dayFromDb) { + apiDayEntity.setId(dayFromDb.getId()); + + daoSession.getDayDao().save(apiDayEntity); + dayFromDb.refresh(); + + return dayFromDb.getId(); + } + + return daoSession.getDayDao().insert(apiDayEntity); + } + + private void updateLessons(List lessons, List updatedLessons, long dayId) { + List lessonsFromApiEntities = DataObjectConverter + .lessonsToTimetableLessonsEntities(lessons); + + for (TimetableLesson apiLessonEntity : lessonsFromApiEntities) { + TimetableLesson lessonFromDb = getLessonFromDb(apiLessonEntity, dayId); + + apiLessonEntity.setDayId(dayId); + + if (lessonFromDb != null) { + apiLessonEntity.setId(lessonFromDb.getId()); + } + + if (!"".equals(apiLessonEntity.getSubject())) { + updatedLessons.add(apiLessonEntity); + } + } + } + + private TimetableLesson getLessonFromDb(TimetableLesson apiEntity, long dayId) { + return daoSession.getTimetableLessonDao().queryBuilder() + .where(TimetableLessonDao.Properties.DayId.eq(dayId), + TimetableLessonDao.Properties.Date.eq(apiEntity.getDate()), + TimetableLessonDao.Properties.StartTime.eq(apiEntity.getStartTime()), + TimetableLessonDao.Properties.EndTime.eq(apiEntity.getEndTime())) + .unique(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java b/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java index 01a0fc02f..b26abaaf3 100644 --- a/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java +++ b/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java @@ -4,6 +4,7 @@ import dagger.Component; import io.github.wulkanowy.di.annotations.PerFragment; import io.github.wulkanowy.di.modules.FragmentModule; import io.github.wulkanowy.ui.main.attendance.AttendanceFragment; +import io.github.wulkanowy.ui.main.attendance.AttendanceTabFragment; import io.github.wulkanowy.ui.main.dashboard.DashboardFragment; import io.github.wulkanowy.ui.main.grades.GradesFragment; import io.github.wulkanowy.ui.main.timetable.TimetableFragment; @@ -17,6 +18,8 @@ public interface FragmentComponent { void inject(AttendanceFragment attendanceFragment); + void inject(AttendanceTabFragment attendanceTabFragment); + void inject(DashboardFragment dashboardFragment); void inject(TimetableFragment timetableFragment); diff --git a/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java b/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java index 58e9909b4..46744c906 100644 --- a/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java +++ b/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java @@ -21,6 +21,8 @@ import io.github.wulkanowy.data.db.resources.ResourcesContract; import io.github.wulkanowy.data.db.shared.SharedPref; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.data.sync.SyncContract; +import io.github.wulkanowy.data.sync.attendance.AttendanceSync; +import io.github.wulkanowy.data.sync.attendance.AttendanceSyncContract; import io.github.wulkanowy.data.sync.grades.GradeSync; import io.github.wulkanowy.data.sync.login.LoginSync; import io.github.wulkanowy.data.sync.login.LoginSyncContract; @@ -122,6 +124,12 @@ public class ApplicationModule { return timetableSync; } + @Singleton + @Provides + AttendanceSyncContract provideAttendanceSync(AttendanceSync attendanceSync) { + return attendanceSync; + } + @Provides FirebaseJobDispatcher provideDispatcher() { return new FirebaseJobDispatcher(new GooglePlayDriver(application)); diff --git a/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java b/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java index 8999bca86..3479a8c4e 100644 --- a/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java +++ b/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java @@ -7,7 +7,11 @@ import dagger.Provides; import eu.davidea.flexibleadapter.FlexibleAdapter; import io.github.wulkanowy.di.annotations.PerFragment; import io.github.wulkanowy.ui.main.attendance.AttendanceContract; +import io.github.wulkanowy.ui.main.attendance.AttendanceHeaderItem; +import io.github.wulkanowy.ui.main.attendance.AttendancePagerAdapter; import io.github.wulkanowy.ui.main.attendance.AttendancePresenter; +import io.github.wulkanowy.ui.main.attendance.AttendanceTabContract; +import io.github.wulkanowy.ui.main.attendance.AttendanceTabPresenter; import io.github.wulkanowy.ui.main.dashboard.DashboardContract; import io.github.wulkanowy.ui.main.dashboard.DashboardPresenter; import io.github.wulkanowy.ui.main.grades.GradeHeaderItem; @@ -47,6 +51,22 @@ public class FragmentModule { return dashboardPresenter; } + @PerFragment + @Provides + AttendanceTabContract.Presenter provideAttendanceTabPresenter(AttendanceTabPresenter timetableTabPresenter) { + return timetableTabPresenter; + } + + @Provides + AttendancePagerAdapter provideAttendancePagerAdapter() { + return new AttendancePagerAdapter(fragment.getChildFragmentManager()); + } + + @Provides + FlexibleAdapter provideAttendanceTabAdapter() { + return new FlexibleAdapter<>(null); + } + @PerFragment @Provides TimetableContract.Presenter provideTimetablePresenter(TimetablePresenter timetablePresenter) { @@ -65,12 +85,12 @@ public class FragmentModule { } @Provides - FlexibleAdapter provideGradesAdapter() { + FlexibleAdapter provideTimetableTabAdapter() { return new FlexibleAdapter<>(null); } @Provides - FlexibleAdapter provideTimetableTabAdapter() { + FlexibleAdapter provideGradesAdapter() { return new FlexibleAdapter<>(null); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java index d4c0b9dab..cc9b1dc8a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java @@ -18,6 +18,7 @@ import butterknife.ButterKnife; import io.github.wulkanowy.R; import io.github.wulkanowy.services.SyncJob; import io.github.wulkanowy.ui.base.BaseActivity; +import io.github.wulkanowy.ui.main.attendance.AttendanceFragment; import io.github.wulkanowy.ui.main.dashboard.DashboardFragment; import io.github.wulkanowy.ui.main.grades.GradesFragment; import io.github.wulkanowy.ui.main.timetable.TimetableFragment; @@ -134,7 +135,7 @@ public class MainActivity extends BaseActivity implements MainContract.View, private void initiationViewPager() { pagerAdapter.addFragment(new GradesFragment()); - pagerAdapter.addFragment(new DashboardFragment()); + pagerAdapter.addFragment(new AttendanceFragment()); pagerAdapter.addFragment(new DashboardFragment()); pagerAdapter.addFragment(new TimetableFragment()); pagerAdapter.addFragment(new DashboardFragment()); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TabsData.java b/app/src/main/java/io/github/wulkanowy/ui/main/TabsData.java similarity index 64% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TabsData.java rename to app/src/main/java/io/github/wulkanowy/ui/main/TabsData.java index 156d1759b..3af29534b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TabsData.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/TabsData.java @@ -1,35 +1,35 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main; import android.support.v4.app.Fragment; import java.util.ArrayList; import java.util.List; -class TabsData { +public class TabsData { private List fragments = new ArrayList<>(); private List titles = new ArrayList<>(); - Fragment getFragment(int index) { + public Fragment getFragment(int index) { return fragments.get(index); } - void addFragment(Fragment fragment) { + public void addFragment(Fragment fragment) { if (fragment != null) { fragments.add(fragment); } } - int getFragmentsCount() { + public int getFragmentsCount() { return fragments.size(); } - String getTitle(int index) { + public String getTitle(int index) { return titles.get(index); } - void addTitle(String title) { + public void addTitle(String title) { if (title != null) { titles.add(title); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java index fe4037171..f8d3b3025 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java @@ -1,8 +1,9 @@ package io.github.wulkanowy.ui.main.attendance; -import io.github.wulkanowy.di.annotations.PerFragment; +import io.github.wulkanowy.di.annotations.PerActivity; import io.github.wulkanowy.ui.base.BaseContract; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.TabsData; public interface AttendanceContract { @@ -10,14 +11,26 @@ public interface AttendanceContract { void setActivityTitle(); + void scrollViewPagerToPosition(int position); + + void setTabDataToAdapter(TabsData tabsData); + + void setAdapterWithTabLayout(); + + void setChildFragmentSelected(int position, boolean selected); + boolean isMenuVisible(); } - @PerFragment + @PerActivity interface Presenter extends BaseContract.Presenter { - void onStart(View view, OnFragmentIsReadyListener listener); - void onFragmentVisible(boolean isVisible); + + void onTabSelected(int position); + + void onTabUnselected(int position); + + void onStart(View view, OnFragmentIsReadyListener listener); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceDialogFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceDialogFragment.java new file mode 100644 index 000000000..f5bbcb414 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceDialogFragment.java @@ -0,0 +1,91 @@ +package io.github.wulkanowy.ui.main.attendance; + +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.TextView; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import io.github.wulkanowy.R; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; + +public class AttendanceDialogFragment extends DialogFragment { + + private static final String ARGUMENT_KEY = "Item"; + + private AttendanceLesson lesson; + + @BindView(R.id.attendance_dialog_subject_value) + TextView subject; + + @BindView(R.id.attendance_dialog_date_value) + TextView date; + + @BindView(R.id.attendance_dialog_number_value) + TextView number; + + @BindView(R.id.attendance_dialog_description_value) + TextView description; + + public AttendanceDialogFragment() { + //empty constructor for fragment + } + + public static AttendanceDialogFragment newInstance(AttendanceLesson lesson) { + AttendanceDialogFragment dialogFragment = new AttendanceDialogFragment(); + + Bundle bundle = new Bundle(); + bundle.putSerializable(ARGUMENT_KEY, lesson); + + dialogFragment.setArguments(bundle); + + return dialogFragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + lesson = (AttendanceLesson) getArguments().getSerializable(ARGUMENT_KEY); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.attendance_dialog, container, false); + + ButterKnife.bind(this, view); + + if (!lesson.getSubject().isEmpty()) { + subject.setText(lesson.getSubject()); + } + + if (!lesson.getDate().isEmpty()) { + date.setText(lesson.getDate()); + } + + if (0 != lesson.getNumber()) { + number.setText(String.valueOf(lesson.getNumber())); + } + + description.setText(lesson.getDescription()); + + if (lesson.getIsAbsenceUnexcused()) { + description.setTextColor(getResources().getColor(R.color.colorPrimaryDark)); + } + + return view; + } + + @OnClick(R.id.attendance_dialog_close) + void onClickCloseButton() { + dismiss(); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java index 6010d1085..82bb2520b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java @@ -2,30 +2,42 @@ package io.github.wulkanowy.ui.main.attendance; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; +import android.support.design.widget.TabLayout; +import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import javax.inject.Inject; +import butterknife.BindView; import butterknife.ButterKnife; import io.github.wulkanowy.R; import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.TabsData; -public class AttendanceFragment extends BaseFragment implements AttendanceContract.View { +public class AttendanceFragment extends BaseFragment implements AttendanceContract.View, TabLayout.OnTabSelectedListener { + + @BindView(R.id.attendance_fragment_viewpager) + ViewPager viewPager; + + @BindView(R.id.attendance_fragment_tab_layout) + TabLayout tabLayout; + + @Inject + AttendancePagerAdapter pagerAdapter; @Inject AttendanceContract.Presenter presenter; - public AttendanceFragment() { - // empty constructor for fragment - } - + @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_attendance, container, false); FragmentComponent component = getFragmentComponent(); @@ -46,14 +58,60 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra } } + @Override + public void onTabSelected(TabLayout.Tab tab) { + presenter.onTabSelected(tab.getPosition()); + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + presenter.onTabUnselected(tab.getPosition()); + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + //do nothing + } + + @Override + public void setTabDataToAdapter(TabsData tabsData) { + pagerAdapter.setTabsData(tabsData); + } + + @Override + public void setAdapterWithTabLayout() { + viewPager.setAdapter(pagerAdapter); + + tabLayout.setupWithViewPager(viewPager); + tabLayout.addOnTabSelectedListener(this); + } + + @Override + public void setChildFragmentSelected(int position, boolean selected) { + ((AttendanceTabFragment) pagerAdapter.getItem(position)).setSelected(selected); + } + + @Override + public void scrollViewPagerToPosition(int position) { + viewPager.setCurrentItem(position, false); + } + @Override public void setActivityTitle() { - setTitle(getString(R.string.dashboard_text)); + setTitle(getString(R.string.attendance_text)); + } + + @Override + public void onError(String message) { + if (getActivity() != null) { + Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), + message, Snackbar.LENGTH_LONG).show(); + } } @Override public void onDestroyView() { - super.onDestroyView(); presenter.onDestroy(); + super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java new file mode 100644 index 000000000..0270f7c1b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java @@ -0,0 +1,136 @@ +package io.github.wulkanowy.ui.main.attendance; + +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.List; + +import butterknife.BindColor; +import butterknife.BindView; +import butterknife.ButterKnife; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem; +import eu.davidea.viewholders.ExpandableViewHolder; +import io.github.wulkanowy.R; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; +import io.github.wulkanowy.data.db.dao.entities.Day; + +public class AttendanceHeaderItem + extends AbstractExpandableHeaderItem { + + private Day day; + + AttendanceHeaderItem(Day day) { + this.day = day; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + AttendanceHeaderItem that = (AttendanceHeaderItem) o; + + return new EqualsBuilder() + .append(day, that.day) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(day) + .toHashCode(); + } + + @Override + public int getLayoutRes() { + return R.layout.attendance_header; + } + + @Override + public HeaderViewHolder createViewHolder(View view, FlexibleAdapter adapter) { + return new HeaderViewHolder(view, adapter); + } + + @Override + public void bindViewHolder(FlexibleAdapter adapter, HeaderViewHolder holder, int position, List payloads) { + holder.onBind(day, getSubItems()); + } + + static class HeaderViewHolder extends ExpandableViewHolder { + + @BindView(R.id.attendance_header_day) + TextView dayName; + + @BindView(R.id.attendance_header_date) + TextView date; + + @BindView(R.id.attendance_header_description) + TextView description; + + @BindView(R.id.attendance_header_alert_image) + ImageView alert; + + @BindView(R.id.attendance_header_free_name) + TextView freeName; + + @BindColor(R.color.secondary_text) + int secondaryColor; + + @BindColor(R.color.free_day) + int backgroundFreeDay; + + HeaderViewHolder(View view, FlexibleAdapter adapter) { + super(view, adapter); + view.setOnClickListener(this); + ButterKnife.bind(this, view); + } + + void onBind(Day item, List subItems) { + dayName.setText(StringUtils.capitalize(item.getDayName())); + date.setText(item.getDate()); + + int numberOfHours = countNotPresentHours(subItems); + description.setText((getContentView().getResources().getQuantityString(R.plurals.numberOfAbsences, + numberOfHours, numberOfHours))); + description.setVisibility(numberOfHours > 0 ? View.VISIBLE : View.INVISIBLE); + alert.setVisibility(isSubItemsHasChanges(subItems) ? View.VISIBLE : View.INVISIBLE); + freeName.setVisibility(subItems.isEmpty() ? View.VISIBLE : View.INVISIBLE); + + if (item.getAttendanceLessons().isEmpty()) { + ((FrameLayout) getContentView()).setForeground(null); + getContentView().setBackgroundColor(backgroundFreeDay); + dayName.setTextColor(secondaryColor); + } + } + + private int countNotPresentHours(List subItems) { + int i = 0; + for (AttendanceSubItem subItem : subItems) { + if (subItem.getLesson().getIsAbsenceUnexcused()) { + i++; + } + } + + return i; + } + + private boolean isSubItemsHasChanges(List subItems) { + for (AttendanceSubItem subItem : subItems) { + if (subItem.getLesson().getIsAbsenceUnexcused() || subItem.getLesson().getIsUnexcusedLateness()) { + return true; + } + } + + return false; + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePagerAdapter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePagerAdapter.java new file mode 100644 index 000000000..3cabff71d --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePagerAdapter.java @@ -0,0 +1,38 @@ +package io.github.wulkanowy.ui.main.attendance; + +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; + +import io.github.wulkanowy.ui.main.TabsData; + +public class AttendancePagerAdapter extends FragmentStatePagerAdapter { + + private TabsData tabsData; + + public AttendancePagerAdapter(FragmentManager fragmentManager) { + super(fragmentManager); + } + + void setTabsData(TabsData tabsData) { + this.tabsData = tabsData; + } + + @Override + public Fragment getItem(int position) { + return tabsData.getFragment(position); + } + + + @Override + public int getCount() { + return tabsData.getFragmentsCount(); + } + + @Nullable + @Override + public CharSequence getPageTitle(int position) { + return tabsData.getTitle(position); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java index da43e320f..73dd44ca7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java @@ -1,16 +1,33 @@ package io.github.wulkanowy.ui.main.attendance; +import java.util.ArrayList; +import java.util.List; + import javax.inject.Inject; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.ui.base.BasePresenter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.TabsData; +import io.github.wulkanowy.utils.TimeUtils; +import io.github.wulkanowy.utils.async.AbstractTask; +import io.github.wulkanowy.utils.async.AsyncListeners; public class AttendancePresenter extends BasePresenter - implements AttendanceContract.Presenter { + implements AttendanceContract.Presenter, AsyncListeners.OnFirstLoadingListener { + + private AbstractTask loadingTask; + + private List dates = new ArrayList<>(); + + private TabsData tabsData = new TabsData(); private OnFragmentIsReadyListener listener; + private int positionToScroll; + + private boolean isFirstSight = false; + @Inject AttendancePresenter(RepositoryContract repository) { super(repository); @@ -25,7 +42,18 @@ public class AttendancePresenter extends BasePresenter getView().setActivityTitle(); } - this.listener.onFragmentIsReady(); + if (dates.isEmpty()) { + dates = TimeUtils.getMondaysFromCurrentSchoolYear(); + } + positionToScroll = dates.indexOf(TimeUtils.getDateOfCurrentMonday(true)); + + if (!isFirstSight) { + isFirstSight = true; + + loadingTask = new AbstractTask(); + loadingTask.setOnFirstLoadingListener(this); + loadingTask.execute(); + } } @Override @@ -34,4 +62,50 @@ public class AttendancePresenter extends BasePresenter getView().setActivityTitle(); } } + + @Override + public void onTabSelected(int position) { + getView().setChildFragmentSelected(position, true); + } + + @Override + public void onTabUnselected(int position) { + getView().setChildFragmentSelected(position, false); + } + + @Override + public void onDoInBackgroundLoading() throws Exception { + for (String date : dates) { + tabsData.addTitle(date); + tabsData.addFragment(AttendanceTabFragment.newInstance(date)); + } + } + + @Override + public void onCanceledLoadingAsync() { + //do nothing + + } + + @Override + public void onEndLoadingAsync(boolean result, Exception exception) { + if (result) { + getView().setTabDataToAdapter(tabsData); + getView().setAdapterWithTabLayout(); + getView().scrollViewPagerToPosition(positionToScroll); + listener.onFragmentIsReady(); + } + } + + @Override + public void onDestroy() { + isFirstSight = false; + + if (loadingTask != null) { + loadingTask.cancel(true); + loadingTask = null; + } + + super.onDestroy(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java new file mode 100644 index 000000000..6da35555a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java @@ -0,0 +1,119 @@ +package io.github.wulkanowy.ui.main.attendance; + +import android.content.Context; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.items.AbstractSectionableItem; +import eu.davidea.viewholders.FlexibleViewHolder; +import io.github.wulkanowy.R; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; + +class AttendanceSubItem + extends AbstractSectionableItem { + + private AttendanceLesson lesson; + + AttendanceSubItem(AttendanceHeaderItem header, AttendanceLesson lesson) { + super(header); + this.lesson = lesson; + } + + AttendanceLesson getLesson() { + return lesson; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + AttendanceSubItem that = (AttendanceSubItem) o; + + return new EqualsBuilder() + .append(lesson, that.lesson) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(lesson) + .toHashCode(); + } + + @Override + public int getLayoutRes() { + return R.layout.attendance_subitem; + } + + @Override + public AttendanceSubItem.SubItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) { + return new AttendanceSubItem.SubItemViewHolder(view, adapter); + } + + @Override + public void bindViewHolder(FlexibleAdapter adapter, AttendanceSubItem.SubItemViewHolder holder, int position, List payloads) { + holder.onBind(lesson); + } + + static class SubItemViewHolder extends FlexibleViewHolder { + + @BindView(R.id.attendance_subItem_lesson) + TextView lessonName; + + @BindView(R.id.attendance_subItem_number) + TextView lessonNumber; + + @BindView(R.id.attendance_subItem_description) + TextView lessonDescription; + + @BindView(R.id.attendance_subItem_alert_image) + ImageView alert; + + private Context context; + + private AttendanceLesson item; + + SubItemViewHolder(View view, FlexibleAdapter adapter) { + super(view, adapter); + ButterKnife.bind(this, view); + context = view.getContext(); + view.setOnClickListener(this); + } + + void onBind(AttendanceLesson lesson) { + item = lesson; + + lessonName.setText(lesson.getSubject()); + lessonNumber.setText((String.valueOf(lesson.getNumber()))); + lessonDescription.setText(lesson.getDescription()); + alert.setVisibility(lesson.getIsAbsenceUnexcused() || lesson.getIsUnexcusedLateness() + ? View.VISIBLE : View.INVISIBLE); + } + + @Override + public void onClick(View view) { + super.onClick(view); + showDialog(); + } + + private void showDialog() { + AttendanceDialogFragment dialogFragment = AttendanceDialogFragment.newInstance(item); + dialogFragment.setStyle(DialogFragment.STYLE_NO_TITLE, 0); + dialogFragment.show(((FragmentActivity) context).getSupportFragmentManager(), item.toString()); + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java new file mode 100644 index 000000000..1bac005d6 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java @@ -0,0 +1,32 @@ +package io.github.wulkanowy.ui.main.attendance; + +import java.util.List; + +import io.github.wulkanowy.ui.base.BaseContract; + +public interface AttendanceTabContract { + + interface View extends BaseContract.View { + + void updateAdapterList(List headerItems); + + void onRefreshSuccess(); + + void hideRefreshingBar(); + + void showNoItem(boolean show); + + void showProgressBar(boolean show); + } + + interface Presenter extends BaseContract.Presenter { + + void onFragmentSelected(boolean isSelected); + + void setArgumentDate(String date); + + void onStart(AttendanceTabContract.View view, boolean isPrimary); + + void onRefresh(); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java new file mode 100644 index 000000000..90313daa6 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java @@ -0,0 +1,170 @@ +package io.github.wulkanowy.ui.main.attendance; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.List; + +import javax.inject.Inject; + +import butterknife.BindView; +import butterknife.ButterKnife; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; +import io.github.wulkanowy.R; +import io.github.wulkanowy.di.component.FragmentComponent; +import io.github.wulkanowy.ui.base.BaseFragment; + +public class AttendanceTabFragment extends BaseFragment implements AttendanceTabContract.View, + SwipeRefreshLayout.OnRefreshListener { + + private static final String ARGUMENT_KEY = "date"; + + private static final String SAVED_KEY = "isSelected"; + + private boolean isPrimary = false; + + private boolean isSelected = false; + + @BindView(R.id.attendance_tab_fragment_recycler) + RecyclerView recyclerView; + + @BindView(R.id.attendance_tab_fragment_swipe_refresh) + SwipeRefreshLayout refreshLayout; + + @BindView(R.id.attendance_tab_fragment_progress_bar) + View progressBar; + + @BindView(R.id.attendance_tab_fragment_no_item_container) + View noItemView; + + @Inject + AttendanceTabContract.Presenter presenter; + + @Inject + FlexibleAdapter adapter; + + public static AttendanceTabFragment newInstance(String date) { + AttendanceTabFragment fragmentTab = new AttendanceTabFragment(); + + Bundle bundle = new Bundle(); + bundle.putString(ARGUMENT_KEY, date); + fragmentTab.setArguments(bundle); + + return fragmentTab; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (savedInstanceState != null) { + isSelected = savedInstanceState.getBoolean(SAVED_KEY, isSelected); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_attendance_tab, container, false); + + FragmentComponent component = getFragmentComponent(); + if (component != null) { + component.inject(this); + setButterKnife(ButterKnife.bind(this, view)); + + if (getArguments() != null) { + presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); + } + + presenter.onStart(this, isPrimary); + } + return view; + } + + @Override + protected void setUpOnViewCreated(View fragmentView) { + adapter.setAutoCollapseOnExpand(true); + adapter.setAutoScrollOnExpand(true); + adapter.expandItemsAtStartUp(); + + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setAdapter(adapter); + + refreshLayout.setColorSchemeResources(android.R.color.black); + refreshLayout.setOnRefreshListener(this); + + } + + @Override + public void updateAdapterList(List headerItems) { + adapter.updateDataSet(headerItems); + } + + @Override + public void setMenuVisibility(boolean menuVisible) { + super.setMenuVisibility(menuVisible); + if (presenter != null && getView() != null) { + presenter.onFragmentSelected(isSelected); + } else if (isSelected) { + isPrimary = true; + } + } + + @Override + public void onRefresh() { + presenter.onRefresh(); + } + + @Override + public void onRefreshSuccess() { + onError(R.string.timetable_refresh_success); + } + + @Override + public void hideRefreshingBar() { + refreshLayout.setRefreshing(false); + } + + @Override + public void showProgressBar(boolean show) { + progressBar.setVisibility(show ? View.VISIBLE : View.INVISIBLE); + } + + @Override + public void showNoItem(boolean show) { + noItemView.setVisibility(show ? View.VISIBLE : View.INVISIBLE); + } + + public void setSelected(boolean selected) { + isSelected = selected; + } + + @Override + public void onError(String message) { + if (getActivity() != null) { + Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), + message, Snackbar.LENGTH_LONG).show(); + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + outState.putBoolean(SAVED_KEY, isSelected); + super.onSaveInstanceState(outState); + } + + @Override + public void onDestroyView() { + isPrimary = false; + presenter.onDestroy(); + super.onDestroyView(); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java new file mode 100644 index 000000000..7f4766c93 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java @@ -0,0 +1,175 @@ +package io.github.wulkanowy.ui.main.attendance; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import io.github.wulkanowy.data.RepositoryContract; +import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; +import io.github.wulkanowy.data.db.dao.entities.Day; +import io.github.wulkanowy.data.db.dao.entities.Week; +import io.github.wulkanowy.ui.base.BasePresenter; +import io.github.wulkanowy.utils.async.AbstractTask; +import io.github.wulkanowy.utils.async.AsyncListeners; + +public class AttendanceTabPresenter extends BasePresenter + implements AttendanceTabContract.Presenter, AsyncListeners.OnRefreshListener, + AsyncListeners.OnFirstLoadingListener { + + private AbstractTask refreshTask; + + private AbstractTask loadingTask; + + private List headerItems = new ArrayList<>(); + + private String date; + + private boolean isFirstSight = false; + + @Inject + AttendanceTabPresenter(RepositoryContract repository) { + super(repository); + } + + @Override + public void onStart(AttendanceTabContract.View view, boolean isPrimary) { + super.onStart(view); + getView().showProgressBar(true); + getView().showNoItem(false); + onFragmentSelected(isPrimary); + } + + @Override + public void onFragmentSelected(boolean isSelected) { + if (!isFirstSight && isSelected) { + isFirstSight = true; + + loadingTask = new AbstractTask(); + loadingTask.setOnFirstLoadingListener(this); + loadingTask.execute(); + } + } + + @Override + public void onRefresh() { + if (getView().isNetworkConnected()) { + refreshTask = new AbstractTask(); + refreshTask.setOnRefreshListener(this); + refreshTask.execute(); + } else { + getView().onNoNetworkError(); + getView().hideRefreshingBar(); + } + } + + @Override + public void onDoInBackgroundRefresh() throws Exception { + syncData(); + } + + @Override + public void onCanceledRefreshAsync() { + if (isViewAttached()) { + getView().hideRefreshingBar(); + } + } + + @Override + public void onEndRefreshAsync(boolean result, Exception exception) { + if (result) { + loadingTask = new AbstractTask(); + loadingTask.setOnFirstLoadingListener(this); + loadingTask.execute(); + + getView().onRefreshSuccess(); + } else { + getView().onError(getRepository().getErrorLoginMessage(exception)); + } + getView().hideRefreshingBar(); + } + + @Override + public void onDoInBackgroundLoading() throws Exception { + Week week = getRepository().getWeek(date); + + if (week == null || !week.getIsAttendanceSynced()) { + syncData(); + week = getRepository().getWeek(date); + } + + List dayList = week.getDayList(); + + headerItems = new ArrayList<>(); + + boolean isEmptyWeek = true; + + for (Day day : dayList) { + AttendanceHeaderItem headerItem = new AttendanceHeaderItem(day); + + if (isEmptyWeek) { + isEmptyWeek = day.getAttendanceLessons().isEmpty(); + } + + List lessonList = day.getAttendanceLessons(); + + List subItems = new ArrayList<>(); + + for (AttendanceLesson lesson : lessonList) { + lesson.setDescription(getRepository().getAttendanceLessonDescription(lesson)); + subItems.add(new AttendanceSubItem(headerItem, lesson)); + } + + headerItem.setSubItems(subItems); + headerItem.setExpanded(false); + headerItems.add(headerItem); + } + + if (isEmptyWeek) { + headerItems = new ArrayList<>(); + } + } + + @Override + public void onCanceledLoadingAsync() { + // do nothing + } + + @Override + public void onEndLoadingAsync(boolean result, Exception exception) { + if (headerItems.isEmpty()) { + getView().showNoItem(true); + getView().updateAdapterList(null); + } else { + getView().updateAdapterList(headerItems); + getView().showNoItem(false); + } + getView().showProgressBar(false); + } + + @Override + public void setArgumentDate(String date) { + this.date = date; + } + + private void syncData() throws Exception { + getRepository().loginCurrentUser(); + getRepository().syncAttendance(date); + } + + @Override + public void onDestroy() { + isFirstSight = false; + + if (refreshTask != null) { + refreshTask.cancel(true); + refreshTask = null; + } + if (loadingTask != null) { + loadingTask.cancel(true); + loadingTask = null; + } + + super.onDestroy(); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java index 18fa33f96..eaad05056 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java @@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.main.timetable; import io.github.wulkanowy.di.annotations.PerActivity; import io.github.wulkanowy.ui.base.BaseContract; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.TabsData; public interface TimetableContract { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableDialogFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableDialogFragment.java index cfc1e0739..b93901953 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableDialogFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableDialogFragment.java @@ -15,13 +15,13 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import io.github.wulkanowy.R; -import io.github.wulkanowy.data.db.dao.entities.Lesson; +import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; public class TimetableDialogFragment extends DialogFragment { private static final String ARGUMENT_KEY = "Item"; - private Lesson lesson; + private TimetableLesson lesson; @BindView(R.id.timetable_dialog_lesson_value) TextView lessonName; @@ -54,7 +54,7 @@ public class TimetableDialogFragment extends DialogFragment { //empty constructor for fragment } - public static TimetableDialogFragment newInstance(Lesson lesson) { + public static TimetableDialogFragment newInstance(TimetableLesson lesson) { TimetableDialogFragment dialogFragment = new TimetableDialogFragment(); Bundle bundle = new Bundle(); @@ -69,7 +69,7 @@ public class TimetableDialogFragment extends DialogFragment { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { - lesson = (Lesson) getArguments().getSerializable(ARGUMENT_KEY); + lesson = (TimetableLesson) getArguments().getSerializable(ARGUMENT_KEY); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java index a9a833917..8bef4fb22 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java @@ -18,6 +18,7 @@ import io.github.wulkanowy.R; import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.TabsData; public class TimetableFragment extends BaseFragment implements TimetableContract.View, TabLayout.OnTabSelectedListener { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java index 6393179e9..39a8f0122 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java @@ -94,10 +94,10 @@ public class TimetableHeaderItem dayName.setText(StringUtils.capitalize(item.getDayName())); date.setText(item.getDate()); alert.setVisibility(isSubItemNewMovedInOrChanged(subItems) ? View.VISIBLE : View.INVISIBLE); - freeName.setVisibility(item.isFreeDay() ? View.VISIBLE : View.INVISIBLE); + freeName.setVisibility(item.getIsFreeDay() ? View.VISIBLE : View.INVISIBLE); freeName.setText(item.getFreeDayName()); - if (item.isFreeDay()) { + if (item.getIsFreeDay()) { ((FrameLayout) getContentView()).setForeground(null); getContentView().setBackgroundColor(backgroundFreeDay); dayName.setTextColor(secondaryColor); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePagerAdapter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePagerAdapter.java index 24e7582d3..0b8523420 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePagerAdapter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePagerAdapter.java @@ -5,6 +5,8 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; +import io.github.wulkanowy.ui.main.TabsData; + public class TimetablePagerAdapter extends FragmentStatePagerAdapter { private TabsData tabsData; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java index 5d17a4422..e816a1907 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java @@ -8,6 +8,7 @@ import javax.inject.Inject; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.ui.base.BasePresenter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.TabsData; import io.github.wulkanowy.utils.TimeUtils; import io.github.wulkanowy.utils.async.AbstractTask; import io.github.wulkanowy.utils.async.AsyncListeners; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java index b4212940f..ca82f783f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java @@ -8,6 +8,9 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + import java.util.List; import butterknife.BindView; @@ -16,26 +19,41 @@ 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.data.db.dao.entities.Lesson; +import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; public class TimetableSubItem extends AbstractSectionableItem { - private Lesson lesson; + private TimetableLesson lesson; - public TimetableSubItem(TimetableHeaderItem header, Lesson lesson) { + public TimetableSubItem(TimetableHeaderItem header, TimetableLesson lesson) { super(header); this.lesson = lesson; } - public Lesson getLesson() { + public TimetableLesson getLesson() { return lesson; } @Override public boolean equals(Object o) { - return this == o; + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + TimetableSubItem that = (TimetableSubItem) o; + + return new EqualsBuilder() + .append(lesson, that.lesson) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(lesson) + .toHashCode(); } @Override @@ -72,7 +90,7 @@ public class TimetableSubItem private Context context; - private Lesson item; + private TimetableLesson item; SubItemViewHolder(View view, FlexibleAdapter adapter) { super(view, adapter); @@ -81,7 +99,7 @@ public class TimetableSubItem view.setOnClickListener(this); } - void onBind(Lesson lesson) { + void onBind(TimetableLesson lesson) { item = lesson; lessonName.setText(lesson.getSubject()); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java index 43ead53e0..00dcef6ac 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java @@ -8,7 +8,7 @@ import javax.inject.Inject; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.data.db.dao.entities.Day; -import io.github.wulkanowy.data.db.dao.entities.Lesson; +import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.ui.base.BasePresenter; import io.github.wulkanowy.utils.async.AbstractTask; @@ -96,7 +96,7 @@ public class TimetableTabPresenter extends BasePresenter lessonList = day.getLessons(); + List lessonList = day.getTimetableLessons(); List subItems = new ArrayList<>(); - for (Lesson lesson : lessonList) { + for (TimetableLesson lesson : lessonList) { subItems.add(new TimetableSubItem(headerItem, lesson)); } @@ -143,8 +143,10 @@ public class TimetableTabPresenter extends BasePresenter lessonsToLessonsEntities(List lessonList) { + public static AttendanceLesson lessonToAttendanceLessonEntity(io.github.wulkanowy.api.generic.Lesson lesson) { + return new AttendanceLesson() + .setNumber(Integer.valueOf(lesson.getNumber())) + .setSubject(lesson.getSubject()) + .setDate(lesson.getDate()) + .setIsPresence(lesson.isPresence()) + .setIsAbsenceUnexcused(lesson.isAbsenceUnexcused()) + .setIsAbsenceExcused(lesson.isAbsenceExcused()) + .setIsUnexcusedLateness(lesson.isUnexcusedLateness()) + .setIsAbsenceForSchoolReasons(lesson.isAbsenceForSchoolReasons()) + .setIsExcusedLateness(lesson.isExcusedLateness()) + .setIsExemption(lesson.isExemption()); + } - List lessonEntityList = new ArrayList<>(); + public static List lessonsToTimetableLessonsEntities(List lessonList) { + + List lessonEntityList = new ArrayList<>(); for (io.github.wulkanowy.api.generic.Lesson lesson : lessonList) { - lessonEntityList.add(lessonToLessonEntity(lesson)); + lessonEntityList.add(lessonToTimetableLessonEntity(lesson)); + } + return lessonEntityList; + } + + public static List lessonsToAttendanceLessonsEntities(List lessonList) { + + List lessonEntityList = new ArrayList<>(); + + for (io.github.wulkanowy.api.generic.Lesson lesson : lessonList) { + lessonEntityList.add(lessonToAttendanceLessonEntity(lesson)); } return lessonEntityList; } diff --git a/app/src/main/res/layout/attendance_dialog.xml b/app/src/main/res/layout/attendance_dialog.xml new file mode 100644 index 000000000..916c993ca --- /dev/null +++ b/app/src/main/res/layout/attendance_dialog.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +