Improve the display of changes in the timetable (#275)

Closes #264
This commit is contained in:
Mikołaj Pich
2019-03-11 20:56:47 +01:00
committed by Rafał Borcz
parent 475e7dd6a3
commit 2621e5680d
13 changed files with 224 additions and 83 deletions

View File

@ -46,6 +46,7 @@ import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration7
import io.github.wulkanowy.data.db.migrations.Migration8
import javax.inject.Singleton
@Singleton
@ -76,7 +77,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 7
const val VERSION_SCHEMA = 8
fun newInstance(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
@ -89,7 +90,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration4(),
Migration5(),
Migration6(),
Migration7()
Migration7(),
Migration8()
)
.build()
}

View File

@ -26,12 +26,18 @@ data class Timetable(
val subject: String,
val subjectOld: String,
val group: String,
val room: String,
val roomOld: String,
val teacher: String,
val teacherOld: String,
val info: String,
val changes: Boolean,

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration8 : Migration(7, 8) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE `Timetable` ADD COLUMN subjectOld TEXT DEFAULT \"\" NOT NULL")
database.execSQL("ALTER TABLE `Timetable` ADD COLUMN roomOld TEXT DEFAULT \"\" NOT NULL")
database.execSQL("ALTER TABLE `Timetable` ADD COLUMN teacherOld TEXT DEFAULT \"\" NOT NULL")
}
}

View File

@ -26,9 +26,12 @@ class TimetableRemote @Inject constructor(private val api: Api) {
end = it.end.toLocalDateTime(),
date = it.date.toLocalDate(),
subject = it.subject,
subjectOld = it.subjectOld,
group = it.group,
room = it.room,
roomOld = it.roomOld,
teacher = it.teacher,
teacherOld = it.teacherOld,
info = it.info,
changes = it.changes,
canceled = it.canceled

View File

@ -19,33 +19,31 @@ class TimetableRepository @Inject constructor(
private val remote: TimetableRemote
) {
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 { newTimetable ->
local.getTimetable(semester, dates.first, dates.second)
.toSingle(emptyList())
.doOnSuccess { oldTimetable ->
local.deleteTimetable(oldTimetable - newTimetable)
local.saveTimetable((newTimetable - oldTimetable).map { item ->
item.apply {
if (room.isEmpty()) {
oldTimetable.singleOrNull { it.start == this.start && it.room.isNotEmpty() }
?.let { return@map copy(room = it.room) }
}
}
})
fun getTimetable(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Timetable>> {
return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) ->
local.getTimetable(semester, monday, friday).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
if (it) remote.getTimetable(semester, monday, friday)
else Single.error(UnknownHostException())
}.flatMap { newTimetable ->
local.getTimetable(semester, monday, friday)
.toSingle(emptyList())
.doOnSuccess { oldTimetable ->
local.deleteTimetable(oldTimetable - newTimetable)
local.saveTimetable((newTimetable - oldTimetable).map { item ->
item.apply {
oldTimetable.singleOrNull { this.start == it.start }?.let {
return@map copy(
room = if (room.isEmpty()) it.room else room,
teacher = if (teacher.isEmpty()) it.teacher else teacher
)
}
}
}.flatMap {
local.getTimetable(semester, dates.first, dates.second)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in startDate..endDate } }
}
})
}
}.flatMap {
local.getTimetable(semester, monday, friday).toSingle(emptyList())
}).map { list -> list.filter { it.date in start..end } }
}
}
}

View File

@ -1,16 +1,19 @@
package io.github.wulkanowy.ui.modules.timetable
import android.annotation.SuppressLint
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
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.*
import org.threeten.bp.LocalDateTime
class TimetableDialog : DialogFragment() {
@ -38,41 +41,110 @@ class TimetableDialog : DialogFragment() {
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
lesson.run {
setInfo(info, teacher, canceled, changes)
setSubject(subject, subjectOld)
setTeacher(teacher, teacherOld)
setGroup(group)
setRoom(room, roomOld)
setTime(start, end)
}
timetableDialogClose.setOnClickListener { dismiss() }
}
private fun setSubject(subject: String, subjectOld: String) {
timetableDialogSubject.text = subject
if (subjectOld.isNotBlank() && subjectOld != subject) {
timetableDialogSubject.run {
paintFlags = paintFlags or STRIKE_THRU_TEXT_FLAG
text = subjectOld
}
timetableDialogSubjectNew.run {
visibility = VISIBLE
text = subject
}
}
}
private fun setInfo(info: String, teacher: String, canceled: Boolean, changes: Boolean) {
when {
info.isNotBlank() -> timetableDialogChanges.text = when {
canceled && !changes -> "Lekcja odwołana: $info"
changes && teacher.isNotBlank() -> "Zastępstwo: $teacher"
changes && teacher.isBlank() -> "Zastępstwo, ${info.decapitalize()}"
else -> info.capitalize()
}
else -> {
timetableDialogChangesTitle.visibility = GONE
timetableDialogChanges.visibility = GONE
}
}
}
private fun setTeacher(teacher: String, teacherOld: String) {
when {
teacherOld.isNotBlank() && teacherOld != teacher -> {
timetableDialogTeacher.run {
visibility = VISIBLE
paintFlags = paintFlags or STRIKE_THRU_TEXT_FLAG
text = teacherOld
}
if (teacher.isNotBlank()) {
timetableDialogTeacherNew.run {
visibility = VISIBLE
text = teacher
}
}
}
teacher.isNotBlank() -> timetableDialogTeacher.text = teacher
else -> {
timetableDialogTeacherTitle.visibility = GONE
timetableDialogTeacher.visibility = GONE
}
}
}
private fun setGroup(group: String) {
group.let {
when {
it.isNotBlank() -> timetableDialogGroup.text = it
else -> {
timetableDialogGroupTitle.visibility = GONE
timetableDialogGroup.visibility = GONE
}
}
}
}
private fun setRoom(room: String, roomOld: String) {
when {
roomOld.isNotBlank() && roomOld != room -> {
timetableDialogRoom.run {
visibility = VISIBLE
paintFlags = paintFlags or STRIKE_THRU_TEXT_FLAG
text = roomOld
}
if (room.isNotBlank()) {
timetableDialogRoomNew.run {
visibility = VISIBLE
text = room
}
}
}
room.isNotBlank() -> timetableDialogRoom.text = room
else -> {
timetableDialogRoomTitle.visibility = GONE
timetableDialogRoom.visibility = GONE
}
}
}
@SuppressLint("SetTextI18n")
private fun setTime(start: LocalDateTime, end: LocalDateTime) {
timetableDialogTime.text = "${start.toFormattedString("HH:mm")} - ${end.toFormattedString("HH:mm")}"
}
}

View File

@ -79,7 +79,14 @@ class TimetableWidgetFactory(
if (it.info.isNotBlank()) {
setViewVisibility(R.id.timetableWidgetItemDescription, VISIBLE)
setTextViewText(R.id.timetableWidgetItemDescription, it.info.capitalize())
setTextViewText(R.id.timetableWidgetItemDescription, it.run {
when (true) {
canceled && !changes -> "Lekcja odwołana: $info"
changes && teacher.isNotBlank() -> "Zastępstwo: $teacher"
changes && teacher.isBlank() -> "Zastępstwo, ${info.decapitalize()}"
else -> it.info.capitalize()
}
})
} else setViewVisibility(R.id.timetableWidgetItemDescription, GONE)
if (it.canceled) {

View File

@ -121,6 +121,3 @@ class TimetableWidgetProvider : BroadcastReceiver() {
}, FLAG_UPDATE_CURRENT)
}
}