forked from github/wulkanowy-mirror
Modules improvements (#164)
This commit is contained in:
parent
bb69d1b643
commit
27f6fc7e04
@ -7,7 +7,7 @@ references:
|
||||
|
||||
container_config: &container_config
|
||||
docker:
|
||||
- image: circleci/android:api-27-alpha
|
||||
- image: circleci/android:api-28-alpha
|
||||
working_directory: *workspace_root
|
||||
environment:
|
||||
environment:
|
||||
|
@ -73,6 +73,7 @@ ext.supportVersion = "28.0.0"
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation('com.github.wulkanowy:api:a5667f8000') { exclude module: "threetenbp" }
|
||||
|
||||
implementation "com.android.support:support-v4:$supportVersion"
|
||||
implementation "com.android.support:appcompat-v7:$supportVersion"
|
||||
implementation "com.android.support:design:$supportVersion"
|
||||
@ -116,6 +117,7 @@ dependencies {
|
||||
testImplementation "junit:junit:4.12"
|
||||
testImplementation "io.mockk:mockk:1.8.8"
|
||||
testImplementation "org.mockito:mockito-inline:2.21.0"
|
||||
testImplementation 'org.threeten:threetenbp:1.3.7'
|
||||
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation "org.mockito:mockito-android:2.21.0"
|
||||
|
@ -34,9 +34,9 @@ class AttendanceLocalTest {
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
attendanceLocal.saveAttendance(listOf(
|
||||
Attendance(0, "1", "2", LocalDate.of(2018, 9, 10), 0, "", ""),
|
||||
Attendance(0, "1", "2", LocalDate.of(2018, 9, 14), 0, "", ""),
|
||||
Attendance(0, "1", "2", LocalDate.of(2018, 9, 17), 0, "", "")
|
||||
Attendance("1", "2", LocalDate.of(2018, 9, 10), 0, "", ""),
|
||||
Attendance("1", "2", LocalDate.of(2018, 9, 14), 0, "", ""),
|
||||
Attendance("1", "2", LocalDate.of(2018, 9, 17), 0, "", "")
|
||||
))
|
||||
|
||||
val attendance = attendanceLocal
|
||||
|
@ -34,9 +34,9 @@ class ExamLocalTest {
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
examLocal.saveExams(listOf(
|
||||
Exam(0, "1", "2", LocalDate.of(2018, 9, 10), LocalDate.now(), "", "", "", "", "", ""),
|
||||
Exam(0, "1", "2", LocalDate.of(2018, 9, 14), LocalDate.now(), "", "", "", "", "", ""),
|
||||
Exam(0, "1", "2", LocalDate.of(2018, 9, 17), LocalDate.now(), "", "", "", "", "", "")
|
||||
Exam("1", "2", LocalDate.of(2018, 9, 10), LocalDate.now(), "", "", "", "", "", ""),
|
||||
Exam("1", "2", LocalDate.of(2018, 9, 14), LocalDate.now(), "", "", "", "", "", ""),
|
||||
Exam("1", "2", LocalDate.of(2018, 9, 17), LocalDate.now(), "", "", "", "", "", "")
|
||||
))
|
||||
|
||||
val exams = examLocal
|
||||
|
@ -11,6 +11,7 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.LocalDateTime
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@ -33,14 +34,17 @@ class TimetableLocalTest {
|
||||
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
timetableDb.saveLessons(listOf(
|
||||
Timetable(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 10)),
|
||||
Timetable(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 14)),
|
||||
Timetable(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 17)) // in next week
|
||||
timetableDb.saveTimetable(listOf(
|
||||
Timetable("1", "2", 1, LocalDateTime.now(), LocalDateTime.now(),
|
||||
LocalDate.of(2018, 9, 10), "", "", "", "", ""),
|
||||
Timetable("1", "2", 1, LocalDateTime.now(), LocalDateTime.now(),
|
||||
LocalDate.of(2018, 9, 14), "", "", "", "", ""),
|
||||
Timetable("1", "2", 1, LocalDateTime.now(), LocalDateTime.now(),
|
||||
LocalDate.of(2018, 9, 17), "", "", "", "", "")
|
||||
))
|
||||
|
||||
val exams = timetableDb.getLessons(
|
||||
Semester(studentId = "1", diaryId = "2", semesterId = "3", diaryName = "", semesterName = 1),
|
||||
val exams = timetableDb.getTimetable(
|
||||
Semester(0, "1", "2", "3", "", 1),
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 14)
|
||||
).blockingGet()
|
||||
|
@ -17,32 +17,32 @@ class ScramblerTest {
|
||||
|
||||
@Test
|
||||
fun encryptDecryptTest() {
|
||||
assertEquals("TEST", Scrambler.decrypt(Scrambler.encrypt("TEST",
|
||||
assertEquals("TEST", decrypt(encrypt("TEST",
|
||||
InstrumentationRegistry.getTargetContext())))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun emptyTextEncryptTest() {
|
||||
assertFailsWith<ScramblerException> {
|
||||
Scrambler.decrypt("")
|
||||
decrypt("")
|
||||
}
|
||||
|
||||
assertFailsWith<ScramblerException> {
|
||||
Scrambler.encrypt("", InstrumentationRegistry.getTargetContext())
|
||||
encrypt("", InstrumentationRegistry.getTargetContext())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SdkSuppress(minSdkVersion = 18)
|
||||
fun emptyKeyStoreTest() {
|
||||
val text = Scrambler.encrypt("test", InstrumentationRegistry.getTargetContext())
|
||||
val text = encrypt("test", InstrumentationRegistry.getTargetContext())
|
||||
|
||||
val keyStore = KeyStore.getInstance("AndroidKeyStore")
|
||||
keyStore.load(null)
|
||||
keyStore.deleteEntry("USER_PASSWORD")
|
||||
|
||||
assertFailsWith<ScramblerException> {
|
||||
Scrambler.decrypt(text)
|
||||
decrypt(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import android.arch.persistence.room.Dao
|
||||
import android.arch.persistence.room.Delete
|
||||
import android.arch.persistence.room.Insert
|
||||
import android.arch.persistence.room.OnConflictStrategy.REPLACE
|
||||
import android.arch.persistence.room.Query
|
||||
@ -13,6 +14,9 @@ interface GradeSummaryDao {
|
||||
@Insert(onConflict = REPLACE)
|
||||
fun insertAll(gradesSummary: List<GradeSummary>)
|
||||
|
||||
@Delete
|
||||
fun deleteAll(gradesSummary: List<GradeSummary>)
|
||||
|
||||
@Query("SELECT * FROM grades_summary WHERE student_id = :studentId AND semester_id = :semesterId")
|
||||
fun getGradesSummary(semesterId: String, studentId: String): Maybe<List<GradeSummary>>
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import android.arch.persistence.room.Dao
|
||||
import android.arch.persistence.room.Insert
|
||||
import android.arch.persistence.room.OnConflictStrategy.REPLACE
|
||||
import android.arch.persistence.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Single
|
||||
@ -10,7 +9,7 @@ import io.reactivex.Single
|
||||
@Dao
|
||||
interface SemesterDao {
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
@Insert
|
||||
fun insertAll(semester: List<Semester>)
|
||||
|
||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
||||
|
@ -2,7 +2,6 @@ package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import android.arch.persistence.room.Dao
|
||||
import android.arch.persistence.room.Insert
|
||||
import android.arch.persistence.room.OnConflictStrategy.REPLACE
|
||||
import android.arch.persistence.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
@ -10,7 +9,7 @@ import io.reactivex.Maybe
|
||||
@Dao
|
||||
interface StudentDao {
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
@Insert
|
||||
fun insert(student: Student): Long
|
||||
|
||||
@Query("SELECT * FROM Students WHERE id = :id")
|
||||
|
@ -9,9 +9,6 @@ import java.io.Serializable
|
||||
@Entity(tableName = "Attendance")
|
||||
data class Attendance(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: String,
|
||||
|
||||
@ -37,4 +34,8 @@ data class Attendance(
|
||||
var excused: Boolean = false,
|
||||
|
||||
var deleted: Boolean = false
|
||||
) : Serializable
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
}
|
||||
|
@ -9,9 +9,6 @@ import java.io.Serializable
|
||||
@Entity(tableName = "Exams")
|
||||
data class Exam(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: String,
|
||||
|
||||
@ -35,4 +32,8 @@ data class Exam(
|
||||
|
||||
@ColumnInfo(name = "teacher_symbol")
|
||||
var teacherSymbol: String
|
||||
) : Serializable
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
}
|
||||
|
@ -2,16 +2,11 @@ package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import android.arch.persistence.room.ColumnInfo
|
||||
import android.arch.persistence.room.Entity
|
||||
import android.arch.persistence.room.Index
|
||||
import android.arch.persistence.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "Grades_Summary",
|
||||
indices = [Index(value = ["semester_id", "student_id", "subject"], unique = true)])
|
||||
@Entity(tableName = "Grades_Summary")
|
||||
data class GradeSummary(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "semester_id")
|
||||
var semesterId: String,
|
||||
|
||||
@ -23,4 +18,8 @@ data class GradeSummary(
|
||||
var predictedGrade: String,
|
||||
|
||||
var finalGrade: String
|
||||
)
|
||||
) {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
}
|
||||
|
@ -2,11 +2,9 @@ package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import android.arch.persistence.room.ColumnInfo
|
||||
import android.arch.persistence.room.Entity
|
||||
import android.arch.persistence.room.Index
|
||||
import android.arch.persistence.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "Semesters",
|
||||
indices = [Index(value = ["semester_id", "diary_id", "student_id"], unique = true)])
|
||||
@Entity(tableName = "Semesters")
|
||||
data class Semester(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
|
@ -2,11 +2,9 @@ package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import android.arch.persistence.room.ColumnInfo
|
||||
import android.arch.persistence.room.Entity
|
||||
import android.arch.persistence.room.Index
|
||||
import android.arch.persistence.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "Students",
|
||||
indices = [Index(value = ["student_id", "student_name"], unique = true)])
|
||||
@Entity(tableName = "Students")
|
||||
data class Student(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
|
@ -10,14 +10,11 @@ import java.io.Serializable
|
||||
@Entity(tableName = "Timetable")
|
||||
data class Timetable(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: String = "",
|
||||
var studentId: String,
|
||||
|
||||
@ColumnInfo(name = "diary_id")
|
||||
var diaryId: String = "",
|
||||
var diaryId: String,
|
||||
|
||||
val number: Int = 0,
|
||||
|
||||
@ -27,17 +24,21 @@ data class Timetable(
|
||||
|
||||
val date: LocalDate,
|
||||
|
||||
val subject: String = "",
|
||||
val subject: String,
|
||||
|
||||
val group: String = "",
|
||||
val group: String,
|
||||
|
||||
val room: String = "",
|
||||
val room: String,
|
||||
|
||||
val teacher: String = "",
|
||||
val teacher: String,
|
||||
|
||||
val info: String = "",
|
||||
val info: String,
|
||||
|
||||
val changes: Boolean = false,
|
||||
|
||||
val canceled: Boolean = false
|
||||
) : Serializable
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
}
|
||||
|
@ -6,11 +6,10 @@ import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.local.AttendanceLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.AttendanceRemote
|
||||
import io.github.wulkanowy.utils.weekFirstDayAlwaysCurrent
|
||||
import io.github.wulkanowy.utils.friday
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.DayOfWeek
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.temporal.TemporalAdjusters
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -22,24 +21,25 @@ class AttendanceRepository @Inject constructor(
|
||||
private val remote: AttendanceRemote
|
||||
) {
|
||||
|
||||
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<Attendance>> {
|
||||
val start = startDate.weekFirstDayAlwaysCurrent
|
||||
val end = endDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))
|
||||
|
||||
return local.getAttendance(semester, start, end).filter { !forceRefresh }
|
||||
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean)
|
||||
: Single<List<Attendance>> {
|
||||
return Single.fromCallable { startDate.monday to endDate.friday }
|
||||
.flatMap { dates ->
|
||||
local.getAttendance(semester, dates.first, dates.second).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||
if (it) remote.getAttendance(semester, start, end)
|
||||
if (it) remote.getAttendance(semester, dates.first, dates.second)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { newLessons ->
|
||||
local.getAttendance(semester, start, end).toSingle(emptyList()).map { grades ->
|
||||
local.deleteAttendance(grades - newLessons)
|
||||
local.saveAttendance(newLessons - grades)
|
||||
newLessons
|
||||
}.flatMap { newAttendance ->
|
||||
local.getAttendance(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { oldAttendance ->
|
||||
local.deleteAttendance(oldAttendance - newAttendance)
|
||||
local.saveAttendance(newAttendance - oldAttendance)
|
||||
}
|
||||
}).map { list ->
|
||||
list.asSequence().filter {
|
||||
it.date in startDate..endDate
|
||||
}.toList()
|
||||
}.flatMap {
|
||||
local.getAttendance(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in startDate..endDate } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,10 @@ import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.local.ExamLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.ExamRemote
|
||||
import io.github.wulkanowy.utils.weekFirstDayAlwaysCurrent
|
||||
import io.github.wulkanowy.utils.friday
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.DayOfWeek
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.temporal.TemporalAdjusters
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -23,23 +22,24 @@ class ExamRepository @Inject constructor(
|
||||
) {
|
||||
|
||||
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<Exam>> {
|
||||
val start = startDate.weekFirstDayAlwaysCurrent
|
||||
val end = endDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))
|
||||
|
||||
return local.getExams(semester, start, end).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||
if (it) remote.getExams(semester, start, end)
|
||||
return Single.fromCallable { startDate.monday to endDate.friday }
|
||||
.flatMap { dates ->
|
||||
local.getExams(semester, dates.first, dates.second).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getExams(semester, dates.first, dates.second)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { newExams ->
|
||||
local.getExams(semester, start, end).toSingle(emptyList()).map { grades ->
|
||||
local.deleteExams(grades - newExams)
|
||||
local.saveExams(newExams - grades)
|
||||
newExams
|
||||
local.getExams(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { oldExams ->
|
||||
local.deleteExams(oldExams - newExams)
|
||||
local.saveExams(newExams - oldExams)
|
||||
}
|
||||
}).map { list ->
|
||||
list.asSequence().filter {
|
||||
it.date in startDate..endDate
|
||||
}.toList()
|
||||
}.flatMap {
|
||||
local.getExams(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in startDate..endDate } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,12 @@ class GradeSummaryRepository @Inject constructor(
|
||||
.flatMap {
|
||||
if (it) remote.getGradeSummary(semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { newGradesSummary ->
|
||||
local.getGradesSummary(semester).toSingle(emptyList())
|
||||
.doOnSuccess { oldGradesSummary ->
|
||||
local.deleteGradesSummary(oldGradesSummary - newGradesSummary)
|
||||
local.saveGradesSummary(newGradesSummary - oldGradesSummary)
|
||||
}
|
||||
).doOnSuccess { local.saveGradesSummary(it) }
|
||||
}.flatMap { local.getGradesSummary(semester).toSingle(emptyList()) })
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,10 @@ import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.repositories.local.TimetableLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.TimetableRemote
|
||||
import io.github.wulkanowy.utils.weekFirstDayAlwaysCurrent
|
||||
import io.github.wulkanowy.utils.friday
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.DayOfWeek
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.temporal.TemporalAdjusters
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -22,24 +21,26 @@ class TimetableRepository @Inject constructor(
|
||||
private val remote: TimetableRemote
|
||||
) {
|
||||
|
||||
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<Timetable>> {
|
||||
val start = startDate.weekFirstDayAlwaysCurrent
|
||||
val end = endDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))
|
||||
|
||||
return local.getLessons(semester, start, end).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||
if (it) remote.getLessons(semester, start, end)
|
||||
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false)
|
||||
: Single<List<Timetable>> {
|
||||
return Single.fromCallable { startDate.monday to endDate.friday }
|
||||
.flatMap { dates ->
|
||||
local.getTimetable(semester, dates.first, dates.second).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getTimetable(semester, dates.first, dates.second)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { newLessons ->
|
||||
local.getLessons(semester, start, end).toSingle(emptyList()).map { lessons ->
|
||||
local.deleteLessons(lessons - newLessons)
|
||||
local.saveLessons(newLessons - lessons)
|
||||
newLessons
|
||||
}.flatMap { newTimetable ->
|
||||
local.getTimetable(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
.doOnSuccess { oldTimetable ->
|
||||
local.deleteTimetable(oldTimetable - newTimetable)
|
||||
local.saveTimetable(newTimetable - oldTimetable)
|
||||
}
|
||||
}).map { list ->
|
||||
list.asSequence().filter {
|
||||
it.date in startDate..endDate
|
||||
}.toList()
|
||||
}.flatMap {
|
||||
local.getTimetable(semester, dates.first, dates.second)
|
||||
.toSingle(emptyList())
|
||||
}).map { list -> list.filter { it.date in startDate..endDate } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,4 +18,8 @@ class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSum
|
||||
fun saveGradesSummary(gradesSummary: List<GradeSummary>) {
|
||||
gradeSummaryDb.insertAll(gradesSummary)
|
||||
}
|
||||
|
||||
fun deleteGradesSummary(gradesSummary: List<GradeSummary>) {
|
||||
gradeSummaryDb.deleteAll(gradesSummary)
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.utils.security.Scrambler.decrypt
|
||||
import io.github.wulkanowy.utils.security.Scrambler.encrypt
|
||||
import io.github.wulkanowy.utils.security.decrypt
|
||||
import io.github.wulkanowy.utils.security.encrypt
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
|
@ -9,16 +9,16 @@ import javax.inject.Inject
|
||||
|
||||
class TimetableLocal @Inject constructor(private val timetableDb: TimetableDao) {
|
||||
|
||||
fun getLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Timetable>> {
|
||||
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Timetable>> {
|
||||
return timetableDb.getTimetable(semester.diaryId, semester.studentId, startDate, endDate)
|
||||
.filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun saveLessons(lessons: List<Timetable>) {
|
||||
timetableDb.insertAll(lessons)
|
||||
fun saveTimetable(timetables: List<Timetable>) {
|
||||
timetableDb.insertAll(timetables)
|
||||
}
|
||||
|
||||
fun deleteLessons(exams: List<Timetable>) {
|
||||
timetableDb.deleteAll(exams)
|
||||
fun deleteTimetable(timetables: List<Timetable>) {
|
||||
timetableDb.deleteAll(timetables)
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class GradeRemote @Inject constructor(private val api: Api) {
|
||||
subject = it.subject,
|
||||
entry = it.entry,
|
||||
value = it.value,
|
||||
modifier = it.modifier.toDouble(),
|
||||
modifier = it.modifier,
|
||||
comment = it.comment,
|
||||
color = it.color,
|
||||
gradeSymbol = it.symbol,
|
||||
|
@ -11,7 +11,7 @@ import javax.inject.Inject
|
||||
|
||||
class TimetableRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Timetable>> {
|
||||
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Timetable>> {
|
||||
return Single.just(api.run {
|
||||
if (diaryId != semester.diaryId) {
|
||||
diaryId = semester.diaryId
|
||||
|
@ -1,10 +1,16 @@
|
||||
package io.github.wulkanowy.ui.base
|
||||
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.design.widget.Snackbar.LENGTH_LONG
|
||||
import android.view.View
|
||||
import dagger.android.support.DaggerFragment
|
||||
|
||||
abstract class BaseFragment : DaggerFragment(), BaseView {
|
||||
|
||||
protected var messageContainer: View? = null
|
||||
|
||||
override fun showMessage(text: String) {
|
||||
(activity as BaseActivity?)?.showMessage(text)
|
||||
if (messageContainer == null) (activity as? BaseActivity)?.showMessage(text)
|
||||
else messageContainer?.also { Snackbar.make(it, text, LENGTH_LONG).show() }
|
||||
}
|
||||
}
|
||||
|
@ -9,15 +9,12 @@ open class BasePresenter<T : BaseView>(private val errorHandler: ErrorHandler) {
|
||||
|
||||
var view: T? = null
|
||||
|
||||
val isViewAttached: Boolean
|
||||
get() = view != null
|
||||
|
||||
open fun attachView(view: T) {
|
||||
open fun onAttachView(view: T) {
|
||||
this.view = view
|
||||
errorHandler.showErrorMessage = { view.showMessage(it) }
|
||||
}
|
||||
|
||||
open fun detachView() {
|
||||
open fun onDetachView() {
|
||||
view = null
|
||||
disposable.clear()
|
||||
errorHandler.clear()
|
||||
|
@ -27,8 +27,9 @@ class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_login)
|
||||
presenter.attachView(this)
|
||||
messageContainer = loginContainer
|
||||
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
@ -65,7 +66,7 @@ class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener {
|
||||
override fun currentViewPosition() = loginViewpager.currentItem
|
||||
|
||||
public override fun onDestroy() {
|
||||
presenter.detachView()
|
||||
presenter.onDetachView()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import javax.inject.Inject
|
||||
class LoginPresenter @Inject constructor(errorHandler: ErrorHandler)
|
||||
: BasePresenter<LoginView>(errorHandler) {
|
||||
|
||||
override fun attachView(view: LoginView) {
|
||||
super.attachView(view)
|
||||
override fun onAttachView(view: LoginView) {
|
||||
super.onAttachView(view)
|
||||
view.run {
|
||||
initAdapter()
|
||||
hideActionBar()
|
||||
|
@ -31,7 +31,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initInputs() {
|
||||
@ -139,6 +139,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
presenter.onDetachView()
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ class LoginFormPresenter @Inject constructor(
|
||||
|
||||
private var wasEmpty = false
|
||||
|
||||
override fun attachView(view: LoginFormView) {
|
||||
super.attachView(view)
|
||||
override fun onAttachView(view: LoginFormView) {
|
||||
super.onAttachView(view)
|
||||
view.initInputs()
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initRecycler() {
|
||||
@ -80,6 +80,6 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView {
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
presenter.onDetachView()
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ class LoginOptionsPresenter @Inject constructor(
|
||||
private val schedulers: SchedulersManager)
|
||||
: BasePresenter<LoginOptionsView>(errorHandler) {
|
||||
|
||||
override fun attachView(view: LoginOptionsView) {
|
||||
super.attachView(view)
|
||||
override fun onAttachView(view: LoginOptionsView) {
|
||||
super.onAttachView(view)
|
||||
view.initRecycler()
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ class MainActivity : BaseActivity(), MainView {
|
||||
setSupportActionBar(mainToolbar)
|
||||
messageContainer = mainFragmentContainer
|
||||
|
||||
presenter.attachView(this)
|
||||
presenter.onAttachView(this)
|
||||
navController.initialize(DEFAULT_TAB, savedInstanceState)
|
||||
}
|
||||
|
||||
@ -90,10 +90,6 @@ class MainActivity : BaseActivity(), MainView {
|
||||
supportActionBar?.title = title
|
||||
}
|
||||
|
||||
override fun expandActionBar(show: Boolean) {
|
||||
mainAppBarContainer.setExpanded(show, true)
|
||||
}
|
||||
|
||||
override fun viewTitle(index: Int): String {
|
||||
return getString(listOf(R.string.grade_title,
|
||||
R.string.attendance_title,
|
||||
@ -119,6 +115,6 @@ class MainActivity : BaseActivity(), MainView {
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
presenter.detachView()
|
||||
presenter.onDetachView()
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import javax.inject.Inject
|
||||
class MainPresenter @Inject constructor(errorHandler: ErrorHandler)
|
||||
: BasePresenter<MainView>(errorHandler) {
|
||||
|
||||
override fun attachView(view: MainView) {
|
||||
super.attachView(view)
|
||||
override fun onAttachView(view: MainView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
}
|
||||
|
||||
@ -22,7 +22,6 @@ class MainPresenter @Inject constructor(errorHandler: ErrorHandler)
|
||||
|
||||
fun onTabSelected(index: Int, wasSelected: Boolean): Boolean {
|
||||
return view?.run {
|
||||
expandActionBar(true)
|
||||
if (wasSelected) {
|
||||
notifyMenuViewReselected()
|
||||
false
|
||||
|
@ -10,8 +10,6 @@ interface MainView : BaseView {
|
||||
|
||||
fun setViewTitle(title: String)
|
||||
|
||||
fun expandActionBar(show: Boolean)
|
||||
|
||||
fun viewTitle(index: Int): String
|
||||
|
||||
fun currentMenuIndex(): Int
|
||||
|
@ -26,14 +26,13 @@ class AttendanceDialog : DialogFragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogFragmentTheme)
|
||||
setStyle(STYLE_NO_TITLE, 0)
|
||||
arguments?.run {
|
||||
attendance = getSerializable(ARGUMENT_KEY) as Attendance
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
dialog.setTitle(getString(R.string.all_details))
|
||||
return inflater.inflate(R.layout.dialog_attendance, container, false)
|
||||
}
|
||||
|
||||
|
@ -10,11 +10,12 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.main.MainView
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_attendance.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class AttendanceFragment : BaseFragment(), AttendanceView {
|
||||
class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MenuFragmentView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: AttendancePresenter
|
||||
@ -24,6 +25,7 @@ class AttendanceFragment : BaseFragment(), AttendanceView {
|
||||
|
||||
companion object {
|
||||
private const val SAVED_DATE_KEY = "CURRENT_DATE"
|
||||
|
||||
fun newInstance() = AttendanceFragment()
|
||||
}
|
||||
|
||||
@ -33,41 +35,42 @@ class AttendanceFragment : BaseFragment(), AttendanceView {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.run {
|
||||
attachView(this@AttendanceFragment)
|
||||
loadData(date = savedInstanceState?.getLong(SAVED_DATE_KEY))
|
||||
}
|
||||
messageContainer = attendanceRecycler
|
||||
presenter.onAttachView(this, savedInstanceState?.getLong(SAVED_DATE_KEY))
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
attendanceAdapter.run {
|
||||
isAutoCollapseOnExpand = true
|
||||
isAutoScrollOnExpand = true
|
||||
attendanceAdapter.apply {
|
||||
setOnItemClickListener { presenter.onAttendanceItemSelected(getItem(it)) }
|
||||
}
|
||||
|
||||
attendanceRecycler.run {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
adapter = attendanceAdapter
|
||||
}
|
||||
attendanceSwipe.setOnRefreshListener { presenter.loadData(date = null, forceRefresh = true) }
|
||||
attendancePreviousButton.setOnClickListener { presenter.loadAttendanceForPreviousDay() }
|
||||
attendanceNextButton.setOnClickListener { presenter.loadAttendanceForNextDay() }
|
||||
attendanceSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
attendancePreviousButton.setOnClickListener { presenter.onPreviousDay() }
|
||||
attendanceNextButton.setOnClickListener { presenter.onNextDay() }
|
||||
}
|
||||
|
||||
override fun updateData(data: List<AttendanceItem>) {
|
||||
attendanceAdapter.updateDataSet(data, true)
|
||||
}
|
||||
|
||||
override fun clearData() {
|
||||
attendanceAdapter.clear()
|
||||
}
|
||||
|
||||
override fun updateNavigationDay(date: String) {
|
||||
attendanceNavDate.text = date
|
||||
}
|
||||
|
||||
override fun clearData() {
|
||||
attendanceAdapter.clear()
|
||||
}
|
||||
|
||||
override fun isViewEmpty() = attendanceAdapter.isEmpty
|
||||
|
||||
override fun onFragmentReselected() {
|
||||
presenter.onViewReselected()
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
attendanceEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
@ -80,8 +83,8 @@ class AttendanceFragment : BaseFragment(), AttendanceView {
|
||||
attendanceRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showRefresh(show: Boolean) {
|
||||
attendanceSwipe.isRefreshing = show
|
||||
override fun hideRefresh() {
|
||||
attendanceSwipe.isRefreshing = false
|
||||
}
|
||||
|
||||
override fun showPreButton(show: Boolean) {
|
||||
@ -102,8 +105,8 @@ class AttendanceFragment : BaseFragment(), AttendanceView {
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package io.github.wulkanowy.ui.main.attendance
|
||||
|
||||
import android.view.View
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
@ -10,9 +12,7 @@ import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_attendance.*
|
||||
|
||||
class AttendanceItem : AbstractFlexibleItem<AttendanceItem.ViewHolder>() {
|
||||
|
||||
lateinit var attendance: Attendance
|
||||
class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem<AttendanceItem.ViewHolder>() {
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
@ -20,6 +20,16 @@ class AttendanceItem : AbstractFlexibleItem<AttendanceItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes(): Int = R.layout.item_attendance
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
attendanceItemNumber.text = attendance.number.toString()
|
||||
attendanceItemSubject.text = attendance.subject
|
||||
attendanceItemDescription.text = attendance.name
|
||||
attendanceItemAlert.visibility = attendance.run { if (absence && !excused) VISIBLE else INVISIBLE }
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
@ -34,22 +44,10 @@ class AttendanceItem : AbstractFlexibleItem<AttendanceItem.ViewHolder>() {
|
||||
return attendance.hashCode()
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.bind(attendance)
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
|
||||
fun bind(lesson: Attendance) {
|
||||
attendanceItemNumber.text = lesson.number.toString()
|
||||
attendanceItemSubject.text = lesson.subject
|
||||
attendanceItemDescription.text = lesson.name
|
||||
attendanceItemAlert.visibility = if (lesson.absence && !lesson.excused) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,15 @@ package io.github.wulkanowy.ui.main.attendance
|
||||
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.LocalDate.now
|
||||
import org.threeten.bp.LocalDate.ofEpochDay
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import javax.inject.Inject
|
||||
|
||||
class AttendancePresenter @Inject constructor(
|
||||
@ -19,79 +20,79 @@ class AttendancePresenter @Inject constructor(
|
||||
private val sessionRepository: SessionRepository
|
||||
) : BasePresenter<AttendanceView>(errorHandler) {
|
||||
|
||||
var currentDate: LocalDate = LocalDate.now().nearSchoolDayPrevOnWeekEnd
|
||||
lateinit var currentDate: LocalDate
|
||||
private set
|
||||
|
||||
override fun attachView(view: AttendanceView) {
|
||||
super.attachView(view)
|
||||
fun onAttachView(view: AttendanceView, date: Long?) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
loadData(ofEpochDay(date ?: now().previousOrSameSchoolDay.toEpochDay()))
|
||||
reloadView()
|
||||
}
|
||||
|
||||
fun loadAttendanceForPreviousDay() = loadData(currentDate.previousWorkDay.toEpochDay())
|
||||
|
||||
fun loadAttendanceForNextDay() = loadData(currentDate.nextWorkDay.toEpochDay())
|
||||
|
||||
fun loadData(date: Long?, forceRefresh: Boolean = false) {
|
||||
this.currentDate = LocalDate.ofEpochDay(date
|
||||
?: currentDate.nearSchoolDayPrevOnWeekEnd.toEpochDay())
|
||||
if (currentDate.isHolidays) return
|
||||
|
||||
disposable.clear()
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map { selectSemester(it, -1) }
|
||||
.flatMap { attendanceRepository.getAttendance(it, currentDate, currentDate, forceRefresh) }
|
||||
.map { createAttendanceItems(it) }
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.doOnSubscribe {
|
||||
view?.run {
|
||||
showRefresh(forceRefresh)
|
||||
showProgress(!forceRefresh)
|
||||
if (!forceRefresh) {
|
||||
showEmpty(false)
|
||||
clearData()
|
||||
}
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||
}
|
||||
}
|
||||
.doFinally {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
view?.run {
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
updateData(it)
|
||||
}
|
||||
}) {
|
||||
view?.run { showEmpty(isViewEmpty()) }
|
||||
errorHandler.proceed(it)
|
||||
})
|
||||
fun onPreviousDay() {
|
||||
loadData(currentDate.previousSchoolDay)
|
||||
reloadView()
|
||||
}
|
||||
|
||||
private fun createAttendanceItems(items: List<Attendance>): List<AttendanceItem> {
|
||||
return items.map {
|
||||
AttendanceItem().apply { attendance = it }
|
||||
fun onNextDay() {
|
||||
loadData(currentDate.nextSchoolDay)
|
||||
reloadView()
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
loadData(currentDate, true)
|
||||
}
|
||||
|
||||
fun onViewReselected() {
|
||||
loadData(now().previousOrSameSchoolDay)
|
||||
reloadView()
|
||||
}
|
||||
|
||||
fun onAttendanceItemSelected(item: AbstractFlexibleItem<*>?) {
|
||||
if (item is AttendanceItem) view?.showAttendanceDialog(item.attendance)
|
||||
}
|
||||
|
||||
private fun selectSemester(semesters: List<Semester>, index: Int): Semester {
|
||||
return semesters.single { it.current }.let { currentSemester ->
|
||||
if (index == -1) currentSemester
|
||||
else semesters.single { semester ->
|
||||
semester.run {
|
||||
semesterName - 1 == index && diaryId == currentSemester.diaryId
|
||||
}
|
||||
}
|
||||
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
||||
currentDate = date
|
||||
disposable.apply {
|
||||
clear()
|
||||
add(sessionRepository.getSemesters()
|
||||
.delay(200, MILLISECONDS)
|
||||
.map { it.single { semester -> semester.current } }
|
||||
.flatMap { attendanceRepository.getAttendance(it, date, date, forceRefresh) }
|
||||
.map { items -> items.map { AttendanceItem(it) } }
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.doFinally {
|
||||
view?.run {
|
||||
hideRefresh()
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
view?.apply {
|
||||
updateData(it)
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
}
|
||||
}) {
|
||||
view?.run { showEmpty(isViewEmpty()) }
|
||||
errorHandler.proceed(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadView() {
|
||||
view?.apply {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
showEmpty(false)
|
||||
clearData()
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,20 +9,20 @@ interface AttendanceView : BaseView {
|
||||
|
||||
fun updateData(data: List<AttendanceItem>)
|
||||
|
||||
fun clearData()
|
||||
|
||||
fun updateNavigationDay(date: String)
|
||||
|
||||
fun clearData()
|
||||
|
||||
fun isViewEmpty(): Boolean
|
||||
|
||||
fun hideRefresh()
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showRefresh(show: Boolean)
|
||||
|
||||
fun showPreButton(show: Boolean)
|
||||
|
||||
fun showNextButton(show: Boolean)
|
||||
|
@ -26,14 +26,13 @@ class ExamDialog : DialogFragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogFragmentTheme)
|
||||
setStyle(STYLE_NO_TITLE, 0)
|
||||
arguments?.run {
|
||||
exam = getSerializable(ARGUMENT_KEY) as Exam
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
dialog.setTitle(getString(R.string.all_details))
|
||||
return inflater.inflate(R.layout.dialog_exam, container, false)
|
||||
}
|
||||
|
||||
|
@ -11,11 +11,12 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.main.MainView
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_exam.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class ExamFragment : BaseFragment(), ExamView {
|
||||
class ExamFragment : BaseFragment(), ExamView, MainView.MenuFragmentView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: ExamPresenter
|
||||
@ -34,10 +35,8 @@ class ExamFragment : BaseFragment(), ExamView {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.run {
|
||||
attachView(this@ExamFragment)
|
||||
loadData(date = savedInstanceState?.getLong(SAVED_DATE_KEY))
|
||||
}
|
||||
messageContainer = examRecycler
|
||||
presenter.onAttachView(this, savedInstanceState?.getLong(SAVED_DATE_KEY))
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
@ -48,9 +47,13 @@ class ExamFragment : BaseFragment(), ExamView {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
adapter = examAdapter
|
||||
}
|
||||
examSwipe.setOnRefreshListener { presenter.loadData(date = null, forceRefresh = true) }
|
||||
examPreviousButton.setOnClickListener { presenter.loadExamsForPreviousWeek() }
|
||||
examNextButton.setOnClickListener { presenter.loadExamsForNextWeek()}
|
||||
examSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
examPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
|
||||
examNextButton.setOnClickListener { presenter.onNextWeek() }
|
||||
}
|
||||
|
||||
override fun hideRefresh() {
|
||||
examSwipe.isRefreshing = false
|
||||
}
|
||||
|
||||
override fun updateData(data: List<ExamItem>) {
|
||||
@ -61,6 +64,16 @@ class ExamFragment : BaseFragment(), ExamView {
|
||||
examNavDate.text = date
|
||||
}
|
||||
|
||||
override fun clearData() {
|
||||
examAdapter.clear()
|
||||
}
|
||||
|
||||
override fun isViewEmpty() = examAdapter.isEmpty
|
||||
|
||||
override fun onFragmentReselected() {
|
||||
presenter.onViewReselected()
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
examEmpty.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
@ -73,10 +86,6 @@ class ExamFragment : BaseFragment(), ExamView {
|
||||
examRecycler.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun showRefresh(show: Boolean) {
|
||||
examSwipe.isRefreshing = show
|
||||
}
|
||||
|
||||
override fun showPreButton(show: Boolean) {
|
||||
examPreviousButton.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
@ -95,7 +104,7 @@ class ExamFragment : BaseFragment(), ExamView {
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
}
|
||||
}
|
||||
|
@ -12,15 +12,21 @@ import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.header_exam.*
|
||||
import org.threeten.bp.LocalDate
|
||||
|
||||
class ExamHeader : AbstractHeaderItem<ExamHeader.ViewHolder>() {
|
||||
class ExamHeader(private val date: LocalDate) : AbstractHeaderItem<ExamHeader.ViewHolder>() {
|
||||
|
||||
lateinit var date: LocalDate
|
||||
override fun getLayoutRes() = R.layout.header_exam
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun getLayoutRes() = R.layout.header_exam
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
examHeaderDay.text = date.weekDayName.capitalize()
|
||||
examHeaderDate.text = date.toFormattedString()
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
@ -37,21 +43,9 @@ class ExamHeader : AbstractHeaderItem<ExamHeader.ViewHolder>() {
|
||||
return date.hashCode()
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
examHeaderDay.text = date.weekDayName.capitalize()
|
||||
examHeaderDate.text = date.toFormattedString()
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : ExpandableViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
init {
|
||||
contentView.setOnClickListener(this)
|
||||
}
|
||||
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
|
@ -13,21 +13,6 @@ import kotlinx.android.synthetic.main.item_exam.*
|
||||
|
||||
class ExamItem(header: ExamHeader, val exam: Exam) : AbstractSectionableItem<ExamItem.ViewHolder, ExamHeader>(header) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as ExamItem
|
||||
|
||||
if (exam != other.exam) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return exam.hashCode()
|
||||
}
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_exam
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): ViewHolder {
|
||||
@ -43,6 +28,21 @@ class ExamItem(header: ExamHeader, val exam: Exam) : AbstractSectionableItem<Exa
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as ExamItem
|
||||
|
||||
if (exam != other.exam) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return exam.hashCode()
|
||||
}
|
||||
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
|
@ -3,15 +3,15 @@ package io.github.wulkanowy.ui.main.exam
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.weekFirstDayNextOnWeekEnd
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.LocalDate.now
|
||||
import org.threeten.bp.LocalDate.ofEpochDay
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import javax.inject.Inject
|
||||
|
||||
class ExamPresenter @Inject constructor(
|
||||
@ -21,79 +21,89 @@ class ExamPresenter @Inject constructor(
|
||||
private val sessionRepository: SessionRepository
|
||||
) : BasePresenter<ExamView>(errorHandler) {
|
||||
|
||||
var currentDate: LocalDate = LocalDate.now().weekFirstDayNextOnWeekEnd
|
||||
lateinit var currentDate: LocalDate
|
||||
private set
|
||||
|
||||
override fun attachView(view: ExamView) {
|
||||
super.attachView(view)
|
||||
fun onAttachView(view: ExamView, date: Long?) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
||||
reloadView()
|
||||
}
|
||||
|
||||
fun loadExamsForPreviousWeek() = loadData(currentDate.minusDays(7).toEpochDay())
|
||||
|
||||
fun loadExamsForNextWeek() = loadData(currentDate.plusDays(7).toEpochDay())
|
||||
|
||||
fun loadData(date: Long?, forceRefresh: Boolean = false) {
|
||||
this.currentDate = LocalDate.ofEpochDay(date
|
||||
?: currentDate.weekFirstDayNextOnWeekEnd.toEpochDay())
|
||||
if (currentDate.isHolidays) return
|
||||
|
||||
disposable.clear()
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map { selectSemester(it, -1) }
|
||||
.flatMap { examRepository.getExams(it, currentDate, currentDate.plusDays(4), forceRefresh) }
|
||||
.map { it.groupBy { exam -> exam.date }.toSortedMap() }
|
||||
.map { createExamItems(it) }
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.doOnSubscribe {
|
||||
view?.run {
|
||||
showRefresh(forceRefresh)
|
||||
showProgress(!forceRefresh)
|
||||
if (!forceRefresh) showEmpty(false)
|
||||
showContent(null == date && forceRefresh)
|
||||
showPreButton(!currentDate.minusDays(7).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(7).isHolidays)
|
||||
updateNavigationWeek(currentDate.toFormattedString("dd.MM") +
|
||||
"-${currentDate.plusDays(4).toFormattedString("dd.MM")}")
|
||||
}
|
||||
}
|
||||
.doAfterSuccess {
|
||||
view?.run {
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
}
|
||||
}
|
||||
.doFinally {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
.subscribe({ view?.updateData(it) }) { errorHandler.proceed(it) })
|
||||
fun onPreviousWeek() {
|
||||
loadData(currentDate.minusDays(7))
|
||||
reloadView()
|
||||
}
|
||||
|
||||
private fun createExamItems(items: Map<LocalDate, List<Exam>>): List<ExamItem> {
|
||||
return items.flatMap {
|
||||
val header = ExamHeader().apply { date = it.key }
|
||||
it.value.reversed().map { item ->
|
||||
ExamItem(header, item)
|
||||
}
|
||||
fun onNextWeek() {
|
||||
loadData(currentDate.plusDays(7))
|
||||
reloadView()
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
loadData(currentDate, true)
|
||||
}
|
||||
|
||||
fun onExamItemSelected(item: AbstractFlexibleItem<*>?) {
|
||||
if (item is ExamItem) view?.showExamDialog(item.exam)
|
||||
}
|
||||
|
||||
private fun selectSemester(semesters: List<Semester>, index: Int): Semester {
|
||||
return semesters.single { it.current }.let { currentSemester ->
|
||||
if (index == -1) currentSemester
|
||||
else semesters.single { semester ->
|
||||
semester.run {
|
||||
semesterName - 1 == index && diaryId == currentSemester.diaryId
|
||||
fun onViewReselected() {
|
||||
loadData(now().nextOrSameSchoolDay)
|
||||
reloadView()
|
||||
}
|
||||
|
||||
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
||||
currentDate = date
|
||||
disposable.apply {
|
||||
clear()
|
||||
add(sessionRepository.getSemesters()
|
||||
.delay(200, MILLISECONDS)
|
||||
.map { it.single { semester -> semester.current } }
|
||||
.flatMap {
|
||||
examRepository.getExams(it, currentDate.monday, currentDate.friday, forceRefresh)
|
||||
}.map { it.groupBy { exam -> exam.date }.toSortedMap() }
|
||||
.map { createExamItems(it) }
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.doFinally {
|
||||
view?.run {
|
||||
hideRefresh()
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
view?.apply {
|
||||
updateData(it)
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
}
|
||||
}) {
|
||||
view?.run { showEmpty(isViewEmpty()) }
|
||||
errorHandler.proceed(it)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun createExamItems(items: Map<LocalDate, List<Exam>>): List<ExamItem> {
|
||||
return items.flatMap {
|
||||
ExamHeader(it.key).let { header ->
|
||||
it.value.reversed().map { item -> ExamItem(header, item) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadView() {
|
||||
view?.apply {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
showEmpty(false)
|
||||
clearData()
|
||||
showPreButton(!currentDate.minusDays(7).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(7).isHolidays)
|
||||
updateNavigationWeek("${currentDate.toFormattedString("dd.MM")} - " +
|
||||
currentDate.plusDays(4).toFormattedString("dd.MM"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,19 +9,23 @@ interface ExamView : BaseView {
|
||||
|
||||
fun updateData(data: List<ExamItem>)
|
||||
|
||||
fun updateNavigationWeek(date: String)
|
||||
|
||||
fun clearData()
|
||||
|
||||
fun isViewEmpty(): Boolean
|
||||
|
||||
fun hideRefresh()
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showRefresh(show: Boolean)
|
||||
|
||||
fun showNextButton(show: Boolean)
|
||||
|
||||
fun showPreButton(show: Boolean)
|
||||
|
||||
fun showExamDialog(exam: Exam)
|
||||
|
||||
fun updateNavigationWeek(date: String)
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MenuFragmentView {
|
||||
lateinit var pagerAdapter: BasePagerAdapter
|
||||
|
||||
companion object {
|
||||
private const val SAVED_SEMESTER_KEY = "CURRENT_SEMESTER"
|
||||
|
||||
fun newInstance() = GradeFragment()
|
||||
}
|
||||
|
||||
@ -38,7 +40,7 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MenuFragmentView {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
presenter.onAttachView(this, savedInstanceState?.getInt(SAVED_SEMESTER_KEY))
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
||||
@ -113,8 +115,13 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MenuFragmentView {
|
||||
(pagerAdapter.registeredFragments[index] as? GradeView.GradeChildView)?.onParentChangeSemester()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putInt(SAVED_SEMESTER_KEY, presenter.selectedIndex)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
presenter.onDetachView()
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import io.reactivex.Completable
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradePresenter @Inject constructor(
|
||||
@ -14,16 +14,18 @@ class GradePresenter @Inject constructor(
|
||||
private val schedulers: SchedulersManager,
|
||||
private val sessionRepository: SessionRepository) : BasePresenter<GradeView>(errorHandler) {
|
||||
|
||||
private var semesters = emptyList<Semester>()
|
||||
var selectedIndex = 0
|
||||
private set
|
||||
|
||||
private var selectedIndex = 0
|
||||
private var semesters = emptyList<Semester>()
|
||||
|
||||
private val loadedSemesterId = mutableMapOf<Int, String>()
|
||||
|
||||
override fun attachView(view: GradeView) {
|
||||
super.attachView(view)
|
||||
disposable.add(Completable.timer(150, TimeUnit.MILLISECONDS, schedulers.mainThread())
|
||||
fun onAttachView(view: GradeView, savedIndex: Int?) {
|
||||
super.onAttachView(view)
|
||||
disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread())
|
||||
.subscribe {
|
||||
selectedIndex = savedIndex ?: 0
|
||||
view.initView()
|
||||
loadData()
|
||||
})
|
||||
@ -34,13 +36,13 @@ class GradePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onSemesterSwitch(): Boolean {
|
||||
if (semesters.isNotEmpty()) view?.showSemesterDialog(selectedIndex)
|
||||
if (semesters.isNotEmpty()) view?.showSemesterDialog(selectedIndex - 1)
|
||||
return true
|
||||
}
|
||||
|
||||
fun onSemesterSelected(index: Int) {
|
||||
if (selectedIndex != index) {
|
||||
selectedIndex = index
|
||||
if (selectedIndex != index - 1) {
|
||||
selectedIndex = index + 1
|
||||
loadedSemesterId.clear()
|
||||
view?.let {
|
||||
notifyChildrenSemesterChange()
|
||||
@ -67,9 +69,9 @@ class GradePresenter @Inject constructor(
|
||||
|
||||
private fun loadData() {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map {
|
||||
.doOnSuccess {
|
||||
it.first { item -> item.current }.also { current ->
|
||||
selectedIndex = current.semesterName - 1
|
||||
selectedIndex = if (selectedIndex == 0) current.semesterName else selectedIndex
|
||||
semesters = it.filter { semester -> semester.diaryId == current.diaryId }
|
||||
}
|
||||
}
|
||||
@ -81,7 +83,7 @@ class GradePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadChild(index: Int, forceRefresh: Boolean = false) {
|
||||
semesters.first { it.semesterName == selectedIndex + 1 }.semesterId.also {
|
||||
semesters.first { it.semesterName == selectedIndex }.semesterId.also {
|
||||
if (forceRefresh || loadedSemesterId[index] != it) {
|
||||
view?.notifyChildLoadData(index, it, forceRefresh)
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ class GradeDetailsDialog : DialogFragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(STYLE_NO_TITLE, 0)
|
||||
arguments?.run {
|
||||
grade = getSerializable(ARGUMENT_KEY) as Grade
|
||||
}
|
||||
@ -48,7 +49,7 @@ class GradeDetailsDialog : DialogFragment() {
|
||||
gradeDialogColorValue.text = getString(grade.colorStringId)
|
||||
|
||||
gradeDialogCommentValue.apply {
|
||||
if (grade.comment.isEmpty()) {
|
||||
if (grade.comment.isBlank()) {
|
||||
visibility = GONE
|
||||
gradeDialogComment.visibility = GONE
|
||||
} else text = grade.comment
|
||||
@ -59,15 +60,15 @@ class GradeDetailsDialog : DialogFragment() {
|
||||
setBackgroundResource(grade.valueColor)
|
||||
}
|
||||
|
||||
gradeDialogTeacherValue.text = if (grade.teacher.isEmpty()) {
|
||||
gradeDialogTeacherValue.text = if (grade.teacher.isBlank()) {
|
||||
getString(R.string.all_no_data)
|
||||
} else grade.teacher
|
||||
|
||||
gradeDialogDescriptionValue.text = grade.run {
|
||||
when {
|
||||
description.isEmpty() && gradeSymbol.isNotEmpty() -> gradeSymbol
|
||||
description.isEmpty() && gradeSymbol.isEmpty() -> getString(R.string.all_no_description)
|
||||
gradeSymbol.isNotEmpty() && description.isNotEmpty() -> "$gradeSymbol - $description"
|
||||
description.isBlank() && gradeSymbol.isNotBlank() -> gradeSymbol
|
||||
description.isBlank() && gradeSymbol.isBlank() -> getString(R.string.all_no_description)
|
||||
gradeSymbol.isNotBlank() && description.isNotBlank() -> "$gradeSymbol - $description"
|
||||
else -> description
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
messageContainer = gradeDetailsRecycler
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
@ -47,6 +48,8 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
setOnItemClickListener { presenter.onGradeItemSelected(getItem(it)) }
|
||||
}
|
||||
|
||||
gradeDetailsAdapter.getItemCountOfTypes()
|
||||
|
||||
gradeDetailsRecycler.run {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
adapter = gradeDetailsAdapter
|
||||
@ -100,7 +103,7 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
}
|
||||
|
||||
override fun onParentLoadData(semesterId: String, forceRefresh: Boolean) {
|
||||
presenter.loadData(semesterId, forceRefresh)
|
||||
presenter.onParentViewLoadData(semesterId, forceRefresh)
|
||||
}
|
||||
|
||||
override fun onParentReselected() {
|
||||
@ -108,7 +111,7 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
}
|
||||
|
||||
override fun onParentChangeSemester() {
|
||||
presenter.onParentChangeSemester()
|
||||
presenter.onParentViewChangeSemester()
|
||||
}
|
||||
|
||||
override fun notifyParentDataLoaded(semesterId: String) {
|
||||
@ -129,6 +132,6 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
presenter.onDetachView()
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class GradeDetailsItem(val grade: Grade, private val weightString: String, priva
|
||||
text = grade.entry
|
||||
setBackgroundResource(valueColor)
|
||||
}
|
||||
gradeItemDescription.text = if (grade.description.isNotEmpty()) grade.description else grade.gradeSymbol
|
||||
gradeItemDescription.text = if (grade.description.isNotBlank()) grade.description else grade.gradeSymbol
|
||||
gradeItemDate.text = grade.date.toFormattedString()
|
||||
gradeItemWeight.text = "$weightString: ${grade.weight}"
|
||||
gradeItemNote.visibility = if (grade.isNew) VISIBLE else GONE
|
||||
|
@ -17,12 +17,12 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
private val gradeRepository: GradeRepository,
|
||||
private val sessionRepository: SessionRepository) : BasePresenter<GradeDetailsView>(errorHandler) {
|
||||
|
||||
override fun attachView(view: GradeDetailsView) {
|
||||
super.attachView(view)
|
||||
override fun onAttachView(view: GradeDetailsView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
}
|
||||
|
||||
fun loadData(semesterId: String, forceRefresh: Boolean) {
|
||||
fun onParentViewLoadData(semesterId: String, forceRefresh: Boolean) {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.flatMap { gradeRepository.getGrades(it.first { item -> item.semesterId == semesterId }, forceRefresh) }
|
||||
.map { createGradeItems(it.groupBy { grade -> grade.subject }.toSortedMap()) }
|
||||
@ -76,7 +76,7 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun onParentChangeSemester() {
|
||||
fun onParentViewChangeSemester() {
|
||||
view?.run {
|
||||
showProgress(true)
|
||||
showRefresh(false)
|
||||
|
@ -33,7 +33,8 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
messageContainer = gradeSummaryRecycler
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
@ -81,7 +82,7 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh
|
||||
}
|
||||
|
||||
override fun onParentLoadData(semesterId: String, forceRefresh: Boolean) {
|
||||
presenter.loadData(semesterId, forceRefresh)
|
||||
presenter.onParentViewLoadData(semesterId, forceRefresh)
|
||||
}
|
||||
|
||||
override fun onParentReselected() {
|
||||
@ -89,7 +90,7 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh
|
||||
}
|
||||
|
||||
override fun onParentChangeSemester() {
|
||||
presenter.onParentChangeSemester()
|
||||
presenter.onParentViewChangeSemester()
|
||||
}
|
||||
|
||||
override fun notifyParentDataLoaded(semesterId: String) {
|
||||
@ -106,6 +107,6 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
presenter.onDetachView()
|
||||
}
|
||||
}
|
||||
|
@ -20,12 +20,12 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
private val schedulers: SchedulersManager)
|
||||
: BasePresenter<GradeSummaryView>(errorHandler) {
|
||||
|
||||
override fun attachView(view: GradeSummaryView) {
|
||||
super.attachView(view)
|
||||
override fun onAttachView(view: GradeSummaryView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
}
|
||||
|
||||
fun loadData(semesterId: String, forceRefresh: Boolean) {
|
||||
fun onParentViewLoadData(semesterId: String, forceRefresh: Boolean) {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map { semester -> semester.first { it.semesterId == semesterId } }
|
||||
.flatMap {
|
||||
@ -76,7 +76,7 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun onParentChangeSemester() {
|
||||
fun onParentViewChangeSemester() {
|
||||
view?.run {
|
||||
showProgress(true)
|
||||
showRefresh(false)
|
||||
@ -110,12 +110,12 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
|
||||
private fun checkEmpty(gradeSummary: GradeSummary, averages: Map<String, Double>): Boolean {
|
||||
return gradeSummary.run {
|
||||
finalGrade.isEmpty() && predictedGrade.isEmpty() && averages[subject] == null
|
||||
finalGrade.isBlank() && predictedGrade.isBlank() && averages[subject] == null
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatAverage(average: Double, defaultValue: String = "-- --"): String {
|
||||
return if (average == 0.0 || average.isNaN()) defaultValue
|
||||
return if (average == 0.0) defaultValue
|
||||
else format(FRANCE, "%.2f", average)
|
||||
}
|
||||
}
|
||||
|
@ -28,14 +28,13 @@ class TimetableDialog : DialogFragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogFragmentTheme)
|
||||
setStyle(STYLE_NO_TITLE, 0)
|
||||
arguments?.run {
|
||||
lesson = getSerializable(ARGUMENT_KEY) as Timetable
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
dialog.setTitle(getString(R.string.all_details))
|
||||
return inflater.inflate(R.layout.dialog_timetable, container, false)
|
||||
}
|
||||
|
||||
|
@ -10,11 +10,12 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.main.MainView
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_timetable.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class TimetableFragment : BaseFragment(), TimetableView {
|
||||
class TimetableFragment : BaseFragment(), TimetableView, MainView.MenuFragmentView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: TimetablePresenter
|
||||
@ -24,6 +25,7 @@ class TimetableFragment : BaseFragment(), TimetableView {
|
||||
|
||||
companion object {
|
||||
private const val SAVED_DATE_KEY = "CURRENT_DATE"
|
||||
|
||||
fun newInstance() = TimetableFragment()
|
||||
}
|
||||
|
||||
@ -33,25 +35,22 @@ class TimetableFragment : BaseFragment(), TimetableView {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.run {
|
||||
attachView(this@TimetableFragment)
|
||||
loadData(date = savedInstanceState?.getLong(SAVED_DATE_KEY))
|
||||
}
|
||||
messageContainer = timetableRecycler
|
||||
presenter.onAttachView(this, savedInstanceState?.getLong(SAVED_DATE_KEY))
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
timetableAdapter.run {
|
||||
isAutoCollapseOnExpand = true
|
||||
isAutoScrollOnExpand = true
|
||||
setOnItemClickListener { presenter.onTimetableItemSelected(getItem(it)) }
|
||||
}
|
||||
|
||||
timetableRecycler.run {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
adapter = timetableAdapter
|
||||
}
|
||||
timetableSwipe.setOnRefreshListener { presenter.loadData(date = null, forceRefresh = true) }
|
||||
timetablePreviousButton.setOnClickListener { presenter.loadTimetableForPreviousDay() }
|
||||
timetableNextButton.setOnClickListener { presenter.loadTimetableForNextDay() }
|
||||
timetableSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
timetablePreviousButton.setOnClickListener { presenter.onPreviousDay() }
|
||||
timetableNextButton.setOnClickListener { presenter.onNextDay() }
|
||||
}
|
||||
|
||||
override fun updateData(data: List<TimetableItem>) {
|
||||
@ -68,6 +67,14 @@ class TimetableFragment : BaseFragment(), TimetableView {
|
||||
|
||||
override fun isViewEmpty() = timetableAdapter.isEmpty
|
||||
|
||||
override fun hideRefresh() {
|
||||
timetableSwipe.isRefreshing = false
|
||||
}
|
||||
|
||||
override fun onFragmentReselected() {
|
||||
presenter.onViewReselected()
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
timetableEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
@ -80,10 +87,6 @@ class TimetableFragment : BaseFragment(), TimetableView {
|
||||
timetableRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showRefresh(show: Boolean) {
|
||||
timetableSwipe.isRefreshing = show
|
||||
}
|
||||
|
||||
override fun showPreButton(show: Boolean) {
|
||||
timetablePreviousButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
@ -96,13 +99,15 @@ class TimetableFragment : BaseFragment(), TimetableView {
|
||||
TimetableDialog.newInstance(lesson).show(fragmentManager, lesson.toString())
|
||||
}
|
||||
|
||||
override fun roomString() = getString(R.string.timetable_room)
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
}
|
||||
}
|
||||
|
@ -15,15 +15,29 @@ import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_timetable.*
|
||||
|
||||
class TimetableItem : AbstractFlexibleItem<TimetableItem.ViewHolder>() {
|
||||
class TimetableItem(val lesson: Timetable, private val roomText: String)
|
||||
: AbstractFlexibleItem<TimetableItem.ViewHolder>() {
|
||||
|
||||
lateinit var lesson: Timetable
|
||||
override fun getLayoutRes(): Int = R.layout.item_timetable
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun getLayoutRes(): Int = R.layout.item_timetable
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
timetableItemNumber.text = lesson.number.toString()
|
||||
timetableItemSubject.text = lesson.subject
|
||||
timetableItemRoom.text = if (lesson.room.isNotBlank()) "$roomText ${lesson.room}" else ""
|
||||
timetableItemTime.text = "${lesson.start.toFormattedString("HH:mm")} - ${lesson.end.toFormattedString("HH:mm")}"
|
||||
timetableItemAlert.visibility = if (lesson.changes || lesson.canceled) VISIBLE else GONE
|
||||
timetableItemSubject.paintFlags =
|
||||
if (lesson.canceled) timetableItemSubject.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
else timetableItemSubject.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
@ -39,27 +53,10 @@ class TimetableItem : AbstractFlexibleItem<TimetableItem.ViewHolder>() {
|
||||
return lesson.hashCode()
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.bind(lesson)
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(lesson: Timetable) {
|
||||
timetableItemNumber.text = lesson.number.toString()
|
||||
timetableItemSubject.text = lesson.subject
|
||||
timetableItemRoom.text = if (lesson.room.isNotBlank()) "${view.context.getString(R.string.timetable_room)} ${lesson.room}" else ""
|
||||
timetableItemTime.text = "${lesson.start.toFormattedString("HH:mm")} - ${lesson.end.toFormattedString("HH:mm")}"
|
||||
timetableItemAlert.visibility = if (lesson.changes || lesson.canceled) VISIBLE else GONE
|
||||
timetableItemSubject.paintFlags =
|
||||
if (lesson.canceled) timetableItemSubject.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
else timetableItemSubject.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,15 @@ package io.github.wulkanowy.ui.main.timetable
|
||||
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.LocalDate.now
|
||||
import org.threeten.bp.LocalDate.ofEpochDay
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import javax.inject.Inject
|
||||
|
||||
class TimetablePresenter @Inject constructor(
|
||||
@ -19,75 +20,78 @@ class TimetablePresenter @Inject constructor(
|
||||
private val sessionRepository: SessionRepository
|
||||
) : BasePresenter<TimetableView>(errorHandler) {
|
||||
|
||||
var currentDate: LocalDate = LocalDate.now().nearSchoolDayNextOnWeekEnd
|
||||
lateinit var currentDate: LocalDate
|
||||
private set
|
||||
|
||||
override fun attachView(view: TimetableView) {
|
||||
super.attachView(view)
|
||||
fun onAttachView(view: TimetableView, date: Long?) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
||||
reloadView()
|
||||
}
|
||||
|
||||
fun loadTimetableForPreviousDay() = loadData(currentDate.previousWorkDay.toEpochDay())
|
||||
|
||||
fun loadTimetableForNextDay() = loadData(currentDate.nextWorkDay.toEpochDay())
|
||||
|
||||
fun loadData(date: Long?, forceRefresh: Boolean = false) {
|
||||
this.currentDate = LocalDate.ofEpochDay(date ?: currentDate.nearSchoolDayNextOnWeekEnd.toEpochDay())
|
||||
if (currentDate.isHolidays) return
|
||||
|
||||
disposable.clear()
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map { selectSemester(it, -1) }
|
||||
.flatMap { timetableRepository.getTimetable(it, currentDate, currentDate, forceRefresh) }
|
||||
.map { createTimetableItems(it) }
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.doOnSubscribe {
|
||||
view?.run {
|
||||
showRefresh(forceRefresh)
|
||||
showProgress(!forceRefresh)
|
||||
if (!forceRefresh) clearData()
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||
}
|
||||
}
|
||||
.doFinally {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
view?.run {
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
updateData(it)
|
||||
}
|
||||
}) {
|
||||
view?.run { showEmpty(isViewEmpty()) }
|
||||
errorHandler.proceed(it)
|
||||
})
|
||||
fun onPreviousDay() {
|
||||
loadData(currentDate.previousSchoolDay)
|
||||
reloadView()
|
||||
}
|
||||
|
||||
private fun createTimetableItems(items: List<Timetable>): List<TimetableItem> {
|
||||
return items.map {
|
||||
TimetableItem().apply { lesson = it }
|
||||
fun onNextDay() {
|
||||
loadData(currentDate.nextSchoolDay)
|
||||
reloadView()
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
loadData(currentDate, true)
|
||||
}
|
||||
|
||||
fun onViewReselected() {
|
||||
loadData(now().nextOrSameSchoolDay)
|
||||
reloadView()
|
||||
}
|
||||
|
||||
fun onTimetableItemSelected(item: AbstractFlexibleItem<*>?) {
|
||||
if (item is TimetableItem) view?.showTimetableDialog(item.lesson)
|
||||
}
|
||||
|
||||
private fun selectSemester(semesters: List<Semester>, index: Int): Semester {
|
||||
return semesters.single { it.current }.let { currentSemester ->
|
||||
if (index == -1) currentSemester
|
||||
else semesters.single { semester ->
|
||||
semester.run {
|
||||
semesterName - 1 == index && diaryId == currentSemester.diaryId
|
||||
}
|
||||
}
|
||||
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
||||
currentDate = date
|
||||
disposable.apply {
|
||||
clear()
|
||||
add(sessionRepository.getSemesters()
|
||||
.delay(200, MILLISECONDS)
|
||||
.map { it.single { semester -> semester.current } }
|
||||
.flatMap { timetableRepository.getTimetable(it, currentDate, currentDate, forceRefresh) }
|
||||
.map { items -> items.map { TimetableItem(it, view?.roomString().orEmpty()) } }
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.doFinally {
|
||||
view?.run {
|
||||
hideRefresh()
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
view?.apply {
|
||||
updateData(it)
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
}
|
||||
}) {
|
||||
view?.run { showEmpty(isViewEmpty()) }
|
||||
errorHandler.proceed(it)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadView() {
|
||||
view?.apply {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
showEmpty(false)
|
||||
clearData()
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,20 +11,23 @@ interface TimetableView : BaseView {
|
||||
|
||||
fun updateNavigationDay(date: String)
|
||||
|
||||
fun isViewEmpty(): Boolean
|
||||
|
||||
fun clearData()
|
||||
|
||||
fun hideRefresh()
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showRefresh(show: Boolean)
|
||||
|
||||
fun showPreButton(show: Boolean)
|
||||
|
||||
fun showNextButton(show: Boolean)
|
||||
|
||||
fun showTimetableDialog(lesson: Timetable)
|
||||
|
||||
fun isViewEmpty(): Boolean
|
||||
fun clearData()
|
||||
fun roomString(): String
|
||||
}
|
||||
|
@ -13,12 +13,7 @@ class SplashActivity : BaseActivity(), SplashView {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
presenter.detachView()
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun openLoginView() {
|
||||
@ -30,4 +25,9 @@ class SplashActivity : BaseActivity(), SplashView {
|
||||
startActivity(MainActivity.getStartIntent(this))
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ class SplashPresenter @Inject constructor(private val sessionRepository: Session
|
||||
errorHandler: ErrorHandler)
|
||||
: BasePresenter<SplashView>(errorHandler) {
|
||||
|
||||
override fun attachView(view: SplashView) {
|
||||
super.attachView(view)
|
||||
override fun onAttachView(view: SplashView) {
|
||||
super.onAttachView(view)
|
||||
view.run { if (sessionRepository.isSessionSaved) openMainView() else openLoginView() }
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ fun List<Grade>.calcAverage(): Double {
|
||||
fun List<GradeSummary>.calcAverage(): Double {
|
||||
return asSequence().mapNotNull {
|
||||
if (it.finalGrade.matches("[0-6]".toRegex())) it.finalGrade.toDouble() else null
|
||||
}.average()
|
||||
}.average().let { if (it.isNaN()) 0.0 else it }
|
||||
}
|
||||
|
||||
inline val Grade.valueColor: Int
|
||||
@ -43,6 +43,7 @@ inline val Grade.colorStringId: Int
|
||||
"F04C4C" -> R.string.all_red
|
||||
"20A4F7" -> R.string.all_blue
|
||||
"6ECD07" -> R.string.all_green
|
||||
"B16CF1" -> R.string.all_purple
|
||||
else -> R.string.all_empty_color
|
||||
}
|
||||
}
|
@ -1,23 +1,24 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import org.threeten.bp.DayOfWeek.*
|
||||
import org.threeten.bp.Instant
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.LocalDateTime
|
||||
import org.threeten.bp.ZoneId
|
||||
import org.threeten.bp.format.DateTimeFormatter
|
||||
import org.threeten.bp.format.DateTimeFormatter.ofPattern
|
||||
import org.threeten.bp.temporal.TemporalAdjusters
|
||||
import org.threeten.bp.temporal.TemporalAdjusters.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
private const val DATE_PATTERN = "yyyy-MM-dd"
|
||||
private const val DATE_PATTERN = "dd.MM.yyyy"
|
||||
|
||||
fun Date.toLocalDate(): LocalDate {
|
||||
return LocalDate.parse(SimpleDateFormat(DATE_PATTERN, Locale.getDefault()).format(this))
|
||||
return Instant.ofEpochMilli(this.time).atZone(ZoneId.systemDefault()).toLocalDate()
|
||||
}
|
||||
|
||||
fun Date.toLocalDateTime(): LocalDateTime = LocalDateTime.parse(SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
|
||||
Locale.getDefault()).format(this), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||
fun Date.toLocalDateTime(): LocalDateTime {
|
||||
return Instant.ofEpochMilli(this.time).atZone(ZoneId.systemDefault()).toLocalDateTime()
|
||||
}
|
||||
|
||||
fun String.toLocalDate(format: String = DATE_PATTERN): LocalDate {
|
||||
return LocalDate.parse(this, DateTimeFormatter.ofPattern(format))
|
||||
@ -25,9 +26,9 @@ fun String.toLocalDate(format: String = DATE_PATTERN): LocalDate {
|
||||
|
||||
fun LocalDate.toFormattedString(format: String = DATE_PATTERN): String = this.format(ofPattern(format))
|
||||
|
||||
fun LocalDateTime.toFormattedString(format: String = DATE_PATTERN): String = this.format(DateTimeFormatter.ofPattern(format))
|
||||
fun LocalDateTime.toFormattedString(format: String = DATE_PATTERN): String = this.format(ofPattern(format))
|
||||
|
||||
inline val LocalDate.nextWorkDay: LocalDate
|
||||
inline val LocalDate.nextSchoolDay: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
FRIDAY, SATURDAY, SUNDAY -> this.with(next(MONDAY))
|
||||
@ -35,7 +36,7 @@ inline val LocalDate.nextWorkDay: LocalDate
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.previousWorkDay: LocalDate
|
||||
inline val LocalDate.previousSchoolDay: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY, MONDAY -> this.with(previous(FRIDAY))
|
||||
@ -43,7 +44,15 @@ inline val LocalDate.previousWorkDay: LocalDate
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.nearSchoolDayPrevOnWeekEnd: LocalDate
|
||||
inline val LocalDate.nextOrSameSchoolDay: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY -> this.with(next(MONDAY))
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.previousOrSameSchoolDay: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY -> this.with(previous(FRIDAY))
|
||||
@ -51,27 +60,14 @@ inline val LocalDate.nearSchoolDayPrevOnWeekEnd: LocalDate
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.nearSchoolDayNextOnWeekEnd: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY -> this.with(next(MONDAY))
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.weekDayName: String
|
||||
get() = this.format(ofPattern("EEEE", Locale.getDefault()))
|
||||
|
||||
inline val LocalDate.weekFirstDayAlwaysCurrent: LocalDate
|
||||
get() = this.with(TemporalAdjusters.previousOrSame(MONDAY))
|
||||
inline val LocalDate.monday: LocalDate
|
||||
get() = this.with(MONDAY)
|
||||
|
||||
inline val LocalDate.weekFirstDayNextOnWeekEnd: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY -> this.with(next(MONDAY))
|
||||
else -> this.with(previousOrSame(MONDAY))
|
||||
}
|
||||
}
|
||||
inline val LocalDate.friday: LocalDate
|
||||
get() = this.with(FRIDAY)
|
||||
|
||||
/**
|
||||
* [Dz.U. 2016 poz. 1335](http://prawo.sejm.gov.pl/isap.nsf/DocDetails.xsp?id=WDU20160001335)
|
||||
|
@ -11,7 +11,7 @@ import android.security.KeyPairGeneratorSpec
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties.*
|
||||
import android.util.Base64
|
||||
import android.util.Base64.DEFAULT
|
||||
import android.util.Base64.*
|
||||
import timber.log.Timber
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
@ -20,8 +20,8 @@ import java.nio.charset.Charset
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.KeyStore
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
import java.util.*
|
||||
import java.util.Calendar.YEAR
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.Cipher.DECRYPT_MODE
|
||||
import javax.crypto.Cipher.ENCRYPT_MODE
|
||||
@ -30,8 +30,6 @@ import javax.crypto.CipherOutputStream
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
object Scrambler {
|
||||
|
||||
private const val KEY_ALIAS = "USER_PASSWORD"
|
||||
|
||||
private const val ALGORITHM_RSA = "RSA"
|
||||
@ -46,7 +44,18 @@ object Scrambler {
|
||||
|
||||
private val KEY_CHARSET = Charset.forName("UTF-8")
|
||||
|
||||
@JvmStatic
|
||||
private val isKeyPairExists: Boolean
|
||||
get() = keyStore.getKey(KEY_ALIAS, null) != null
|
||||
|
||||
private val cipher: Cipher
|
||||
get() {
|
||||
return if (SDK_INT >= M) Cipher.getInstance(KEY_TRANSFORMATION_ALGORITHM, KEY_CIPHER_M_PROVIDER)
|
||||
else Cipher.getInstance(KEY_TRANSFORMATION_ALGORITHM, KEY_CIPHER_JELLY_PROVIDER)
|
||||
}
|
||||
|
||||
private val keyStore: KeyStore
|
||||
get() = KeyStore.getInstance(KEYSTORE_NAME).apply { load(null) }
|
||||
|
||||
fun encrypt(plainText: String, context: Context): String {
|
||||
if (plainText.isEmpty()) throw ScramblerException("Text to be encrypted is empty")
|
||||
|
||||
@ -55,79 +64,59 @@ object Scrambler {
|
||||
}
|
||||
|
||||
return try {
|
||||
if (!isKeyPairExist()) generateKeyPair(context)
|
||||
if (!isKeyPairExists) generateKeyPair(context)
|
||||
cipher.let {
|
||||
it.init(ENCRYPT_MODE, keyStore.getCertificate(KEY_ALIAS).publicKey)
|
||||
|
||||
val cipher = getCipher()
|
||||
cipher.init(ENCRYPT_MODE, getPublicKey())
|
||||
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
val cipherOutputStream = CipherOutputStream(outputStream, cipher)
|
||||
cipherOutputStream.write(plainText.toByteArray(KEY_CHARSET))
|
||||
cipherOutputStream.close()
|
||||
|
||||
Base64.encodeToString(outputStream.toByteArray(), DEFAULT)
|
||||
ByteArrayOutputStream().let { output ->
|
||||
CipherOutputStream(output, it).apply {
|
||||
write(plainText.toByteArray(KEY_CHARSET))
|
||||
close()
|
||||
}
|
||||
encodeToString(output.toByteArray(), DEFAULT)
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
Timber.e(exception, "An error occurred while encrypting text")
|
||||
String(Base64.encode(plainText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
|
||||
String(encode(plainText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun decrypt(cipherText: String): String {
|
||||
if (cipherText.isEmpty()) throw ScramblerException("Text to be encrypted is empty")
|
||||
|
||||
if (SDK_INT < JELLY_BEAN_MR2 || cipherText.length < 250) {
|
||||
return String(Base64.decode(cipherText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
|
||||
return String(decode(cipherText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
|
||||
}
|
||||
|
||||
if (!isKeyPairExist()) throw ScramblerException("KeyPair doesn't exist")
|
||||
if (!isKeyPairExists) throw ScramblerException("KeyPair doesn't exist")
|
||||
|
||||
try {
|
||||
val cipher = getCipher()
|
||||
cipher.init(DECRYPT_MODE, getPrivateKey())
|
||||
return try {
|
||||
cipher.let {
|
||||
it.init(DECRYPT_MODE, (keyStore.getKey(KEY_ALIAS, null) as PrivateKey))
|
||||
|
||||
val input = CipherInputStream(ByteArrayInputStream(Base64.decode(cipherText, DEFAULT)), cipher)
|
||||
CipherInputStream(ByteArrayInputStream(decode(cipherText, DEFAULT)), it).let { input ->
|
||||
val values = ArrayList<Byte>()
|
||||
|
||||
var nextByte = 0
|
||||
while ({ nextByte = input.read(); nextByte }() != -1) {
|
||||
values.add(nextByte.toByte())
|
||||
}
|
||||
|
||||
val bytes = ByteArray(values.size)
|
||||
for (i in bytes.indices) {
|
||||
bytes[i] = values[i]
|
||||
}
|
||||
return String(bytes, 0, bytes.size, KEY_CHARSET)
|
||||
String(bytes, 0, bytes.size, KEY_CHARSET)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw ScramblerException("An error occurred while decrypting text", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getKeyStoreInstance(): KeyStore {
|
||||
val keyStore = KeyStore.getInstance(KEYSTORE_NAME)
|
||||
keyStore.load(null)
|
||||
return keyStore
|
||||
}
|
||||
|
||||
private fun getPublicKey(): PublicKey =
|
||||
(getKeyStoreInstance().getEntry(KEY_ALIAS, null) as KeyStore.PrivateKeyEntry)
|
||||
.certificate.publicKey
|
||||
|
||||
|
||||
private fun getPrivateKey(): PrivateKey =
|
||||
(getKeyStoreInstance().getEntry(KEY_ALIAS, null) as KeyStore.PrivateKeyEntry).privateKey
|
||||
|
||||
|
||||
private fun getCipher(): Cipher {
|
||||
return if (SDK_INT >= M) Cipher.getInstance(KEY_TRANSFORMATION_ALGORITHM, KEY_CIPHER_M_PROVIDER)
|
||||
else Cipher.getInstance(KEY_TRANSFORMATION_ALGORITHM, KEY_CIPHER_JELLY_PROVIDER)
|
||||
}
|
||||
|
||||
@TargetApi(JELLY_BEAN_MR2)
|
||||
private fun generateKeyPair(context: Context) {
|
||||
val spec = if (SDK_INT >= M) {
|
||||
(if (SDK_INT >= M) {
|
||||
KeyGenParameterSpec.Builder(KEY_ALIAS, PURPOSE_DECRYPT or PURPOSE_ENCRYPT)
|
||||
.setDigests(DIGEST_SHA256, DIGEST_SHA512)
|
||||
.setCertificateSubject(X500Principal("CN=Wulkanowy"))
|
||||
@ -136,25 +125,19 @@ object Scrambler {
|
||||
.setCertificateSerialNumber(BigInteger.TEN)
|
||||
.build()
|
||||
} else {
|
||||
val start = Calendar.getInstance()
|
||||
val end = Calendar.getInstance()
|
||||
end.add(Calendar.YEAR, 99)
|
||||
|
||||
KeyPairGeneratorSpec.Builder(context)
|
||||
.setAlias(KEY_ALIAS)
|
||||
.setSubject(X500Principal("CN=Wulkanowy"))
|
||||
.setSerialNumber(BigInteger.TEN)
|
||||
.setStartDate(start.time)
|
||||
.setEndDate(end.time)
|
||||
.setStartDate(Calendar.getInstance().time)
|
||||
.setEndDate(Calendar.getInstance().apply { add(YEAR, 99) }.time)
|
||||
.build()
|
||||
}).let {
|
||||
KeyPairGenerator.getInstance(ALGORITHM_RSA, KEYSTORE_NAME).apply {
|
||||
initialize(it)
|
||||
genKeyPair()
|
||||
}
|
||||
}
|
||||
|
||||
val generator = KeyPairGenerator.getInstance(ALGORITHM_RSA, KEYSTORE_NAME)
|
||||
generator.initialize(spec)
|
||||
generator.generateKeyPair()
|
||||
|
||||
Timber.i("A new KeyPair has been generated")
|
||||
}
|
||||
|
||||
private fun isKeyPairExist(): Boolean = getKeyStoreInstance().getKey(KEY_ALIAS, null) != null
|
||||
}
|
||||
|
@ -4,17 +4,24 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="300dp"
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendance_dialog_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:text="@string/all_details"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/all_subject"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
@ -81,10 +88,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="15dp"
|
||||
android:padding="0dp"
|
||||
android:text="@string/all_close"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="15sp" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
@ -4,18 +4,25 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="300dp"
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exam_dialog_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:text="@string/all_details"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/examDialogSubject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/all_subject"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
@ -33,7 +40,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/exam_type"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
@ -102,8 +108,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="15dp"
|
||||
android:padding="0dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="@string/all_close"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="15sp" />
|
||||
|
@ -4,12 +4,20 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="300dp"
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exam_dialog_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:text="@string/all_details"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableDialogChangesTitle"
|
||||
android:layout_width="wrap_content"
|
||||
@ -33,7 +41,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/timetable_lesson"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
@ -119,7 +126,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="15dp"
|
||||
android:padding="0dp"
|
||||
android:text="@string/all_close"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="15sp" />
|
||||
|
@ -1,15 +1,13 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="50dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/attendanceProgress"
|
||||
@ -42,8 +40,8 @@
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="100dp"
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
app:srcCompat="@drawable/ic_menu_main_attendance_24dp"
|
||||
app:tint="?android:attr/textColorPrimary"
|
||||
tools:ignore="contentDescription" />
|
||||
@ -56,12 +54,14 @@
|
||||
android:text="@string/attendance_no_items"
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="50dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@android:color/white"
|
||||
android:elevation="10dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
@ -72,7 +72,7 @@
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="start|center"
|
||||
android:text="@string/prev"
|
||||
android:text="@string/all_prev"
|
||||
android:textAlignment="gravity" />
|
||||
|
||||
<TextView
|
||||
@ -91,9 +91,7 @@
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="end|center"
|
||||
android:text="@string/next"
|
||||
android:text="@string/all_next"
|
||||
android:textAlignment="gravity" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -1,63 +0,0 @@
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/attendance_tab_fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="io.github.wulkanowy.ui.main.grades.GradesFragment">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/attendance_tab_fragment_progress_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/attendance_tab_fragment_no_item_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center">
|
||||
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/attendance_tab_fragment_no_item_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/attendance_tab_fragment_no_item_text"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="40dp"
|
||||
android:minHeight="100dp"
|
||||
android:minWidth="100dp"
|
||||
app:tint="?android:attr/textColorPrimary"
|
||||
app:srcCompat="@drawable/ic_menu_main_attendance_24dp"
|
||||
tools:ignore="contentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendance_tab_fragment_no_item_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="46dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/attendance_no_items"
|
||||
android:textSize="20sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/attendance_tab_fragment_swipe_refresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/attendance_tab_fragment_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
@ -1,15 +1,13 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="50dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/examProgress"
|
||||
@ -42,8 +40,8 @@
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="100dp"
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
app:srcCompat="@drawable/ic_menu_main_exam_24dp"
|
||||
app:tint="?android:attr/textColorPrimary"
|
||||
tools:ignore="contentDescription" />
|
||||
@ -56,12 +54,14 @@
|
||||
android:text="@string/exam_no_items"
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="50dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@android:color/white"
|
||||
android:elevation="10dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
@ -72,7 +72,7 @@
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="start|center"
|
||||
android:text="@string/prev"
|
||||
android:text="@string/all_prev"
|
||||
android:textAlignment="gravity" />
|
||||
|
||||
<TextView
|
||||
@ -91,9 +91,7 @@
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="end|center"
|
||||
android:text="@string/next"
|
||||
android:text="@string/all_next"
|
||||
android:textAlignment="gravity" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
@ -7,7 +7,7 @@
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/gradeTabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:background="@color/colorPrimary"
|
||||
android:elevation="5dp"
|
||||
android:visibility="invisible"
|
||||
@ -21,13 +21,13 @@
|
||||
android:id="@+id/gradeViewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/gradeTabLayout"
|
||||
android:layout_marginTop="48dp"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/gradeProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true" />
|
||||
</RelativeLayout>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
@ -1,15 +1,13 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="50dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/timetableProgress"
|
||||
@ -42,8 +40,8 @@
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="100dp"
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
app:srcCompat="@drawable/ic_menu_main_timetable_24dp"
|
||||
app:tint="?android:attr/textColorPrimary"
|
||||
tools:ignore="contentDescription" />
|
||||
@ -56,12 +54,14 @@
|
||||
android:text="@string/timetable_no_items"
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="50dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@android:color/white"
|
||||
android:elevation="10dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
@ -72,7 +72,7 @@
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="start|center"
|
||||
android:text="@string/prev"
|
||||
android:text="@string/all_prev"
|
||||
android:textAlignment="gravity" />
|
||||
|
||||
<TextView
|
||||
@ -91,9 +91,7 @@
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="end|center"
|
||||
android:text="@string/next"
|
||||
android:text="@string/all_next"
|
||||
android:textAlignment="gravity" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -1,86 +0,0 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless">
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendance_header_day"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_toLeftOf="@id/attendance_header_alert_image"
|
||||
android:layout_toStartOf="@+id/attendance_header_alert_image"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="19sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendance_header_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/attendance_header_day"
|
||||
android:layout_marginTop="5dp"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendance_header_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/attendance_header_date"
|
||||
android:layout_toRightOf="@+id/attendance_header_date"
|
||||
android:layout_below="@+id/attendance_header_day"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendance_header_free_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="180dp"
|
||||
android:layout_marginStart="180dp"
|
||||
android:gravity="end"
|
||||
android:maxLines="2"
|
||||
android:text="@string/attendance_no_items"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/attendance_header_alert_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="10dp"
|
||||
app:srcCompat="@drawable/ic_all_note_24dp"
|
||||
tools:ignore="contentDescription" />
|
||||
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
@ -1,19 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorControlHighlight"
|
||||
android:minHeight="40dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingTop="10dp">
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/examHeaderDay"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="18sp" />
|
||||
|
||||
@ -21,15 +22,10 @@
|
||||
android:id="@+id/examHeaderDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_toEndOf="@id/examHeaderDay"
|
||||
android:layout_toRightOf="@id/examHeaderDay"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:gravity="end"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="13sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
@ -1,22 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorControlHighlight"
|
||||
android:paddingBottom="7dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingTop="7dp">
|
||||
android:paddingBottom="7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeSummaryHeaderName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toLeftOf="@id/gradeSummaryHeaderAverage"
|
||||
android:layout_toStartOf="@id/gradeSummaryHeaderAverage"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="17sp" />
|
||||
|
||||
@ -24,11 +23,8 @@
|
||||
android:id="@+id/gradeSummaryHeaderAverage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="end"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="12sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
@ -1,71 +0,0 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless">
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetable_header_day"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_toLeftOf="@id/timetable_header_alert_image"
|
||||
android:layout_toStartOf="@+id/timetable_header_alert_image"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="19sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetable_header_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/timetable_header_day"
|
||||
android:layout_marginTop="5dp"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetable_header_free_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="180dp"
|
||||
android:layout_marginStart="180dp"
|
||||
android:gravity="end"
|
||||
android:maxLines="2"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/timetable_header_alert_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="10dp"
|
||||
app:srcCompat="@drawable/ic_all_note_24dp"
|
||||
tools:ignore="contentDescription" />
|
||||
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
@ -4,6 +4,7 @@
|
||||
android:id="@+id/attendanceItemContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingLeft="12dp"
|
||||
|
@ -2,14 +2,15 @@
|
||||
android:id="@+id/exams_subitem_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/examItemSubject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="15sp" />
|
||||
@ -18,11 +19,11 @@
|
||||
android:id="@+id/examItemType"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/examItemSubject"
|
||||
android:layout_alignStart="@id/examItemSubject"
|
||||
android:layout_below="@id/examItemSubject"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_alignStart="@id/examItemSubject"
|
||||
android:layout_alignLeft="@id/examItemSubject"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="13sp" />
|
||||
|
||||
@ -30,15 +31,15 @@
|
||||
android:id="@+id/examItemTeacher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/examItemSubject"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_below="@id/examItemSubject"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_toEndOf="@id/examItemType"
|
||||
android:layout_toRightOf="@id/examItemType"
|
||||
android:gravity="end"
|
||||
|
@ -1,16 +1,18 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:minHeight="35dp">
|
||||
android:minHeight="35dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeSummaryItemTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/grade_summary_predicted_grade"
|
||||
android:textSize="14sp" />
|
||||
|
||||
@ -18,16 +20,12 @@
|
||||
android:id="@+id/gradeSummaryItemGrade"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="25dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_toEndOf="@id/gradeSummaryItemTitle"
|
||||
android:layout_toRightOf="@id/gradeSummaryItemTitle"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginRight="25dp"
|
||||
android:gravity="end"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
@ -4,13 +4,14 @@
|
||||
android:id="@+id/timetable_subitem_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingBottom="7dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingTop="7dp">
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableItemNumber"
|
||||
@ -28,10 +29,10 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toEndOf="@+id/timetableItemNumber"
|
||||
android:layout_toRightOf="@+id/timetableItemNumber"
|
||||
android:ellipsize="end"
|
||||
@ -44,9 +45,9 @@
|
||||
android:id="@+id/timetableItemTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/timetableItemNumber"
|
||||
android:layout_alignLeft="@id/timetableItemSubject"
|
||||
android:layout_alignStart="@id/timetableItemSubject"
|
||||
android:layout_alignLeft="@id/timetableItemSubject"
|
||||
android:layout_alignBottom="@+id/timetableItemNumber"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
@ -57,10 +58,10 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/timetableItemNumber"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toEndOf="@+id/timetableItemTime"
|
||||
android:layout_toRightOf="@+id/timetableItemTime"
|
||||
android:maxLines="1"
|
||||
|
@ -104,6 +104,8 @@
|
||||
<string name="all_cancel">Anuluj</string>
|
||||
<string name="all_no_data">Brak danych</string>
|
||||
<string name="all_subject">Przedmiot</string>
|
||||
<string name="all_prev">Poprzedni</string>
|
||||
<string name="all_next">Następny</string>
|
||||
|
||||
|
||||
<!--Timetable Widget-->
|
||||
@ -157,6 +159,7 @@
|
||||
<string name="all_red">Czerwony</string>
|
||||
<string name="all_blue">Niebieski</string>
|
||||
<string name="all_green">Zielony</string>
|
||||
<string name="all_purple">Fioletowy</string>
|
||||
<string name="all_empty_color">Brak koloru</string>
|
||||
|
||||
|
||||
@ -166,7 +169,4 @@
|
||||
<string name="all_sync_fail">Podczas synchronizacji wystąpił błąd</string>
|
||||
<string name="all_timeout">Zbyt długie oczekiwanie na połączenie</string>
|
||||
<string name="all_login_failed">Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację</string>
|
||||
|
||||
<string name="prev">Poprzedni</string>
|
||||
<string name="next">Następny</string>
|
||||
</resources>
|
||||
|
@ -59,7 +59,7 @@
|
||||
|
||||
<!--Timetable-->
|
||||
<string name="timetable_lesson">Lesson</string>
|
||||
<string name="timetable_room">Room %s</string>
|
||||
<string name="timetable_room">Room</string>
|
||||
<string name="timetable_group">Group</string>
|
||||
<string name="timetable_time">Hours</string>
|
||||
<string name="timetable_changes">Changes</string>
|
||||
@ -99,6 +99,8 @@
|
||||
<string name="all_cancel">Cancel</string>
|
||||
<string name="all_no_data">No data</string>
|
||||
<string name="all_subject">Subject</string>
|
||||
<string name="all_prev">Prev</string>
|
||||
<string name="all_next">Next</string>
|
||||
|
||||
|
||||
<!--Timetable Widget-->
|
||||
@ -150,6 +152,7 @@
|
||||
<string name="all_red">Red</string>
|
||||
<string name="all_blue">Blue</string>
|
||||
<string name="all_green">Green</string>
|
||||
<string name="all_purple">Purple</string>
|
||||
<string name="all_empty_color">No color</string>
|
||||
|
||||
|
||||
@ -159,6 +162,4 @@
|
||||
<string name="all_sync_fail">There was an error during synchronization</string>
|
||||
<string name="all_timeout">Too long wait for connection</string>
|
||||
<string name="all_login_failed">Login is failed. Try again or restart the app</string>
|
||||
<string name="prev">Prev</string>
|
||||
<string name="next">Next</string>
|
||||
</resources>
|
||||
|
@ -11,7 +11,6 @@ import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.LocalDateTime
|
||||
import java.sql.Date
|
||||
|
||||
class TimetableRemoteTest {
|
||||
@ -41,7 +40,7 @@ class TimetableRemoteTest {
|
||||
every { semesterMock.studentId } returns "1"
|
||||
every { semesterMock.diaryId } returns "1"
|
||||
|
||||
val timetable = TimetableRemote(mockApi).getLessons(semesterMock,
|
||||
val timetable = TimetableRemote(mockApi).getTimetable(semesterMock,
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 15)
|
||||
).blockingGet()
|
||||
|
@ -22,7 +22,7 @@ class LoginPresenterTest {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
clearInvocations(loginView)
|
||||
presenter = LoginPresenter(errorHandler)
|
||||
presenter.attachView(loginView)
|
||||
presenter.onAttachView(loginView)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -31,7 +31,7 @@ class LoginFormPresenterTest {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
clearInvocations(repository, loginFormView)
|
||||
presenter = LoginFormPresenter(TestSchedulers(), errorHandler, repository)
|
||||
presenter.attachView(loginFormView)
|
||||
presenter.onAttachView(loginFormView)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -35,7 +35,7 @@ class LoginOptionsPresenterTest {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
clearInvocations(repository, loginOptionsView)
|
||||
presenter = LoginOptionsPresenter(errorHandler, repository, TestSchedulers())
|
||||
presenter.attachView(loginOptionsView)
|
||||
presenter.onAttachView(loginOptionsView)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -23,7 +23,7 @@ class MainPresenterTest {
|
||||
clearInvocations(mainView)
|
||||
|
||||
presenter = MainPresenter(errorHandler)
|
||||
presenter.attachView(mainView)
|
||||
presenter.onAttachView(mainView)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -31,14 +31,14 @@ class SplashPresenterTest {
|
||||
@Test
|
||||
fun testOpenLoginView() {
|
||||
doReturn(false).`when`(sessionRepository).isSessionSaved
|
||||
presenter.attachView(splashView)
|
||||
presenter.onAttachView(splashView)
|
||||
verify(splashView).openLoginView()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMainMainView() {
|
||||
doReturn(true).`when`(sessionRepository).isSessionSaved
|
||||
presenter.attachView(splashView)
|
||||
presenter.onAttachView(splashView)
|
||||
verify(splashView).openMainView()
|
||||
}
|
||||
}
|
||||
|
@ -34,14 +34,10 @@ class GradeExtensionTest {
|
||||
@Test
|
||||
fun calcSummaryAverage() {
|
||||
assertEquals(2.5, listOf(
|
||||
GradeSummary(0, "", "", "", "",
|
||||
"5"),
|
||||
GradeSummary(0, "", "", "", "",
|
||||
"-5"),
|
||||
GradeSummary(0, "", "", "", "",
|
||||
"test"),
|
||||
GradeSummary(0, "", "", "", "",
|
||||
"0")
|
||||
GradeSummary("", "", "", "", "5"),
|
||||
GradeSummary("", "", "", "", "-5"),
|
||||
GradeSummary("", "", "", "", "test"),
|
||||
GradeSummary("", "", "", "", "0")
|
||||
).calcAverage(), 0.005)
|
||||
}
|
||||
}
|
||||
|
@ -14,33 +14,33 @@ class TimeExtensionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun toFormattedStringTest() {
|
||||
assertEquals("2018-10-01", LocalDate.of(2018, 10, 1).toFormattedString())
|
||||
fun toFormattedStringLocalDateTest() {
|
||||
assertEquals("01.10.2018", LocalDate.of(2018, 10, 1).toFormattedString())
|
||||
assertEquals("2018-10.01", LocalDate.of(2018, 10, 1).toFormattedString("yyyy-MM.dd"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun toFormat_LocalDateTime() {
|
||||
assertEquals("2018-10-01", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString())
|
||||
fun toFormattedStringLocalDateTimeTest() {
|
||||
assertEquals("01.10.2018", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString())
|
||||
assertEquals("2018-10-01 10:00:00", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString("uuuu-MM-dd HH:mm:ss"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun weekFirstDayAlwaysCurrentTest() {
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 2).weekFirstDayAlwaysCurrent)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 5).weekFirstDayAlwaysCurrent)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 6).weekFirstDayAlwaysCurrent)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 7).weekFirstDayAlwaysCurrent)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 8).weekFirstDayAlwaysCurrent)
|
||||
fun mondayTest() {
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 2).monday)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 5).monday)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 6).monday)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 7).monday)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 8).monday)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun weekFirstDayNextOnWeekEndTest() {
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 2).weekFirstDayNextOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 5).weekFirstDayNextOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 6).weekFirstDayNextOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 7).weekFirstDayNextOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 8).weekFirstDayNextOnWeekEnd)
|
||||
fun fridayTest() {
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 2).friday)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 5).friday)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 6).friday)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 7).friday)
|
||||
assertEquals(LocalDate.of(2018, 10, 12), LocalDate.of(2018, 10, 8).friday)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -53,43 +53,44 @@ class TimeExtensionTest {
|
||||
|
||||
@Test
|
||||
fun nextSchoolDayTest() {
|
||||
assertEquals(LocalDate.of(2018, 10, 2), LocalDate.of(2018, 10, 1).nextWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 3), LocalDate.of(2018, 10, 2).nextWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 4), LocalDate.of(2018, 10, 3).nextWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 4).nextWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 5).nextWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 6).nextWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 7).nextWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 9), LocalDate.of(2018, 10, 8).nextWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 2), LocalDate.of(2018, 10, 1).nextSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 3), LocalDate.of(2018, 10, 2).nextSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 4), LocalDate.of(2018, 10, 3).nextSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 4).nextSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 5).nextSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 6).nextSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 7).nextSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 9), LocalDate.of(2018, 10, 8).nextSchoolDay)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun previousSchoolDayTest() {
|
||||
assertEquals(LocalDate.of(2018, 10, 9), LocalDate.of(2018, 10, 10).previousWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 9).previousWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 8).previousWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 7).previousWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 6).previousWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 4), LocalDate.of(2018, 10, 5).previousWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 3), LocalDate.of(2018, 10, 4).previousWorkDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 9), LocalDate.of(2018, 10, 10).previousSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 8), LocalDate.of(2018, 10, 9).previousSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 8).previousSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 7).previousSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 5), LocalDate.of(2018, 10, 6).previousSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 4), LocalDate.of(2018, 10, 5).previousSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 3), LocalDate.of(2018, 10, 4).previousSchoolDay)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun nextOrSameSchoolDayTest() {
|
||||
assertEquals(LocalDate.of(2018, 9, 28), LocalDate.of(2018, 9, 28).nextOrSameSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 9, 29).nextOrSameSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 9, 30).nextOrSameSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 1).nextOrSameSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 2), LocalDate.of(2018, 10, 2).nextOrSameSchoolDay)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nearSchoolDayPrevOnWeekEndTest() {
|
||||
assertEquals(LocalDate.of(2018, 9, 28), LocalDate.of(2018, 9, 28).nearSchoolDayPrevOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 9, 28), LocalDate.of(2018, 9, 29).nearSchoolDayPrevOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 9, 28), LocalDate.of(2018, 9, 30).nearSchoolDayPrevOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 1).nearSchoolDayPrevOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 2), LocalDate.of(2018, 10, 2).nearSchoolDayPrevOnWeekEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nearSchoolDayNextOnWeekEndTest() {
|
||||
assertEquals(LocalDate.of(2018, 9, 28), LocalDate.of(2018, 9, 28).nearSchoolDayNextOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 9, 29).nearSchoolDayNextOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 9, 30).nearSchoolDayNextOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 1).nearSchoolDayNextOnWeekEnd)
|
||||
assertEquals(LocalDate.of(2018, 10, 2), LocalDate.of(2018, 10, 2).nearSchoolDayNextOnWeekEnd)
|
||||
fun previousOrSameSchoolDayTest() {
|
||||
assertEquals(LocalDate.of(2018, 9, 28), LocalDate.of(2018, 9, 28).previousOrSameSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 9, 28), LocalDate.of(2018, 9, 29).previousOrSameSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 9, 28), LocalDate.of(2018, 9, 30).previousOrSameSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 1).previousOrSameSchoolDay)
|
||||
assertEquals(LocalDate.of(2018, 10, 2), LocalDate.of(2018, 10, 2).previousOrSameSchoolDay)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user