forked from github/wulkanowy-mirror
Refactor timetable module (#160)
This commit is contained in:
parent
f2b7c0e781
commit
5cd8ed88c0
226
.idea/codeStyleSettings.xml
generated
226
.idea/codeStyleSettings.xml
generated
@ -1,226 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectCodeStyleSettingsManager">
|
|
||||||
<option name="PER_PROJECT_SETTINGS">
|
|
||||||
<value>
|
|
||||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
|
|
||||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
|
|
||||||
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
|
||||||
<value />
|
|
||||||
</option>
|
|
||||||
<option name="IMPORT_LAYOUT_TABLE">
|
|
||||||
<value>
|
|
||||||
<package name="android" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="com" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="junit" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="net" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="org" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="java" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="javax" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="" withSubpackages="true" static="false" />
|
|
||||||
<emptyLine />
|
|
||||||
<package name="" withSubpackages="true" static="true" />
|
|
||||||
<emptyLine />
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="RIGHT_MARGIN" value="100" />
|
|
||||||
<AndroidXmlCodeStyleSettings>
|
|
||||||
<option name="USE_CUSTOM_SETTINGS" value="true" />
|
|
||||||
</AndroidXmlCodeStyleSettings>
|
|
||||||
<Objective-C-extensions>
|
|
||||||
<file>
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
|
||||||
</file>
|
|
||||||
<class>
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
|
||||||
</class>
|
|
||||||
<extensions>
|
|
||||||
<pair source="cpp" header="h" />
|
|
||||||
<pair source="c" header="h" />
|
|
||||||
</extensions>
|
|
||||||
</Objective-C-extensions>
|
|
||||||
<XML>
|
|
||||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
|
||||||
</XML>
|
|
||||||
<codeStyleSettings language="XML">
|
|
||||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
</indentOptions>
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:android</NAME>
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:.*</NAME>
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:id</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:name</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>name</NAME>
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>style</NAME>
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:layout_width</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:layout_height</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:layout_.*</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:width</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:height</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -72,10 +72,7 @@ ext.supportVersion = "28.0.0"
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation('com.github.wulkanowy:api:07201a4') {
|
implementation('com.github.wulkanowy:api:f54b673') { exclude module: "threetenbp" }
|
||||||
exclude module: "threetenbp"
|
|
||||||
}
|
|
||||||
|
|
||||||
implementation "com.android.support:support-v4:$supportVersion"
|
implementation "com.android.support:support-v4:$supportVersion"
|
||||||
implementation "com.android.support:appcompat-v7:$supportVersion"
|
implementation "com.android.support:appcompat-v7:$supportVersion"
|
||||||
implementation "com.android.support:design:$supportVersion"
|
implementation "com.android.support:design:$supportVersion"
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.local
|
||||||
|
|
||||||
|
import android.arch.persistence.room.Room
|
||||||
|
import android.support.test.InstrumentationRegistry
|
||||||
|
import android.support.test.runner.AndroidJUnit4
|
||||||
|
import io.github.wulkanowy.data.db.AppDatabase
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class TimetableLocalTest {
|
||||||
|
|
||||||
|
private lateinit var timetableDb: TimetableLocal
|
||||||
|
|
||||||
|
private lateinit var testDb: AppDatabase
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun createDb() {
|
||||||
|
testDb = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getContext(), AppDatabase::class.java).build()
|
||||||
|
timetableDb = TimetableLocal(testDb.timetableDao())
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun closeDb() {
|
||||||
|
testDb.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
||||||
|
))
|
||||||
|
|
||||||
|
val exams = timetableDb.getLessons(
|
||||||
|
Semester(studentId = "1", diaryId = "2", semesterId = "3", diaryName = "", semesterName = 1),
|
||||||
|
LocalDate.of(2018, 9, 10),
|
||||||
|
LocalDate.of(2018, 9, 14)
|
||||||
|
).blockingGet()
|
||||||
|
assertEquals(2, exams.size)
|
||||||
|
assertEquals(exams[0].date, LocalDate.of(2018, 9, 10))
|
||||||
|
assertEquals(exams[1].date, LocalDate.of(2018, 9, 14))
|
||||||
|
}
|
||||||
|
}
|
@ -63,4 +63,8 @@ internal class RepositoryModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideAttendanceDao(database: AppDatabase) = database.attendanceDao()
|
fun provideAttendanceDao(database: AppDatabase) = database.attendanceDao()
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideTimetableDao(database: AppDatabase) = database.timetableDao()
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import javax.inject.Singleton
|
|||||||
Student::class,
|
Student::class,
|
||||||
Semester::class,
|
Semester::class,
|
||||||
Exam::class,
|
Exam::class,
|
||||||
|
Timetable::class,
|
||||||
Attendance::class,
|
Attendance::class,
|
||||||
Grade::class,
|
Grade::class,
|
||||||
GradeSummary::class
|
GradeSummary::class
|
||||||
@ -38,6 +39,8 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
|
|
||||||
abstract fun examsDao(): ExamDao
|
abstract fun examsDao(): ExamDao
|
||||||
|
|
||||||
|
abstract fun timetableDao(): TimetableDao
|
||||||
|
|
||||||
abstract fun attendanceDao(): AttendanceDao
|
abstract fun attendanceDao(): AttendanceDao
|
||||||
|
|
||||||
abstract fun gradeDao(): GradeDao
|
abstract fun gradeDao(): GradeDao
|
||||||
|
@ -7,7 +7,7 @@ import java.util.*
|
|||||||
class Converters {
|
class Converters {
|
||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun fromTimestamp(value: Long?): LocalDate? = value?.run {
|
fun timestampToDate(value: Long?): LocalDate? = value?.run {
|
||||||
DateTimeUtils.toInstant(Date(value)).atZone(ZoneOffset.UTC).toLocalDate()
|
DateTimeUtils.toInstant(Date(value)).atZone(ZoneOffset.UTC).toLocalDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,4 +15,14 @@ class Converters {
|
|||||||
fun dateToTimestamp(date: LocalDate?): Long? {
|
fun dateToTimestamp(date: LocalDate?): Long? {
|
||||||
return date?.atStartOfDay()?.toInstant(ZoneOffset.UTC)?.toEpochMilli()
|
return date?.atStartOfDay()?.toInstant(ZoneOffset.UTC)?.toEpochMilli()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun timestampToTime(value: Long?): LocalDateTime? = value?.let {
|
||||||
|
LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneOffset.UTC)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun timeToTimestamp(date: LocalDateTime?): Long? {
|
||||||
|
return date?.atZone(ZoneOffset.UTC)?.toInstant()?.toEpochMilli()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
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.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface TimetableDao {
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insertAll(exams: List<Timetable>): List<Long>
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun deleteAll(exams: List<Timetable>)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||||
|
fun getTimetable(diaryId: String, studentId: String, from: LocalDate, end: LocalDate): Maybe<List<Timetable>>
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import android.arch.persistence.room.ColumnInfo
|
||||||
|
import android.arch.persistence.room.Entity
|
||||||
|
import android.arch.persistence.room.PrimaryKey
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
@Entity(tableName = "Timetable")
|
||||||
|
data class Timetable(
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long = 0,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "student_id")
|
||||||
|
var studentId: String = "",
|
||||||
|
|
||||||
|
@ColumnInfo(name = "diary_id")
|
||||||
|
var diaryId: String = "",
|
||||||
|
|
||||||
|
val number: Int = 0,
|
||||||
|
|
||||||
|
val start: LocalDateTime = LocalDateTime.now(),
|
||||||
|
|
||||||
|
val end: LocalDateTime = LocalDateTime.now(),
|
||||||
|
|
||||||
|
val date: LocalDate,
|
||||||
|
|
||||||
|
val subject: String = "",
|
||||||
|
|
||||||
|
val group: String = "",
|
||||||
|
|
||||||
|
val room: String = "",
|
||||||
|
|
||||||
|
val teacher: String = "",
|
||||||
|
|
||||||
|
val info: String = "",
|
||||||
|
|
||||||
|
val changes: Boolean = false,
|
||||||
|
|
||||||
|
val canceled: Boolean = false
|
||||||
|
) : Serializable
|
@ -13,7 +13,9 @@ import org.threeten.bp.LocalDate
|
|||||||
import org.threeten.bp.temporal.TemporalAdjusters
|
import org.threeten.bp.temporal.TemporalAdjusters
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
class AttendanceRepository @Inject constructor(
|
class AttendanceRepository @Inject constructor(
|
||||||
private val settings: InternetObservingSettings,
|
private val settings: InternetObservingSettings,
|
||||||
private val local: AttendanceLocal,
|
private val local: AttendanceLocal,
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
|
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||||
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
|
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.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
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class TimetableRepository @Inject constructor(
|
||||||
|
private val settings: InternetObservingSettings,
|
||||||
|
private val local: TimetableLocal,
|
||||||
|
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)
|
||||||
|
else Single.error(UnknownHostException())
|
||||||
|
}.flatMap { newLessons ->
|
||||||
|
local.getLessons(semester, start, end).toSingle(emptyList()).map { lessons ->
|
||||||
|
local.deleteLessons(lessons - newLessons)
|
||||||
|
local.saveLessons(newLessons - lessons)
|
||||||
|
newLessons
|
||||||
|
}
|
||||||
|
}).map { list ->
|
||||||
|
list.asSequence().filter {
|
||||||
|
it.date in startDate..endDate
|
||||||
|
}.toList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.local
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class TimetableLocal @Inject constructor(private val timetableDb: TimetableDao) {
|
||||||
|
|
||||||
|
fun getLessons(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 deleteLessons(exams: List<Timetable>) {
|
||||||
|
timetableDb.deleteAll(exams)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.remote
|
||||||
|
|
||||||
|
import io.github.wulkanowy.api.Api
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import io.github.wulkanowy.utils.toLocalDate
|
||||||
|
import io.github.wulkanowy.utils.toLocalDateTime
|
||||||
|
import io.reactivex.Single
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class TimetableRemote @Inject constructor(private val api: Api) {
|
||||||
|
|
||||||
|
fun getLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Timetable>> {
|
||||||
|
return Single.just(api.run {
|
||||||
|
if (diaryId != semester.diaryId) {
|
||||||
|
diaryId = semester.diaryId
|
||||||
|
notifyDataChanged()
|
||||||
|
}
|
||||||
|
}).flatMap { api.getTimetable(startDate, endDate) }.map { lessons ->
|
||||||
|
lessons.map {
|
||||||
|
Timetable(
|
||||||
|
studentId = semester.studentId,
|
||||||
|
diaryId = semester.diaryId,
|
||||||
|
number = it.number,
|
||||||
|
start = it.start.toLocalDateTime(),
|
||||||
|
end = it.end.toLocalDateTime(),
|
||||||
|
date = it.date.toLocalDate(),
|
||||||
|
subject = it.subject,
|
||||||
|
group = it.group,
|
||||||
|
room = it.room,
|
||||||
|
teacher = it.teacher,
|
||||||
|
info = it.info,
|
||||||
|
changes = it.changes,
|
||||||
|
canceled = it.canceled
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -101,11 +101,6 @@ class AttendanceFragment : BaseFragment(), AttendanceView {
|
|||||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
|
||||||
super.onViewStateRestored(savedInstanceState)
|
|
||||||
presenter.loadData(date = savedInstanceState?.getLong(SAVED_DATE_KEY))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
presenter.detachView()
|
presenter.detachView()
|
||||||
|
@ -40,7 +40,7 @@ class AttendancePresenter @Inject constructor(
|
|||||||
disposable.add(sessionRepository.getSemesters()
|
disposable.add(sessionRepository.getSemesters()
|
||||||
.map { selectSemester(it, -1) }
|
.map { selectSemester(it, -1) }
|
||||||
.flatMap { attendanceRepository.getAttendance(it, currentDate, currentDate, forceRefresh) }
|
.flatMap { attendanceRepository.getAttendance(it, currentDate, currentDate, forceRefresh) }
|
||||||
.map { createTimetableItems(it) }
|
.map { createAttendanceItems(it) }
|
||||||
.subscribeOn(schedulers.backgroundThread())
|
.subscribeOn(schedulers.backgroundThread())
|
||||||
.observeOn(schedulers.mainThread())
|
.observeOn(schedulers.mainThread())
|
||||||
.doOnSubscribe {
|
.doOnSubscribe {
|
||||||
@ -74,7 +74,7 @@ class AttendancePresenter @Inject constructor(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createTimetableItems(items: List<Attendance>): List<AttendanceItem> {
|
private fun createAttendanceItems(items: List<Attendance>): List<AttendanceItem> {
|
||||||
return items.map {
|
return items.map {
|
||||||
AttendanceItem().apply { attendance = it }
|
AttendanceItem().apply { attendance = it }
|
||||||
}
|
}
|
||||||
|
@ -94,11 +94,6 @@ class ExamFragment : BaseFragment(), ExamView {
|
|||||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
|
||||||
super.onViewStateRestored(savedInstanceState)
|
|
||||||
presenter.loadData(date = savedInstanceState?.getLong(SAVED_DATE_KEY))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
presenter.detachView()
|
presenter.detachView()
|
||||||
|
@ -2,7 +2,6 @@ package io.github.wulkanowy.ui.main.exam
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Exam
|
import io.github.wulkanowy.data.db.entities.Exam
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
import org.threeten.bp.LocalDate
|
|
||||||
|
|
||||||
interface ExamView : BaseView {
|
interface ExamView : BaseView {
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class MoreFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_timetable, container, false)
|
return inflater.inflate(R.layout.fragment_attendance, container, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package io.github.wulkanowy.ui.main.timetable
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v4.app.DialogFragment
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import kotlinx.android.synthetic.main.dialog_timetable.*
|
||||||
|
|
||||||
|
class TimetableDialog : DialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var lesson: Timetable
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
|
fun newInstance(exam: Timetable): TimetableDialog {
|
||||||
|
return TimetableDialog().apply {
|
||||||
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogFragmentTheme)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
timetableDialogSubject.text = lesson.subject
|
||||||
|
timetableDialogTime.text = "${lesson.start.toFormattedString("HH:mm")} - ${lesson.end.toFormattedString("HH:mm")}"
|
||||||
|
|
||||||
|
lesson.group.let {
|
||||||
|
if (it.isBlank()) {
|
||||||
|
timetableDialogGroupTitle.visibility = GONE
|
||||||
|
timetableDialogGroup.visibility = GONE
|
||||||
|
} else timetableDialogGroup.text = it
|
||||||
|
}
|
||||||
|
|
||||||
|
lesson.room.let {
|
||||||
|
if (it.isBlank()) {
|
||||||
|
timetableDialogRoomTitle.visibility = GONE
|
||||||
|
timetableDialogRoom.visibility = GONE
|
||||||
|
} else timetableDialogRoom.text = it
|
||||||
|
}
|
||||||
|
|
||||||
|
lesson.teacher.let {
|
||||||
|
if (it.isBlank()) {
|
||||||
|
timetableDialogTeacherTitle.visibility = GONE
|
||||||
|
timetableDialogTeacher.visibility = GONE
|
||||||
|
} else timetableDialogTeacher.text = it
|
||||||
|
}
|
||||||
|
|
||||||
|
lesson.info.let {
|
||||||
|
if (it.isBlank()) {
|
||||||
|
timetableDialogChangesTitle.visibility = GONE
|
||||||
|
timetableDialogChanges.visibility = GONE
|
||||||
|
} else timetableDialogChanges.text = it
|
||||||
|
}
|
||||||
|
|
||||||
|
timetableDialogClose.setOnClickListener { dismiss() }
|
||||||
|
}
|
||||||
|
}
|
@ -4,17 +4,105 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.R
|
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.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
|
import kotlinx.android.synthetic.main.fragment_timetable.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TimetableFragment : BaseFragment() {
|
class TimetableFragment : BaseFragment(), TimetableView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: TimetablePresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var timetableAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val SAVED_DATE_KEY = "CURRENT_DATE"
|
||||||
fun newInstance() = TimetableFragment()
|
fun newInstance() = TimetableFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_timetable, container, false)
|
return inflater.inflate(R.layout.fragment_timetable, container, false)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
presenter.run {
|
||||||
|
attachView(this@TimetableFragment)
|
||||||
|
loadData(date = 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() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<TimetableItem>) {
|
||||||
|
timetableAdapter.updateDataSet(data, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearData() {
|
||||||
|
timetableAdapter.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateNavigationDay(date: String) {
|
||||||
|
timetableNavDate.text = date
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isViewEmpty() = timetableAdapter.isEmpty
|
||||||
|
|
||||||
|
override fun showEmpty(show: Boolean) {
|
||||||
|
timetableEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showProgress(show: Boolean) {
|
||||||
|
timetableProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showContent(show: Boolean) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showNextButton(show: Boolean) {
|
||||||
|
timetableNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showTimetableDialog(lesson: Timetable) {
|
||||||
|
TimetableDialog.newInstance(lesson).show(fragmentManager, lesson.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
presenter.detachView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
package io.github.wulkanowy.ui.main.timetable
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.item_timetable.*
|
||||||
|
|
||||||
|
class TimetableItem : AbstractFlexibleItem<TimetableItem.ViewHolder>() {
|
||||||
|
|
||||||
|
lateinit var lesson: Timetable
|
||||||
|
|
||||||
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||||
|
return ViewHolder(view, adapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLayoutRes(): Int = R.layout.item_timetable
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as TimetableItem
|
||||||
|
|
||||||
|
if (lesson != other.lesson) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
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 javax.inject.Inject
|
||||||
|
|
||||||
|
class TimetablePresenter @Inject constructor(
|
||||||
|
private val errorHandler: ErrorHandler,
|
||||||
|
private val schedulers: SchedulersManager,
|
||||||
|
private val timetableRepository: TimetableRepository,
|
||||||
|
private val sessionRepository: SessionRepository
|
||||||
|
) : BasePresenter<TimetableView>(errorHandler) {
|
||||||
|
|
||||||
|
var currentDate: LocalDate = LocalDate.now().nearSchoolDayNextOnWeekEnd
|
||||||
|
private set
|
||||||
|
|
||||||
|
override fun attachView(view: TimetableView) {
|
||||||
|
super.attachView(view)
|
||||||
|
view.initView()
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTimetableItems(items: List<Timetable>): List<TimetableItem> {
|
||||||
|
return items.map {
|
||||||
|
TimetableItem().apply { lesson = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package io.github.wulkanowy.ui.main.timetable
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface TimetableView : BaseView {
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<TimetableItem>)
|
||||||
|
|
||||||
|
fun updateNavigationDay(date: String)
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.utils
|
|||||||
|
|
||||||
import org.threeten.bp.DayOfWeek.*
|
import org.threeten.bp.DayOfWeek.*
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
import org.threeten.bp.format.DateTimeFormatter
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
import org.threeten.bp.format.DateTimeFormatter.ofPattern
|
import org.threeten.bp.format.DateTimeFormatter.ofPattern
|
||||||
import org.threeten.bp.temporal.TemporalAdjusters
|
import org.threeten.bp.temporal.TemporalAdjusters
|
||||||
@ -15,13 +16,16 @@ fun Date.toLocalDate(): LocalDate {
|
|||||||
return LocalDate.parse(SimpleDateFormat(DATE_PATTERN, Locale.getDefault()).format(this))
|
return LocalDate.parse(SimpleDateFormat(DATE_PATTERN, Locale.getDefault()).format(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 String.toLocalDate(format: String = DATE_PATTERN): LocalDate {
|
fun String.toLocalDate(format: String = DATE_PATTERN): LocalDate {
|
||||||
return LocalDate.parse(this, DateTimeFormatter.ofPattern(format))
|
return LocalDate.parse(this, DateTimeFormatter.ofPattern(format))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun LocalDate.toFormattedString(format: String): String = this.format(ofPattern(format))
|
fun LocalDate.toFormattedString(format: String = DATE_PATTERN): String = this.format(ofPattern(format))
|
||||||
|
|
||||||
fun LocalDate.toFormattedString(): String = this.toFormattedString(DATE_PATTERN)
|
fun LocalDateTime.toFormattedString(format: String = DATE_PATTERN): String = this.format(DateTimeFormatter.ofPattern(format))
|
||||||
|
|
||||||
inline val LocalDate.nextWorkDay: LocalDate
|
inline val LocalDate.nextWorkDay: LocalDate
|
||||||
get() {
|
get() {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
@ -8,194 +7,122 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minWidth="300dp"
|
android:minWidth="300dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
<RelativeLayout
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_relative_layout"
|
android:id="@+id/timetableDialogChangesTitle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="20dp"
|
android:text="@string/timetable_changes"
|
||||||
android:paddingEnd="20dp"
|
android:textColor="@color/colorPrimary"
|
||||||
android:paddingLeft="20dp"
|
android:textSize="17sp" />
|
||||||
android:paddingRight="20dp"
|
|
||||||
android:paddingStart="20dp"
|
|
||||||
android:paddingTop="10dp"
|
|
||||||
tools:ignore="UselessParent">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_details"
|
android:id="@+id/timetableDialogChanges"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="3dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/all_no_data"
|
||||||
android:layout_alignParentTop="true"
|
android:textColor="@color/colorPrimary"
|
||||||
android:layout_gravity="start"
|
android:textIsSelectable="true"
|
||||||
android:gravity="center_vertical"
|
android:textSize="12sp" />
|
||||||
android:maxLines="5"
|
|
||||||
android:minHeight="60dp"
|
|
||||||
android:minLines="2"
|
|
||||||
android:paddingTop="10dp"
|
|
||||||
android:text="@string/all_details"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="20sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_description"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_alignParentLeft="true"
|
android:text="@string/timetable_lesson"
|
||||||
android:layout_alignParentStart="true"
|
android:textIsSelectable="true"
|
||||||
android:layout_below="@+id/timetable_dialog_details"
|
android:textSize="17sp" />
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:text="@string/timetable_changes"
|
|
||||||
android:textColor="@color/colorPrimary"
|
|
||||||
android:textSize="17sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_description_value"
|
android:id="@+id/timetableDialogSubject"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="3dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/all_no_data"
|
||||||
android:layout_below="@+id/timetable_dialog_description"
|
android:textIsSelectable="true"
|
||||||
android:layout_marginTop="3dp"
|
android:textSize="12sp" />
|
||||||
android:text="@string/all_no_data"
|
|
||||||
android:textColor="@color/colorPrimary"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_lesson"
|
android:id="@+id/timetableDialogTeacherTitle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/all_teacher"
|
||||||
android:layout_below="@+id/timetable_dialog_description_value"
|
android:textSize="17sp" />
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:text="@string/timetable_lesson"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="17sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_lesson_value"
|
android:id="@+id/timetableDialogTeacher"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="3dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/all_no_data"
|
||||||
android:layout_below="@+id/timetable_dialog_lesson"
|
android:textIsSelectable="true"
|
||||||
android:layout_marginTop="3dp"
|
android:textSize="12sp" />
|
||||||
android:text="@string/all_no_data"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_teacher"
|
android:id="@+id/timetableDialogGroupTitle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/timetable_group"
|
||||||
android:layout_below="@+id/timetable_dialog_lesson_value"
|
android:textSize="17sp" />
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:text="@string/all_teacher"
|
|
||||||
android:textSize="17sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_teacher_value"
|
android:id="@+id/timetableDialogGroup"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="3dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/all_no_data"
|
||||||
android:layout_below="@+id/timetable_dialog_teacher"
|
android:textIsSelectable="true"
|
||||||
android:layout_marginTop="3dp"
|
android:textSize="12sp" />
|
||||||
android:text="@string/all_no_data"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_group"
|
android:id="@+id/timetableDialogRoomTitle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/timetable_room"
|
||||||
android:layout_below="@+id/timetable_dialog_teacher_value"
|
android:textSize="17sp" />
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:text="@string/timetable_group"
|
|
||||||
android:textSize="17sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_group_value"
|
android:id="@+id/timetableDialogRoom"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="3dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/all_no_data"
|
||||||
android:layout_below="@+id/timetable_dialog_group"
|
android:textIsSelectable="true"
|
||||||
android:layout_marginTop="3dp"
|
android:textSize="12sp" />
|
||||||
android:text="@string/all_no_data"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_room"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_alignParentLeft="true"
|
android:text="@string/timetable_time"
|
||||||
android:layout_alignParentStart="true"
|
android:textSize="17sp" />
|
||||||
android:layout_below="@+id/timetable_dialog_group_value"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:text="@string/timetable_room"
|
|
||||||
android:textSize="17sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_dialog_room_value"
|
android:id="@+id/timetableDialogTime"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_marginTop="3dp"
|
||||||
android:layout_alignParentStart="true"
|
android:text="@string/all_no_data"
|
||||||
android:layout_below="@id/timetable_dialog_room"
|
android:textIsSelectable="true"
|
||||||
android:layout_marginTop="3dp"
|
android:textSize="12sp" />
|
||||||
android:text="@string/all_no_data"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<TextView
|
<Button
|
||||||
android:id="@+id/timetable_dialog_time"
|
android:id="@+id/timetableDialogClose"
|
||||||
android:layout_width="wrap_content"
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_gravity="end"
|
||||||
android:layout_below="@+id/timetable_dialog_room_value"
|
android:layout_marginTop="15dp"
|
||||||
android:layout_marginTop="10dp"
|
android:padding="0dp"
|
||||||
android:text="@string/timetable_time"
|
android:text="@string/all_close"
|
||||||
android:textSize="17sp" />
|
android:textAllCaps="true"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/timetable_dialog_time_value"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_below="@+id/timetable_dialog_time"
|
|
||||||
android:layout_marginTop="3dp"
|
|
||||||
android:text="@string/all_no_data"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/timetable_dialog_close"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignTop="@+id/timetable_dialog_time_value"
|
|
||||||
android:layout_marginTop="25dp"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:focusable="true"
|
|
||||||
android:text="@string/all_close"
|
|
||||||
android:textColor="?android:attr/android:textColorSecondary"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:textSize="15sp" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -1,12 +1,99 @@
|
|||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/timetable_fragment_container"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_alignParentBottom="true">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:gravity="center"
|
android:layout_weight="1"
|
||||||
android:text="Timetable" />
|
android:orientation="vertical">
|
||||||
</FrameLayout>
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/timetableProgress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:indeterminate="true" />
|
||||||
|
|
||||||
|
<android.support.v4.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/timetableSwipe"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/timetableRecycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</android.support.v4.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/timetableEmpty"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<android.support.v7.widget.AppCompatImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="100dp"
|
||||||
|
android:minWidth="100dp"
|
||||||
|
app:srcCompat="@drawable/ic_menu_main_timetable_24dp"
|
||||||
|
app:tint="?android:attr/textColorPrimary"
|
||||||
|
tools:ignore="contentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/timetable_no_items"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/timetablePreviousButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
android:gravity="start|center"
|
||||||
|
android:text="@string/prev"
|
||||||
|
android:textAlignment="gravity" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/timetableNavDate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/app_name" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/timetableNextButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
android:gravity="end|center"
|
||||||
|
android:text="@string/next"
|
||||||
|
android:textAlignment="gravity" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
@ -1,73 +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/timetable_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/timetable_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/timetable_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/timetable_tab_fragment_no_item_image"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@+id/timetable_tab_fragment_no_item_text"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_marginTop="40dp"
|
|
||||||
android:minHeight="100dp"
|
|
||||||
android:minWidth="100dp"
|
|
||||||
app:srcCompat="@drawable/ic_menu_main_timetable_24dp"
|
|
||||||
app:tint="?android:attr/textColorPrimary"
|
|
||||||
tools:ignore="contentDescription" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/timetable_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/timetable_no_items"
|
|
||||||
android:textSize="20sp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/timetable_tab_fragment_no_item_name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/timetable_tab_fragment_no_item_image"
|
|
||||||
android:layout_marginTop="15dp"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:text="@string/app_name"
|
|
||||||
android:textSize="20sp" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<android.support.v4.widget.SwipeRefreshLayout
|
|
||||||
android:id="@+id/timetable_tab_fragment_swipe_refresh"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
|
||||||
android:id="@+id/timetable_tab_fragment_recycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
|
|
||||||
</android.support.v4.widget.SwipeRefreshLayout>
|
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
|
@ -1,94 +1,82 @@
|
|||||||
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tool="http://schemas.android.com/tools"
|
xmlns:tool="http://schemas.android.com/tools"
|
||||||
android:id="@+id/timetable_subItem_cardView"
|
android:id="@+id/timetable_subitem_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="7dp"
|
|
||||||
android:layout_marginEnd="5dp"
|
|
||||||
android:layout_marginLeft="5dp"
|
|
||||||
android:layout_marginRight="5dp"
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||||
card_view:cardElevation="0dp">
|
android:paddingBottom="7dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingLeft="12dp"
|
||||||
|
android:paddingRight="12dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingTop="7dp">
|
||||||
|
|
||||||
<RelativeLayout
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/timetableItemNumber"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:maxLength="2"
|
||||||
|
android:text="0"
|
||||||
|
android:textSize="32sp"
|
||||||
|
tool:ignore="all" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/timetableItemSubject"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="7dp"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_marginEnd="7dp"
|
android:layout_marginEnd="40dp"
|
||||||
android:layout_marginLeft="7dp"
|
android:layout_marginLeft="10dp"
|
||||||
android:layout_marginRight="7dp"
|
android:layout_marginRight="40dp"
|
||||||
android:layout_marginStart="7dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginTop="7dp">
|
android:layout_toEndOf="@+id/timetableItemNumber"
|
||||||
|
android:layout_toRightOf="@+id/timetableItemNumber"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textSize="17sp"
|
||||||
|
tool:ignore="RelativeOverlap" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_subItem_number_of_lesson"
|
android:id="@+id/timetableItemTime"
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_alignBottom="@+id/timetableItemNumber"
|
||||||
android:gravity="center"
|
android:layout_alignLeft="@id/timetableItemSubject"
|
||||||
android:maxLength="2"
|
android:layout_alignStart="@id/timetableItemSubject"
|
||||||
android:text="0"
|
android:maxLines="1"
|
||||||
android:textSize="32sp"
|
android:text="@string/app_name"
|
||||||
tool:ignore="all"/>
|
android:textColor="?android:attr/android:textColorSecondary"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timetable_subItem_lesson"
|
android:id="@+id/timetableItemRoom"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignBottom="@+id/timetableItemNumber"
|
||||||
android:layout_marginEnd="40dp"
|
android:layout_marginEnd="40dp"
|
||||||
android:layout_marginLeft="10dp"
|
android:layout_marginLeft="10dp"
|
||||||
android:layout_marginRight="40dp"
|
android:layout_marginRight="40dp"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_toEndOf="@+id/timetable_subItem_number_of_lesson"
|
android:layout_toEndOf="@+id/timetableItemTime"
|
||||||
android:layout_toRightOf="@+id/timetable_subItem_number_of_lesson"
|
android:layout_toRightOf="@+id/timetableItemTime"
|
||||||
android:ellipsize="end"
|
android:maxLines="1"
|
||||||
android:maxLines="1"
|
android:text="@string/app_name"
|
||||||
android:text="@string/app_name"
|
android:textColor="?android:attr/android:textColorSecondary"
|
||||||
android:textSize="17sp"
|
android:textSize="12sp"
|
||||||
tool:ignore="all"/>
|
tool:ignore="RelativeOverlap" />
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/timetable_subItem_time"
|
android:id="@+id/timetableItemAlert"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignBottom="@+id/timetable_subItem_number_of_lesson"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignLeft="@id/timetable_subItem_lesson"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_alignStart="@id/timetable_subItem_lesson"
|
android:layout_marginTop="10dp"
|
||||||
android:maxLines="1"
|
app:srcCompat="@drawable/ic_timetable_swap_30dp"
|
||||||
android:text="@string/app_name"
|
tool:ignore="contentDescription" />
|
||||||
android:textColor="?android:attr/android:textColorSecondary"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<TextView
|
</RelativeLayout>
|
||||||
android:id="@+id/timetable_subItem_room"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignBottom="@+id/timetable_subItem_number_of_lesson"
|
|
||||||
android:layout_marginEnd="40dp"
|
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:layout_marginRight="40dp"
|
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:layout_toEndOf="@+id/timetable_subItem_time"
|
|
||||||
android:layout_toRightOf="@+id/timetable_subItem_time"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:text="@string/app_name"
|
|
||||||
android:textColor="?android:attr/android:textColorSecondary"
|
|
||||||
android:textSize="12sp"
|
|
||||||
tool:ignore="all"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/timetable_subItem_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_timetable_swap_30dp"
|
|
||||||
tool:ignore="contentDescription"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
</android.support.v7.widget.CardView>
|
|
||||||
|
@ -63,11 +63,11 @@
|
|||||||
|
|
||||||
<!--Timetable-->
|
<!--Timetable-->
|
||||||
<string name="timetable_lesson">Lekcja</string>
|
<string name="timetable_lesson">Lekcja</string>
|
||||||
<string name="timetable_room">Sala %s</string>
|
<string name="timetable_room">Sala</string>
|
||||||
<string name="timetable_group">Grupa</string>
|
<string name="timetable_group">Grupa</string>
|
||||||
<string name="timetable_time">Godziny</string>
|
<string name="timetable_time">Godziny</string>
|
||||||
<string name="timetable_changes">Zmiany</string>
|
<string name="timetable_changes">Zmiany</string>
|
||||||
<string name="timetable_no_items">Brak lekcji w tym tygodniu</string>
|
<string name="timetable_no_items">Brak lekcji w tym dniu</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Attendance-->
|
<!--Attendance-->
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
<string name="timetable_group">Group</string>
|
<string name="timetable_group">Group</string>
|
||||||
<string name="timetable_time">Hours</string>
|
<string name="timetable_time">Hours</string>
|
||||||
<string name="timetable_changes">Changes</string>
|
<string name="timetable_changes">Changes</string>
|
||||||
<string name="timetable_no_items">No lesson in this week</string>
|
<string name="timetable_no_items">No lesson in this day</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Attendance-->
|
<!--Attendance-->
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.remote
|
||||||
|
|
||||||
|
import io.github.wulkanowy.api.Api
|
||||||
|
import io.github.wulkanowy.api.timetable.Timetable
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.impl.annotations.MockK
|
||||||
|
import io.reactivex.Single
|
||||||
|
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 {
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
private lateinit var mockApi: Api
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
private lateinit var semesterMock: Semester
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun initApi() {
|
||||||
|
MockKAnnotations.init(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getExamsTest() {
|
||||||
|
every { mockApi.getTimetable(
|
||||||
|
LocalDate.of(2018, 9, 10),
|
||||||
|
LocalDate.of(2018, 9, 15)
|
||||||
|
) } returns Single.just(listOf(
|
||||||
|
getTimetable("2018-09-10"),
|
||||||
|
getTimetable("2018-09-17")
|
||||||
|
))
|
||||||
|
|
||||||
|
every { mockApi.diaryId } returns "1"
|
||||||
|
every { semesterMock.studentId } returns "1"
|
||||||
|
every { semesterMock.diaryId } returns "1"
|
||||||
|
|
||||||
|
val timetable = TimetableRemote(mockApi).getLessons(semesterMock,
|
||||||
|
LocalDate.of(2018, 9, 10),
|
||||||
|
LocalDate.of(2018, 9, 15)
|
||||||
|
).blockingGet()
|
||||||
|
assertEquals(2, timetable.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTimetable(dateString: String): Timetable {
|
||||||
|
return Timetable(date = Date.valueOf(dateString))
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.utils
|
|||||||
import org.junit.Assert.*
|
import org.junit.Assert.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class TimeExtensionTest {
|
class TimeExtensionTest {
|
||||||
@ -18,6 +19,12 @@ class TimeExtensionTest {
|
|||||||
assertEquals("2018-10.01", LocalDate.of(2018, 10, 1).toFormattedString("yyyy-MM.dd"))
|
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())
|
||||||
|
assertEquals("2018-10-01 10:00:00", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString("uuuu-MM-dd HH:mm:ss"))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun weekFirstDayAlwaysCurrentTest() {
|
fun weekFirstDayAlwaysCurrentTest() {
|
||||||
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 2).weekFirstDayAlwaysCurrent)
|
assertEquals(LocalDate.of(2018, 10, 1), LocalDate.of(2018, 10, 2).weekFirstDayAlwaysCurrent)
|
||||||
|
@ -10,7 +10,7 @@ buildscript {
|
|||||||
dependencies {
|
dependencies {
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath 'com.android.tools.build:gradle:3.2.0'
|
classpath 'com.android.tools.build:gradle:3.2.0'
|
||||||
classpath "io.fabric.tools:gradle:1.25.4"
|
classpath "io.fabric.tools:gradle:1.26.0"
|
||||||
classpath "com.google.gms:oss-licenses:0.9.2"
|
classpath "com.google.gms:oss-licenses:0.9.2"
|
||||||
classpath "com.github.triplet.gradle:play-publisher:1.2.2"
|
classpath "com.github.triplet.gradle:play-publisher:1.2.2"
|
||||||
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2"
|
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2"
|
||||||
|
1
gradle/wrapper/gradle-wrapper.properties
vendored
1
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,4 +1,3 @@
|
|||||||
#Mon Sep 24 22:45:58 CEST 2018
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
Loading…
x
Reference in New Issue
Block a user