mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-01-19 00:26:45 -06:00
Fix error handling in widgets (#2430)
This commit is contained in:
parent
cfec79405f
commit
ec101c1f52
@ -30,8 +30,15 @@ val <T> Resource<T>.dataOrNull: T?
|
|||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
is Resource.Success -> this.data
|
is Resource.Success -> this.data
|
||||||
is Resource.Intermediate -> this.data
|
is Resource.Intermediate -> this.data
|
||||||
is Resource.Loading -> null
|
else -> null
|
||||||
is Resource.Error -> null
|
}
|
||||||
|
|
||||||
|
val <T> Resource<T>.dataOrThrow: T
|
||||||
|
get() = when (this) {
|
||||||
|
is Resource.Success -> this.data
|
||||||
|
is Resource.Intermediate -> this.data
|
||||||
|
is Resource.Loading -> throw IllegalStateException("Resource is in loading state")
|
||||||
|
is Resource.Error -> throw this.error
|
||||||
}
|
}
|
||||||
|
|
||||||
val <T> Resource<T>.errorOrNull: Throwable?
|
val <T> Resource<T>.errorOrNull: Throwable?
|
||||||
|
@ -11,10 +11,8 @@ import android.view.View
|
|||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.dataOrThrow
|
||||||
import io.github.wulkanowy.data.dataOrNull
|
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
|
||||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.toFirstResult
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
@ -69,8 +67,7 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
|
|
||||||
appWidgetIds?.forEach { widgetId ->
|
appWidgetIds?.forEach { widgetId ->
|
||||||
val studentId = sharedPref.getLong(getStudentWidgetKey(widgetId), 0)
|
val studentId = sharedPref.getLong(getStudentWidgetKey(widgetId), 0)
|
||||||
val luckyNumberResource = getLuckyNumber(studentId, widgetId)
|
val luckyNumber = getLuckyNumber(studentId, widgetId)?.luckyNumber?.toString()
|
||||||
val luckyNumber = luckyNumberResource.dataOrNull?.luckyNumber?.toString()
|
|
||||||
val remoteView = RemoteViews(context.packageName, R.layout.widget_luckynumber)
|
val remoteView = RemoteViews(context.packageName, R.layout.widget_luckynumber)
|
||||||
.apply {
|
.apply {
|
||||||
setTextViewText(R.id.luckyNumberWidgetValue, luckyNumber ?: "-")
|
setTextViewText(R.id.luckyNumberWidgetValue, luckyNumber ?: "-")
|
||||||
@ -143,18 +140,18 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id)
|
sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentStudent != null) {
|
if (currentStudent != null) {
|
||||||
luckyNumberRepository.getLuckyNumber(currentStudent, forceRefresh = false)
|
luckyNumberRepository.getLuckyNumber(currentStudent, forceRefresh = false)
|
||||||
.toFirstResult()
|
.toFirstResult()
|
||||||
} else {
|
.dataOrThrow
|
||||||
Resource.Success<LuckyNumber?>(null)
|
} else null
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "An error has occurred in lucky number provider")
|
Timber.e(e, "An error has occurred in lucky number provider")
|
||||||
Resource.Error(e)
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import android.view.View.VISIBLE
|
|||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import android.widget.RemoteViewsService
|
import android.widget.RemoteViewsService
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.dataOrNull
|
import io.github.wulkanowy.data.dataOrThrow
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
@ -27,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.getStudentWidgetKey
|
||||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getTodayLastLessonEndDateTimeWidgetKey
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getTodayLastLessonEndDateTimeWidgetKey
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
|
import io.github.wulkanowy.utils.getErrorString
|
||||||
import io.github.wulkanowy.utils.getPlural
|
import io.github.wulkanowy.utils.getPlural
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
@ -67,25 +68,31 @@ class TimetableWidgetFactory(
|
|||||||
override fun onDestroy() {}
|
override fun onDestroy() {}
|
||||||
|
|
||||||
override fun onDataSetChanged() {
|
override fun onDataSetChanged() {
|
||||||
intent?.extras?.getInt(EXTRA_APPWIDGET_ID)?.let { appWidgetId ->
|
val appWidgetId = intent?.extras?.getInt(EXTRA_APPWIDGET_ID) ?: return
|
||||||
val date = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(appWidgetId), 0))
|
val date = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(appWidgetId), 0))
|
||||||
val studentId = sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0)
|
val studentId = sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0)
|
||||||
|
|
||||||
runCatching {
|
items = emptyList()
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
runCatching {
|
||||||
val student = getStudent(studentId) ?: return@runBlocking
|
val student = getStudent(studentId) ?: return@runBlocking
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
items = createItems(
|
val lessons = getLessons(student, semester, date)
|
||||||
lessons = getLessons(student, semester, date),
|
val lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
|
||||||
lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
|
|
||||||
)
|
createItems(lessons, lastSync)
|
||||||
|
}
|
||||||
|
.onFailure {
|
||||||
|
items = listOf(TimetableWidgetItem.Error(it))
|
||||||
|
Timber.e(it, "An error has occurred in timetable widget factory")
|
||||||
|
}
|
||||||
|
.onSuccess {
|
||||||
|
items = it
|
||||||
if (date == LocalDate.now()) {
|
if (date == LocalDate.now()) {
|
||||||
updateTodayLastLessonEnd(appWidgetId)
|
updateTodayLastLessonEnd(appWidgetId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onFailure {
|
|
||||||
Timber.e(it, "An error has occurred in timetable widget factory")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +105,7 @@ class TimetableWidgetFactory(
|
|||||||
student: Student, semester: Semester, date: LocalDate
|
student: Student, semester: Semester, date: LocalDate
|
||||||
): List<Timetable> {
|
): List<Timetable> {
|
||||||
val timetable = timetableRepository.getTimetable(student, semester, date, date, false)
|
val timetable = timetableRepository.getTimetable(student, semester, date, date, false)
|
||||||
val lessons = timetable.toFirstResult().dataOrNull?.lessons.orEmpty()
|
val lessons = timetable.toFirstResult().dataOrThrow.lessons
|
||||||
return lessons.sortedBy { it.number }
|
return lessons.sortedBy { it.number }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +117,7 @@ class TimetableWidgetFactory(
|
|||||||
BETWEEN_AND_BEFORE_LESSONS -> 0
|
BETWEEN_AND_BEFORE_LESSONS -> 0
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildList {
|
return buildList {
|
||||||
lessons.forEach {
|
lessons.forEach {
|
||||||
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
|
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
|
||||||
@ -133,15 +141,12 @@ class TimetableWidgetFactory(
|
|||||||
sharedPref.putLong(key, todayLastLessonEnd.epochSecond, true)
|
sharedPref.putLong(key, todayLastLessonEnd.epochSecond, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TIME_FORMAT_STYLE = "HH:mm"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getViewAt(position: Int): RemoteViews? {
|
override fun getViewAt(position: Int): RemoteViews? {
|
||||||
return when (val item = items.getOrNull(position) ?: return null) {
|
return when (val item = items.getOrNull(position) ?: return null) {
|
||||||
is TimetableWidgetItem.Normal -> getNormalItemRemoteView(item)
|
is TimetableWidgetItem.Normal -> getNormalItemRemoteView(item)
|
||||||
is TimetableWidgetItem.Empty -> getEmptyItemRemoteView(item)
|
is TimetableWidgetItem.Empty -> getEmptyItemRemoteView(item)
|
||||||
is TimetableWidgetItem.Synchronized -> getSynchronizedItemRemoteView(item)
|
is TimetableWidgetItem.Synchronized -> getSynchronizedItemRemoteView(item)
|
||||||
|
is TimetableWidgetItem.Error -> getErrorItemRemoteView(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +218,18 @@ class TimetableWidgetFactory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getErrorItemRemoteView(item: TimetableWidgetItem.Error): RemoteViews {
|
||||||
|
return RemoteViews(
|
||||||
|
context.packageName,
|
||||||
|
R.layout.item_widget_timetable_error
|
||||||
|
).apply {
|
||||||
|
setTextViewText(
|
||||||
|
R.id.timetable_widget_item_error_message,
|
||||||
|
context.resources.getErrorString(item.error)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateTheme() {
|
private fun updateTheme() {
|
||||||
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
||||||
Configuration.UI_MODE_NIGHT_YES -> {
|
Configuration.UI_MODE_NIGHT_YES -> {
|
||||||
@ -300,4 +317,8 @@ class TimetableWidgetFactory(
|
|||||||
synchronizationTime,
|
synchronizationTime,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val TIME_FORMAT_STYLE = "HH:mm"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,15 @@ sealed class TimetableWidgetItem(val type: TimetableWidgetItemType) {
|
|||||||
data class Synchronized(
|
data class Synchronized(
|
||||||
val timestamp: Instant,
|
val timestamp: Instant,
|
||||||
) : TimetableWidgetItem(TimetableWidgetItemType.SYNCHRONIZED)
|
) : TimetableWidgetItem(TimetableWidgetItemType.SYNCHRONIZED)
|
||||||
|
|
||||||
|
data class Error(
|
||||||
|
val error: Throwable
|
||||||
|
) : TimetableWidgetItem(TimetableWidgetItemType.ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class TimetableWidgetItemType {
|
enum class TimetableWidgetItemType {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
EMPTY,
|
EMPTY,
|
||||||
SYNCHRONIZED,
|
SYNCHRONIZED,
|
||||||
|
ERROR,
|
||||||
}
|
}
|
||||||
|
12
app/src/main/res/layout/item_widget_timetable_error.xml
Normal file
12
app/src/main/res/layout/item_widget_timetable_error.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/timetable_widget_item_error_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingHorizontal="12dp"
|
||||||
|
android:paddingTop="48dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="@string/error_unknown" />
|
@ -114,7 +114,5 @@
|
|||||||
android:text="@string/widget_timetable_no_items"
|
android:text="@string/widget_timetable_no_items"
|
||||||
android:textAppearance="?attr/textAppearanceBody1"
|
android:textAppearance="?attr/textAppearanceBody1"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user