forked from github/wulkanowy-mirror
Dashboard fixes (#1463)
This commit is contained in:
parent
2b55ec02ff
commit
77c5330f91
@ -33,10 +33,16 @@ class GradeRepository @Inject constructor(
|
||||
|
||||
private val cacheKey = "grade"
|
||||
|
||||
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
|
||||
fun getGrades(
|
||||
student: Student,
|
||||
semester: Semester,
|
||||
forceRefresh: Boolean,
|
||||
notify: Boolean = false
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = { (details, summaries) ->
|
||||
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
val isShouldBeRefreshed =
|
||||
refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
details.isEmpty() || summaries.isEmpty() || forceRefresh || isShouldBeRefreshed
|
||||
},
|
||||
query = {
|
||||
@ -59,8 +65,14 @@ class GradeRepository @Inject constructor(
|
||||
}
|
||||
)
|
||||
|
||||
private suspend fun refreshGradeDetails(student: Student, oldGrades: List<Grade>, newDetails: List<Grade>, notify: Boolean) {
|
||||
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
|
||||
private suspend fun refreshGradeDetails(
|
||||
student: Student,
|
||||
oldGrades: List<Grade>,
|
||||
newDetails: List<Grade>,
|
||||
notify: Boolean
|
||||
) {
|
||||
val notifyBreakDate =
|
||||
oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
|
||||
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
|
||||
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
|
||||
if (it.date >= notifyBreakDate) it.apply {
|
||||
@ -70,10 +82,15 @@ class GradeRepository @Inject constructor(
|
||||
})
|
||||
}
|
||||
|
||||
private suspend fun refreshGradeSummaries(oldSummaries: List<GradeSummary>, newSummary: List<GradeSummary>, notify: Boolean) {
|
||||
private suspend fun refreshGradeSummaries(
|
||||
oldSummaries: List<GradeSummary>,
|
||||
newSummary: List<GradeSummary>,
|
||||
notify: Boolean
|
||||
) {
|
||||
gradeSummaryDb.deleteAll(oldSummaries uniqueSubtract newSummary)
|
||||
gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
|
||||
val oldSummary = oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
|
||||
val oldSummary =
|
||||
oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
|
||||
summary.isPredictedGradeNotified = when {
|
||||
summary.predictedGrade.isEmpty() -> true
|
||||
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
|
||||
|
@ -22,7 +22,11 @@ class SemesterRepository @Inject constructor(
|
||||
private val dispatchers: DispatchersProvider
|
||||
) {
|
||||
|
||||
suspend fun getSemesters(student: Student, forceRefresh: Boolean = false, refreshOnNoCurrent: Boolean = false) = withContext(dispatchers.backgroundThread) {
|
||||
suspend fun getSemesters(
|
||||
student: Student,
|
||||
forceRefresh: Boolean = false,
|
||||
refreshOnNoCurrent: Boolean = false
|
||||
) = withContext(dispatchers.backgroundThread) {
|
||||
val semesters = semesterDb.loadAll(student.studentId, student.classId)
|
||||
|
||||
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
|
||||
@ -31,14 +35,21 @@ class SemesterRepository @Inject constructor(
|
||||
} else semesters
|
||||
}
|
||||
|
||||
private fun isShouldFetch(student: Student, semesters: List<Semester>, forceRefresh: Boolean, refreshOnNoCurrent: Boolean): Boolean {
|
||||
private fun isShouldFetch(
|
||||
student: Student,
|
||||
semesters: List<Semester>,
|
||||
forceRefresh: Boolean,
|
||||
refreshOnNoCurrent: Boolean
|
||||
): Boolean {
|
||||
val isNoSemesters = semesters.isEmpty()
|
||||
|
||||
val isRefreshOnModeChangeRequired = if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||
semesters.firstOrNull { it.isCurrent }?.diaryId == 0
|
||||
} else false
|
||||
val isRefreshOnModeChangeRequired =
|
||||
if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||
semesters.firstOrNull { it.isCurrent }?.diaryId == 0
|
||||
} else false
|
||||
|
||||
val isRefreshOnNoCurrentAppropriate = refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
|
||||
val isRefreshOnNoCurrentAppropriate =
|
||||
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
|
||||
|
||||
return forceRefresh || isNoSemesters || isRefreshOnModeChangeRequired || isRefreshOnNoCurrentAppropriate
|
||||
}
|
||||
@ -52,7 +63,8 @@ class SemesterRepository @Inject constructor(
|
||||
semesterDb.insertSemesters(new.uniqueSubtract(old))
|
||||
}
|
||||
|
||||
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) = withContext(dispatchers.backgroundThread) {
|
||||
getSemesters(student, forceRefresh).getCurrentOrLast()
|
||||
}
|
||||
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) =
|
||||
withContext(dispatchers.backgroundThread) {
|
||||
getSemesters(student, forceRefresh).getCurrentOrLast()
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ open class BasePresenter<T : BaseView>(
|
||||
protected val studentRepository: StudentRepository
|
||||
) : CoroutineScope {
|
||||
|
||||
private var job: Job = Job()
|
||||
private var job = Job()
|
||||
|
||||
private val jobs = mutableMapOf<String, Job>()
|
||||
|
||||
|
@ -8,7 +8,7 @@ import androidx.core.view.get
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.databinding.FragmentAccountBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
||||
@ -75,9 +75,7 @@ class AccountFragment : BaseFragment<FragmentAccountBinding>(R.layout.fragment_a
|
||||
}
|
||||
}
|
||||
|
||||
override fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters) {
|
||||
(activity as? MainActivity)?.pushView(
|
||||
AccountDetailsFragment.newInstance(studentWithSemesters)
|
||||
)
|
||||
override fun openAccountDetailsView(student: Student) {
|
||||
(activity as? MainActivity)?.pushView(AccountDetailsFragment.newInstance(student))
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class AccountPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onItemSelected(studentWithSemesters: StudentWithSemesters) {
|
||||
view?.openAccountDetailsView(studentWithSemesters)
|
||||
view?.openAccountDetailsView(studentWithSemesters.student)
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.account
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface AccountView : BaseView {
|
||||
@ -11,5 +11,5 @@ interface AccountView : BaseView {
|
||||
|
||||
fun openLoginView()
|
||||
|
||||
fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters)
|
||||
fun openAccountDetailsView(student: Student)
|
||||
}
|
||||
|
@ -37,9 +37,9 @@ class AccountDetailsFragment :
|
||||
|
||||
private const val ARGUMENT_KEY = "Data"
|
||||
|
||||
fun newInstance(studentWithSemesters: StudentWithSemesters) =
|
||||
fun newInstance(student: Student) =
|
||||
AccountDetailsFragment().apply {
|
||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, studentWithSemesters) }
|
||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, student) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ class AccountDetailsFragment :
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentAccountDetailsBinding.bind(view)
|
||||
presenter.onAttachView(this, requireArguments()[ARGUMENT_KEY] as StudentWithSemesters)
|
||||
presenter.onAttachView(this, requireArguments()[ARGUMENT_KEY] as Student)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.account.accountdetails
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.services.sync.SyncManager
|
||||
@ -27,9 +28,9 @@ class AccountDetailsPresenter @Inject constructor(
|
||||
|
||||
private var studentId: Long? = null
|
||||
|
||||
fun onAttachView(view: AccountDetailsView, studentWithSemesters: StudentWithSemesters) {
|
||||
fun onAttachView(view: AccountDetailsView, student: Student) {
|
||||
super.onAttachView(view)
|
||||
studentId = studentWithSemesters.student.id
|
||||
studentId = student.id
|
||||
|
||||
view.initView()
|
||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||
|
@ -14,6 +14,7 @@ import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||
import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
|
||||
@ -41,7 +42,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
|
||||
private var lessonsTimer: Timer? = null
|
||||
|
||||
var onAccountTileClickListener: () -> Unit = {}
|
||||
var onAccountTileClickListener: (Student) -> Unit = {}
|
||||
|
||||
var onLuckyNumberTileClickListener: () -> Unit = {}
|
||||
|
||||
@ -152,7 +153,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
dashboardAccountItemName.text = student?.nickOrName.orEmpty()
|
||||
dashboardAccountItemSchoolName.text = student?.schoolName.orEmpty()
|
||||
|
||||
root.setOnClickListener { onAccountTileClickListener() }
|
||||
root.setOnClickListener { student?.let(onAccountTileClickListener) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,38 +171,41 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
val binding = horizontalGroupViewHolder.binding
|
||||
val context = binding.root.context
|
||||
val attendanceColor = when {
|
||||
attendancePercentage ?: 0.0 <= ATTENDANCE_SECOND_WARNING_THRESHOLD -> {
|
||||
attendancePercentage == null || attendancePercentage == .0 -> {
|
||||
context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||
}
|
||||
attendancePercentage <= ATTENDANCE_SECOND_WARNING_THRESHOLD -> {
|
||||
context.getThemeAttrColor(R.attr.colorPrimary)
|
||||
}
|
||||
attendancePercentage ?: 0.0 <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> {
|
||||
attendancePercentage <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> {
|
||||
context.getThemeAttrColor(R.attr.colorTimetableChange)
|
||||
}
|
||||
else -> context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||
}
|
||||
val attendanceString = if (attendancePercentage == null || attendancePercentage == .0) {
|
||||
context.getString(R.string.dashboard_horizontal_group_no_data)
|
||||
} else {
|
||||
"%.2f%%".format(attendancePercentage)
|
||||
}
|
||||
|
||||
with(binding.dashboardHorizontalGroupItemAttendanceValue) {
|
||||
text = "%.2f%%".format(attendancePercentage)
|
||||
text = attendanceString
|
||||
setTextColor(attendanceColor)
|
||||
}
|
||||
|
||||
with(binding) {
|
||||
dashboardHorizontalGroupItemMessageValue.text = unreadMessagesCount.toString()
|
||||
dashboardHorizontalGroupItemLuckyValue.text = if (luckyNumber == -1) {
|
||||
context.getString(R.string.dashboard_horizontal_group_no_lukcy_number)
|
||||
dashboardHorizontalGroupItemLuckyValue.text = if (luckyNumber == 0) {
|
||||
context.getString(R.string.dashboard_horizontal_group_no_data)
|
||||
} else luckyNumber?.toString()
|
||||
|
||||
if (dashboardHorizontalGroupItemInfoContainer.isVisible != (error != null || isLoading)) {
|
||||
dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoading
|
||||
}
|
||||
|
||||
if (dashboardHorizontalGroupItemInfoProgress.isVisible != isLoading) {
|
||||
dashboardHorizontalGroupItemInfoProgress.isVisible = isLoading
|
||||
}
|
||||
|
||||
dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoading
|
||||
dashboardHorizontalGroupItemInfoProgress.isVisible =
|
||||
(isLoading && !item.isDataLoaded) || (isLoading && !item.isFullDataLoaded)
|
||||
dashboardHorizontalGroupItemInfoErrorText.isVisible = error != null
|
||||
|
||||
with(dashboardHorizontalGroupItemLuckyContainer) {
|
||||
isVisible = error == null && !isLoading && luckyNumber != null
|
||||
isVisible = luckyNumber != null && luckyNumber != -1
|
||||
setOnClickListener { onLuckyNumberTileClickListener() }
|
||||
|
||||
updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
@ -216,7 +220,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
}
|
||||
|
||||
with(dashboardHorizontalGroupItemAttendanceContainer) {
|
||||
isVisible = error == null && !isLoading && attendancePercentage != null
|
||||
isVisible = attendancePercentage != null && attendancePercentage != -1.0
|
||||
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
matchConstraintPercentWidth = when {
|
||||
luckyNumber == null && unreadMessagesCount == null -> 1.0f
|
||||
@ -228,7 +232,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
}
|
||||
|
||||
with(dashboardHorizontalGroupItemMessageContainer) {
|
||||
isVisible = error == null && !isLoading && unreadMessagesCount != null
|
||||
isVisible = unreadMessagesCount != null && unreadMessagesCount != -1
|
||||
setOnClickListener { onMessageTileClickListener() }
|
||||
}
|
||||
}
|
||||
@ -291,14 +295,14 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
updateLessonView(item, currentTimetable, binding)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||
}
|
||||
currentDayHeader != null && currentDayHeader.content.isNotBlank() -> {
|
||||
updateLessonView(item, emptyList(), binding, currentDayHeader)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||
}
|
||||
tomorrowTimetable.isNotEmpty() -> {
|
||||
updateLessonView(item, tomorrowTimetable, binding)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
||||
}
|
||||
currentDayHeader != null && currentDayHeader.content.isNotBlank() -> {
|
||||
updateLessonView(item, emptyList(), binding, currentDayHeader)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||
}
|
||||
tomorrowDayHeader != null && tomorrowDayHeader.content.isNotBlank() -> {
|
||||
updateLessonView(item, emptyList(), binding, tomorrowDayHeader)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
||||
@ -348,6 +352,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun updateFirstLessonView(
|
||||
binding: ItemDashboardLessonsBinding,
|
||||
firstLesson: Timetable?,
|
||||
@ -367,7 +372,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
firstLesson ?: return
|
||||
|
||||
val minutesToStartLesson =
|
||||
Duration.between(currentDateTime, firstLesson.start).toMinutes()
|
||||
Duration.between(currentDateTime, firstLesson.start).toMinutes() + 1
|
||||
val isFirstTimeVisible: Boolean
|
||||
val isFirstTimeRangeVisible: Boolean
|
||||
val firstTimeText: String
|
||||
@ -376,12 +381,12 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
val firstTitleAndValueTextColor: Int
|
||||
val firstTitleAndValueTextFont: Typeface
|
||||
|
||||
if (currentDateTime.isBefore(firstLesson.start)) {
|
||||
if (currentDateTime < firstLesson.start) {
|
||||
if (minutesToStartLesson > 60) {
|
||||
val formattedStartTime = firstLesson.start.toFormattedString("HH:mm")
|
||||
val formattedEndTime = firstLesson.end.toFormattedString("HH:mm")
|
||||
|
||||
firstTimeRangeText = "${formattedStartTime}-${formattedEndTime}"
|
||||
firstTimeRangeText = "$formattedStartTime - $formattedEndTime"
|
||||
firstTimeText = ""
|
||||
|
||||
isFirstTimeRangeVisible = true
|
||||
@ -421,7 +426,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val minutesToEndLesson = firstLesson.left!!.toMinutes()
|
||||
val minutesToEndLesson = firstLesson.left!!.toMinutes() + 1
|
||||
|
||||
firstTimeText = context.resources.getQuantityString(
|
||||
R.plurals.dashboard_timetable_first_lesson_time_more_minutes,
|
||||
@ -454,11 +459,8 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
with(binding.dashboardLessonsItemFirstValue) {
|
||||
setTextColor(firstTitleAndValueTextColor)
|
||||
typeface = firstTitleAndValueTextFont
|
||||
text = context.getString(
|
||||
R.string.dashboard_timetable_lesson_value,
|
||||
firstLesson.subject,
|
||||
firstLesson.room
|
||||
)
|
||||
text =
|
||||
"${firstLesson.subject} ${if (firstLesson.room.isNotBlank()) "(${firstLesson.room})" else ""}"
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,13 +474,11 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
val formattedStartTime = secondLesson?.start?.toFormattedString("HH:mm")
|
||||
val formattedEndTime = secondLesson?.end?.toFormattedString("HH:mm")
|
||||
|
||||
val secondTimeText = "${formattedStartTime}-${formattedEndTime}"
|
||||
val secondTimeText = "$formattedStartTime - $formattedEndTime"
|
||||
val secondValueText = if (secondLesson != null) {
|
||||
context.getString(
|
||||
R.string.dashboard_timetable_lesson_value,
|
||||
secondLesson.subject,
|
||||
secondLesson.room
|
||||
)
|
||||
val roomString = if (secondLesson.room.isNotBlank()) "(${secondLesson.room})" else ""
|
||||
|
||||
"${secondLesson.subject} $roomString"
|
||||
} else {
|
||||
context.getString(R.string.dashboard_timetable_second_lesson_value_end)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.FragmentDashboardBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.account.AccountFragment
|
||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
||||
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
|
||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||
@ -77,7 +77,9 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
||||
)
|
||||
|
||||
dashboardAdapter.apply {
|
||||
onAccountTileClickListener = { mainActivity.pushView(AccountFragment.newInstance()) }
|
||||
onAccountTileClickListener = {
|
||||
mainActivity.pushView(AccountDetailsFragment.newInstance(it))
|
||||
}
|
||||
onLuckyNumberTileClickListener = {
|
||||
mainActivity.pushView(LuckyNumberFragment.newInstance())
|
||||
}
|
||||
|
@ -35,6 +35,9 @@ sealed class DashboardItem(val type: Type) {
|
||||
|
||||
override val isDataLoaded
|
||||
get() = unreadMessagesCount != null || attendancePercentage != null || luckyNumber != null
|
||||
|
||||
val isFullDataLoaded
|
||||
get() = luckyNumber != -1 && attendancePercentage != -1.0 && unreadMessagesCount != -1
|
||||
}
|
||||
|
||||
data class Grades(
|
||||
|
@ -2,6 +2,8 @@ package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.enums.MessageFolder
|
||||
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
|
||||
import io.github.wulkanowy.data.repositories.ConferenceRepository
|
||||
@ -18,11 +20,18 @@ 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.calculatePercentage
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.filterNot
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
@ -48,9 +57,11 @@ class DashboardPresenter @Inject constructor(
|
||||
|
||||
private val dashboardItemRefreshLoadedList = mutableListOf<DashboardItem>()
|
||||
|
||||
private lateinit var dashboardItemsToLoad: Set<DashboardItem.Type>
|
||||
private var dashboardItemsToLoad = emptySet<DashboardItem.Type>()
|
||||
|
||||
private var dashboardTilesToLoad: Set<DashboardItem.Tile> = emptySet()
|
||||
private var dashboardTileLoadedList = emptySet<DashboardItem.Tile>()
|
||||
|
||||
private val firstLoadedItemList = mutableListOf<DashboardItem.Type>()
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
||||
@ -69,8 +80,10 @@ class DashboardPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onDragAndDropEnd(list: List<DashboardItem>) {
|
||||
dashboardItemLoadedList.clear()
|
||||
dashboardItemLoadedList.addAll(list)
|
||||
with(dashboardItemLoadedList) {
|
||||
clear()
|
||||
addAll(list)
|
||||
}
|
||||
|
||||
val positionList =
|
||||
list.mapIndexed { index, dashboardItem -> Pair(dashboardItem.type, index) }.toMap()
|
||||
@ -78,87 +91,102 @@ class DashboardPresenter @Inject constructor(
|
||||
preferencesRepository.dashboardItemsPosition = positionList
|
||||
}
|
||||
|
||||
fun loadData(forceRefresh: Boolean = false, tilesToLoad: Set<DashboardItem.Tile>) {
|
||||
val oldDashboardDataToLoad = dashboardTilesToLoad
|
||||
fun loadData(
|
||||
tilesToLoad: Set<DashboardItem.Tile>,
|
||||
forceRefresh: Boolean = false,
|
||||
) {
|
||||
val oldDashboardTileLoadedList = dashboardTileLoadedList
|
||||
dashboardItemsToLoad = tilesToLoad.map { it.toDashboardItemType() }.toSet()
|
||||
dashboardTileLoadedList = tilesToLoad
|
||||
|
||||
dashboardTilesToLoad = tilesToLoad
|
||||
dashboardItemsToLoad = dashboardTilesToLoad.map { it.toDashboardItemType() }.toSet()
|
||||
val itemsToLoad = generateDashboardTileListToLoad(
|
||||
dashboardTilesToLoad = tilesToLoad,
|
||||
dashboardLoadedTiles = oldDashboardTileLoadedList,
|
||||
forceRefresh = forceRefresh
|
||||
).map { it.toDashboardItemType() }
|
||||
|
||||
removeUnselectedTiles()
|
||||
|
||||
val newTileList = generateTileListToLoad(oldDashboardDataToLoad, forceRefresh)
|
||||
loadTiles(forceRefresh, newTileList)
|
||||
removeUnselectedTiles(tilesToLoad.toList())
|
||||
loadTiles(tileList = itemsToLoad, forceRefresh = forceRefresh)
|
||||
}
|
||||
|
||||
private fun removeUnselectedTiles() {
|
||||
val isLuckyNumberToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.LUCKY_NUMBER }
|
||||
val isMessagesToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.MESSAGES }
|
||||
val isAttendanceToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.ATTENDANCE }
|
||||
private fun generateDashboardTileListToLoad(
|
||||
dashboardTilesToLoad: Set<DashboardItem.Tile>,
|
||||
dashboardLoadedTiles: Set<DashboardItem.Tile>,
|
||||
forceRefresh: Boolean
|
||||
) = dashboardTilesToLoad.filter { newItemToLoad ->
|
||||
dashboardLoadedTiles.none { it == newItemToLoad } || forceRefresh
|
||||
}
|
||||
|
||||
private fun removeUnselectedTiles(tilesToLoad: List<DashboardItem.Tile>) {
|
||||
dashboardItemLoadedList.removeAll { loadedTile -> dashboardItemsToLoad.none { it == loadedTile.type } }
|
||||
|
||||
val horizontalGroup =
|
||||
dashboardItemLoadedList.find { it is DashboardItem.HorizontalGroup } as DashboardItem.HorizontalGroup?
|
||||
|
||||
if (horizontalGroup != null) {
|
||||
val horizontalIndex = dashboardItemLoadedList.indexOf(horizontalGroup)
|
||||
dashboardItemLoadedList.remove(horizontalGroup)
|
||||
val isLuckyNumberToLoad = DashboardItem.Tile.LUCKY_NUMBER in tilesToLoad
|
||||
val isMessagesToLoad = DashboardItem.Tile.MESSAGES in tilesToLoad
|
||||
val isAttendanceToLoad = DashboardItem.Tile.ATTENDANCE in tilesToLoad
|
||||
|
||||
var updatedHorizontalGroup = horizontalGroup
|
||||
val horizontalGroupIndex = dashboardItemLoadedList.indexOf(horizontalGroup)
|
||||
|
||||
if (horizontalGroup.luckyNumber != null && !isLuckyNumberToLoad) {
|
||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(luckyNumber = null)
|
||||
val newHorizontalGroup = horizontalGroup.copy(
|
||||
attendancePercentage = horizontalGroup.attendancePercentage.takeIf { isAttendanceToLoad },
|
||||
unreadMessagesCount = horizontalGroup.unreadMessagesCount.takeIf { isMessagesToLoad },
|
||||
luckyNumber = horizontalGroup.luckyNumber.takeIf { isLuckyNumberToLoad }
|
||||
)
|
||||
|
||||
with(dashboardItemLoadedList) {
|
||||
removeAt(horizontalGroupIndex)
|
||||
add(horizontalGroupIndex, newHorizontalGroup)
|
||||
}
|
||||
|
||||
if (horizontalGroup.attendancePercentage != null && !isAttendanceToLoad) {
|
||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(attendancePercentage = null)
|
||||
}
|
||||
|
||||
if (horizontalGroup.unreadMessagesCount != null && !isMessagesToLoad) {
|
||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(unreadMessagesCount = null)
|
||||
}
|
||||
|
||||
if (horizontalGroup.error != null) {
|
||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(error = null, isLoading = true)
|
||||
}
|
||||
|
||||
dashboardItemLoadedList.add(horizontalIndex, updatedHorizontalGroup)
|
||||
}
|
||||
|
||||
view?.updateData(dashboardItemLoadedList)
|
||||
}
|
||||
|
||||
private fun loadTiles(forceRefresh: Boolean, tileList: List<DashboardItem.Tile>) {
|
||||
tileList.forEach {
|
||||
when (it) {
|
||||
DashboardItem.Tile.ACCOUNT -> loadCurrentAccount(forceRefresh)
|
||||
DashboardItem.Tile.LUCKY_NUMBER -> loadLuckyNumber(forceRefresh)
|
||||
DashboardItem.Tile.MESSAGES -> loadMessages(forceRefresh)
|
||||
DashboardItem.Tile.ATTENDANCE -> loadAttendance(forceRefresh)
|
||||
DashboardItem.Tile.LESSONS -> loadLessons(forceRefresh)
|
||||
DashboardItem.Tile.GRADES -> loadGrades(forceRefresh)
|
||||
DashboardItem.Tile.HOMEWORK -> loadHomework(forceRefresh)
|
||||
DashboardItem.Tile.ANNOUNCEMENTS -> loadSchoolAnnouncements(forceRefresh)
|
||||
DashboardItem.Tile.EXAMS -> loadExams(forceRefresh)
|
||||
DashboardItem.Tile.CONFERENCES -> loadConferences(forceRefresh)
|
||||
DashboardItem.Tile.ADS -> TODO()
|
||||
private fun loadTiles(
|
||||
tileList: List<DashboardItem.Type>,
|
||||
forceRefresh: Boolean
|
||||
) {
|
||||
launch {
|
||||
Timber.i("Loading dashboard account data started")
|
||||
val student = runCatching { studentRepository.getCurrentStudent(true) }
|
||||
.onFailure {
|
||||
Timber.i("Loading dashboard account result: An exception occurred")
|
||||
errorHandler.dispatch(it)
|
||||
updateData(DashboardItem.Account(error = it), forceRefresh)
|
||||
}
|
||||
.onSuccess { Timber.i("Loading dashboard account result: Success") }
|
||||
.getOrNull() ?: return@launch
|
||||
|
||||
tileList.forEach {
|
||||
when (it) {
|
||||
DashboardItem.Type.ACCOUNT -> {
|
||||
updateData(DashboardItem.Account(student), forceRefresh)
|
||||
}
|
||||
DashboardItem.Type.HORIZONTAL_GROUP -> {
|
||||
loadHorizontalGroup(student, forceRefresh)
|
||||
}
|
||||
DashboardItem.Type.LESSONS -> loadLessons(student, forceRefresh)
|
||||
DashboardItem.Type.GRADES -> loadGrades(student, forceRefresh)
|
||||
DashboardItem.Type.HOMEWORK -> loadHomework(student, forceRefresh)
|
||||
DashboardItem.Type.ANNOUNCEMENTS -> {
|
||||
loadSchoolAnnouncements(student, forceRefresh)
|
||||
}
|
||||
DashboardItem.Type.EXAMS -> loadExams(student, forceRefresh)
|
||||
DashboardItem.Type.CONFERENCES -> {
|
||||
loadConferences(student, forceRefresh)
|
||||
}
|
||||
DashboardItem.Type.ADS -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateTileListToLoad(
|
||||
oldDashboardTileToLoad: Set<DashboardItem.Tile>,
|
||||
forceRefresh: Boolean
|
||||
) = dashboardTilesToLoad.filter { newTileToLoad ->
|
||||
oldDashboardTileToLoad.none { it == newTileToLoad } || forceRefresh
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
Timber.i("Force refreshing the dashboard")
|
||||
loadData(true, preferencesRepository.selectedDashboardTiles)
|
||||
loadData(preferencesRepository.selectedDashboardTiles, forceRefresh = true)
|
||||
}
|
||||
|
||||
fun onRetry() {
|
||||
@ -166,7 +194,7 @@ class DashboardPresenter @Inject constructor(
|
||||
showErrorView(false)
|
||||
showProgress(true)
|
||||
}
|
||||
loadData(true, preferencesRepository.selectedDashboardTiles)
|
||||
loadData(preferencesRepository.selectedDashboardTiles, forceRefresh = true)
|
||||
}
|
||||
|
||||
fun onViewReselected() {
|
||||
@ -192,139 +220,86 @@ class DashboardPresenter @Inject constructor(
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
private fun loadCurrentAccount(forceRefresh: Boolean) {
|
||||
flowWithResource { studentRepository.getCurrentStudent(false) }
|
||||
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
||||
flow {
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
||||
|
||||
val luckyNumberFlow = luckyNumberRepository.getLuckyNumber(student, forceRefresh)
|
||||
.map {
|
||||
if (it.data == null) {
|
||||
it.copy(data = LuckyNumber(0, LocalDate.now(), 0))
|
||||
} else it
|
||||
}
|
||||
.takeIf { DashboardItem.Tile.LUCKY_NUMBER in selectedTiles } ?: flowOf(null)
|
||||
|
||||
val messageFLow = messageRepository.getMessages(
|
||||
student = student,
|
||||
semester = semester,
|
||||
folder = MessageFolder.RECEIVED,
|
||||
forceRefresh = forceRefresh
|
||||
).takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowOf(null)
|
||||
|
||||
val attendanceFlow = attendanceSummaryRepository.getAttendanceSummary(
|
||||
student = student,
|
||||
semester = semester,
|
||||
subjectId = -1,
|
||||
forceRefresh = forceRefresh
|
||||
).takeIf { DashboardItem.Tile.ATTENDANCE in selectedTiles } ?: flowOf(null)
|
||||
|
||||
emitAll(
|
||||
combine(
|
||||
luckyNumberFlow,
|
||||
messageFLow,
|
||||
attendanceFlow
|
||||
) { luckyNumberResource, messageResource, attendanceResource ->
|
||||
val error =
|
||||
luckyNumberResource?.error ?: messageResource?.error ?: attendanceResource?.error
|
||||
error?.let { throw it }
|
||||
|
||||
val luckyNumber = luckyNumberResource?.data?.luckyNumber
|
||||
val messageCount = messageResource?.data?.count { it.unread }
|
||||
val attendancePercentage = attendanceResource?.data?.calculatePercentage()
|
||||
|
||||
val isLoading =
|
||||
luckyNumberResource?.status == Status.LOADING || messageResource?.status == Status.LOADING || attendanceResource?.status == Status.LOADING
|
||||
|
||||
DashboardItem.HorizontalGroup(
|
||||
isLoading = isLoading,
|
||||
attendancePercentage = if (attendancePercentage == 0.0 && isLoading) -1.0 else attendancePercentage,
|
||||
unreadMessagesCount = if (messageCount == 0 && isLoading) -1 else messageCount,
|
||||
luckyNumber = if (luckyNumber == 0 && isLoading) -1 else luckyNumber
|
||||
)
|
||||
})
|
||||
}
|
||||
.filterNot { it.isLoading && forceRefresh }
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard account data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(DashboardItem.Account(it.data, isLoading = true), forceRefresh)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard account result: Success")
|
||||
updateData(DashboardItem.Account(it.data), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard account result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Account(error = it.error), forceRefresh)
|
||||
updateData(it, forceRefresh)
|
||||
|
||||
if (it.isLoading) {
|
||||
Timber.i("Loading horizontal group data started")
|
||||
|
||||
if (it.isFullDataLoaded) {
|
||||
firstLoadedItemList += DashboardItem.Type.HORIZONTAL_GROUP
|
||||
}
|
||||
} else {
|
||||
Timber.i("Loading horizontal group result: Success")
|
||||
}
|
||||
}
|
||||
.launch("dashboard_account")
|
||||
}
|
||||
|
||||
private fun loadLuckyNumber(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
|
||||
luckyNumberRepository.getLuckyNumber(student, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard lucky number data started")
|
||||
if (forceRefresh) return@onEach
|
||||
processHorizontalGroupData(
|
||||
luckyNumber = it.data?.luckyNumber,
|
||||
isLoading = true,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard lucky number result: Success")
|
||||
processHorizontalGroupData(
|
||||
luckyNumber = it.data?.luckyNumber ?: -1,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard lucky number result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
processHorizontalGroupData(error = it.error, forceRefresh = forceRefresh)
|
||||
}
|
||||
.catch {
|
||||
Timber.i("Loading horizontal group result: An exception occurred")
|
||||
updateData(
|
||||
DashboardItem.HorizontalGroup(error = it),
|
||||
forceRefresh,
|
||||
)
|
||||
errorHandler.dispatch(it)
|
||||
}
|
||||
}.launch("dashboard_lucky_number")
|
||||
.launch("horizontal_group")
|
||||
}
|
||||
|
||||
private fun loadMessages(forceRefresh: Boolean) {
|
||||
private fun loadGrades(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
messageRepository.getMessages(student, semester, MessageFolder.RECEIVED, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard messages data started")
|
||||
if (forceRefresh) return@onEach
|
||||
val unreadMessagesCount = it.data?.count { message -> message.unread }
|
||||
|
||||
processHorizontalGroupData(
|
||||
unreadMessagesCount = unreadMessagesCount,
|
||||
isLoading = true,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard messages result: Success")
|
||||
val unreadMessagesCount = it.data?.count { message -> message.unread }
|
||||
|
||||
processHorizontalGroupData(
|
||||
unreadMessagesCount = unreadMessagesCount,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard messages result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
processHorizontalGroupData(error = it.error, forceRefresh = forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_messages")
|
||||
}
|
||||
|
||||
private fun loadAttendance(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
attendanceSummaryRepository.getAttendanceSummary(student, semester, -1, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard attendance data started")
|
||||
if (forceRefresh) return@onEach
|
||||
val attendancePercentage = it.data?.calculatePercentage()
|
||||
|
||||
processHorizontalGroupData(
|
||||
attendancePercentage = attendancePercentage,
|
||||
isLoading = true,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard attendance result: Success")
|
||||
val attendancePercentage = it.data?.calculatePercentage()
|
||||
|
||||
processHorizontalGroupData(
|
||||
attendancePercentage = attendancePercentage,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard attendance result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
|
||||
processHorizontalGroupData(error = it.error, forceRefresh = forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_attendance")
|
||||
}
|
||||
|
||||
private fun loadGrades(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
gradeRepository.getGrades(student, semester, forceRefresh)
|
||||
@ -353,6 +328,7 @@ class DashboardPresenter @Inject constructor(
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard grades data started")
|
||||
if (forceRefresh) return@onEach
|
||||
|
||||
updateData(
|
||||
DashboardItem.Grades(
|
||||
subjectWithGrades = it.data,
|
||||
@ -360,6 +336,10 @@ class DashboardPresenter @Inject constructor(
|
||||
isLoading = true
|
||||
), forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.GRADES
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard grades result: Success")
|
||||
@ -367,7 +347,8 @@ class DashboardPresenter @Inject constructor(
|
||||
DashboardItem.Grades(
|
||||
subjectWithGrades = it.data,
|
||||
gradeTheme = preferencesRepository.gradeColorTheme
|
||||
), forceRefresh
|
||||
),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
@ -379,9 +360,8 @@ class DashboardPresenter @Inject constructor(
|
||||
}.launch("dashboard_grades")
|
||||
}
|
||||
|
||||
private fun loadLessons(forceRefresh: Boolean) {
|
||||
private fun loadLessons(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val date = LocalDate.now().nextOrSameSchoolDay
|
||||
|
||||
@ -398,24 +378,34 @@ class DashboardPresenter @Inject constructor(
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard lessons data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(DashboardItem.Lessons(it.data, isLoading = true), forceRefresh)
|
||||
updateData(
|
||||
DashboardItem.Lessons(it.data, isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data?.lessons.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.LESSONS
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard lessons result: Success")
|
||||
updateData(DashboardItem.Lessons(it.data), forceRefresh)
|
||||
updateData(
|
||||
DashboardItem.Lessons(it.data), forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard lessons result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Lessons(error = it.error), forceRefresh)
|
||||
updateData(
|
||||
DashboardItem.Lessons(error = it.error), forceRefresh
|
||||
)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_lessons")
|
||||
}
|
||||
|
||||
private fun loadHomework(forceRefresh: Boolean) {
|
||||
private fun loadHomework(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val date = LocalDate.now().nextOrSameSchoolDay
|
||||
|
||||
@ -443,6 +433,10 @@ class DashboardPresenter @Inject constructor(
|
||||
DashboardItem.Homework(it.data ?: emptyList(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.HOMEWORK
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard homework result: Success")
|
||||
@ -457,10 +451,8 @@ class DashboardPresenter @Inject constructor(
|
||||
}.launch("dashboard_homework")
|
||||
}
|
||||
|
||||
private fun loadSchoolAnnouncements(forceRefresh: Boolean) {
|
||||
private fun loadSchoolAnnouncements(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
|
||||
schoolAnnouncementRepository.getSchoolAnnouncements(student, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
@ -468,11 +460,13 @@ class DashboardPresenter @Inject constructor(
|
||||
Timber.i("Loading dashboard announcements data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Announcements(
|
||||
it.data ?: emptyList(),
|
||||
isLoading = true
|
||||
), forceRefresh
|
||||
DashboardItem.Announcements(it.data ?: emptyList(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.ANNOUNCEMENTS
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard announcements result: Success")
|
||||
@ -487,9 +481,8 @@ class DashboardPresenter @Inject constructor(
|
||||
}.launch("dashboard_announcements")
|
||||
}
|
||||
|
||||
private fun loadExams(forceRefresh: Boolean) {
|
||||
private fun loadExams(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
examRepository.getExams(
|
||||
@ -508,6 +501,10 @@ class DashboardPresenter @Inject constructor(
|
||||
DashboardItem.Exams(it.data.orEmpty(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.EXAMS
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard exams result: Success")
|
||||
@ -522,9 +519,8 @@ class DashboardPresenter @Inject constructor(
|
||||
}.launch("dashboard_exams")
|
||||
}
|
||||
|
||||
private fun loadConferences(forceRefresh: Boolean) {
|
||||
private fun loadConferences(student: Student, forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
conferenceRepository.getConferences(
|
||||
@ -542,6 +538,10 @@ class DashboardPresenter @Inject constructor(
|
||||
DashboardItem.Conferences(it.data ?: emptyList(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
|
||||
if (!it.data.isNullOrEmpty()) {
|
||||
firstLoadedItemList += DashboardItem.Type.CONFERENCES
|
||||
}
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard conferences result: Success")
|
||||
@ -556,145 +556,119 @@ class DashboardPresenter @Inject constructor(
|
||||
}.launch("dashboard_conferences")
|
||||
}
|
||||
|
||||
private fun processHorizontalGroupData(
|
||||
luckyNumber: Int? = null,
|
||||
unreadMessagesCount: Int? = null,
|
||||
attendancePercentage: Double? = null,
|
||||
error: Throwable? = null,
|
||||
isLoading: Boolean = false,
|
||||
forceRefresh: Boolean
|
||||
) {
|
||||
val isLuckyNumberToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.LUCKY_NUMBER }
|
||||
val isMessagesToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.MESSAGES }
|
||||
val isAttendanceToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.ATTENDANCE }
|
||||
val isPushedToList =
|
||||
dashboardItemLoadedList.any { it.type == DashboardItem.Type.HORIZONTAL_GROUP }
|
||||
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
||||
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
||||
val isFirstRunDataLoadedError =
|
||||
dashboardItem.type in firstLoadedItemList && dashboardItem.error != null
|
||||
|
||||
if (error != null) {
|
||||
updateData(DashboardItem.HorizontalGroup(error = error), forceRefresh)
|
||||
return
|
||||
with(dashboardItemLoadedList) {
|
||||
removeAll { it.type == dashboardItem.type && !isForceRefreshError && !isFirstRunDataLoadedError }
|
||||
if (!isForceRefreshError && !isFirstRunDataLoadedError) add(dashboardItem)
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
val horizontalGroup =
|
||||
dashboardItemLoadedList.find { it is DashboardItem.HorizontalGroup } as DashboardItem.HorizontalGroup?
|
||||
val updatedHorizontalGroup =
|
||||
horizontalGroup?.copy(isLoading = true) ?: DashboardItem.HorizontalGroup(isLoading = true)
|
||||
sortDashboardItems()
|
||||
|
||||
updateData(updatedHorizontalGroup, forceRefresh)
|
||||
}
|
||||
|
||||
if (forceRefresh && !isPushedToList) {
|
||||
updateData(DashboardItem.HorizontalGroup(), forceRefresh)
|
||||
}
|
||||
|
||||
val horizontalGroup =
|
||||
dashboardItemLoadedList.single { it is DashboardItem.HorizontalGroup } as DashboardItem.HorizontalGroup
|
||||
|
||||
when {
|
||||
luckyNumber != null -> {
|
||||
updateData(horizontalGroup.copy(luckyNumber = luckyNumber), forceRefresh)
|
||||
}
|
||||
unreadMessagesCount != null -> {
|
||||
updateData(
|
||||
horizontalGroup.copy(unreadMessagesCount = unreadMessagesCount),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
attendancePercentage != null -> {
|
||||
updateData(
|
||||
horizontalGroup.copy(attendancePercentage = attendancePercentage),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val isHorizontalGroupLoaded = dashboardItemLoadedList.any {
|
||||
if (it !is DashboardItem.HorizontalGroup) return@any false
|
||||
|
||||
val isLuckyNumberStateCorrect = (it.luckyNumber != null) == isLuckyNumberToLoad
|
||||
val isMessagesStateCorrect = (it.unreadMessagesCount != null) == isMessagesToLoad
|
||||
val isAttendanceStateCorrect = (it.attendancePercentage != null) == isAttendanceToLoad
|
||||
|
||||
isLuckyNumberStateCorrect && isAttendanceStateCorrect && isMessagesStateCorrect
|
||||
}
|
||||
|
||||
if (isHorizontalGroupLoaded) {
|
||||
val updatedHorizontalGroup =
|
||||
dashboardItemLoadedList.single { it is DashboardItem.HorizontalGroup } as DashboardItem.HorizontalGroup
|
||||
|
||||
updateData(updatedHorizontalGroup.copy(isLoading = false, error = null), forceRefresh)
|
||||
if (forceRefresh) {
|
||||
updateForceRefreshData(dashboardItem)
|
||||
} else {
|
||||
updateNormalData()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
||||
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
||||
val dashboardItemsPosition = preferencesRepository.dashboardItemsPosition
|
||||
|
||||
with(dashboardItemLoadedList) {
|
||||
removeAll { it.type == dashboardItem.type && !isForceRefreshError }
|
||||
if (!isForceRefreshError) add(dashboardItem)
|
||||
sortBy { tile -> dashboardItemsToLoad.single { it == tile.type }.ordinal }
|
||||
private fun updateNormalData() {
|
||||
val isItemsLoaded =
|
||||
dashboardItemsToLoad.all { type -> dashboardItemLoadedList.any { it.type == type } }
|
||||
val isItemsDataLoaded = isItemsLoaded && dashboardItemLoadedList.all {
|
||||
it.isDataLoaded || it.error != null
|
||||
}
|
||||
|
||||
if (forceRefresh) {
|
||||
with(dashboardItemRefreshLoadedList) {
|
||||
removeAll { it.type == dashboardItem.type }
|
||||
add(dashboardItem)
|
||||
if (isItemsDataLoaded) {
|
||||
view?.run {
|
||||
showProgress(false)
|
||||
showErrorView(false)
|
||||
showContent(true)
|
||||
updateData(dashboardItemLoadedList.toList())
|
||||
}
|
||||
}
|
||||
|
||||
showErrorIfExists(
|
||||
isItemsLoaded = isItemsLoaded,
|
||||
itemsLoadedList = dashboardItemLoadedList,
|
||||
forceRefresh = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateForceRefreshData(dashboardItem: DashboardItem) {
|
||||
with(dashboardItemRefreshLoadedList) {
|
||||
removeAll { it.type == dashboardItem.type }
|
||||
add(dashboardItem)
|
||||
}
|
||||
|
||||
val isRefreshItemLoaded =
|
||||
dashboardItemsToLoad.all { type -> dashboardItemRefreshLoadedList.any { it.type == type } }
|
||||
val isRefreshItemsDataLoaded = isRefreshItemLoaded && dashboardItemRefreshLoadedList.all {
|
||||
it.isDataLoaded || it.error != null
|
||||
}
|
||||
|
||||
if (isRefreshItemsDataLoaded) {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showErrorView(false)
|
||||
showContent(true)
|
||||
updateData(dashboardItemLoadedList.toList())
|
||||
}
|
||||
}
|
||||
|
||||
showErrorIfExists(
|
||||
isItemsLoaded = isRefreshItemLoaded,
|
||||
itemsLoadedList = dashboardItemRefreshLoadedList,
|
||||
forceRefresh = true
|
||||
)
|
||||
|
||||
if (isRefreshItemsDataLoaded) dashboardItemRefreshLoadedList.clear()
|
||||
}
|
||||
|
||||
private fun showErrorIfExists(
|
||||
isItemsLoaded: Boolean,
|
||||
itemsLoadedList: List<DashboardItem>,
|
||||
forceRefresh: Boolean
|
||||
) {
|
||||
val filteredItems = itemsLoadedList.filterNot { it.type == DashboardItem.Type.ACCOUNT }
|
||||
val isAccountItemError =
|
||||
itemsLoadedList.find { it.type == DashboardItem.Type.ACCOUNT }?.error != null
|
||||
val isGeneralError =
|
||||
filteredItems.none { it.error == null } && filteredItems.isNotEmpty() || isAccountItemError
|
||||
val errorMessage = itemsLoadedList.map { it.error?.stackTraceToString() }.toString()
|
||||
|
||||
val filteredOriginalLoadedList =
|
||||
dashboardItemLoadedList.filterNot { it.type == DashboardItem.Type.ACCOUNT }
|
||||
val wasAccountItemError =
|
||||
dashboardItemLoadedList.find { it.type == DashboardItem.Type.ACCOUNT }?.error != null
|
||||
val wasGeneralError =
|
||||
filteredOriginalLoadedList.none { it.error == null } && filteredOriginalLoadedList.isNotEmpty() || wasAccountItemError
|
||||
|
||||
if (isGeneralError && isItemsLoaded) {
|
||||
lastError = Exception(errorMessage)
|
||||
|
||||
view?.run {
|
||||
showProgress(false)
|
||||
showRefresh(false)
|
||||
if ((forceRefresh && wasGeneralError) || !forceRefresh) {
|
||||
showContent(false)
|
||||
showErrorView(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sortDashboardItems() {
|
||||
val dashboardItemsPosition = preferencesRepository.dashboardItemsPosition
|
||||
|
||||
dashboardItemLoadedList.sortBy { tile ->
|
||||
dashboardItemsPosition?.getOrDefault(
|
||||
tile.type,
|
||||
tile.type.ordinal + 100
|
||||
) ?: tile.type.ordinal
|
||||
}
|
||||
|
||||
val isItemsLoaded =
|
||||
dashboardItemsToLoad.all { type -> dashboardItemLoadedList.any { it.type == type } }
|
||||
val isRefreshItemLoaded =
|
||||
dashboardItemsToLoad.all { type -> dashboardItemRefreshLoadedList.any { it.type == type } }
|
||||
val isItemsDataLoaded = isItemsLoaded && dashboardItemLoadedList.all {
|
||||
it.isDataLoaded || it.error != null
|
||||
}
|
||||
val isRefreshItemsDataLoaded = isRefreshItemLoaded && dashboardItemRefreshLoadedList.all {
|
||||
it.isDataLoaded || it.error != null
|
||||
}
|
||||
|
||||
if (isRefreshItemsDataLoaded) {
|
||||
view?.showRefresh(false)
|
||||
dashboardItemRefreshLoadedList.clear()
|
||||
}
|
||||
|
||||
view?.run {
|
||||
if (!forceRefresh) {
|
||||
showProgress(!isItemsDataLoaded)
|
||||
showContent(isItemsDataLoaded)
|
||||
}
|
||||
updateData(dashboardItemLoadedList.toList())
|
||||
}
|
||||
|
||||
if (isItemsLoaded) {
|
||||
val filteredItems =
|
||||
dashboardItemLoadedList.filterNot { it.type == DashboardItem.Type.ACCOUNT }
|
||||
val isAccountItemError =
|
||||
dashboardItemLoadedList.single { it.type == DashboardItem.Type.ACCOUNT }.error != null
|
||||
val isGeneralError =
|
||||
filteredItems.all { it.error != null } && filteredItems.isNotEmpty() || isAccountItemError
|
||||
|
||||
val errorMessage = filteredItems.map { it.error?.stackTraceToString() }.toString()
|
||||
|
||||
lastError = Exception(errorMessage)
|
||||
|
||||
view?.run {
|
||||
showProgress(false)
|
||||
showContent(!isGeneralError)
|
||||
showErrorView(isGeneralError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ inline val Timetable.left: Duration?
|
||||
get() = when {
|
||||
canceled -> null
|
||||
!isStudentPlan -> null
|
||||
end.isAfter(now()) && start.isBefore(now()) -> between(now(), end)
|
||||
end >= now() && start <= now() -> between(now(), end)
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
@ -4,14 +4,14 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:layout_marginVertical="2dp"
|
||||
android:clipToPadding="false">
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="12dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/dashboard_horizontal_group_item_lucky_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginVertical="4dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
@ -62,7 +62,7 @@
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/dashboard_horizontal_group_item_message_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:cardElevation="4dp"
|
||||
@ -119,7 +119,7 @@
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/dashboard_horizontal_group_item_attendance_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginVertical="4dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
@ -169,10 +169,8 @@
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/dashboard_horizontal_group_item_info_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:visibility="gone"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
@ -496,7 +496,6 @@
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Lekce</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Zítra)</string>
|
||||
<string name="dashboard_timetable_lesson_value">%1$s (%2$s)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">Za chvíli:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Brzy:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">První:</string>
|
||||
@ -566,7 +565,7 @@
|
||||
<item quantity="other">Ještě %1$d dalších setkání</item>
|
||||
</plurals>
|
||||
<string name="dashboard_horizontal_group_error">Při načítání dat došlo k chybě</string>
|
||||
<string name="dashboard_horizontal_group_no_lukcy_number">Žádné</string>
|
||||
<string name="dashboard_horizontal_group_no_data">Žádné</string>
|
||||
<!--Error dialog-->
|
||||
<string name="dialog_error_check_update">Zkontrolovat aktualizace</string>
|
||||
<string name="dialog_error_check_update_message">Před hlášením chyby zkontrolujte, zda je k dispozici aktualizace s opravou chyb</string>
|
||||
|
@ -432,7 +432,6 @@
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Lektionen</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Morgen)</string>
|
||||
<string name="dashboard_timetable_lesson_value">%1$s (%2$s)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">Gleich:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Bald:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">Erstens:</string>
|
||||
@ -488,7 +487,7 @@
|
||||
<item quantity="other">%1$d weitere Konferenzen</item>
|
||||
</plurals>
|
||||
<string name="dashboard_horizontal_group_error">Fehler beim Laden der Daten</string>
|
||||
<string name="dashboard_horizontal_group_no_lukcy_number">Keine</string>
|
||||
<string name="dashboard_horizontal_group_no_data">Keine</string>
|
||||
<!--Error dialog-->
|
||||
<string name="dialog_error_check_update">Auf Updates prüfen</string>
|
||||
<string name="dialog_error_check_update_message">Bevor Sie einen Fehler melden, prüfen Sie zuerst, ob ein Update mit der Fehlerbehebung verfügbar ist</string>
|
||||
|
@ -496,7 +496,6 @@
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Lekcje</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Jutro)</string>
|
||||
<string name="dashboard_timetable_lesson_value">%1$s (%2$s)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">Za chwilę:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Wkrótce:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">Pierwsza:</string>
|
||||
@ -566,7 +565,7 @@
|
||||
<item quantity="other">Jeszcze %1$d dodatkowych zebrań</item>
|
||||
</plurals>
|
||||
<string name="dashboard_horizontal_group_error">Wystąpił błąd podczas ładowania danych</string>
|
||||
<string name="dashboard_horizontal_group_no_lukcy_number">Brak</string>
|
||||
<string name="dashboard_horizontal_group_no_data">Brak</string>
|
||||
<!--Error dialog-->
|
||||
<string name="dialog_error_check_update">Sprawdź dostępność aktualizacji</string>
|
||||
<string name="dialog_error_check_update_message">Przed zgłoszeniem błędu sprawdź wcześniej, czy dostępna jest już aktualizacja z poprawką błędu</string>
|
||||
|
@ -496,7 +496,6 @@
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Уроки</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Завтра)</string>
|
||||
<string name="dashboard_timetable_lesson_value">%1$s (%2$s)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">Сейчас:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Скоро:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">Первый:</string>
|
||||
@ -566,7 +565,7 @@
|
||||
<item quantity="other">Еще %1$d конференций</item>
|
||||
</plurals>
|
||||
<string name="dashboard_horizontal_group_error">Произошла ошибка при загрузке данных</string>
|
||||
<string name="dashboard_horizontal_group_no_lukcy_number">Отсутствует</string>
|
||||
<string name="dashboard_horizontal_group_no_data">Отсутствует</string>
|
||||
<!--Error dialog-->
|
||||
<string name="dialog_error_check_update">Проверить наличие обновлений</string>
|
||||
<string name="dialog_error_check_update_message">Прежде чем сообщать об ошибке, проверьте наличие обновлений</string>
|
||||
|
@ -496,7 +496,6 @@
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Lekcie</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Zajtra)</string>
|
||||
<string name="dashboard_timetable_lesson_value">%1$s (%2$s)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">Za chvíľu:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Čoskoro:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">Prvá:</string>
|
||||
@ -566,7 +565,7 @@
|
||||
<item quantity="other">Ešte %1$d ďalších stretnutí</item>
|
||||
</plurals>
|
||||
<string name="dashboard_horizontal_group_error">Pri načítaní dát došlo k chybe</string>
|
||||
<string name="dashboard_horizontal_group_no_lukcy_number">Žiadne</string>
|
||||
<string name="dashboard_horizontal_group_no_data">Žiadne</string>
|
||||
<!--Error dialog-->
|
||||
<string name="dialog_error_check_update">Skontrolovať aktualizácie</string>
|
||||
<string name="dialog_error_check_update_message">Pred hlásením chyby skontrolujte, či je k dispozícii aktualizácia s opravou chýb</string>
|
||||
|
@ -496,7 +496,6 @@
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Уроки</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Завтра)</string>
|
||||
<string name="dashboard_timetable_lesson_value">%1$s (%2$s)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">Через мить:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Незабаром:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">Перше:</string>
|
||||
@ -566,7 +565,7 @@
|
||||
<item quantity="other">%1$d більше конференцій</item>
|
||||
</plurals>
|
||||
<string name="dashboard_horizontal_group_error">Помилка при завантаженні даних</string>
|
||||
<string name="dashboard_horizontal_group_no_lukcy_number">Нічого</string>
|
||||
<string name="dashboard_horizontal_group_no_data">Нічого</string>
|
||||
<!--Error dialog-->
|
||||
<string name="dialog_error_check_update">Провірити наявність оновлень</string>
|
||||
<string name="dialog_error_check_update_message">Перед тим, як повідомлювати о помілці, перевірте наявність оновлень</string>
|
||||
|
@ -495,7 +495,6 @@
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Lessons</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Tomorrow)</string>
|
||||
<string name="dashboard_timetable_lesson_value">%1$s (%2$s)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">In a moment:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Soon:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">First:</string>
|
||||
@ -557,7 +556,7 @@
|
||||
</plurals>
|
||||
|
||||
<string name="dashboard_horizontal_group_error">An error occurred while loading data</string>
|
||||
<string name="dashboard_horizontal_group_no_lukcy_number">None</string>
|
||||
<string name="dashboard_horizontal_group_no_data">None</string>
|
||||
|
||||
|
||||
<!--Error dialog-->
|
||||
|
@ -32,7 +32,22 @@ class TimetableExtensionTest {
|
||||
assertEquals(null, getTimetableEntity(canceled = true).left)
|
||||
assertEquals(null, getTimetableEntity(start = now().plusMinutes(5), end = now().plusMinutes(50)).left)
|
||||
assertEquals(null, getTimetableEntity(start = now().minusMinutes(1), end = now().plusMinutes(44), isStudentPlan = false).left)
|
||||
assertNotEquals(null, getTimetableEntity(start = now().minusMinutes(1), end = now().plusMinutes(44), isStudentPlan = true).left)
|
||||
assertNotEquals(
|
||||
null,
|
||||
getTimetableEntity(
|
||||
start = now().minusMinutes(1),
|
||||
end = now().plusMinutes(44),
|
||||
isStudentPlan = true
|
||||
).left
|
||||
)
|
||||
assertNotEquals(
|
||||
null,
|
||||
getTimetableEntity(
|
||||
start = now(),
|
||||
end = now().plusMinutes(45),
|
||||
isStudentPlan = true
|
||||
).left
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user