forked from github/wulkanowy-mirror
Add option to show empty tiles in the timetable (#2236)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
This commit is contained in:
parent
024ca89708
commit
533157709b
@ -50,5 +50,9 @@
|
||||
{
|
||||
"displayName": "Tomasz F.",
|
||||
"githubUsername": "Pengwius"
|
||||
},
|
||||
{
|
||||
"displayName": "Antoni Paduch",
|
||||
"githubUsername": "janAte1"
|
||||
}
|
||||
]
|
||||
|
@ -0,0 +1,11 @@
|
||||
package io.github.wulkanowy.data.enums
|
||||
|
||||
enum class TimetableGapsMode(val value: String) {
|
||||
NO_GAPS("no_gaps"),
|
||||
BETWEEN_LESSONS("between"),
|
||||
BETWEEN_AND_BEFORE_LESSONS("before_and_between");
|
||||
|
||||
companion object {
|
||||
fun getByValue(value: String) = entries.find { it.value == value } ?: BETWEEN_LESSONS
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@ import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
||||
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.time.Instant
|
||||
@ -201,6 +200,14 @@ class PreferencesRepository @Inject constructor(
|
||||
R.bool.pref_default_timetable_show_timers
|
||||
)
|
||||
|
||||
val showTimetableGaps: TimetableGapsMode
|
||||
get() = TimetableGapsMode.getByValue(
|
||||
getString(
|
||||
R.string.pref_key_timetable_show_gaps,
|
||||
R.string.pref_default_timetable_show_gaps
|
||||
)
|
||||
)
|
||||
|
||||
val showSubjectsWithoutGrades: Boolean
|
||||
get() = getBoolean(
|
||||
R.string.pref_key_subjects_without_grades,
|
||||
|
@ -4,6 +4,7 @@ import android.content.Intent
|
||||
import android.widget.RemoteViewsService
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
@ -26,10 +27,19 @@ class TimetableWidgetService : RemoteViewsService() {
|
||||
@Inject
|
||||
lateinit var sharedPref: SharedPrefProvider
|
||||
|
||||
@Inject
|
||||
lateinit var prefRepository: PreferencesRepository
|
||||
|
||||
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
|
||||
Timber.d("TimetableWidgetFactory created")
|
||||
return TimetableWidgetFactory(
|
||||
timetableRepo, studentRepo, semesterRepo, sharedPref, applicationContext, intent
|
||||
timetableRepository = timetableRepo,
|
||||
studentRepository = studentRepo,
|
||||
semesterRepository = semesterRepo,
|
||||
sharedPref = sharedPref,
|
||||
prefRepository = prefRepository,
|
||||
context = applicationContext,
|
||||
intent = intent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.databinding.ItemTimetableBinding
|
||||
import io.github.wulkanowy.databinding.ItemTimetableEmptyBinding
|
||||
import io.github.wulkanowy.databinding.ItemTimetableSmallBinding
|
||||
import io.github.wulkanowy.utils.getPlural
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import javax.inject.Inject
|
||||
@ -29,9 +31,14 @@ class TimetableAdapter @Inject constructor() :
|
||||
TimetableItemType.SMALL -> SmallViewHolder(
|
||||
ItemTimetableSmallBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
TimetableItemType.NORMAL -> NormalViewHolder(
|
||||
ItemTimetableBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
TimetableItemType.EMPTY -> EmptyViewHolder(
|
||||
ItemTimetableEmptyBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,12 +47,12 @@ class TimetableAdapter @Inject constructor() :
|
||||
position: Int,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
if (payloads.isEmpty()) return super.onBindViewHolder(holder, position, payloads)
|
||||
|
||||
if (holder is NormalViewHolder) updateTimeLeft(
|
||||
binding = holder.binding,
|
||||
timeLeft = (getItem(position) as TimetableItem.Normal).timeLeft,
|
||||
)
|
||||
if (payloads.isNotEmpty() && holder is NormalViewHolder) {
|
||||
updateTimeLeft(
|
||||
binding = holder.binding,
|
||||
timeLeft = (getItem(position) as TimetableItem.Normal).timeLeft,
|
||||
)
|
||||
} else super.onBindViewHolder(holder, position, payloads)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
@ -54,10 +61,16 @@ class TimetableAdapter @Inject constructor() :
|
||||
binding = holder.binding,
|
||||
item = getItem(position) as TimetableItem.Small,
|
||||
)
|
||||
|
||||
is NormalViewHolder -> bindNormalView(
|
||||
binding = holder.binding,
|
||||
item = getItem(position) as TimetableItem.Normal,
|
||||
)
|
||||
|
||||
is EmptyViewHolder -> bindEmptyView(
|
||||
binding = holder.binding,
|
||||
item = getItem(position) as TimetableItem.Empty,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,6 +113,19 @@ class TimetableAdapter @Inject constructor() :
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindEmptyView(binding: ItemTimetableEmptyBinding, item: TimetableItem.Empty) {
|
||||
with(binding) {
|
||||
timetableEmptyItemNumber.text = when (item.numFrom) {
|
||||
item.numTo -> item.numFrom.toString()
|
||||
else -> "${item.numFrom}-${item.numTo}"
|
||||
}
|
||||
timetableEmptyItemSubject.text = timetableEmptyItemSubject.context.getPlural(
|
||||
R.plurals.timetable_no_lesson,
|
||||
item.numTo - item.numFrom + 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTimeLeft(binding: ItemTimetableBinding, timeLeft: TimeLeft?) {
|
||||
with(binding) {
|
||||
when {
|
||||
@ -137,6 +163,7 @@ class TimetableAdapter @Inject constructor() :
|
||||
timetableItemTimeLeft.visibility = VISIBLE
|
||||
timetableItemTimeLeft.text = root.context.getString(R.string.timetable_finished)
|
||||
}
|
||||
|
||||
else -> {
|
||||
timetableItemTimeUntil.visibility = GONE
|
||||
timetableItemTimeLeft.visibility = GONE
|
||||
@ -191,7 +218,8 @@ class TimetableAdapter @Inject constructor() :
|
||||
)
|
||||
} else {
|
||||
timetableItemDescription.visibility = GONE
|
||||
timetableItemRoom.isVisible = lesson.room.isNotBlank() || lesson.roomOld.isNotBlank()
|
||||
timetableItemRoom.isVisible =
|
||||
lesson.room.isNotBlank() || lesson.roomOld.isNotBlank()
|
||||
timetableItemGroup.isVisible = item.showGroupsInPlan && lesson.group.isNotBlank()
|
||||
timetableItemTeacher.visibility = VISIBLE
|
||||
}
|
||||
@ -274,6 +302,9 @@ class TimetableAdapter @Inject constructor() :
|
||||
private class SmallViewHolder(val binding: ItemTimetableSmallBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
private class EmptyViewHolder(val binding: ItemTimetableEmptyBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
private val differ = object : DiffUtil.ItemCallback<TimetableItem>() {
|
||||
override fun areItemsTheSame(oldItem: TimetableItem, newItem: TimetableItem): Boolean =
|
||||
@ -281,9 +312,11 @@ class TimetableAdapter @Inject constructor() :
|
||||
oldItem is TimetableItem.Small && newItem is TimetableItem.Small -> {
|
||||
oldItem.lesson.start == newItem.lesson.start
|
||||
}
|
||||
|
||||
oldItem is TimetableItem.Normal && newItem is TimetableItem.Normal -> {
|
||||
oldItem.lesson.start == newItem.lesson.start
|
||||
}
|
||||
|
||||
else -> oldItem == newItem
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,11 @@ sealed class TimetableItem(val type: TimetableItemType) {
|
||||
val timeLeft: TimeLeft?,
|
||||
val onClick: (Timetable) -> Unit,
|
||||
) : TimetableItem(TimetableItemType.NORMAL)
|
||||
|
||||
data class Empty(
|
||||
val numFrom: Int,
|
||||
val numTo: Int
|
||||
) : TimetableItem(TimetableItemType.EMPTY)
|
||||
}
|
||||
|
||||
data class TimeLeft(
|
||||
@ -27,4 +32,5 @@ data class TimeLeft(
|
||||
enum class TimetableItemType {
|
||||
SMALL,
|
||||
NORMAL,
|
||||
EMPTY
|
||||
}
|
||||
|
@ -1,23 +1,44 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS
|
||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS
|
||||
import io.github.wulkanowy.data.enums.TimetableMode
|
||||
import io.github.wulkanowy.data.flatResourceFlow
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceData
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceIntermediate
|
||||
import io.github.wulkanowy.data.onResourceNotLoading
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.capitalise
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.isJustFinished
|
||||
import io.github.wulkanowy.utils.isShowTimeUntil
|
||||
import io.github.wulkanowy.utils.left
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.nextSchoolDay
|
||||
import io.github.wulkanowy.utils.previousSchoolDay
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.until
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDate.*
|
||||
import java.util.*
|
||||
import java.time.LocalDate.now
|
||||
import java.time.LocalDate.of
|
||||
import java.time.LocalDate.ofEpochDay
|
||||
import java.util.Timer
|
||||
import javax.inject.Inject
|
||||
import kotlin.concurrent.timer
|
||||
|
||||
@ -192,16 +213,38 @@ class TimetablePresenter @Inject constructor(
|
||||
compareBy({ item -> item.number }, { item -> !item.isStudentPlan })
|
||||
)
|
||||
|
||||
return filteredItems.mapIndexed { i, it ->
|
||||
if (it.isStudentPlan) TimetableItem.Normal(
|
||||
lesson = it,
|
||||
showGroupsInPlan = prefRepository.showGroupsInPlan,
|
||||
timeLeft = filteredItems.getTimeLeftForLesson(it, i),
|
||||
onClick = ::onTimetableItemSelected
|
||||
) else TimetableItem.Small(
|
||||
lesson = it,
|
||||
onClick = ::onTimetableItemSelected
|
||||
)
|
||||
var prevNum = when (prefRepository.showTimetableGaps) {
|
||||
BETWEEN_AND_BEFORE_LESSONS -> 0
|
||||
else -> null
|
||||
}
|
||||
return buildList {
|
||||
filteredItems.forEachIndexed { i, it ->
|
||||
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
|
||||
val emptyLesson = TimetableItem.Empty(
|
||||
numFrom = prevNum!! + 1,
|
||||
numTo = it.number - 1
|
||||
)
|
||||
add(emptyLesson)
|
||||
}
|
||||
|
||||
if (it.isStudentPlan) {
|
||||
val normalLesson = TimetableItem.Normal(
|
||||
lesson = it,
|
||||
showGroupsInPlan = prefRepository.showGroupsInPlan,
|
||||
timeLeft = filteredItems.getTimeLeftForLesson(it, i),
|
||||
onClick = ::onTimetableItemSelected
|
||||
)
|
||||
add(normalLesson)
|
||||
} else {
|
||||
val smallLesson = TimetableItem.Small(
|
||||
lesson = it,
|
||||
onClick = ::onTimetableItemSelected
|
||||
)
|
||||
add(smallLesson)
|
||||
}
|
||||
|
||||
prevNum = it.number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,9 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS
|
||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
@ -24,6 +27,7 @@ import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Co
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getTodayLastLessonEndDateTimeWidgetKey
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import io.github.wulkanowy.utils.getPlural
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
@ -35,11 +39,12 @@ class TimetableWidgetFactory(
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val sharedPref: SharedPrefProvider,
|
||||
private val prefRepository: PreferencesRepository,
|
||||
private val context: Context,
|
||||
private val intent: Intent?
|
||||
) : RemoteViewsService.RemoteViewsFactory {
|
||||
|
||||
private var lessons = emptyList<Timetable>()
|
||||
private var items = emptyList<TimetableWidgetItem>()
|
||||
|
||||
private var timetableCanceledColor: Int? = null
|
||||
|
||||
@ -47,18 +52,13 @@ class TimetableWidgetFactory(
|
||||
|
||||
private var timetableChangeColor: Int? = null
|
||||
|
||||
private var lastSyncInstant: Instant? = null
|
||||
|
||||
override fun getLoadingView() = null
|
||||
|
||||
override fun hasStableIds() = true
|
||||
|
||||
override fun getCount() = when {
|
||||
lessons.isEmpty() -> 0
|
||||
else -> lessons.size + 1
|
||||
}
|
||||
override fun getCount() = items.size
|
||||
|
||||
override fun getViewTypeCount() = 2
|
||||
override fun getViewTypeCount() = 3
|
||||
|
||||
override fun getItemId(position: Int) = position.toLong()
|
||||
|
||||
@ -75,9 +75,10 @@ class TimetableWidgetFactory(
|
||||
runBlocking {
|
||||
val student = getStudent(studentId) ?: return@runBlocking
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
lessons = getLessons(student, semester, date)
|
||||
lastSyncInstant =
|
||||
timetableRepository.getLastRefreshTimestamp(semester, date, date)
|
||||
items = createItems(
|
||||
lessons = getLessons(student, semester, date),
|
||||
lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
|
||||
)
|
||||
if (date == LocalDate.now()) {
|
||||
updateTodayLastLessonEnd(appWidgetId)
|
||||
}
|
||||
@ -101,8 +102,33 @@ class TimetableWidgetFactory(
|
||||
return lessons.sortedBy { it.number }
|
||||
}
|
||||
|
||||
private fun createItems(
|
||||
lessons: List<Timetable>,
|
||||
lastSync: Instant?,
|
||||
): List<TimetableWidgetItem> {
|
||||
var prevNum = when (prefRepository.showTimetableGaps) {
|
||||
BETWEEN_AND_BEFORE_LESSONS -> 0
|
||||
else -> null
|
||||
}
|
||||
return buildList {
|
||||
lessons.forEach {
|
||||
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
|
||||
val emptyItem = TimetableWidgetItem.Empty(
|
||||
numFrom = prevNum!! + 1,
|
||||
numTo = it.number - 1
|
||||
)
|
||||
add(emptyItem)
|
||||
}
|
||||
add(TimetableWidgetItem.Normal(it))
|
||||
prevNum = it.number
|
||||
}
|
||||
add(TimetableWidgetItem.Synchronized(lastSync ?: Instant.MIN))
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTodayLastLessonEnd(appWidgetId: Int) {
|
||||
val todayLastLessonEnd = lessons.maxOfOrNull { it.end } ?: return
|
||||
val todayLastLessonEnd = items.filterIsInstance<TimetableWidgetItem.Normal>()
|
||||
.maxOfOrNull { it.lesson.end } ?: return
|
||||
val key = getTodayLastLessonEndDateTimeWidgetKey(appWidgetId)
|
||||
sharedPref.putLong(key, todayLastLessonEnd.epochSecond, true)
|
||||
}
|
||||
@ -112,15 +138,15 @@ class TimetableWidgetFactory(
|
||||
}
|
||||
|
||||
override fun getViewAt(position: Int): RemoteViews? {
|
||||
if (position == lessons.size) {
|
||||
val synchronizationInstant = lastSyncInstant ?: Instant.MIN
|
||||
val synchronizationText = getSynchronizationInfoText(synchronizationInstant)
|
||||
return RemoteViews(context.packageName, R.layout.item_widget_timetable_footer).apply {
|
||||
setTextViewText(R.id.timetableWidgetSynchronizationTime, synchronizationText)
|
||||
}
|
||||
return when (val item = items.getOrNull(position) ?: return null) {
|
||||
is TimetableWidgetItem.Normal -> getNormalItemRemoteView(item)
|
||||
is TimetableWidgetItem.Empty -> getEmptyItemRemoteView(item)
|
||||
is TimetableWidgetItem.Synchronized -> getSynchronizedItemRemoteView(item)
|
||||
}
|
||||
}
|
||||
|
||||
val lesson = lessons.getOrNull(position) ?: return null
|
||||
private fun getNormalItemRemoteView(item: TimetableWidgetItem.Normal): RemoteViews {
|
||||
val lesson = item.lesson
|
||||
|
||||
val lessonStartTime = lesson.start.toFormattedString(TIME_FORMAT_STYLE)
|
||||
val lessonEndTime = lesson.end.toFormattedString(TIME_FORMAT_STYLE)
|
||||
@ -130,30 +156,63 @@ class TimetableWidgetFactory(
|
||||
setTextViewText(R.id.timetableWidgetItemTimeStart, lessonStartTime)
|
||||
setTextViewText(R.id.timetableWidgetItemTimeFinish, lessonEndTime)
|
||||
setTextViewText(R.id.timetableWidgetItemSubject, lesson.subject)
|
||||
|
||||
setTextViewText(R.id.timetableWidgetItemTeacher, lesson.teacher)
|
||||
setTextViewText(R.id.timetableWidgetItemDescription, lesson.info)
|
||||
setOnClickFillInIntent(R.id.timetableWidgetItemContainer, Intent())
|
||||
}
|
||||
|
||||
updateTheme()
|
||||
clearLessonStyles(remoteViews)
|
||||
|
||||
if (lesson.room.isBlank()) {
|
||||
remoteViews.setViewVisibility(R.id.timetableWidgetItemRoom, GONE)
|
||||
} else {
|
||||
remoteViews.setTextViewText(R.id.timetableWidgetItemRoom, lesson.room)
|
||||
}
|
||||
|
||||
when {
|
||||
lesson.canceled -> applyCancelledLessonStyles(remoteViews)
|
||||
lesson.changes or lesson.info.isNotBlank() -> applyChangedLessonStyles(
|
||||
remoteViews, lesson
|
||||
remoteViews = remoteViews,
|
||||
lesson = lesson,
|
||||
)
|
||||
}
|
||||
|
||||
return remoteViews
|
||||
}
|
||||
|
||||
private fun getEmptyItemRemoteView(item: TimetableWidgetItem.Empty): RemoteViews {
|
||||
return RemoteViews(
|
||||
context.packageName,
|
||||
R.layout.item_widget_timetable_empty
|
||||
).apply {
|
||||
setTextViewText(
|
||||
R.id.timetableWidgetEmptyItemNumber,
|
||||
when (item.numFrom) {
|
||||
item.numTo -> item.numFrom.toString()
|
||||
else -> "${item.numFrom}-${item.numTo}"
|
||||
}
|
||||
)
|
||||
setTextViewText(
|
||||
R.id.timetableWidgetEmptyItemText,
|
||||
context.getPlural(
|
||||
R.plurals.timetable_no_lesson,
|
||||
item.numTo - item.numFrom + 1
|
||||
)
|
||||
)
|
||||
setOnClickFillInIntent(R.id.timetableWidgetEmptyItemContainer, Intent())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSynchronizedItemRemoteView(item: TimetableWidgetItem.Synchronized): RemoteViews {
|
||||
return RemoteViews(
|
||||
context.packageName,
|
||||
R.layout.item_widget_timetable_footer
|
||||
).apply {
|
||||
setTextViewText(
|
||||
R.id.timetableWidgetSynchronizationTime,
|
||||
getSynchronizationInfoText(item.timestamp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTheme() {
|
||||
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
||||
Configuration.UI_MODE_NIGHT_YES -> {
|
||||
|
@ -0,0 +1,26 @@
|
||||
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import java.time.Instant
|
||||
|
||||
sealed class TimetableWidgetItem(val type: TimetableWidgetItemType) {
|
||||
|
||||
data class Normal(
|
||||
val lesson: Timetable,
|
||||
) : TimetableWidgetItem(TimetableWidgetItemType.NORMAL)
|
||||
|
||||
data class Empty(
|
||||
val numFrom: Int,
|
||||
val numTo: Int
|
||||
) : TimetableWidgetItem(TimetableWidgetItemType.EMPTY)
|
||||
|
||||
data class Synchronized(
|
||||
val timestamp: Instant,
|
||||
) : TimetableWidgetItem(TimetableWidgetItemType.SYNCHRONIZED)
|
||||
}
|
||||
|
||||
enum class TimetableWidgetItemType {
|
||||
NORMAL,
|
||||
EMPTY,
|
||||
SYNCHRONIZED,
|
||||
}
|
43
app/src/main/res/layout/item_timetable_empty.xml
Normal file
43
app/src/main/res/layout/item_timetable_empty.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingBottom="6dp"
|
||||
tools:context=".ui.modules.timetable.TimetableAdapter">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableEmptyItemNumber"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLength="5"
|
||||
android:minWidth="40dp"
|
||||
android:minHeight="40dp"
|
||||
android:textColor="?android:textColorHint"
|
||||
android:textSize="32sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="1-4" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableEmptyItemSubject"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorHint"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/timetableEmptyItemNumber"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/timetableEmptyItemNumber"
|
||||
app:layout_constraintTop_toTopOf="@+id/timetableEmptyItemNumber"
|
||||
tools:text="No lessons" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
36
app/src/main/res/layout/item_widget_timetable_empty.xml
Normal file
36
app/src/main/res/layout/item_widget_timetable_empty.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/timetableWidgetEmptyItemContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_widget_item_timetable"
|
||||
android:backgroundTint="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="8dp"
|
||||
android:theme="@style/Wulkanowy.Widget.Theme"
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetFactory">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetEmptyItemNumber"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||
android:textColor="?android:textColorHint"
|
||||
android:textSize="22sp"
|
||||
tools:text="1-4" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetEmptyItemText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textColor="?android:textColorHint"
|
||||
tools:text="No lessons" />
|
||||
|
||||
</LinearLayout>
|
@ -51,6 +51,11 @@
|
||||
<item>Średnia ze średnich z obu semestrów</item>
|
||||
<item>Średnia wszystkich ocen z całego roku</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Nie pokauj</item>
|
||||
<item>Tylko między lekcjami</item>
|
||||
<item>Przed i między lekcjami</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Szczęśliwy numerek</item>
|
||||
<item>Nieprzeczytane wiadomości</item>
|
||||
|
@ -185,6 +185,12 @@
|
||||
<string name="timetable_notify_change_room">Zmiana sali z %1$s na %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Zmiana nauczyciela z %1$s na %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Zmiana przedmiotu z %1$s na %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">Brak lekcji</item>
|
||||
<item quantity="few">Brak lekcji</item>
|
||||
<item quantity="many">Brak lekcji</item>
|
||||
<item quantity="other">Brak lekcji</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Zmiana planu lekcji</item>
|
||||
<item quantity="few">Zmiany planu lekcji</item>
|
||||
@ -700,6 +706,7 @@
|
||||
<string name="pref_view_expand_grade">Rozwijanie ocen</string>
|
||||
<string name="pref_view_timetable_show_timers">Oznaczaj bieżącą lekcję</string>
|
||||
<string name="pref_view_timetable_show_groups">Pokazuj grupę obok przedmiotu</string>
|
||||
<string name="pref_view_timetable_show_gaps">Pokazuj puste kafelki gdzie nie ma lekcji</string>
|
||||
<string name="pref_view_grade_statistics_list">Pokazuj listę wykresów w ocenach klasy</string>
|
||||
<string name="pref_view_subjects_without_grades">Pokazuj przedmioty bez ocen</string>
|
||||
<string name="pref_view_grade_color_scheme">Schemat kolorów ocen</string>
|
||||
|
@ -23,6 +23,7 @@
|
||||
<string name="pref_default_timetable_show_whole_class">no</string>
|
||||
<string name="pref_default_grade_sorting_mode">alphabetic</string>
|
||||
<bool name="pref_default_timetable_show_timers">false</bool>
|
||||
<string name="pref_default_timetable_show_gaps">between</string>
|
||||
<bool name="pref_default_subjects_without_grades">false</bool>
|
||||
<bool name="pref_default_optional_arithmetic_average">false</bool>
|
||||
<string name="pref_default_last_sync_date">0</string>
|
||||
|
@ -28,6 +28,7 @@
|
||||
<string name="pref_key_timetable_show_whole_class">show_whole_class_plan</string>
|
||||
<string name="pref_key_timetable_show_groups">show_groups_in_plan</string>
|
||||
<string name="pref_key_timetable_show_timers">timetable_show_timers</string>
|
||||
<string name="pref_key_timetable_show_gaps">timetable_show_gaps</string>
|
||||
<string name="pref_key_subjects_without_grades">subjects_without_grades</string>
|
||||
<string name="pref_key_optional_arithmetic_average">optional_arithmetic_average</string>
|
||||
<string name="pref_key_message_draft">message_draft</string>
|
||||
|
@ -123,6 +123,17 @@
|
||||
<item>all_year</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_values" translatable="false">
|
||||
<item>no_gaps</item>
|
||||
<item>between</item>
|
||||
<item>before_and_between</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Lucky number</item>
|
||||
<item>Unread messages</item>
|
||||
|
@ -186,6 +186,10 @@
|
||||
<string name="timetable_notify_change_room">Change of room from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Change of teacher from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Change of subject from %1$s to %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Timetable change</item>
|
||||
<item quantity="other">Timetable changes</item>
|
||||
@ -690,6 +694,7 @@
|
||||
<string name="pref_view_expand_grade">Grades expanding</string>
|
||||
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
|
||||
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
|
||||
<string name="pref_view_subjects_without_grades">Show subjects without grades</string>
|
||||
<string name="pref_view_grade_color_scheme">Grades color scheme</string>
|
||||
|
@ -111,5 +111,13 @@
|
||||
app:title="@string/pref_view_timetable_show_whole_class"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
-->
|
||||
<ListPreference
|
||||
app:defaultValue="@string/pref_default_timetable_show_gaps"
|
||||
app:entries="@array/timetable_show_gaps_entries"
|
||||
app:entryValues="@array/timetable_show_gaps_values"
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="@string/pref_key_timetable_show_gaps"
|
||||
app:title="@string/pref_view_timetable_show_gaps"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
Loading…
x
Reference in New Issue
Block a user