forked from github/wulkanowy-mirror
Merge branch 'release/1.2.1'
This commit is contained in:
commit
3d0dcead50
@ -21,8 +21,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 93
|
versionCode 94
|
||||||
versionName "1.2.0"
|
versionName "1.2.1"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ play {
|
|||||||
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
|
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
|
||||||
serviceAccountCredentials = file('key.p12')
|
serviceAccountCredentials = file('key.p12')
|
||||||
defaultToAppBundles = false
|
defaultToAppBundles = false
|
||||||
track = 'beta'
|
track = 'production'
|
||||||
updatePriority = 3
|
updatePriority = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,11 +157,11 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:1.2.0"
|
implementation "io.github.wulkanowy:sdk:1.2.1"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
|
||||||
|
|
||||||
implementation "androidx.core:core-ktx:1.6.0"
|
implementation "androidx.core:core-ktx:1.6.0"
|
||||||
implementation "androidx.activity:activity-ktx:1.3.1"
|
implementation "androidx.activity:activity-ktx:1.3.1"
|
||||||
@ -215,10 +215,10 @@ dependencies {
|
|||||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||||
playImplementation 'com.google.firebase:firebase-messaging:'
|
playImplementation 'com.google.firebase:firebase-messaging:'
|
||||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||||
playImplementation 'com.google.android.play:core:1.10.0'
|
playImplementation 'com.google.android.play:core:1.10.1'
|
||||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
|
|
||||||
hmsImplementation 'com.huawei.hms:hianalytics:6.1.1.300'
|
hmsImplementation 'com.huawei.hms:hianalytics:6.2.0.301'
|
||||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.0.300'
|
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.0.300'
|
||||||
|
|
||||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||||
@ -228,7 +228,7 @@ dependencies {
|
|||||||
|
|
||||||
testImplementation "junit:junit:4.13.2"
|
testImplementation "junit:junit:4.13.2"
|
||||||
testImplementation "io.mockk:mockk:$mockk"
|
testImplementation "io.mockk:mockk:$mockk"
|
||||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.1'
|
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2'
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
|
||||||
testImplementation 'org.robolectric:robolectric:4.6.1'
|
testImplementation 'org.robolectric:robolectric:4.6.1'
|
||||||
|
@ -33,10 +33,16 @@ class GradeRepository @Inject constructor(
|
|||||||
|
|
||||||
private val cacheKey = "grade"
|
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,
|
mutex = saveFetchResultMutex,
|
||||||
shouldFetch = { (details, summaries) ->
|
shouldFetch = { (details, summaries) ->
|
||||||
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
val isShouldBeRefreshed =
|
||||||
|
refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||||
details.isEmpty() || summaries.isEmpty() || forceRefresh || isShouldBeRefreshed
|
details.isEmpty() || summaries.isEmpty() || forceRefresh || isShouldBeRefreshed
|
||||||
},
|
},
|
||||||
query = {
|
query = {
|
||||||
@ -59,8 +65,14 @@ class GradeRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
private suspend fun refreshGradeDetails(student: Student, oldGrades: List<Grade>, newDetails: List<Grade>, notify: Boolean) {
|
private suspend fun refreshGradeDetails(
|
||||||
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
|
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.deleteAll(oldGrades uniqueSubtract newDetails)
|
||||||
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
|
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
|
||||||
if (it.date >= notifyBreakDate) it.apply {
|
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.deleteAll(oldSummaries uniqueSubtract newSummary)
|
||||||
gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
|
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.isPredictedGradeNotified = when {
|
||||||
summary.predictedGrade.isEmpty() -> true
|
summary.predictedGrade.isEmpty() -> true
|
||||||
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
|
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
|
||||||
|
@ -22,7 +22,11 @@ class SemesterRepository @Inject constructor(
|
|||||||
private val dispatchers: DispatchersProvider
|
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)
|
val semesters = semesterDb.loadAll(student.studentId, student.classId)
|
||||||
|
|
||||||
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
|
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
|
||||||
@ -31,14 +35,21 @@ class SemesterRepository @Inject constructor(
|
|||||||
} else semesters
|
} 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 isNoSemesters = semesters.isEmpty()
|
||||||
|
|
||||||
val isRefreshOnModeChangeRequired = if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
val isRefreshOnModeChangeRequired =
|
||||||
|
if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
||||||
semesters.firstOrNull { it.isCurrent }?.diaryId == 0
|
semesters.firstOrNull { it.isCurrent }?.diaryId == 0
|
||||||
} else false
|
} else false
|
||||||
|
|
||||||
val isRefreshOnNoCurrentAppropriate = refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
|
val isRefreshOnNoCurrentAppropriate =
|
||||||
|
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
|
||||||
|
|
||||||
return forceRefresh || isNoSemesters || isRefreshOnModeChangeRequired || isRefreshOnNoCurrentAppropriate
|
return forceRefresh || isNoSemesters || isRefreshOnModeChangeRequired || isRefreshOnNoCurrentAppropriate
|
||||||
}
|
}
|
||||||
@ -52,7 +63,8 @@ class SemesterRepository @Inject constructor(
|
|||||||
semesterDb.insertSemesters(new.uniqueSubtract(old))
|
semesterDb.insertSemesters(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) = withContext(dispatchers.backgroundThread) {
|
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) =
|
||||||
|
withContext(dispatchers.backgroundThread) {
|
||||||
getSemesters(student, forceRefresh).getCurrentOrLast()
|
getSemesters(student, forceRefresh).getCurrentOrLast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ open class BasePresenter<T : BaseView>(
|
|||||||
protected val studentRepository: StudentRepository
|
protected val studentRepository: StudentRepository
|
||||||
) : CoroutineScope {
|
) : CoroutineScope {
|
||||||
|
|
||||||
private var job: Job = Job()
|
private var job = Job()
|
||||||
|
|
||||||
private val jobs = mutableMapOf<String, Job>()
|
private val jobs = mutableMapOf<String, Job>()
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import androidx.core.view.get
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
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.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.databinding.FragmentAccountBinding
|
import io.github.wulkanowy.databinding.FragmentAccountBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
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) {
|
override fun openAccountDetailsView(student: Student) {
|
||||||
(activity as? MainActivity)?.pushView(
|
(activity as? MainActivity)?.pushView(AccountDetailsFragment.newInstance(student))
|
||||||
AccountDetailsFragment.newInstance(studentWithSemesters)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class AccountPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onItemSelected(studentWithSemesters: StudentWithSemesters) {
|
fun onItemSelected(studentWithSemesters: StudentWithSemesters) {
|
||||||
view?.openAccountDetailsView(studentWithSemesters)
|
view?.openAccountDetailsView(studentWithSemesters.student)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.account
|
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
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
interface AccountView : BaseView {
|
interface AccountView : BaseView {
|
||||||
@ -11,5 +11,5 @@ interface AccountView : BaseView {
|
|||||||
|
|
||||||
fun openLoginView()
|
fun openLoginView()
|
||||||
|
|
||||||
fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters)
|
fun openAccountDetailsView(student: Student)
|
||||||
}
|
}
|
||||||
|
@ -37,9 +37,9 @@ class AccountDetailsFragment :
|
|||||||
|
|
||||||
private const val ARGUMENT_KEY = "Data"
|
private const val ARGUMENT_KEY = "Data"
|
||||||
|
|
||||||
fun newInstance(studentWithSemesters: StudentWithSemesters) =
|
fun newInstance(student: Student) =
|
||||||
AccountDetailsFragment().apply {
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentAccountDetailsBinding.bind(view)
|
binding = FragmentAccountDetailsBinding.bind(view)
|
||||||
presenter.onAttachView(this, requireArguments()[ARGUMENT_KEY] as StudentWithSemesters)
|
presenter.onAttachView(this, requireArguments()[ARGUMENT_KEY] as Student)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
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.Resource
|
||||||
import io.github.wulkanowy.data.Status
|
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.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
@ -27,9 +28,9 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
|
|
||||||
private var studentId: Long? = null
|
private var studentId: Long? = null
|
||||||
|
|
||||||
fun onAttachView(view: AccountDetailsView, studentWithSemesters: StudentWithSemesters) {
|
fun onAttachView(view: AccountDetailsView, student: Student) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
studentId = studentWithSemesters.student.id
|
studentId = student.id
|
||||||
|
|
||||||
view.initView()
|
view.initView()
|
||||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
|
@ -14,6 +14,7 @@ import androidx.recyclerview.widget.DiffUtil
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.github.wulkanowy.R
|
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.Timetable
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
|
import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
|
||||||
@ -41,7 +42,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
|
|
||||||
private var lessonsTimer: Timer? = null
|
private var lessonsTimer: Timer? = null
|
||||||
|
|
||||||
var onAccountTileClickListener: () -> Unit = {}
|
var onAccountTileClickListener: (Student) -> Unit = {}
|
||||||
|
|
||||||
var onLuckyNumberTileClickListener: () -> Unit = {}
|
var onLuckyNumberTileClickListener: () -> Unit = {}
|
||||||
|
|
||||||
@ -152,7 +153,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
dashboardAccountItemName.text = student?.nickOrName.orEmpty()
|
dashboardAccountItemName.text = student?.nickOrName.orEmpty()
|
||||||
dashboardAccountItemSchoolName.text = student?.schoolName.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 binding = horizontalGroupViewHolder.binding
|
||||||
val context = binding.root.context
|
val context = binding.root.context
|
||||||
val attendanceColor = when {
|
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)
|
context.getThemeAttrColor(R.attr.colorPrimary)
|
||||||
}
|
}
|
||||||
attendancePercentage ?: 0.0 <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> {
|
attendancePercentage <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> {
|
||||||
context.getThemeAttrColor(R.attr.colorTimetableChange)
|
context.getThemeAttrColor(R.attr.colorTimetableChange)
|
||||||
}
|
}
|
||||||
else -> context.getThemeAttrColor(R.attr.colorOnSurface)
|
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) {
|
with(binding.dashboardHorizontalGroupItemAttendanceValue) {
|
||||||
text = "%.2f%%".format(attendancePercentage)
|
text = attendanceString
|
||||||
setTextColor(attendanceColor)
|
setTextColor(attendanceColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding) {
|
with(binding) {
|
||||||
dashboardHorizontalGroupItemMessageValue.text = unreadMessagesCount.toString()
|
dashboardHorizontalGroupItemMessageValue.text = unreadMessagesCount.toString()
|
||||||
dashboardHorizontalGroupItemLuckyValue.text = if (luckyNumber == -1) {
|
dashboardHorizontalGroupItemLuckyValue.text = if (luckyNumber == 0) {
|
||||||
context.getString(R.string.dashboard_horizontal_group_no_lukcy_number)
|
context.getString(R.string.dashboard_horizontal_group_no_data)
|
||||||
} else luckyNumber?.toString()
|
} else luckyNumber?.toString()
|
||||||
|
|
||||||
if (dashboardHorizontalGroupItemInfoContainer.isVisible != (error != null || isLoading)) {
|
|
||||||
dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoading
|
dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoading
|
||||||
}
|
dashboardHorizontalGroupItemInfoProgress.isVisible =
|
||||||
|
(isLoading && !item.isDataLoaded) || (isLoading && !item.isFullDataLoaded)
|
||||||
if (dashboardHorizontalGroupItemInfoProgress.isVisible != isLoading) {
|
|
||||||
dashboardHorizontalGroupItemInfoProgress.isVisible = isLoading
|
|
||||||
}
|
|
||||||
|
|
||||||
dashboardHorizontalGroupItemInfoErrorText.isVisible = error != null
|
dashboardHorizontalGroupItemInfoErrorText.isVisible = error != null
|
||||||
|
|
||||||
with(dashboardHorizontalGroupItemLuckyContainer) {
|
with(dashboardHorizontalGroupItemLuckyContainer) {
|
||||||
isVisible = error == null && !isLoading && luckyNumber != null
|
isVisible = luckyNumber != null && luckyNumber != -1
|
||||||
setOnClickListener { onLuckyNumberTileClickListener() }
|
setOnClickListener { onLuckyNumberTileClickListener() }
|
||||||
|
|
||||||
updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
@ -216,7 +220,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
}
|
}
|
||||||
|
|
||||||
with(dashboardHorizontalGroupItemAttendanceContainer) {
|
with(dashboardHorizontalGroupItemAttendanceContainer) {
|
||||||
isVisible = error == null && !isLoading && attendancePercentage != null
|
isVisible = attendancePercentage != null && attendancePercentage != -1.0
|
||||||
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||||
matchConstraintPercentWidth = when {
|
matchConstraintPercentWidth = when {
|
||||||
luckyNumber == null && unreadMessagesCount == null -> 1.0f
|
luckyNumber == null && unreadMessagesCount == null -> 1.0f
|
||||||
@ -228,7 +232,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
}
|
}
|
||||||
|
|
||||||
with(dashboardHorizontalGroupItemMessageContainer) {
|
with(dashboardHorizontalGroupItemMessageContainer) {
|
||||||
isVisible = error == null && !isLoading && unreadMessagesCount != null
|
isVisible = unreadMessagesCount != null && unreadMessagesCount != -1
|
||||||
setOnClickListener { onMessageTileClickListener() }
|
setOnClickListener { onMessageTileClickListener() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,14 +295,14 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
updateLessonView(item, currentTimetable, binding)
|
updateLessonView(item, currentTimetable, binding)
|
||||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||||
}
|
}
|
||||||
currentDayHeader != null && currentDayHeader.content.isNotBlank() -> {
|
|
||||||
updateLessonView(item, emptyList(), binding, currentDayHeader)
|
|
||||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
|
||||||
}
|
|
||||||
tomorrowTimetable.isNotEmpty() -> {
|
tomorrowTimetable.isNotEmpty() -> {
|
||||||
updateLessonView(item, tomorrowTimetable, binding)
|
updateLessonView(item, tomorrowTimetable, binding)
|
||||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
||||||
}
|
}
|
||||||
|
currentDayHeader != null && currentDayHeader.content.isNotBlank() -> {
|
||||||
|
updateLessonView(item, emptyList(), binding, currentDayHeader)
|
||||||
|
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||||
|
}
|
||||||
tomorrowDayHeader != null && tomorrowDayHeader.content.isNotBlank() -> {
|
tomorrowDayHeader != null && tomorrowDayHeader.content.isNotBlank() -> {
|
||||||
updateLessonView(item, emptyList(), binding, tomorrowDayHeader)
|
updateLessonView(item, emptyList(), binding, tomorrowDayHeader)
|
||||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
||||||
@ -348,6 +352,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
private fun updateFirstLessonView(
|
private fun updateFirstLessonView(
|
||||||
binding: ItemDashboardLessonsBinding,
|
binding: ItemDashboardLessonsBinding,
|
||||||
firstLesson: Timetable?,
|
firstLesson: Timetable?,
|
||||||
@ -367,7 +372,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
firstLesson ?: return
|
firstLesson ?: return
|
||||||
|
|
||||||
val minutesToStartLesson =
|
val minutesToStartLesson =
|
||||||
Duration.between(currentDateTime, firstLesson.start).toMinutes()
|
Duration.between(currentDateTime, firstLesson.start).toMinutes() + 1
|
||||||
val isFirstTimeVisible: Boolean
|
val isFirstTimeVisible: Boolean
|
||||||
val isFirstTimeRangeVisible: Boolean
|
val isFirstTimeRangeVisible: Boolean
|
||||||
val firstTimeText: String
|
val firstTimeText: String
|
||||||
@ -376,12 +381,12 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
val firstTitleAndValueTextColor: Int
|
val firstTitleAndValueTextColor: Int
|
||||||
val firstTitleAndValueTextFont: Typeface
|
val firstTitleAndValueTextFont: Typeface
|
||||||
|
|
||||||
if (currentDateTime.isBefore(firstLesson.start)) {
|
if (currentDateTime < firstLesson.start) {
|
||||||
if (minutesToStartLesson > 60) {
|
if (minutesToStartLesson > 60) {
|
||||||
val formattedStartTime = firstLesson.start.toFormattedString("HH:mm")
|
val formattedStartTime = firstLesson.start.toFormattedString("HH:mm")
|
||||||
val formattedEndTime = firstLesson.end.toFormattedString("HH:mm")
|
val formattedEndTime = firstLesson.end.toFormattedString("HH:mm")
|
||||||
|
|
||||||
firstTimeRangeText = "${formattedStartTime}-${formattedEndTime}"
|
firstTimeRangeText = "$formattedStartTime - $formattedEndTime"
|
||||||
firstTimeText = ""
|
firstTimeText = ""
|
||||||
|
|
||||||
isFirstTimeRangeVisible = true
|
isFirstTimeRangeVisible = true
|
||||||
@ -421,7 +426,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val minutesToEndLesson = firstLesson.left!!.toMinutes()
|
val minutesToEndLesson = firstLesson.left!!.toMinutes() + 1
|
||||||
|
|
||||||
firstTimeText = context.resources.getQuantityString(
|
firstTimeText = context.resources.getQuantityString(
|
||||||
R.plurals.dashboard_timetable_first_lesson_time_more_minutes,
|
R.plurals.dashboard_timetable_first_lesson_time_more_minutes,
|
||||||
@ -454,11 +459,8 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
with(binding.dashboardLessonsItemFirstValue) {
|
with(binding.dashboardLessonsItemFirstValue) {
|
||||||
setTextColor(firstTitleAndValueTextColor)
|
setTextColor(firstTitleAndValueTextColor)
|
||||||
typeface = firstTitleAndValueTextFont
|
typeface = firstTitleAndValueTextFont
|
||||||
text = context.getString(
|
text =
|
||||||
R.string.dashboard_timetable_lesson_value,
|
"${firstLesson.subject} ${if (firstLesson.room.isNotBlank()) "(${firstLesson.room})" else ""}"
|
||||||
firstLesson.subject,
|
|
||||||
firstLesson.room
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,13 +474,11 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
val formattedStartTime = secondLesson?.start?.toFormattedString("HH:mm")
|
val formattedStartTime = secondLesson?.start?.toFormattedString("HH:mm")
|
||||||
val formattedEndTime = secondLesson?.end?.toFormattedString("HH:mm")
|
val formattedEndTime = secondLesson?.end?.toFormattedString("HH:mm")
|
||||||
|
|
||||||
val secondTimeText = "${formattedStartTime}-${formattedEndTime}"
|
val secondTimeText = "$formattedStartTime - $formattedEndTime"
|
||||||
val secondValueText = if (secondLesson != null) {
|
val secondValueText = if (secondLesson != null) {
|
||||||
context.getString(
|
val roomString = if (secondLesson.room.isNotBlank()) "(${secondLesson.room})" else ""
|
||||||
R.string.dashboard_timetable_lesson_value,
|
|
||||||
secondLesson.subject,
|
"${secondLesson.subject} $roomString"
|
||||||
secondLesson.room
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
context.getString(R.string.dashboard_timetable_second_lesson_value_end)
|
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.R
|
||||||
import io.github.wulkanowy.databinding.FragmentDashboardBinding
|
import io.github.wulkanowy.databinding.FragmentDashboardBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
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.attendance.summary.AttendanceSummaryFragment
|
||||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||||
@ -77,7 +77,9 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
)
|
)
|
||||||
|
|
||||||
dashboardAdapter.apply {
|
dashboardAdapter.apply {
|
||||||
onAccountTileClickListener = { mainActivity.pushView(AccountFragment.newInstance()) }
|
onAccountTileClickListener = {
|
||||||
|
mainActivity.pushView(AccountDetailsFragment.newInstance(it))
|
||||||
|
}
|
||||||
onLuckyNumberTileClickListener = {
|
onLuckyNumberTileClickListener = {
|
||||||
mainActivity.pushView(LuckyNumberFragment.newInstance())
|
mainActivity.pushView(LuckyNumberFragment.newInstance())
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,9 @@ sealed class DashboardItem(val type: Type) {
|
|||||||
|
|
||||||
override val isDataLoaded
|
override val isDataLoaded
|
||||||
get() = unreadMessagesCount != null || attendancePercentage != null || luckyNumber != null
|
get() = unreadMessagesCount != null || attendancePercentage != null || luckyNumber != null
|
||||||
|
|
||||||
|
val isFullDataLoaded
|
||||||
|
get() = luckyNumber != -1 && attendancePercentage != -1.0 && unreadMessagesCount != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Grades(
|
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.Resource
|
||||||
import io.github.wulkanowy.data.Status
|
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.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
|
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
|
||||||
import io.github.wulkanowy.data.repositories.ConferenceRepository
|
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.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.calculatePercentage
|
import io.github.wulkanowy.utils.calculatePercentage
|
||||||
import io.github.wulkanowy.utils.flowWithResource
|
|
||||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
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.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
@ -48,9 +57,11 @@ class DashboardPresenter @Inject constructor(
|
|||||||
|
|
||||||
private val dashboardItemRefreshLoadedList = mutableListOf<DashboardItem>()
|
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
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
@ -69,8 +80,10 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onDragAndDropEnd(list: List<DashboardItem>) {
|
fun onDragAndDropEnd(list: List<DashboardItem>) {
|
||||||
dashboardItemLoadedList.clear()
|
with(dashboardItemLoadedList) {
|
||||||
dashboardItemLoadedList.addAll(list)
|
clear()
|
||||||
|
addAll(list)
|
||||||
|
}
|
||||||
|
|
||||||
val positionList =
|
val positionList =
|
||||||
list.mapIndexed { index, dashboardItem -> Pair(dashboardItem.type, index) }.toMap()
|
list.mapIndexed { index, dashboardItem -> Pair(dashboardItem.type, index) }.toMap()
|
||||||
@ -78,87 +91,102 @@ class DashboardPresenter @Inject constructor(
|
|||||||
preferencesRepository.dashboardItemsPosition = positionList
|
preferencesRepository.dashboardItemsPosition = positionList
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadData(forceRefresh: Boolean = false, tilesToLoad: Set<DashboardItem.Tile>) {
|
fun loadData(
|
||||||
val oldDashboardDataToLoad = dashboardTilesToLoad
|
tilesToLoad: Set<DashboardItem.Tile>,
|
||||||
|
forceRefresh: Boolean = false,
|
||||||
|
) {
|
||||||
|
val oldDashboardTileLoadedList = dashboardTileLoadedList
|
||||||
|
dashboardItemsToLoad = tilesToLoad.map { it.toDashboardItemType() }.toSet()
|
||||||
|
dashboardTileLoadedList = tilesToLoad
|
||||||
|
|
||||||
dashboardTilesToLoad = tilesToLoad
|
val itemsToLoad = generateDashboardTileListToLoad(
|
||||||
dashboardItemsToLoad = dashboardTilesToLoad.map { it.toDashboardItemType() }.toSet()
|
dashboardTilesToLoad = tilesToLoad,
|
||||||
|
dashboardLoadedTiles = oldDashboardTileLoadedList,
|
||||||
|
forceRefresh = forceRefresh
|
||||||
|
).map { it.toDashboardItemType() }
|
||||||
|
|
||||||
removeUnselectedTiles()
|
removeUnselectedTiles(tilesToLoad.toList())
|
||||||
|
loadTiles(tileList = itemsToLoad, forceRefresh = forceRefresh)
|
||||||
val newTileList = generateTileListToLoad(oldDashboardDataToLoad, forceRefresh)
|
|
||||||
loadTiles(forceRefresh, newTileList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeUnselectedTiles() {
|
private fun generateDashboardTileListToLoad(
|
||||||
val isLuckyNumberToLoad =
|
dashboardTilesToLoad: Set<DashboardItem.Tile>,
|
||||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.LUCKY_NUMBER }
|
dashboardLoadedTiles: Set<DashboardItem.Tile>,
|
||||||
val isMessagesToLoad =
|
forceRefresh: Boolean
|
||||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.MESSAGES }
|
) = dashboardTilesToLoad.filter { newItemToLoad ->
|
||||||
val isAttendanceToLoad =
|
dashboardLoadedTiles.none { it == newItemToLoad } || forceRefresh
|
||||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.ATTENDANCE }
|
}
|
||||||
|
|
||||||
|
private fun removeUnselectedTiles(tilesToLoad: List<DashboardItem.Tile>) {
|
||||||
dashboardItemLoadedList.removeAll { loadedTile -> dashboardItemsToLoad.none { it == loadedTile.type } }
|
dashboardItemLoadedList.removeAll { loadedTile -> dashboardItemsToLoad.none { it == loadedTile.type } }
|
||||||
|
|
||||||
val horizontalGroup =
|
val horizontalGroup =
|
||||||
dashboardItemLoadedList.find { it is DashboardItem.HorizontalGroup } as DashboardItem.HorizontalGroup?
|
dashboardItemLoadedList.find { it is DashboardItem.HorizontalGroup } as DashboardItem.HorizontalGroup?
|
||||||
|
|
||||||
if (horizontalGroup != null) {
|
if (horizontalGroup != null) {
|
||||||
val horizontalIndex = dashboardItemLoadedList.indexOf(horizontalGroup)
|
val isLuckyNumberToLoad = DashboardItem.Tile.LUCKY_NUMBER in tilesToLoad
|
||||||
dashboardItemLoadedList.remove(horizontalGroup)
|
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) {
|
val newHorizontalGroup = horizontalGroup.copy(
|
||||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(luckyNumber = null)
|
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)
|
view?.updateData(dashboardItemLoadedList)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadTiles(forceRefresh: Boolean, tileList: List<DashboardItem.Tile>) {
|
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 {
|
tileList.forEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
DashboardItem.Tile.ACCOUNT -> loadCurrentAccount(forceRefresh)
|
DashboardItem.Type.ACCOUNT -> {
|
||||||
DashboardItem.Tile.LUCKY_NUMBER -> loadLuckyNumber(forceRefresh)
|
updateData(DashboardItem.Account(student), forceRefresh)
|
||||||
DashboardItem.Tile.MESSAGES -> loadMessages(forceRefresh)
|
}
|
||||||
DashboardItem.Tile.ATTENDANCE -> loadAttendance(forceRefresh)
|
DashboardItem.Type.HORIZONTAL_GROUP -> {
|
||||||
DashboardItem.Tile.LESSONS -> loadLessons(forceRefresh)
|
loadHorizontalGroup(student, forceRefresh)
|
||||||
DashboardItem.Tile.GRADES -> loadGrades(forceRefresh)
|
}
|
||||||
DashboardItem.Tile.HOMEWORK -> loadHomework(forceRefresh)
|
DashboardItem.Type.LESSONS -> loadLessons(student, forceRefresh)
|
||||||
DashboardItem.Tile.ANNOUNCEMENTS -> loadSchoolAnnouncements(forceRefresh)
|
DashboardItem.Type.GRADES -> loadGrades(student, forceRefresh)
|
||||||
DashboardItem.Tile.EXAMS -> loadExams(forceRefresh)
|
DashboardItem.Type.HOMEWORK -> loadHomework(student, forceRefresh)
|
||||||
DashboardItem.Tile.CONFERENCES -> loadConferences(forceRefresh)
|
DashboardItem.Type.ANNOUNCEMENTS -> {
|
||||||
DashboardItem.Tile.ADS -> TODO()
|
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() {
|
fun onSwipeRefresh() {
|
||||||
Timber.i("Force refreshing the dashboard")
|
Timber.i("Force refreshing the dashboard")
|
||||||
loadData(true, preferencesRepository.selectedDashboardTiles)
|
loadData(preferencesRepository.selectedDashboardTiles, forceRefresh = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRetry() {
|
fun onRetry() {
|
||||||
@ -166,7 +194,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
}
|
}
|
||||||
loadData(true, preferencesRepository.selectedDashboardTiles)
|
loadData(preferencesRepository.selectedDashboardTiles, forceRefresh = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onViewReselected() {
|
fun onViewReselected() {
|
||||||
@ -192,139 +220,86 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}.toSet()
|
}.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadCurrentAccount(forceRefresh: Boolean) {
|
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
||||||
flowWithResource { studentRepository.getCurrentStudent(false) }
|
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 {
|
.onEach {
|
||||||
when (it.status) {
|
updateData(it, forceRefresh)
|
||||||
Status.LOADING -> {
|
|
||||||
Timber.i("Loading dashboard account data started")
|
if (it.isLoading) {
|
||||||
if (forceRefresh) return@onEach
|
Timber.i("Loading horizontal group data started")
|
||||||
updateData(DashboardItem.Account(it.data, isLoading = true), forceRefresh)
|
|
||||||
|
if (it.isFullDataLoaded) {
|
||||||
|
firstLoadedItemList += DashboardItem.Type.HORIZONTAL_GROUP
|
||||||
}
|
}
|
||||||
Status.SUCCESS -> {
|
} else {
|
||||||
Timber.i("Loading dashboard account result: Success")
|
Timber.i("Loading horizontal group 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.catch {
|
||||||
|
Timber.i("Loading horizontal group result: An exception occurred")
|
||||||
|
updateData(
|
||||||
|
DashboardItem.HorizontalGroup(error = it),
|
||||||
|
forceRefresh,
|
||||||
|
)
|
||||||
|
errorHandler.dispatch(it)
|
||||||
}
|
}
|
||||||
.launch("dashboard_account")
|
.launch("horizontal_group")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadLuckyNumber(forceRefresh: Boolean) {
|
private fun loadGrades(student: Student, forceRefresh: Boolean) {
|
||||||
flowWithResourceIn {
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.launch("dashboard_lucky_number")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadMessages(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)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
|
|
||||||
gradeRepository.getGrades(student, semester, forceRefresh)
|
gradeRepository.getGrades(student, semester, forceRefresh)
|
||||||
@ -353,6 +328,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
Status.LOADING -> {
|
Status.LOADING -> {
|
||||||
Timber.i("Loading dashboard grades data started")
|
Timber.i("Loading dashboard grades data started")
|
||||||
if (forceRefresh) return@onEach
|
if (forceRefresh) return@onEach
|
||||||
|
|
||||||
updateData(
|
updateData(
|
||||||
DashboardItem.Grades(
|
DashboardItem.Grades(
|
||||||
subjectWithGrades = it.data,
|
subjectWithGrades = it.data,
|
||||||
@ -360,6 +336,10 @@ class DashboardPresenter @Inject constructor(
|
|||||||
isLoading = true
|
isLoading = true
|
||||||
), forceRefresh
|
), forceRefresh
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!it.data.isNullOrEmpty()) {
|
||||||
|
firstLoadedItemList += DashboardItem.Type.GRADES
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading dashboard grades result: Success")
|
Timber.i("Loading dashboard grades result: Success")
|
||||||
@ -367,7 +347,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
DashboardItem.Grades(
|
DashboardItem.Grades(
|
||||||
subjectWithGrades = it.data,
|
subjectWithGrades = it.data,
|
||||||
gradeTheme = preferencesRepository.gradeColorTheme
|
gradeTheme = preferencesRepository.gradeColorTheme
|
||||||
), forceRefresh
|
),
|
||||||
|
forceRefresh
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Status.ERROR -> {
|
Status.ERROR -> {
|
||||||
@ -379,9 +360,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}.launch("dashboard_grades")
|
}.launch("dashboard_grades")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadLessons(forceRefresh: Boolean) {
|
private fun loadLessons(student: Student, forceRefresh: Boolean) {
|
||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
val student = studentRepository.getCurrentStudent(true)
|
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
val date = LocalDate.now().nextOrSameSchoolDay
|
val date = LocalDate.now().nextOrSameSchoolDay
|
||||||
|
|
||||||
@ -398,24 +378,34 @@ class DashboardPresenter @Inject constructor(
|
|||||||
Status.LOADING -> {
|
Status.LOADING -> {
|
||||||
Timber.i("Loading dashboard lessons data started")
|
Timber.i("Loading dashboard lessons data started")
|
||||||
if (forceRefresh) return@onEach
|
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 -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading dashboard lessons result: Success")
|
Timber.i("Loading dashboard lessons result: Success")
|
||||||
updateData(DashboardItem.Lessons(it.data), forceRefresh)
|
updateData(
|
||||||
|
DashboardItem.Lessons(it.data), forceRefresh
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Status.ERROR -> {
|
Status.ERROR -> {
|
||||||
Timber.i("Loading dashboard lessons result: An exception occurred")
|
Timber.i("Loading dashboard lessons result: An exception occurred")
|
||||||
errorHandler.dispatch(it.error!!)
|
errorHandler.dispatch(it.error!!)
|
||||||
updateData(DashboardItem.Lessons(error = it.error), forceRefresh)
|
updateData(
|
||||||
|
DashboardItem.Lessons(error = it.error), forceRefresh
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.launch("dashboard_lessons")
|
}.launch("dashboard_lessons")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadHomework(forceRefresh: Boolean) {
|
private fun loadHomework(student: Student, forceRefresh: Boolean) {
|
||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
val student = studentRepository.getCurrentStudent(true)
|
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
val date = LocalDate.now().nextOrSameSchoolDay
|
val date = LocalDate.now().nextOrSameSchoolDay
|
||||||
|
|
||||||
@ -443,6 +433,10 @@ class DashboardPresenter @Inject constructor(
|
|||||||
DashboardItem.Homework(it.data ?: emptyList(), isLoading = true),
|
DashboardItem.Homework(it.data ?: emptyList(), isLoading = true),
|
||||||
forceRefresh
|
forceRefresh
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!it.data.isNullOrEmpty()) {
|
||||||
|
firstLoadedItemList += DashboardItem.Type.HOMEWORK
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading dashboard homework result: Success")
|
Timber.i("Loading dashboard homework result: Success")
|
||||||
@ -457,10 +451,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}.launch("dashboard_homework")
|
}.launch("dashboard_homework")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadSchoolAnnouncements(forceRefresh: Boolean) {
|
private fun loadSchoolAnnouncements(student: Student, forceRefresh: Boolean) {
|
||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
val student = studentRepository.getCurrentStudent(true)
|
|
||||||
|
|
||||||
schoolAnnouncementRepository.getSchoolAnnouncements(student, forceRefresh)
|
schoolAnnouncementRepository.getSchoolAnnouncements(student, forceRefresh)
|
||||||
}.onEach {
|
}.onEach {
|
||||||
when (it.status) {
|
when (it.status) {
|
||||||
@ -468,11 +460,13 @@ class DashboardPresenter @Inject constructor(
|
|||||||
Timber.i("Loading dashboard announcements data started")
|
Timber.i("Loading dashboard announcements data started")
|
||||||
if (forceRefresh) return@onEach
|
if (forceRefresh) return@onEach
|
||||||
updateData(
|
updateData(
|
||||||
DashboardItem.Announcements(
|
DashboardItem.Announcements(it.data ?: emptyList(), isLoading = true),
|
||||||
it.data ?: emptyList(),
|
forceRefresh
|
||||||
isLoading = true
|
|
||||||
), forceRefresh
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!it.data.isNullOrEmpty()) {
|
||||||
|
firstLoadedItemList += DashboardItem.Type.ANNOUNCEMENTS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading dashboard announcements result: Success")
|
Timber.i("Loading dashboard announcements result: Success")
|
||||||
@ -487,9 +481,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}.launch("dashboard_announcements")
|
}.launch("dashboard_announcements")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadExams(forceRefresh: Boolean) {
|
private fun loadExams(student: Student, forceRefresh: Boolean) {
|
||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
val student = studentRepository.getCurrentStudent(true)
|
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
|
|
||||||
examRepository.getExams(
|
examRepository.getExams(
|
||||||
@ -508,6 +501,10 @@ class DashboardPresenter @Inject constructor(
|
|||||||
DashboardItem.Exams(it.data.orEmpty(), isLoading = true),
|
DashboardItem.Exams(it.data.orEmpty(), isLoading = true),
|
||||||
forceRefresh
|
forceRefresh
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!it.data.isNullOrEmpty()) {
|
||||||
|
firstLoadedItemList += DashboardItem.Type.EXAMS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading dashboard exams result: Success")
|
Timber.i("Loading dashboard exams result: Success")
|
||||||
@ -522,9 +519,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}.launch("dashboard_exams")
|
}.launch("dashboard_exams")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadConferences(forceRefresh: Boolean) {
|
private fun loadConferences(student: Student, forceRefresh: Boolean) {
|
||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
val student = studentRepository.getCurrentStudent(true)
|
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
|
|
||||||
conferenceRepository.getConferences(
|
conferenceRepository.getConferences(
|
||||||
@ -542,6 +538,10 @@ class DashboardPresenter @Inject constructor(
|
|||||||
DashboardItem.Conferences(it.data ?: emptyList(), isLoading = true),
|
DashboardItem.Conferences(it.data ?: emptyList(), isLoading = true),
|
||||||
forceRefresh
|
forceRefresh
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!it.data.isNullOrEmpty()) {
|
||||||
|
firstLoadedItemList += DashboardItem.Type.CONFERENCES
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
Timber.i("Loading dashboard conferences result: Success")
|
Timber.i("Loading dashboard conferences result: Success")
|
||||||
@ -556,145 +556,119 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}.launch("dashboard_conferences")
|
}.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 }
|
|
||||||
|
|
||||||
if (error != null) {
|
|
||||||
updateData(DashboardItem.HorizontalGroup(error = error), forceRefresh)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
val horizontalGroup =
|
|
||||||
dashboardItemLoadedList.find { it is DashboardItem.HorizontalGroup } as DashboardItem.HorizontalGroup?
|
|
||||||
val updatedHorizontalGroup =
|
|
||||||
horizontalGroup?.copy(isLoading = true) ?: DashboardItem.HorizontalGroup(isLoading = true)
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
||||||
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
||||||
val dashboardItemsPosition = preferencesRepository.dashboardItemsPosition
|
val isFirstRunDataLoadedError =
|
||||||
|
dashboardItem.type in firstLoadedItemList && dashboardItem.error != null
|
||||||
|
|
||||||
with(dashboardItemLoadedList) {
|
with(dashboardItemLoadedList) {
|
||||||
removeAll { it.type == dashboardItem.type && !isForceRefreshError }
|
removeAll { it.type == dashboardItem.type && !isForceRefreshError && !isFirstRunDataLoadedError }
|
||||||
if (!isForceRefreshError) add(dashboardItem)
|
if (!isForceRefreshError && !isFirstRunDataLoadedError) add(dashboardItem)
|
||||||
sortBy { tile -> dashboardItemsToLoad.single { it == tile.type }.ordinal }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sortDashboardItems()
|
||||||
|
|
||||||
if (forceRefresh) {
|
if (forceRefresh) {
|
||||||
|
updateForceRefreshData(dashboardItem)
|
||||||
|
} else {
|
||||||
|
updateNormalData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateNormalData() {
|
||||||
|
val isItemsLoaded =
|
||||||
|
dashboardItemsToLoad.all { type -> dashboardItemLoadedList.any { it.type == type } }
|
||||||
|
val isItemsDataLoaded = isItemsLoaded && dashboardItemLoadedList.all {
|
||||||
|
it.isDataLoaded || it.error != null
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
with(dashboardItemRefreshLoadedList) {
|
||||||
removeAll { it.type == dashboardItem.type }
|
removeAll { it.type == dashboardItem.type }
|
||||||
add(dashboardItem)
|
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 ->
|
dashboardItemLoadedList.sortBy { tile ->
|
||||||
dashboardItemsPosition?.getOrDefault(
|
dashboardItemsPosition?.getOrDefault(
|
||||||
tile.type,
|
tile.type,
|
||||||
tile.type.ordinal + 100
|
tile.type.ordinal + 100
|
||||||
) ?: tile.type.ordinal
|
) ?: 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ package io.github.wulkanowy.ui.modules.schoolannouncement
|
|||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.parseAsHtml
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||||
import io.github.wulkanowy.databinding.ItemSchoolAnnouncementBinding
|
import io.github.wulkanowy.databinding.ItemSchoolAnnouncementBinding
|
||||||
@ -14,6 +14,8 @@ class SchoolAnnouncementAdapter @Inject constructor() :
|
|||||||
|
|
||||||
var items = emptyList<SchoolAnnouncement>()
|
var items = emptyList<SchoolAnnouncement>()
|
||||||
|
|
||||||
|
var onItemClickListener: (SchoolAnnouncement) -> Unit = {}
|
||||||
|
|
||||||
override fun getItemCount() = items.size
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
@ -26,9 +28,9 @@ class SchoolAnnouncementAdapter @Inject constructor() :
|
|||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
schoolAnnouncementItemDate.text = item.date.toFormattedString()
|
schoolAnnouncementItemDate.text = item.date.toFormattedString()
|
||||||
schoolAnnouncementItemType.text = item.subject
|
schoolAnnouncementItemType.text = item.subject
|
||||||
schoolAnnouncementItemContent.text = HtmlCompat.fromHtml(
|
schoolAnnouncementItemContent.text = item.content.parseAsHtml()
|
||||||
item.content, HtmlCompat.FROM_HTML_MODE_COMPACT
|
|
||||||
)
|
root.setOnClickListener { onItemClickListener(item) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.schoolannouncement
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||||
|
import io.github.wulkanowy.databinding.DialogSchoolAnnouncementBinding
|
||||||
|
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
|
||||||
|
class SchoolAnnouncementDialog : DialogFragment() {
|
||||||
|
|
||||||
|
private var binding: DialogSchoolAnnouncementBinding by lifecycleAwareVariable()
|
||||||
|
|
||||||
|
private lateinit var announcement: SchoolAnnouncement
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val ARGUMENT_KEY = "item"
|
||||||
|
|
||||||
|
fun newInstance(exam: SchoolAnnouncement) = SchoolAnnouncementDialog().apply {
|
||||||
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
|
arguments?.run {
|
||||||
|
announcement = getSerializable(ARGUMENT_KEY) as SchoolAnnouncement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogSchoolAnnouncementBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
with(binding) {
|
||||||
|
announcementDialogSubjectValue.text = announcement.subject
|
||||||
|
announcementDialogDateValue.text = announcement.date.toFormattedString()
|
||||||
|
announcementDialogDescriptionValue.text = announcement.content.parseAsHtml()
|
||||||
|
|
||||||
|
announcementDialogClose.setOnClickListener { dismiss() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||||
import io.github.wulkanowy.databinding.FragmentSchoolAnnouncementBinding
|
import io.github.wulkanowy.databinding.FragmentSchoolAnnouncementBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
@ -43,7 +44,9 @@ class SchoolAnnouncementFragment :
|
|||||||
override fun initView() {
|
override fun initView() {
|
||||||
with(binding.directorInformationRecycler) {
|
with(binding.directorInformationRecycler) {
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = LinearLayoutManager(context)
|
||||||
adapter = schoolAnnouncementAdapter
|
adapter = schoolAnnouncementAdapter.apply {
|
||||||
|
onItemClickListener = presenter::onItemClickListener
|
||||||
|
}
|
||||||
addItemDecoration(DividerItemDecoration(context))
|
addItemDecoration(DividerItemDecoration(context))
|
||||||
}
|
}
|
||||||
with(binding) {
|
with(binding) {
|
||||||
@ -99,6 +102,10 @@ class SchoolAnnouncementFragment :
|
|||||||
binding.directorInformationSwipe.isRefreshing = show
|
binding.directorInformationSwipe.isRefreshing = show
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openSchoolAnnouncementDialog(item: SchoolAnnouncement) {
|
||||||
|
(activity as? MainActivity)?.showDialogFragment(SchoolAnnouncementDialog.newInstance(item))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.schoolannouncement
|
package io.github.wulkanowy.ui.modules.schoolannouncement
|
||||||
|
|
||||||
import io.github.wulkanowy.data.Status
|
import io.github.wulkanowy.data.Status
|
||||||
|
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||||
import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
|
import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -46,6 +47,10 @@ class SchoolAnnouncementPresenter @Inject constructor(
|
|||||||
view?.showErrorDetailsDialog(lastError)
|
view?.showErrorDetailsDialog(lastError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onItemClickListener(item: SchoolAnnouncement) {
|
||||||
|
view?.openSchoolAnnouncementDialog(item)
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadData(forceRefresh: Boolean = false) {
|
private fun loadData(forceRefresh: Boolean = false) {
|
||||||
Timber.i("Loading School announcement data started")
|
Timber.i("Loading School announcement data started")
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ interface SchoolAnnouncementView : BaseView {
|
|||||||
|
|
||||||
fun setErrorDetails(message: String)
|
fun setErrorDetails(message: String)
|
||||||
|
|
||||||
|
fun openSchoolAnnouncementDialog(item: SchoolAnnouncement)
|
||||||
|
|
||||||
fun showProgress(show: Boolean)
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
fun enableSwipe(enable: Boolean)
|
fun enableSwipe(enable: Boolean)
|
||||||
|
@ -13,7 +13,7 @@ class StudentInfoAdapter @Inject constructor() :
|
|||||||
|
|
||||||
var items = listOf<StudentInfoItem>()
|
var items = listOf<StudentInfoItem>()
|
||||||
|
|
||||||
var onItemClickListener: (position: Int) -> Unit = {}
|
var onItemClickListener: (StudentInfoView.Type?) -> Unit = {}
|
||||||
|
|
||||||
var onItemLongClickListener: (text: String) -> Unit = {}
|
var onItemLongClickListener: (text: String) -> Unit = {}
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ class StudentInfoAdapter @Inject constructor() :
|
|||||||
studentInfoItemArrow.visibility = if (item.showArrow) VISIBLE else GONE
|
studentInfoItemArrow.visibility = if (item.showArrow) VISIBLE else GONE
|
||||||
|
|
||||||
with(root) {
|
with(root) {
|
||||||
setOnClickListener { onItemClickListener(position) }
|
setOnClickListener { onItemClickListener(item.viewType) }
|
||||||
setOnLongClickListener {
|
setOnLongClickListener {
|
||||||
onItemLongClickListener(studentInfoItemSubtitle.text.toString())
|
onItemLongClickListener(studentInfoItemSubtitle.text.toString())
|
||||||
true
|
true
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.studentinfo
|
package io.github.wulkanowy.ui.modules.studentinfo
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -130,9 +129,9 @@ class StudentInfoFragment :
|
|||||||
getString(R.string.student_info_parents_name) to studentInfo.parentsNames
|
getString(R.string.student_info_parents_name) to studentInfo.parentsNames
|
||||||
).map {
|
).map {
|
||||||
StudentInfoItem(
|
StudentInfoItem(
|
||||||
it.first,
|
title = it.first,
|
||||||
it.second.ifBlank { getString(R.string.all_no_data) },
|
subtitle = it.second.ifBlank { getString(R.string.all_no_data) },
|
||||||
false,
|
showArrow = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -146,25 +145,33 @@ class StudentInfoFragment :
|
|||||||
getString(R.string.student_info_email) to studentInfo.email
|
getString(R.string.student_info_email) to studentInfo.email
|
||||||
).map {
|
).map {
|
||||||
StudentInfoItem(
|
StudentInfoItem(
|
||||||
it.first,
|
title = it.first,
|
||||||
it.second.ifBlank { getString(R.string.all_no_data) },
|
subtitle = it.second.ifBlank { getString(R.string.all_no_data) },
|
||||||
false,
|
showArrow = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
override fun showFamilyTypeData(studentInfo: StudentInfo) {
|
override fun showFamilyTypeData(studentInfo: StudentInfo) {
|
||||||
|
val items = buildList {
|
||||||
|
add(studentInfo.firstGuardian?.let {
|
||||||
|
Triple(it.kinship.capitalise(), it.fullName, StudentInfoView.Type.FIRST_GUARDIAN)
|
||||||
|
})
|
||||||
|
|
||||||
|
add(studentInfo.secondGuardian?.let {
|
||||||
|
Triple(it.kinship.capitalise(), it.fullName, StudentInfoView.Type.SECOND_GUARDIAN)
|
||||||
|
})
|
||||||
|
}.filterNotNull()
|
||||||
|
|
||||||
updateData(
|
updateData(
|
||||||
listOfNotNull(
|
items.map { (title, value, type) ->
|
||||||
studentInfo.firstGuardian?.let { it.kinship.capitalise() to it.fullName },
|
|
||||||
studentInfo.secondGuardian?.let { it.kinship.capitalise() to it.fullName },
|
|
||||||
).map { (title, value) ->
|
|
||||||
StudentInfoItem(
|
StudentInfoItem(
|
||||||
title.ifBlank { getString(R.string.all_no_data) },
|
title = title.ifBlank { getString(R.string.all_no_data) },
|
||||||
value.ifBlank { getString(R.string.all_no_data) },
|
subtitle = value.ifBlank { getString(R.string.all_no_data) },
|
||||||
true,
|
showArrow = true,
|
||||||
|
viewType = type,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -178,15 +185,15 @@ class StudentInfoFragment :
|
|||||||
getString(R.string.student_info_correspondence_address) to studentInfo.correspondenceAddress
|
getString(R.string.student_info_correspondence_address) to studentInfo.correspondenceAddress
|
||||||
).map {
|
).map {
|
||||||
StudentInfoItem(
|
StudentInfoItem(
|
||||||
it.first,
|
title = it.first,
|
||||||
it.second.ifBlank { getString(R.string.all_no_data) },
|
subtitle = it.second.ifBlank { getString(R.string.all_no_data) },
|
||||||
false,
|
showArrow = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showFirstGuardianTypeData(studentGuardian: StudentGuardian) {
|
override fun showGuardianTypeData(studentGuardian: StudentGuardian) {
|
||||||
updateData(
|
updateData(
|
||||||
listOf(
|
listOf(
|
||||||
getString(R.string.student_info_full_name) to studentGuardian.fullName,
|
getString(R.string.student_info_full_name) to studentGuardian.fullName,
|
||||||
@ -196,27 +203,9 @@ class StudentInfoFragment :
|
|||||||
getString(R.string.student_info_email) to studentGuardian.email
|
getString(R.string.student_info_email) to studentGuardian.email
|
||||||
).map {
|
).map {
|
||||||
StudentInfoItem(
|
StudentInfoItem(
|
||||||
it.first,
|
title = it.first,
|
||||||
it.second.ifBlank { getString(R.string.all_no_data) },
|
subtitle = it.second.ifBlank { getString(R.string.all_no_data) },
|
||||||
false,
|
showArrow = false,
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showSecondGuardianTypeData(studentGuardian: StudentGuardian) {
|
|
||||||
updateData(
|
|
||||||
listOf(
|
|
||||||
getString(R.string.student_info_full_name) to studentGuardian.fullName,
|
|
||||||
getString(R.string.student_info_kinship) to studentGuardian.kinship,
|
|
||||||
getString(R.string.student_info_guardian_address) to studentGuardian.address,
|
|
||||||
getString(R.string.student_info_phones) to studentGuardian.phones,
|
|
||||||
getString(R.string.student_info_email) to studentGuardian.email
|
|
||||||
).map {
|
|
||||||
StudentInfoItem(
|
|
||||||
it.first,
|
|
||||||
it.second.ifBlank { getString(R.string.all_no_data) },
|
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -3,5 +3,6 @@ package io.github.wulkanowy.ui.modules.studentinfo
|
|||||||
data class StudentInfoItem(
|
data class StudentInfoItem(
|
||||||
val title: String,
|
val title: String,
|
||||||
val subtitle: String,
|
val subtitle: String,
|
||||||
val showArrow: Boolean
|
val showArrow: Boolean,
|
||||||
|
val viewType: StudentInfoView.Type? = null,
|
||||||
)
|
)
|
||||||
|
@ -58,13 +58,12 @@ class StudentInfoPresenter @Inject constructor(
|
|||||||
view?.showErrorDetailsDialog(lastError)
|
view?.showErrorDetailsDialog(lastError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onItemSelected(position: Int) {
|
fun onItemSelected(viewType: StudentInfoView.Type?) {
|
||||||
if (infoType != StudentInfoView.Type.FAMILY) return
|
viewType ?: return
|
||||||
|
|
||||||
view?.openStudentInfoView(
|
view?.openStudentInfoView(
|
||||||
if (position == 0) StudentInfoView.Type.FIRST_GUARDIAN
|
studentWithSemesters = studentWithSemesters,
|
||||||
else StudentInfoView.Type.SECOND_GUARDIAN,
|
infoType = viewType,
|
||||||
studentWithSemesters
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,15 +75,19 @@ class StudentInfoPresenter @Inject constructor(
|
|||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
val semester = studentWithSemesters.semesters.getCurrentOrLast()
|
val semester = studentWithSemesters.semesters.getCurrentOrLast()
|
||||||
studentInfoRepository.getStudentInfo(
|
studentInfoRepository.getStudentInfo(
|
||||||
studentWithSemesters.student,
|
student = studentWithSemesters.student,
|
||||||
semester,
|
semester = semester,
|
||||||
forceRefresh
|
forceRefresh = forceRefresh
|
||||||
)
|
)
|
||||||
}.onEach {
|
}.onEach {
|
||||||
when (it.status) {
|
when (it.status) {
|
||||||
Status.LOADING -> Timber.i("Loading student info $infoType started")
|
Status.LOADING -> Timber.i("Loading student info $infoType started")
|
||||||
Status.SUCCESS -> {
|
Status.SUCCESS -> {
|
||||||
if (it.data != null && !(infoType == StudentInfoView.Type.FAMILY && it.data.firstGuardian == null && it.data.secondGuardian == null)) {
|
val isFamily = infoType == StudentInfoView.Type.FAMILY
|
||||||
|
val isFirstGuardianEmpty = it.data?.firstGuardian == null
|
||||||
|
val isSecondGuardianEmpty = it.data?.secondGuardian == null
|
||||||
|
|
||||||
|
if (it.data != null && !(isFamily && isFirstGuardianEmpty && isSecondGuardianEmpty)) {
|
||||||
Timber.i("Loading student info $infoType result: Success")
|
Timber.i("Loading student info $infoType result: Success")
|
||||||
showCorrectData(it.data)
|
showCorrectData(it.data)
|
||||||
view?.run {
|
view?.run {
|
||||||
@ -122,8 +125,8 @@ class StudentInfoPresenter @Inject constructor(
|
|||||||
StudentInfoView.Type.CONTACT -> view?.showContactTypeData(studentInfo)
|
StudentInfoView.Type.CONTACT -> view?.showContactTypeData(studentInfo)
|
||||||
StudentInfoView.Type.ADDRESS -> view?.showAddressTypeData(studentInfo)
|
StudentInfoView.Type.ADDRESS -> view?.showAddressTypeData(studentInfo)
|
||||||
StudentInfoView.Type.FAMILY -> view?.showFamilyTypeData(studentInfo)
|
StudentInfoView.Type.FAMILY -> view?.showFamilyTypeData(studentInfo)
|
||||||
StudentInfoView.Type.SECOND_GUARDIAN -> view?.showSecondGuardianTypeData(studentInfo.secondGuardian!!)
|
StudentInfoView.Type.SECOND_GUARDIAN -> view?.showGuardianTypeData(studentInfo.secondGuardian!!)
|
||||||
StudentInfoView.Type.FIRST_GUARDIAN -> view?.showFirstGuardianTypeData(studentInfo.firstGuardian!!)
|
StudentInfoView.Type.FIRST_GUARDIAN -> view?.showGuardianTypeData(studentInfo.firstGuardian!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,9 +25,7 @@ interface StudentInfoView : BaseView {
|
|||||||
|
|
||||||
fun showFamilyTypeData(studentInfo: StudentInfo)
|
fun showFamilyTypeData(studentInfo: StudentInfo)
|
||||||
|
|
||||||
fun showFirstGuardianTypeData(studentGuardian: StudentGuardian)
|
fun showGuardianTypeData(studentGuardian: StudentGuardian)
|
||||||
|
|
||||||
fun showSecondGuardianTypeData(studentGuardian: StudentGuardian)
|
|
||||||
|
|
||||||
fun openStudentInfoView(infoType: Type, studentWithSemesters: StudentWithSemesters)
|
fun openStudentInfoView(infoType: Type, studentWithSemesters: StudentWithSemesters)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import android.view.MenuItem
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.parseAsHtml
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.datepicker.CalendarConstraints
|
import com.google.android.material.datepicker.CalendarConstraints
|
||||||
import com.google.android.material.datepicker.MaterialDatePicker
|
import com.google.android.material.datepicker.MaterialDatePicker
|
||||||
@ -49,7 +49,7 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||||||
|
|
||||||
override val titleStringId get() = R.string.timetable_title
|
override val titleStringId get() = R.string.timetable_title
|
||||||
|
|
||||||
override val isViewEmpty get() = timetableAdapter.itemCount > 0
|
override val isViewEmpty get() = timetableAdapter.itemCount == 0
|
||||||
|
|
||||||
override val currentStackSize get() = (activity as? MainActivity)?.currentStackSize
|
override val currentStackSize get() = (activity as? MainActivity)?.currentStackSize
|
||||||
|
|
||||||
@ -147,9 +147,7 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
|||||||
|
|
||||||
override fun setDayHeaderMessage(message: String?) {
|
override fun setDayHeaderMessage(message: String?) {
|
||||||
binding.timetableEmptyMessage.visibility = if (message.isNullOrEmpty()) GONE else VISIBLE
|
binding.timetableEmptyMessage.visibility = if (message.isNullOrEmpty()) GONE else VISIBLE
|
||||||
binding.timetableEmptyMessage.text = HtmlCompat.fromHtml(
|
binding.timetableEmptyMessage.text = message.orEmpty().parseAsHtml()
|
||||||
message.orEmpty(), HtmlCompat.FROM_HTML_MODE_COMPACT
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showErrorView(show: Boolean) {
|
override fun showErrorView(show: Boolean) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.utils
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
@ -58,8 +59,11 @@ fun Context.getCompatBitmap(@DrawableRes drawableRes: Int, @ColorRes colorRes: I
|
|||||||
|
|
||||||
fun Context.openInternetBrowser(uri: String, onActivityNotFound: (uri: String) -> Unit = {}) {
|
fun Context.openInternetBrowser(uri: String, onActivityNotFound: (uri: String) -> Unit = {}) {
|
||||||
Intent.parseUri(uri, 0).let {
|
Intent.parseUri(uri, 0).let {
|
||||||
if (it.resolveActivity(packageManager) != null) startActivity(it)
|
try {
|
||||||
else onActivityNotFound(uri)
|
startActivity(it)
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
onActivityNotFound(uri)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ inline val Timetable.left: Duration?
|
|||||||
get() = when {
|
get() = when {
|
||||||
canceled -> null
|
canceled -> null
|
||||||
!isStudentPlan -> null
|
!isStudentPlan -> null
|
||||||
end.isAfter(now()) && start.isBefore(now()) -> between(now(), end)
|
end >= now() && start <= now() -> between(now(), end)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
Wersja 1.2.0
|
Wersja 1.2.1
|
||||||
|
|
||||||
- dodaliśmy nowy ekran startowy 🎉
|
- dodaliśmy brakujące okienka z podglądem szczegółów ogłoszeń szkolnych
|
||||||
- usprawniliśmy powiadomienia
|
- naprawiliśmy rzucające się w oczy błędy na ekranie startowym
|
||||||
- dodaliśmy wersje robocze, filtrowanie oraz informację o odczytaniu przez odbiorcę w wiadomościach
|
- naprawiliśmy też inne drobne błędy w wyglądzie i stabilności aplikacji
|
||||||
- dodaliśmy informacje o liczeniu średniej w podsumowaniu ocen
|
|
||||||
- dodaliśmy opcję generowania wiadomości z usprawiedliwieniem dni w szkołach pozbawionych funkcji usprawiedliwiania przez zakładkę frekwencja
|
|
||||||
- oraz wiele wiele innych ulepszeń i poprawek
|
|
||||||
|
|
||||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||||
|
148
app/src/main/res/layout/dialog_school_announcement.xml
Normal file
148
app/src/main/res/layout/dialog_school_announcement.xml
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.core.widget.NestedScrollView 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="match_parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="24dp"
|
||||||
|
android:paddingEnd="8dp">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="280dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/allDetailsHeader"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:text="@string/all_details"
|
||||||
|
android:textSize="21sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/announcementDialogSubjectTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginTop="28dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:text="@string/all_subject"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/allDetailsHeader" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/announcementDialogSubjectValue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/announcementDialogSubjectTitle" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/announcementDialogDateTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:text="@string/exam_entry_date"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/announcementDialogSubjectValue" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/announcementDialogDateValue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/announcementDialogDateTitle" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/announcementDialogDescriptionTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:text="@string/all_description"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/announcementDialogDateValue" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/announcementDialogDescriptionValue"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/announcementDialogDescriptionTitle"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/announcementDialogClose"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginTop="36dp"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:minWidth="88dp"
|
||||||
|
android:text="@string/all_close"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/announcementDialogDescriptionValue" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
@ -36,7 +36,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<FrameLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
@ -44,24 +44,44 @@
|
|||||||
android:id="@+id/gradeStatisticsProgress"
|
android:id="@+id/gradeStatisticsProgress"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
|
||||||
android:indeterminate="true"
|
android:indeterminate="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:visibility="gone" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/gradeStatisticsRecycler"
|
android:id="@+id/gradeStatisticsRecycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
tools:listitem="@layout/item_grade_statistics_pie" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:listitem="@layout/item_grade_statistics_pie"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:fillViewport="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/gradeStatisticsRecycler">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/gradeStatisticsEmpty"
|
android:id="@+id/gradeStatisticsEmpty"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
tools:ignore="UseCompoundDrawables">
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:ignore="UseCompoundDrawables"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
@ -82,12 +102,14 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/gradeStatisticsError"
|
android:id="@+id/gradeStatisticsError"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:visibility="invisible"
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:ignore="UseCompoundDrawables"
|
tools:ignore="UseCompoundDrawables"
|
||||||
tools:visibility="invisible">
|
tools:visibility="gone">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
@ -129,6 +151,8 @@
|
|||||||
android:text="@string/all_retry" />
|
android:text="@string/all_retry" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</FrameLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="12dp"
|
|
||||||
android:layout_marginVertical="2dp"
|
android:layout_marginVertical="2dp"
|
||||||
android:clipToPadding="false">
|
android:clipToPadding="false"
|
||||||
|
android:paddingHorizontal="12dp">
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/dashboard_horizontal_group_item_lucky_container"
|
android:id="@+id/dashboard_horizontal_group_item_lucky_container"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="44dp"
|
||||||
android:layout_marginVertical="4dp"
|
android:layout_marginVertical="4dp"
|
||||||
app:cardElevation="4dp"
|
app:cardElevation="4dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
@ -62,7 +62,7 @@
|
|||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/dashboard_horizontal_group_item_message_container"
|
android:id="@+id/dashboard_horizontal_group_item_message_container"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="44dp"
|
||||||
android:layout_marginVertical="4dp"
|
android:layout_marginVertical="4dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
app:cardElevation="4dp"
|
app:cardElevation="4dp"
|
||||||
@ -119,7 +119,7 @@
|
|||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/dashboard_horizontal_group_item_attendance_container"
|
android:id="@+id/dashboard_horizontal_group_item_attendance_container"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="44dp"
|
||||||
android:layout_marginVertical="4dp"
|
android:layout_marginVertical="4dp"
|
||||||
app:cardElevation="4dp"
|
app:cardElevation="4dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
@ -169,10 +169,8 @@
|
|||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/dashboard_horizontal_group_item_info_container"
|
android:id="@+id/dashboard_horizontal_group_item_info_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="44dp"
|
||||||
android:layout_marginVertical="4dp"
|
android:layout_marginVertical="4dp"
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:cardElevation="4dp"
|
app:cardElevation="4dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
@ -496,7 +496,6 @@
|
|||||||
<!--Dashboard-->
|
<!--Dashboard-->
|
||||||
<string name="dashboard_timetable_title">Lekce</string>
|
<string name="dashboard_timetable_title">Lekce</string>
|
||||||
<string name="dashboard_timetable_title_tomorrow">(Zítra)</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_moment">Za chvíli:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_soon">Brzy:</string>
|
<string name="dashboard_timetable_first_lesson_title_soon">Brzy:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_first">První:</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>
|
<item quantity="other">Ještě %1$d dalších setkání</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="dashboard_horizontal_group_error">Při načítání dat došlo k chybě</string>
|
<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-->
|
<!--Error dialog-->
|
||||||
<string name="dialog_error_check_update">Zkontrolovat aktualizace</string>
|
<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>
|
<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-->
|
<!--Dashboard-->
|
||||||
<string name="dashboard_timetable_title">Lektionen</string>
|
<string name="dashboard_timetable_title">Lektionen</string>
|
||||||
<string name="dashboard_timetable_title_tomorrow">(Morgen)</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_moment">Gleich:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_soon">Bald:</string>
|
<string name="dashboard_timetable_first_lesson_title_soon">Bald:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_first">Erstens:</string>
|
<string name="dashboard_timetable_first_lesson_title_first">Erstens:</string>
|
||||||
@ -488,7 +487,7 @@
|
|||||||
<item quantity="other">%1$d weitere Konferenzen</item>
|
<item quantity="other">%1$d weitere Konferenzen</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="dashboard_horizontal_group_error">Fehler beim Laden der Daten</string>
|
<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-->
|
<!--Error dialog-->
|
||||||
<string name="dialog_error_check_update">Auf Updates prüfen</string>
|
<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>
|
<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>
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
<string name="login_incorrect_symbol">Nie znaleziono ucznia. Sprawdź poprawność symbolu i wybranej odmiany dziennika UONET+</string>
|
<string name="login_incorrect_symbol">Nie znaleziono ucznia. Sprawdź poprawność symbolu i wybranej odmiany dziennika UONET+</string>
|
||||||
<string name="login_field_required">To pole jest wymagane</string>
|
<string name="login_field_required">To pole jest wymagane</string>
|
||||||
<string name="login_duplicate_student">Wybrany uczeń jest już zalogowany</string>
|
<string name="login_duplicate_student">Wybrany uczeń jest już zalogowany</string>
|
||||||
<string name="login_symbol_helper">Symbol znajdziesz na stronie dziennika w <b>Uczeń</b> → <b>Dostęp Mobilny</b> → <b>Zarejestruj urządzenie mobilne</b>.\n\nUpewnij się, że w polu <b>Dziennik UONET+</b> na poprzednim ekranie została ustawiona odpowiednia odmiana dziennika. Wulkanowy na chwilę obecną nie wykrywa uczniów przedszkolnych</string>
|
<string name="login_symbol_helper">Symbol znajdziesz na stronie dziennika w <b>Uczeń</b> → <b>Dostęp Mobilny</b> → <b>Zarejestruj urządzenie mobilne</b>.\n\nUpewnij się, że w polu <b>Dziennik UONET+</b> na poprzednim ekranie została ustawiona odpowiednia odmiana dziennika.\n\n<b>Wulkanowy na chwilę obecną nie wykrywa uczniów przedszkolnych (z zerówki)</b></string>
|
||||||
<string name="login_select_student">Wybierz uczniów do zalogowania w aplikacji</string>
|
<string name="login_select_student">Wybierz uczniów do zalogowania w aplikacji</string>
|
||||||
<string name="login_advanced">Inne opcje</string>
|
<string name="login_advanced">Inne opcje</string>
|
||||||
<string name="login_advanced_warning_mobile_api">W tym trybie nie działa szczęśliwy numerek, uczeń na tle klasy, podsumowanie frekwencji, usprawiedliwianie nieobecności, lekcje zrealizowane, informacje o szkole i podgląd listy zarejestrowanych urządzeń</string>
|
<string name="login_advanced_warning_mobile_api">W tym trybie nie działa szczęśliwy numerek, uczeń na tle klasy, podsumowanie frekwencji, usprawiedliwianie nieobecności, lekcje zrealizowane, informacje o szkole i podgląd listy zarejestrowanych urządzeń</string>
|
||||||
@ -496,7 +496,6 @@
|
|||||||
<!--Dashboard-->
|
<!--Dashboard-->
|
||||||
<string name="dashboard_timetable_title">Lekcje</string>
|
<string name="dashboard_timetable_title">Lekcje</string>
|
||||||
<string name="dashboard_timetable_title_tomorrow">(Jutro)</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_moment">Za chwilę:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_soon">Wkrótce:</string>
|
<string name="dashboard_timetable_first_lesson_title_soon">Wkrótce:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_first">Pierwsza:</string>
|
<string name="dashboard_timetable_first_lesson_title_first">Pierwsza:</string>
|
||||||
@ -566,7 +565,7 @@
|
|||||||
<item quantity="other">Jeszcze %1$d dodatkowych zebrań</item>
|
<item quantity="other">Jeszcze %1$d dodatkowych zebrań</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="dashboard_horizontal_group_error">Wystąpił błąd podczas ładowania danych</string>
|
<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-->
|
<!--Error dialog-->
|
||||||
<string name="dialog_error_check_update">Sprawdź dostępność aktualizacji</string>
|
<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>
|
<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-->
|
<!--Dashboard-->
|
||||||
<string name="dashboard_timetable_title">Уроки</string>
|
<string name="dashboard_timetable_title">Уроки</string>
|
||||||
<string name="dashboard_timetable_title_tomorrow">(Завтра)</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_moment">Сейчас:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_soon">Скоро:</string>
|
<string name="dashboard_timetable_first_lesson_title_soon">Скоро:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_first">Первый:</string>
|
<string name="dashboard_timetable_first_lesson_title_first">Первый:</string>
|
||||||
@ -566,7 +565,7 @@
|
|||||||
<item quantity="other">Еще %1$d конференций</item>
|
<item quantity="other">Еще %1$d конференций</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="dashboard_horizontal_group_error">Произошла ошибка при загрузке данных</string>
|
<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-->
|
<!--Error dialog-->
|
||||||
<string name="dialog_error_check_update">Проверить наличие обновлений</string>
|
<string name="dialog_error_check_update">Проверить наличие обновлений</string>
|
||||||
<string name="dialog_error_check_update_message">Прежде чем сообщать об ошибке, проверьте наличие обновлений</string>
|
<string name="dialog_error_check_update_message">Прежде чем сообщать об ошибке, проверьте наличие обновлений</string>
|
||||||
|
@ -496,7 +496,6 @@
|
|||||||
<!--Dashboard-->
|
<!--Dashboard-->
|
||||||
<string name="dashboard_timetable_title">Lekcie</string>
|
<string name="dashboard_timetable_title">Lekcie</string>
|
||||||
<string name="dashboard_timetable_title_tomorrow">(Zajtra)</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_moment">Za chvíľu:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_soon">Čoskoro:</string>
|
<string name="dashboard_timetable_first_lesson_title_soon">Čoskoro:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_first">Prvá:</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>
|
<item quantity="other">Ešte %1$d ďalších stretnutí</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="dashboard_horizontal_group_error">Pri načítaní dát došlo k chybe</string>
|
<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-->
|
<!--Error dialog-->
|
||||||
<string name="dialog_error_check_update">Skontrolovať aktualizácie</string>
|
<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>
|
<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-->
|
<!--Dashboard-->
|
||||||
<string name="dashboard_timetable_title">Уроки</string>
|
<string name="dashboard_timetable_title">Уроки</string>
|
||||||
<string name="dashboard_timetable_title_tomorrow">(Завтра)</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_moment">Через мить:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_soon">Незабаром:</string>
|
<string name="dashboard_timetable_first_lesson_title_soon">Незабаром:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_first">Перше:</string>
|
<string name="dashboard_timetable_first_lesson_title_first">Перше:</string>
|
||||||
@ -566,7 +565,7 @@
|
|||||||
<item quantity="other">%1$d більше конференцій</item>
|
<item quantity="other">%1$d більше конференцій</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="dashboard_horizontal_group_error">Помилка при завантаженні даних</string>
|
<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-->
|
<!--Error dialog-->
|
||||||
<string name="dialog_error_check_update">Провірити наявність оновлень</string>
|
<string name="dialog_error_check_update">Провірити наявність оновлень</string>
|
||||||
<string name="dialog_error_check_update_message">Перед тим, як повідомлювати о помілці, перевірте наявність оновлень</string>
|
<string name="dialog_error_check_update_message">Перед тим, як повідомлювати о помілці, перевірте наявність оновлень</string>
|
||||||
|
@ -495,7 +495,6 @@
|
|||||||
<!--Dashboard-->
|
<!--Dashboard-->
|
||||||
<string name="dashboard_timetable_title">Lessons</string>
|
<string name="dashboard_timetable_title">Lessons</string>
|
||||||
<string name="dashboard_timetable_title_tomorrow">(Tomorrow)</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_moment">In a moment:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_soon">Soon:</string>
|
<string name="dashboard_timetable_first_lesson_title_soon">Soon:</string>
|
||||||
<string name="dashboard_timetable_first_lesson_title_first">First:</string>
|
<string name="dashboard_timetable_first_lesson_title_first">First:</string>
|
||||||
@ -557,7 +556,7 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
<string name="dashboard_horizontal_group_error">An error occurred while loading data</string>
|
<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-->
|
<!--Error dialog-->
|
||||||
|
@ -32,7 +32,22 @@ class TimetableExtensionTest {
|
|||||||
assertEquals(null, getTimetableEntity(canceled = true).left)
|
assertEquals(null, getTimetableEntity(canceled = true).left)
|
||||||
assertEquals(null, getTimetableEntity(start = now().plusMinutes(5), end = now().plusMinutes(50)).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)
|
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
|
@Test
|
||||||
|
@ -12,13 +12,13 @@ buildscript {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath 'com.android.tools.build:gradle:7.0.1'
|
classpath 'com.android.tools.build:gradle:7.0.2'
|
||||||
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
|
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
|
||||||
classpath 'com.google.gms:google-services:4.3.10'
|
classpath 'com.google.gms:google-services:4.3.10'
|
||||||
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
|
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
|
||||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'
|
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'
|
||||||
classpath "com.github.triplet.gradle:play-publisher:2.8.0"
|
classpath "com.github.triplet.gradle:play-publisher:2.8.0"
|
||||||
classpath "ru.cian:huawei-publish-gradle-plugin:1.2.4"
|
classpath "ru.cian:huawei-publish-gradle-plugin:1.3.0"
|
||||||
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3"
|
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.3"
|
||||||
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
|
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
|
||||||
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries"
|
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user