mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-01-31 17:52:45 +01:00
Add dashboard (#1267)
This commit is contained in:
parent
3278c11cce
commit
3422951e47
@ -164,7 +164,7 @@ ext {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.github.wulkanowy:sdk:bb08354"
|
||||
implementation "io.github.wulkanowy:sdk:496dc01d15"
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
@ -182,7 +182,7 @@ dependencies {
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||
implementation "androidx.viewpager:viewpager:1.0.0"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.0-beta02"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
|
||||
implementation "com.google.android.material:material:1.4.0"
|
||||
implementation "com.github.wulkanowy:material-chips-input:2.2.0"
|
||||
@ -209,6 +209,7 @@ dependencies {
|
||||
implementation "com.squareup.moshi:moshi:$moshi"
|
||||
implementation "com.squareup.moshi:moshi-adapters:$moshi"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi"
|
||||
|
||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||
implementation 'com.github.bastienpaulfr:Treessence:1.0.4'
|
||||
@ -216,6 +217,7 @@ dependencies {
|
||||
implementation "io.coil-kt:coil:1.3.0"
|
||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
|
||||
implementation 'com.fredporciuncula:flow-preferences:1.5.0'
|
||||
|
||||
playImplementation platform('com.google.firebase:firebase-bom:28.3.0')
|
||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||
@ -244,9 +246,9 @@ dependencies {
|
||||
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||
|
||||
androidTestImplementation "androidx.test:core:1.3.0"
|
||||
androidTestImplementation "androidx.test:runner:1.3.0"
|
||||
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
||||
androidTestImplementation "androidx.test:core:1.4.0"
|
||||
androidTestImplementation "androidx.test:runner:1.4.0"
|
||||
androidTestImplementation "androidx.test.ext:junit:1.1.3"
|
||||
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import androidx.preference.PreferenceManager
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||
import com.chuckerteam.chucker.api.RetentionManager
|
||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@ -18,6 +19,7 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import timber.log.Timber
|
||||
import javax.inject.Singleton
|
||||
|
||||
@ -77,6 +79,12 @@ internal class RepositoryModule {
|
||||
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
|
||||
FlowSharedPreferences(sharedPreferences)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideStudentDao(database: AppDatabase) = database.studentDao
|
||||
|
@ -4,12 +4,13 @@ import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Conference
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.time.LocalDateTime
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Dao
|
||||
@Singleton
|
||||
interface ConferenceDao : BaseDao<Conference> {
|
||||
|
||||
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId")
|
||||
fun loadAll(diaryId: Int, studentId: Int): Flow<List<Conference>>
|
||||
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :startDate")
|
||||
fun loadAll(diaryId: Int, studentId: Int, startDate: LocalDateTime): Flow<List<Conference>>
|
||||
}
|
||||
|
@ -25,9 +25,17 @@ class AttendanceSummaryRepository @Inject constructor(
|
||||
|
||||
private val cacheKey = "attendance_summary"
|
||||
|
||||
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
|
||||
fun getAttendanceSummary(
|
||||
student: Student,
|
||||
semester: Semester,
|
||||
subjectId: Int,
|
||||
forceRefresh: Boolean
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
|
||||
shouldFetch = {
|
||||
it.isEmpty() || forceRefresh
|
||||
|| refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
},
|
||||
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
|
||||
fetch = {
|
||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
|
@ -13,6 +13,9 @@ import io.github.wulkanowy.utils.networkBoundResource
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@ -31,7 +34,8 @@ class ConferenceRepository @Inject constructor(
|
||||
student: Student,
|
||||
semester: Semester,
|
||||
forceRefresh: Boolean,
|
||||
notify: Boolean = false
|
||||
notify: Boolean = false,
|
||||
startDate: LocalDateTime = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)
|
||||
) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
shouldFetch = {
|
||||
@ -39,15 +43,13 @@ class ConferenceRepository @Inject constructor(
|
||||
|| refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||
},
|
||||
query = {
|
||||
conferenceDb.loadAll(
|
||||
semester.diaryId,
|
||||
student.studentId
|
||||
)
|
||||
conferenceDb.loadAll(semester.diaryId, student.studentId, startDate)
|
||||
},
|
||||
fetch = {
|
||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||
.getConferences()
|
||||
.mapToEntities(semester)
|
||||
.filter { it.date >= startDate }
|
||||
},
|
||||
saveFetchResult = { old, new ->
|
||||
val conferencesToSave = (new uniqueSubtract old).onEach {
|
||||
@ -60,9 +62,12 @@ class ConferenceRepository @Inject constructor(
|
||||
}
|
||||
)
|
||||
|
||||
fun getConferenceFromDatabase(semester: Semester): Flow<List<Conference>> {
|
||||
return conferenceDb.loadAll(semester.diaryId, semester.studentId)
|
||||
}
|
||||
fun getConferenceFromDatabase(semester: Semester): Flow<List<Conference>> =
|
||||
conferenceDb.loadAll(
|
||||
diaryId = semester.diaryId,
|
||||
studentId = semester.studentId,
|
||||
startDate = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)
|
||||
)
|
||||
|
||||
suspend fun updateConference(conference: List<Conference>) = conferenceDb.updateAll(conference)
|
||||
}
|
||||
|
@ -2,16 +2,24 @@ package io.github.wulkanowy.data.repositories
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
||||
import com.fredporciuncula.flow.preferences.Preference
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Singleton
|
||||
class PreferencesRepository @Inject constructor(
|
||||
private val sharedPref: SharedPreferences,
|
||||
private val flowSharedPref: FlowSharedPreferences,
|
||||
@ApplicationContext val context: Context
|
||||
) {
|
||||
val startMenuIndex: Int
|
||||
@ -151,6 +159,36 @@ class PreferencesRepository @Inject constructor(
|
||||
R.bool.pref_default_optional_arithmetic_average
|
||||
)
|
||||
|
||||
val selectedDashboardTilesFlow: Flow<Set<DashboardItem.Tile>>
|
||||
get() = selectedDashboardTilesPreference.asFlow()
|
||||
.map { set ->
|
||||
set.map { DashboardItem.Tile.valueOf(it) }
|
||||
.plus(DashboardItem.Tile.ACCOUNT)
|
||||
.toSet()
|
||||
}
|
||||
|
||||
var selectedDashboardTiles: Set<DashboardItem.Tile>
|
||||
get() = selectedDashboardTilesPreference.get()
|
||||
.map { DashboardItem.Tile.valueOf(it) }
|
||||
.plus(DashboardItem.Tile.ACCOUNT)
|
||||
.toSet()
|
||||
set(value) {
|
||||
val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
|
||||
.map { it.name }
|
||||
.toSet()
|
||||
|
||||
selectedDashboardTilesPreference.set(filteredValue)
|
||||
}
|
||||
|
||||
private val selectedDashboardTilesPreference: Preference<Set<String>>
|
||||
get() {
|
||||
val defaultSet =
|
||||
context.resources.getStringArray(R.array.pref_default_dashboard_tiles).toSet()
|
||||
val prefKey = context.getString(R.string.pref_key_dashboard_tiles)
|
||||
|
||||
return flowSharedPref.getStringSet(prefKey, defaultSet)
|
||||
}
|
||||
|
||||
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
|
||||
|
||||
private fun getString(id: String, default: Int) =
|
||||
|
@ -0,0 +1,713 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Typeface
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||
import io.github.wulkanowy.databinding.ItemDashboardAccountBinding
|
||||
import io.github.wulkanowy.databinding.ItemDashboardAnnouncementsBinding
|
||||
import io.github.wulkanowy.databinding.ItemDashboardConferencesBinding
|
||||
import io.github.wulkanowy.databinding.ItemDashboardExamsBinding
|
||||
import io.github.wulkanowy.databinding.ItemDashboardGradesBinding
|
||||
import io.github.wulkanowy.databinding.ItemDashboardHomeworkBinding
|
||||
import io.github.wulkanowy.databinding.ItemDashboardHorizontalGroupBinding
|
||||
import io.github.wulkanowy.databinding.ItemDashboardLessonsBinding
|
||||
import io.github.wulkanowy.utils.createNameInitialsDrawable
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.left
|
||||
import io.github.wulkanowy.utils.nickOrName
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.Duration
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.util.Timer
|
||||
import javax.inject.Inject
|
||||
import kotlin.concurrent.timer
|
||||
|
||||
class DashboardAdapter @Inject constructor() :
|
||||
ListAdapter<DashboardItem, RecyclerView.ViewHolder>(DashboardAdapterDiffCallback()) {
|
||||
|
||||
var lessonsTimer: Timer? = null
|
||||
|
||||
var onAccountTileClickListener: () -> Unit = {}
|
||||
|
||||
var onLuckyNumberTileClickListener: () -> Unit = {}
|
||||
|
||||
var onMessageTileClickListener: () -> Unit = {}
|
||||
|
||||
var onGradeTileClickListener: () -> Unit = {}
|
||||
|
||||
var onAttendanceTileClickListener: () -> Unit = {}
|
||||
|
||||
var onLessonsTileClickListener: () -> Unit = {}
|
||||
|
||||
var onHomeworkTileClickListener: () -> Unit = {}
|
||||
|
||||
var onAnnouncementsTileClickListener: () -> Unit = {}
|
||||
|
||||
var onExamsTileClickListener: () -> Unit = {}
|
||||
|
||||
var onConferencesTileClickListener: () -> Unit = {}
|
||||
|
||||
override fun getItemViewType(position: Int) = getItem(position).type.ordinal
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
|
||||
return when (viewType) {
|
||||
DashboardItem.Type.ACCOUNT.ordinal -> AccountViewHolder(
|
||||
ItemDashboardAccountBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
DashboardItem.Type.HORIZONTAL_GROUP.ordinal -> HorizontalGroupViewHolder(
|
||||
ItemDashboardHorizontalGroupBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
DashboardItem.Type.GRADES.ordinal -> GradesViewHolder(
|
||||
ItemDashboardGradesBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
DashboardItem.Type.LESSONS.ordinal -> LessonsViewHolder(
|
||||
ItemDashboardLessonsBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
DashboardItem.Type.HOMEWORK.ordinal -> HomeworkViewHolder(
|
||||
ItemDashboardHomeworkBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
DashboardItem.Type.ANNOUNCEMENTS.ordinal -> AnnouncementsViewHolder(
|
||||
ItemDashboardAnnouncementsBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
DashboardItem.Type.EXAMS.ordinal -> ExamsViewHolder(
|
||||
ItemDashboardExamsBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
DashboardItem.Type.CONFERENCES.ordinal -> ConferencesViewHolder(
|
||||
ItemDashboardConferencesBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is AccountViewHolder -> bindAccountViewHolder(holder, position)
|
||||
is HorizontalGroupViewHolder -> bindHorizontalGroupViewHolder(holder, position)
|
||||
is GradesViewHolder -> bindGradesViewHolder(holder, position)
|
||||
is LessonsViewHolder -> bindLessonsViewHolder(holder, position)
|
||||
is HomeworkViewHolder -> bindHomeworkViewHolder(holder, position)
|
||||
is AnnouncementsViewHolder -> bindAnnouncementsViewHolder(holder, position)
|
||||
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
||||
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
||||
}
|
||||
}
|
||||
|
||||
fun clearTimers() {
|
||||
lessonsTimer?.let {
|
||||
it.cancel()
|
||||
it.purge()
|
||||
}
|
||||
lessonsTimer = null
|
||||
}
|
||||
|
||||
private fun bindAccountViewHolder(accountViewHolder: AccountViewHolder, position: Int) {
|
||||
val item = getItem(position) as DashboardItem.Account
|
||||
val student = item.student
|
||||
val isLoading = item.isLoading
|
||||
|
||||
val avatar = student?.let {
|
||||
accountViewHolder.binding.root.context.createNameInitialsDrawable(
|
||||
text = it.nickOrName,
|
||||
backgroundColor = it.avatarColor
|
||||
)
|
||||
}
|
||||
|
||||
with(accountViewHolder.binding) {
|
||||
dashboardAccountItemContent.isVisible = !isLoading
|
||||
dashboardAccountItemProgress.isVisible = isLoading
|
||||
|
||||
dashboardAccountItemAvatar.setImageDrawable(avatar)
|
||||
dashboardAccountItemName.text = student?.nickOrName.orEmpty()
|
||||
dashboardAccountItemSchoolName.text = student?.schoolName.orEmpty()
|
||||
|
||||
root.setOnClickListener { onAccountTileClickListener() }
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindHorizontalGroupViewHolder(
|
||||
horizontalGroupViewHolder: HorizontalGroupViewHolder,
|
||||
position: Int
|
||||
) {
|
||||
val item = getItem(position) as DashboardItem.HorizontalGroup
|
||||
val unreadMessagesCount = item.unreadMessagesCount
|
||||
val attendancePercentage = item.attendancePercentage
|
||||
val luckyNumber = item.luckyNumber
|
||||
val error = item.error
|
||||
val isLoading = item.isLoading
|
||||
val binding = horizontalGroupViewHolder.binding
|
||||
val context = binding.root.context
|
||||
val attendanceColor = when {
|
||||
attendancePercentage ?: 0.0 <= ATTENDANCE_SECOND_WARNING_THRESHOLD -> {
|
||||
context.getThemeAttrColor(R.attr.colorPrimary)
|
||||
}
|
||||
attendancePercentage ?: 0.0 <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> {
|
||||
context.getThemeAttrColor(R.attr.colorTimetableChange)
|
||||
}
|
||||
else -> context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||
}
|
||||
|
||||
with(binding.dashboardHorizontalGroupItemAttendanceValue) {
|
||||
text = "%.2f%%".format(attendancePercentage)
|
||||
setTextColor(attendanceColor)
|
||||
}
|
||||
|
||||
with(binding) {
|
||||
dashboardHorizontalGroupItemMessageValue.text = unreadMessagesCount.toString()
|
||||
dashboardHorizontalGroupItemLuckyValue.text = if (luckyNumber == -1) {
|
||||
context.getString(R.string.dashboard_horizontal_group_no_lukcy_number)
|
||||
} else luckyNumber?.toString()
|
||||
|
||||
if (dashboardHorizontalGroupItemInfoContainer.isVisible != (error != null || isLoading)) {
|
||||
dashboardHorizontalGroupItemInfoContainer.isVisible = error != null || isLoading
|
||||
}
|
||||
|
||||
if (dashboardHorizontalGroupItemInfoProgress.isVisible != isLoading) {
|
||||
dashboardHorizontalGroupItemInfoProgress.isVisible = isLoading
|
||||
}
|
||||
|
||||
dashboardHorizontalGroupItemInfoErrorText.isVisible = error != null
|
||||
|
||||
with(dashboardHorizontalGroupItemLuckyContainer) {
|
||||
isVisible = error == null && !isLoading && luckyNumber != null
|
||||
setOnClickListener { onLuckyNumberTileClickListener() }
|
||||
}
|
||||
|
||||
with(dashboardHorizontalGroupItemAttendanceContainer) {
|
||||
isVisible = error == null && !isLoading && attendancePercentage != null
|
||||
updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
matchConstraintPercentWidth = when {
|
||||
luckyNumber == null && unreadMessagesCount == null -> 1.0f
|
||||
luckyNumber == null || unreadMessagesCount == null -> 0.5f
|
||||
else -> 0.4f
|
||||
}
|
||||
}
|
||||
setOnClickListener { onAttendanceTileClickListener() }
|
||||
}
|
||||
|
||||
with(dashboardHorizontalGroupItemMessageContainer) {
|
||||
isVisible = error == null && !isLoading && unreadMessagesCount != null
|
||||
setOnClickListener { onMessageTileClickListener() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindGradesViewHolder(gradesViewHolder: GradesViewHolder, position: Int) {
|
||||
val item = getItem(position) as DashboardItem.Grades
|
||||
val subjectWithGrades = item.subjectWithGrades.orEmpty()
|
||||
val gradeTheme = item.gradeTheme
|
||||
val error = item.error
|
||||
val isLoading = item.isLoading
|
||||
val dashboardGradesAdapter = gradesViewHolder.adapter.apply {
|
||||
this.items = subjectWithGrades.toList()
|
||||
this.gradeTheme = gradeTheme.orEmpty()
|
||||
}
|
||||
|
||||
with(gradesViewHolder.binding) {
|
||||
dashboardGradesItemEmpty.isVisible =
|
||||
subjectWithGrades.isEmpty() && error == null && !isLoading
|
||||
dashboardGradesItemError.isVisible = error != null && !isLoading
|
||||
dashboardGradesItemProgress.isVisible =
|
||||
isLoading && error == null && subjectWithGrades.isEmpty()
|
||||
|
||||
with(dashboardGradesItemRecycler) {
|
||||
adapter = dashboardGradesAdapter
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
isVisible = subjectWithGrades.isNotEmpty() && error == null
|
||||
suppressLayout(true)
|
||||
}
|
||||
|
||||
root.setOnClickListener { onGradeTileClickListener() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindLessonsViewHolder(lessonsViewHolder: LessonsViewHolder, position: Int) {
|
||||
val item = getItem(position) as DashboardItem.Lessons
|
||||
val timetableFull = item.lessons
|
||||
val binding = lessonsViewHolder.binding
|
||||
|
||||
fun updateLessonState() {
|
||||
val currentDateTime = LocalDateTime.now()
|
||||
val currentDate = LocalDate.now()
|
||||
|
||||
val currentTimetable = timetableFull?.lessons
|
||||
.orEmpty()
|
||||
.filter { it.date == currentDate }
|
||||
.filter { it.end.isAfter(currentDateTime) }
|
||||
.filterNot { it.canceled }
|
||||
val currentDayHeader =
|
||||
timetableFull?.headers.orEmpty().singleOrNull { it.date == currentDate }
|
||||
|
||||
val tomorrowTimetable = timetableFull?.lessons.orEmpty()
|
||||
.filter { it.date == currentDate.plusDays(1) }
|
||||
.filterNot { it.canceled }
|
||||
val tomorrowDayHeader =
|
||||
timetableFull?.headers.orEmpty().singleOrNull { it.date == currentDate.plusDays(1) }
|
||||
|
||||
when {
|
||||
currentTimetable.isNotEmpty() -> {
|
||||
updateLessonView(item, currentTimetable, binding)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||
}
|
||||
currentDayHeader != null && currentDayHeader.content.isNotBlank() -> {
|
||||
updateLessonView(item, emptyList(), binding, currentDayHeader)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||
}
|
||||
tomorrowTimetable.isNotEmpty() -> {
|
||||
updateLessonView(item, tomorrowTimetable, binding)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
||||
}
|
||||
tomorrowDayHeader != null && tomorrowDayHeader.content.isNotBlank() -> {
|
||||
updateLessonView(item, emptyList(), binding, tomorrowDayHeader)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
||||
}
|
||||
else -> {
|
||||
updateLessonView(item, emptyList(), binding)
|
||||
binding.dashboardLessonsItemTitleTomorrow.isVisible =
|
||||
!(item.isLoading && item.error == null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateLessonState()
|
||||
|
||||
lessonsTimer?.cancel()
|
||||
lessonsTimer = timer(period = 1000) {
|
||||
Handler(Looper.getMainLooper()).post { updateLessonState() }
|
||||
}
|
||||
|
||||
binding.root.setOnClickListener { onLessonsTileClickListener() }
|
||||
}
|
||||
|
||||
private fun updateLessonView(
|
||||
item: DashboardItem.Lessons,
|
||||
timetableToShow: List<Timetable>,
|
||||
binding: ItemDashboardLessonsBinding,
|
||||
header: TimetableHeader? = null,
|
||||
) {
|
||||
val currentDateTime = LocalDateTime.now()
|
||||
val nextLessons = timetableToShow.filter { it.end.isAfter(currentDateTime) }
|
||||
.sortedBy { it.start }
|
||||
|
||||
with(binding) {
|
||||
dashboardLessonsItemEmpty.isVisible =
|
||||
(timetableToShow.isEmpty() || nextLessons.isEmpty()) && item.error == null && header == null && !item.isLoading
|
||||
dashboardLessonsItemError.isVisible = item.error != null && !item.isLoading
|
||||
dashboardLessonsItemProgress.isVisible =
|
||||
item.isLoading && (timetableToShow.isEmpty() || nextLessons.isEmpty()) && item.error == null && header == null
|
||||
|
||||
val secondLesson = nextLessons.getOrNull(1)
|
||||
val firstLesson = nextLessons.getOrNull(0)
|
||||
|
||||
updateFirstLessonView(binding, firstLesson, currentDateTime)
|
||||
updateSecondLesson(binding, firstLesson, secondLesson)
|
||||
updateLessonSummary(binding, nextLessons)
|
||||
updateLessonHeader(binding, header)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateFirstLessonView(
|
||||
binding: ItemDashboardLessonsBinding,
|
||||
firstLesson: Timetable?,
|
||||
currentDateTime: LocalDateTime
|
||||
) {
|
||||
val context = binding.root.context
|
||||
val sansSerifFont = Typeface.create("sans-serif", Typeface.NORMAL)
|
||||
val sansSerifMediumFont = Typeface.create("sans-serif-medium", Typeface.NORMAL)
|
||||
|
||||
with(binding) {
|
||||
dashboardLessonsItemFirstTitle.isVisible = firstLesson != null
|
||||
dashboardLessonsItemFirstTime.isVisible = firstLesson != null
|
||||
dashboardLessonsItemFirstTimeRange.isVisible = firstLesson != null
|
||||
dashboardLessonsItemFirstValue.isVisible = firstLesson != null
|
||||
}
|
||||
|
||||
firstLesson ?: return
|
||||
|
||||
val minutesToStartLesson =
|
||||
Duration.between(currentDateTime, firstLesson.start).toMinutes()
|
||||
val isFirstTimeVisible: Boolean
|
||||
val isFirstTimeRangeVisible: Boolean
|
||||
val firstTimeText: String
|
||||
val firstTimeRangeText: String
|
||||
val firstTitleText: String
|
||||
val firstTitleAndValueTextColor: Int
|
||||
val firstTitleAndValueTextFont: Typeface
|
||||
|
||||
if (currentDateTime.isBefore(firstLesson.start)) {
|
||||
if (minutesToStartLesson > 60) {
|
||||
val formattedStartTime = firstLesson.start.toFormattedString("HH:mm")
|
||||
val formattedEndTime = firstLesson.end.toFormattedString("HH:mm")
|
||||
|
||||
firstTimeRangeText = "${formattedStartTime}-${formattedEndTime}"
|
||||
firstTimeText = ""
|
||||
|
||||
isFirstTimeRangeVisible = true
|
||||
isFirstTimeVisible = false
|
||||
} else {
|
||||
firstTimeText = context.resources.getQuantityString(
|
||||
R.plurals.dashboard_timetable_first_lesson_time_in_minutes,
|
||||
minutesToStartLesson.toInt(),
|
||||
minutesToStartLesson
|
||||
)
|
||||
firstTimeRangeText = ""
|
||||
|
||||
isFirstTimeRangeVisible = false
|
||||
isFirstTimeVisible = true
|
||||
}
|
||||
|
||||
when {
|
||||
minutesToStartLesson < 60 -> {
|
||||
firstTitleAndValueTextColor = context.getThemeAttrColor(R.attr.colorPrimary)
|
||||
firstTitleAndValueTextFont = sansSerifMediumFont
|
||||
firstTitleText =
|
||||
context.getString(R.string.dashboard_timetable_first_lesson_title_moment)
|
||||
}
|
||||
minutesToStartLesson < 240 -> {
|
||||
firstTitleAndValueTextColor =
|
||||
context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||
firstTitleAndValueTextFont = sansSerifFont
|
||||
firstTitleText =
|
||||
context.getString(R.string.dashboard_timetable_first_lesson_title_soon)
|
||||
}
|
||||
else -> {
|
||||
firstTitleAndValueTextColor =
|
||||
context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||
firstTitleAndValueTextFont = sansSerifFont
|
||||
firstTitleText =
|
||||
context.getString(R.string.dashboard_timetable_first_lesson_title_first)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val minutesToEndLesson = firstLesson.left!!.toMinutes()
|
||||
|
||||
firstTimeText = context.resources.getQuantityString(
|
||||
R.plurals.dashboard_timetable_first_lesson_time_more_minutes,
|
||||
minutesToEndLesson.toInt(),
|
||||
minutesToEndLesson
|
||||
)
|
||||
firstTimeRangeText = ""
|
||||
|
||||
isFirstTimeRangeVisible = false
|
||||
isFirstTimeVisible = true
|
||||
|
||||
firstTitleAndValueTextColor = context.getThemeAttrColor(R.attr.colorPrimary)
|
||||
firstTitleAndValueTextFont = sansSerifMediumFont
|
||||
firstTitleText = context.getString(R.string.dashboard_timetable_first_lesson_title_now)
|
||||
}
|
||||
|
||||
with(binding.dashboardLessonsItemFirstTime) {
|
||||
isVisible = isFirstTimeVisible
|
||||
text = firstTimeText
|
||||
}
|
||||
with(binding.dashboardLessonsItemFirstTimeRange) {
|
||||
isVisible = isFirstTimeRangeVisible
|
||||
text = firstTimeRangeText
|
||||
}
|
||||
with(binding.dashboardLessonsItemFirstTitle) {
|
||||
setTextColor(firstTitleAndValueTextColor)
|
||||
typeface = firstTitleAndValueTextFont
|
||||
text = firstTitleText
|
||||
}
|
||||
with(binding.dashboardLessonsItemFirstValue) {
|
||||
setTextColor(firstTitleAndValueTextColor)
|
||||
typeface = firstTitleAndValueTextFont
|
||||
text = context.getString(
|
||||
R.string.dashboard_timetable_lesson_value,
|
||||
firstLesson.subject,
|
||||
firstLesson.room
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSecondLesson(
|
||||
binding: ItemDashboardLessonsBinding,
|
||||
firstLesson: Timetable?,
|
||||
secondLesson: Timetable?
|
||||
) {
|
||||
val context = binding.root.context
|
||||
|
||||
val formattedStartTime = secondLesson?.start?.toFormattedString("HH:mm")
|
||||
val formattedEndTime = secondLesson?.end?.toFormattedString("HH:mm")
|
||||
|
||||
val secondTimeText = "${formattedStartTime}-${formattedEndTime}"
|
||||
val secondValueText = if (secondLesson != null) {
|
||||
context.getString(
|
||||
R.string.dashboard_timetable_lesson_value,
|
||||
secondLesson.subject,
|
||||
secondLesson.room
|
||||
)
|
||||
} else {
|
||||
context.getString(R.string.dashboard_timetable_second_lesson_value_end)
|
||||
}
|
||||
|
||||
with(binding.dashboardLessonsItemSecondTime) {
|
||||
isVisible = secondLesson != null
|
||||
text = secondTimeText
|
||||
}
|
||||
with(binding.dashboardLessonsItemSecondValue) {
|
||||
isVisible = !(secondLesson == null && firstLesson == null)
|
||||
text = secondValueText
|
||||
}
|
||||
binding.dashboardLessonsItemSecondTitle.isVisible =
|
||||
!(secondLesson == null && firstLesson == null)
|
||||
}
|
||||
|
||||
private fun updateLessonSummary(
|
||||
binding: ItemDashboardLessonsBinding,
|
||||
nextLessons: List<Timetable>
|
||||
) {
|
||||
val context = binding.root.context
|
||||
val formattedEndTime = nextLessons.lastOrNull()?.end?.toFormattedString("HH:mm")
|
||||
|
||||
with(binding) {
|
||||
dashboardLessonsItemThirdTime.isVisible =
|
||||
nextLessons.size > LESSON_SUMMARY_VISIBILITY_THRESHOLD
|
||||
dashboardLessonsItemThirdTitle.isVisible =
|
||||
nextLessons.size > LESSON_SUMMARY_VISIBILITY_THRESHOLD
|
||||
dashboardLessonsItemThirdValue.isVisible =
|
||||
nextLessons.size > LESSON_SUMMARY_VISIBILITY_THRESHOLD
|
||||
dashboardLessonsItemDivider.isVisible =
|
||||
nextLessons.size > LESSON_SUMMARY_VISIBILITY_THRESHOLD
|
||||
|
||||
dashboardLessonsItemThirdValue.text = context.resources.getQuantityString(
|
||||
R.plurals.dashboard_timetable_third_value,
|
||||
nextLessons.size - LESSON_SUMMARY_VISIBILITY_THRESHOLD,
|
||||
nextLessons.size - LESSON_SUMMARY_VISIBILITY_THRESHOLD
|
||||
)
|
||||
dashboardLessonsItemThirdTime.text =
|
||||
context.getString(R.string.dashboard_timetable_third_time, formattedEndTime)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateLessonHeader(
|
||||
binding: ItemDashboardLessonsBinding,
|
||||
header: TimetableHeader?
|
||||
) {
|
||||
with(binding.dashboardLessonsItemDayHeader) {
|
||||
isVisible = header != null
|
||||
text = header?.content
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindHomeworkViewHolder(homeworkViewHolder: HomeworkViewHolder, position: Int) {
|
||||
val item = getItem(position) as DashboardItem.Homework
|
||||
val homeworkList = item.homework.orEmpty()
|
||||
val error = item.error
|
||||
val isLoading = item.isLoading
|
||||
val context = homeworkViewHolder.binding.root.context
|
||||
val homeworkAdapter = homeworkViewHolder.adapter.apply {
|
||||
this.items = homeworkList.take(MAX_VISIBLE_LIST_ITEMS)
|
||||
}
|
||||
|
||||
with(homeworkViewHolder.binding) {
|
||||
dashboardHomeworkItemEmpty.isVisible =
|
||||
homeworkList.isEmpty() && error == null && !isLoading
|
||||
dashboardHomeworkItemError.isVisible = error != null && !isLoading
|
||||
dashboardHomeworkItemProgress.isVisible =
|
||||
isLoading && error == null && homeworkList.isEmpty()
|
||||
dashboardHomeworkItemDivider.isVisible = homeworkList.size > MAX_VISIBLE_LIST_ITEMS
|
||||
dashboardHomeworkItemMore.isVisible = homeworkList.size > MAX_VISIBLE_LIST_ITEMS
|
||||
dashboardHomeworkItemMore.text = context.resources.getQuantityString(
|
||||
R.plurals.dashboard_homework_more,
|
||||
homeworkList.size - MAX_VISIBLE_LIST_ITEMS,
|
||||
homeworkList.size - MAX_VISIBLE_LIST_ITEMS
|
||||
)
|
||||
|
||||
with(dashboardHomeworkItemRecycler) {
|
||||
adapter = homeworkAdapter
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
isVisible = homeworkList.isNotEmpty() && error == null
|
||||
suppressLayout(true)
|
||||
}
|
||||
|
||||
root.setOnClickListener { onHomeworkTileClickListener() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindAnnouncementsViewHolder(
|
||||
announcementsViewHolder: AnnouncementsViewHolder,
|
||||
position: Int
|
||||
) {
|
||||
val item = getItem(position) as DashboardItem.Announcements
|
||||
val schoolAnnouncementList = item.announcement.orEmpty()
|
||||
val error = item.error
|
||||
val isLoading = item.isLoading
|
||||
val context = announcementsViewHolder.binding.root.context
|
||||
val schoolAnnouncementsAdapter = announcementsViewHolder.adapter.apply {
|
||||
this.items = schoolAnnouncementList.take(MAX_VISIBLE_LIST_ITEMS)
|
||||
}
|
||||
|
||||
with(announcementsViewHolder.binding) {
|
||||
dashboardAnnouncementsItemEmpty.isVisible =
|
||||
schoolAnnouncementList.isEmpty() && error == null && !isLoading
|
||||
dashboardAnnouncementsItemError.isVisible = error != null && !isLoading
|
||||
dashboardAnnouncementsItemProgress.isVisible =
|
||||
isLoading && error == null && schoolAnnouncementList.isEmpty()
|
||||
dashboardAnnouncementsItemDivider.isVisible =
|
||||
schoolAnnouncementList.size > MAX_VISIBLE_LIST_ITEMS
|
||||
dashboardAnnouncementsItemMore.isVisible =
|
||||
schoolAnnouncementList.size > MAX_VISIBLE_LIST_ITEMS
|
||||
dashboardAnnouncementsItemMore.text = context.resources.getQuantityString(
|
||||
R.plurals.dashboard_announcements_more,
|
||||
schoolAnnouncementList.size - MAX_VISIBLE_LIST_ITEMS,
|
||||
schoolAnnouncementList.size - MAX_VISIBLE_LIST_ITEMS
|
||||
)
|
||||
|
||||
with(dashboardAnnouncementsItemRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = schoolAnnouncementsAdapter
|
||||
isVisible = schoolAnnouncementList.isNotEmpty() && error == null
|
||||
suppressLayout(true)
|
||||
}
|
||||
|
||||
root.setOnClickListener { onAnnouncementsTileClickListener() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindExamsViewHolder(examsViewHolder: ExamsViewHolder, position: Int) {
|
||||
val item = getItem(position) as DashboardItem.Exams
|
||||
val exams = item.exams.orEmpty()
|
||||
val error = item.error
|
||||
val isLoading = item.isLoading
|
||||
val context = examsViewHolder.binding.root.context
|
||||
val examAdapter = examsViewHolder.adapter.apply {
|
||||
this.items = exams.take(MAX_VISIBLE_LIST_ITEMS)
|
||||
}
|
||||
|
||||
with(examsViewHolder.binding) {
|
||||
dashboardExamsItemEmpty.isVisible = exams.isEmpty() && error == null && !isLoading
|
||||
dashboardExamsItemError.isVisible = error != null && !isLoading
|
||||
dashboardExamsItemProgress.isVisible = isLoading && error == null && exams.isEmpty()
|
||||
dashboardExamsItemDivider.isVisible = exams.size > MAX_VISIBLE_LIST_ITEMS
|
||||
dashboardExamsItemMore.isVisible = exams.size > MAX_VISIBLE_LIST_ITEMS
|
||||
dashboardExamsItemMore.text = context.resources.getQuantityString(
|
||||
R.plurals.dashboard_exams_more,
|
||||
exams.size - MAX_VISIBLE_LIST_ITEMS,
|
||||
exams.size - MAX_VISIBLE_LIST_ITEMS
|
||||
)
|
||||
|
||||
with(dashboardExamsItemRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = examAdapter
|
||||
isVisible = exams.isNotEmpty() && error == null
|
||||
suppressLayout(true)
|
||||
}
|
||||
|
||||
root.setOnClickListener { onExamsTileClickListener() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindConferencesViewHolder(
|
||||
conferencesViewHolder: ConferencesViewHolder,
|
||||
position: Int
|
||||
) {
|
||||
val item = getItem(position) as DashboardItem.Conferences
|
||||
val conferences = item.conferences.orEmpty()
|
||||
val error = item.error
|
||||
val isLoading = item.isLoading
|
||||
val context = conferencesViewHolder.binding.root.context
|
||||
val conferenceAdapter = conferencesViewHolder.adapter.apply {
|
||||
this.items = conferences.take(MAX_VISIBLE_LIST_ITEMS)
|
||||
}
|
||||
|
||||
with(conferencesViewHolder.binding) {
|
||||
dashboardConferencesItemEmpty.isVisible =
|
||||
conferences.isEmpty() && error == null && !isLoading
|
||||
dashboardConferencesItemError.isVisible = error != null && !isLoading
|
||||
dashboardConferencesItemProgress.isVisible =
|
||||
isLoading && error == null && conferences.isEmpty()
|
||||
dashboardConferencesItemDivider.isVisible = conferences.size > MAX_VISIBLE_LIST_ITEMS
|
||||
dashboardConferencesItemMore.isVisible = conferences.size > MAX_VISIBLE_LIST_ITEMS
|
||||
dashboardConferencesItemMore.text = context.resources.getQuantityString(
|
||||
R.plurals.dashboard_conference_more,
|
||||
conferences.size - MAX_VISIBLE_LIST_ITEMS,
|
||||
conferences.size - MAX_VISIBLE_LIST_ITEMS
|
||||
)
|
||||
|
||||
with(dashboardConferencesItemRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = conferenceAdapter
|
||||
isVisible = conferences.isNotEmpty() && error == null
|
||||
suppressLayout(true)
|
||||
}
|
||||
|
||||
root.setOnClickListener { onConferencesTileClickListener() }
|
||||
}
|
||||
}
|
||||
|
||||
class AccountViewHolder(val binding: ItemDashboardAccountBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
class HorizontalGroupViewHolder(val binding: ItemDashboardHorizontalGroupBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
class GradesViewHolder(val binding: ItemDashboardGradesBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
val adapter by lazy { DashboardGradesAdapter() }
|
||||
}
|
||||
|
||||
class LessonsViewHolder(val binding: ItemDashboardLessonsBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
class HomeworkViewHolder(val binding: ItemDashboardHomeworkBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
val adapter by lazy { DashboardHomeworkAdapter() }
|
||||
}
|
||||
|
||||
class AnnouncementsViewHolder(val binding: ItemDashboardAnnouncementsBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
val adapter by lazy { DashboardAnnouncementsAdapter() }
|
||||
}
|
||||
|
||||
class ExamsViewHolder(val binding: ItemDashboardExamsBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
val adapter by lazy { DashboardExamsAdapter() }
|
||||
}
|
||||
|
||||
class ConferencesViewHolder(val binding: ItemDashboardConferencesBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
val adapter by lazy { DashboardConferencesAdapter() }
|
||||
}
|
||||
|
||||
class DashboardAdapterDiffCallback : DiffUtil.ItemCallback<DashboardItem>() {
|
||||
|
||||
override fun areItemsTheSame(oldItem: DashboardItem, newItem: DashboardItem) =
|
||||
oldItem.type == newItem.type
|
||||
|
||||
override fun areContentsTheSame(oldItem: DashboardItem, newItem: DashboardItem) =
|
||||
oldItem == newItem
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
private const val LESSON_SUMMARY_VISIBILITY_THRESHOLD = 2
|
||||
|
||||
private const val MAX_VISIBLE_LIST_ITEMS = 5
|
||||
|
||||
private const val ATTENDANCE_FIRST_WARNING_THRESHOLD = 75.0
|
||||
|
||||
private const val ATTENDANCE_SECOND_WARNING_THRESHOLD = 50.0
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||
import io.github.wulkanowy.databinding.SubitemDashboardAnnouncementsBinding
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
|
||||
class DashboardAnnouncementsAdapter :
|
||||
RecyclerView.Adapter<DashboardAnnouncementsAdapter.ViewHolder>() {
|
||||
|
||||
var items = emptyList<SchoolAnnouncement>()
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
SubitemDashboardAnnouncementsBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
|
||||
with(holder.binding) {
|
||||
dashboardHomeworkSubitemTime.text = item.date.toFormattedString()
|
||||
dashboardHomeworkSubitemTitle.text = item.subject
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(val binding: SubitemDashboardAnnouncementsBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.data.db.entities.Conference
|
||||
import io.github.wulkanowy.databinding.SubitemDashboardConferencesBinding
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
|
||||
class DashboardConferencesAdapter :
|
||||
RecyclerView.Adapter<DashboardConferencesAdapter.ViewHolder>() {
|
||||
|
||||
var items = emptyList<Conference>()
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
SubitemDashboardConferencesBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
|
||||
with(holder.binding) {
|
||||
dashboardHomeworkSubitemTime.text = item.date.toFormattedString("HH:mm dd.MM.yyyy")
|
||||
dashboardHomeworkSubitemTitle.text = item.title
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(val binding: SubitemDashboardConferencesBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.databinding.SubitemDashboardExamsBinding
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.LocalDate
|
||||
|
||||
class DashboardExamsAdapter :
|
||||
RecyclerView.Adapter<DashboardExamsAdapter.ViewHolder>() {
|
||||
|
||||
var items = emptyList<Exam>()
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
SubitemDashboardExamsBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
val context = holder.binding.root.context
|
||||
val primaryWarningTextColor = context.getThemeAttrColor(
|
||||
if (item.date == LocalDate.now()) {
|
||||
R.attr.colorPrimary
|
||||
} else {
|
||||
android.R.attr.textColorPrimary
|
||||
}
|
||||
)
|
||||
val secondaryWarningTextColor = context.getThemeAttrColor(
|
||||
if (item.date == LocalDate.now()) {
|
||||
R.attr.colorPrimary
|
||||
} else {
|
||||
android.R.attr.textColorSecondary
|
||||
}
|
||||
)
|
||||
|
||||
with(holder.binding) {
|
||||
dashboardHomeworkSubitemTime.text = item.date.toFormattedString("dd.MM")
|
||||
dashboardHomeworkSubitemTime.setTextColor(secondaryWarningTextColor)
|
||||
|
||||
dashboardHomeworkSubitemTitle.text = "${item.type} - ${item.subject}"
|
||||
dashboardHomeworkSubitemTitle.setTextColor(primaryWarningTextColor)
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(val binding: SubitemDashboardExamsBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.FragmentDashboardBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.account.AccountFragment
|
||||
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||
import io.github.wulkanowy.utils.capitalise
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragment_dashboard),
|
||||
DashboardView, MainView.TitledView, MainView.MainChildView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: DashboardPresenter
|
||||
|
||||
@Inject
|
||||
lateinit var dashboardAdapter: DashboardAdapter
|
||||
|
||||
override val titleStringId get() = R.string.dashboard_title
|
||||
|
||||
override var subtitleString =
|
||||
LocalDate.now().toFormattedString("EEEE, d MMMM yyyy").capitalise()
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance() = DashboardFragment()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentDashboardBinding.bind(view)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.action_menu_dashboard, menu)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
val mainActivity = requireActivity() as MainActivity
|
||||
|
||||
dashboardAdapter.apply {
|
||||
onAccountTileClickListener = { mainActivity.pushView(AccountFragment.newInstance()) }
|
||||
onLuckyNumberTileClickListener = {
|
||||
mainActivity.pushView(LuckyNumberFragment.newInstance())
|
||||
}
|
||||
onMessageTileClickListener = { mainActivity.pushView(MessageFragment.newInstance()) }
|
||||
onAttendanceTileClickListener = {
|
||||
mainActivity.pushView(AttendanceFragment.newInstance())
|
||||
}
|
||||
onLessonsTileClickListener = { mainActivity.pushView(TimetableFragment.newInstance()) }
|
||||
onGradeTileClickListener = { mainActivity.pushView(GradeFragment.newInstance()) }
|
||||
onHomeworkTileClickListener = { mainActivity.pushView(HomeworkFragment.newInstance()) }
|
||||
onAnnouncementsTileClickListener = {
|
||||
mainActivity.pushView(SchoolAnnouncementFragment.newInstance())
|
||||
}
|
||||
onExamsTileClickListener = { mainActivity.pushView(ExamFragment.newInstance()) }
|
||||
onConferencesTileClickListener = {
|
||||
mainActivity.pushView(ConferenceFragment.newInstance())
|
||||
}
|
||||
}
|
||||
|
||||
with(binding) {
|
||||
dashboardErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||
dashboardErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||
dashboardSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||
dashboardSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||
dashboardSwipe.setProgressBackgroundColorSchemeColor(
|
||||
requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
|
||||
)
|
||||
|
||||
with(dashboardRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = dashboardAdapter
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.dashboard_menu_tiles -> presenter.onDashboardTileSettingsSelected()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun showDashboardTileSettings(selectedItems: List<DashboardItem.Tile>) {
|
||||
val entries = requireContext().resources.getStringArray(R.array.dashboard_tile_entries)
|
||||
val values = requireContext().resources.getStringArray(R.array.dashboard_tile_values)
|
||||
val selectedItemsState = values.map { value -> selectedItems.any { it.name == value } }
|
||||
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.pref_dashboard_appearance_tiles_title)
|
||||
.setMultiChoiceItems(entries, selectedItemsState.toBooleanArray()) { _, _, _ -> }
|
||||
.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||
val selectedState = (dialog as AlertDialog).listView.checkedItemPositions
|
||||
val selectedValues = values.filterIndexed { index, _ -> selectedState[index] }
|
||||
|
||||
presenter.onDashboardTileSettingSelected(selectedValues)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun updateData(data: List<DashboardItem>) {
|
||||
dashboardAdapter.submitList(data.toMutableList())
|
||||
}
|
||||
|
||||
override fun showMessage(text: String) {
|
||||
//Empty function to avoid message flood
|
||||
}
|
||||
|
||||
override fun showRefresh(show: Boolean) {
|
||||
binding.dashboardSwipe.isRefreshing = show
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
binding.dashboardProgress.isVisible = show
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
binding.dashboardRecycler.isVisible = show
|
||||
}
|
||||
|
||||
override fun showErrorView(show: Boolean) {
|
||||
binding.dashboardErrorContainer.isVisible = show
|
||||
}
|
||||
|
||||
override fun setErrorDetails(message: String) {
|
||||
binding.dashboardErrorMessage.text = message
|
||||
}
|
||||
|
||||
override fun resetView() {
|
||||
binding.dashboardRecycler.smoothScrollToPosition(0)
|
||||
}
|
||||
|
||||
override fun popViewToRoot() {
|
||||
(requireActivity() as MainActivity).popView(20)
|
||||
}
|
||||
|
||||
override fun onFragmentReselected() {
|
||||
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
dashboardAdapter.clearTimers()
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.databinding.SubitemDashboardGradesBinding
|
||||
import io.github.wulkanowy.databinding.SubitemDashboardSmallGradeBinding
|
||||
import io.github.wulkanowy.utils.getBackgroundColor
|
||||
|
||||
class DashboardGradesAdapter : RecyclerView.Adapter<DashboardGradesAdapter.ViewHolder>() {
|
||||
|
||||
var items = listOf<Pair<String, List<Grade>>>()
|
||||
|
||||
var gradeTheme = ""
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
SubitemDashboardGradesBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val (subject, grades) = items[position]
|
||||
val context = holder.binding.root.context
|
||||
|
||||
with(holder.binding) {
|
||||
dashboardGradesSubitemTitle.text = subject
|
||||
|
||||
grades.forEach {
|
||||
val subitemBinding = SubitemDashboardSmallGradeBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
dashboardGradesSubitemGradeContainer,
|
||||
false
|
||||
)
|
||||
|
||||
with(subitemBinding.dashboardSmallGradeSubitemValue) {
|
||||
text = it.entry
|
||||
setBackgroundResource(it.getBackgroundColor(gradeTheme))
|
||||
}
|
||||
|
||||
dashboardGradesSubitemGradeContainer.addView(subitemBinding.root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(val binding: SubitemDashboardGradesBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.databinding.SubitemDashboardHomeworkBinding
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import java.time.LocalDate
|
||||
|
||||
class DashboardHomeworkAdapter : RecyclerView.Adapter<DashboardHomeworkAdapter.ViewHolder>() {
|
||||
|
||||
var items = emptyList<Homework>()
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
SubitemDashboardHomeworkBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
val context = holder.binding.root.context
|
||||
val formattedDate = item.date.toFormattedString("dd.MM")
|
||||
val primaryWarningTextColor = context.getThemeAttrColor(
|
||||
if (item.date == LocalDate.now()) {
|
||||
R.attr.colorPrimary
|
||||
} else {
|
||||
android.R.attr.textColorPrimary
|
||||
}
|
||||
)
|
||||
val secondaryWarningTextColor = context.getThemeAttrColor(
|
||||
if (item.date == LocalDate.now()) {
|
||||
R.attr.colorPrimary
|
||||
} else {
|
||||
android.R.attr.textColorSecondary
|
||||
}
|
||||
)
|
||||
|
||||
with(holder.binding) {
|
||||
dashboardHomeworkSubitemTitle.text = "${item.subject} - ${item.content}"
|
||||
dashboardHomeworkSubitemTitle.setTextColor(primaryWarningTextColor)
|
||||
|
||||
dashboardHomeworkSubitemTime.text =
|
||||
context.getString(R.string.dashboard_homework_time, formattedDate)
|
||||
dashboardHomeworkSubitemTime.setTextColor(secondaryWarningTextColor)
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(val binding: SubitemDashboardHomeworkBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Conference
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||
import io.github.wulkanowy.data.db.entities.Homework as EntitiesHomework
|
||||
|
||||
sealed class DashboardItem(val type: Type) {
|
||||
|
||||
abstract val error: Throwable?
|
||||
|
||||
abstract val isLoading: Boolean
|
||||
|
||||
abstract val isDataLoaded: Boolean
|
||||
|
||||
data class Account(
|
||||
val student: Student? = null,
|
||||
override val error: Throwable? = null,
|
||||
override val isLoading: Boolean = false
|
||||
) : DashboardItem(Type.ACCOUNT) {
|
||||
|
||||
override val isDataLoaded get() = student != null
|
||||
}
|
||||
|
||||
data class HorizontalGroup(
|
||||
val unreadMessagesCount: Int? = null,
|
||||
val attendancePercentage: Double? = null,
|
||||
val luckyNumber: Int? = null,
|
||||
override val error: Throwable? = null,
|
||||
override val isLoading: Boolean = false
|
||||
) : DashboardItem(Type.HORIZONTAL_GROUP) {
|
||||
|
||||
override val isDataLoaded
|
||||
get() = unreadMessagesCount != null || attendancePercentage != null || luckyNumber != null
|
||||
}
|
||||
|
||||
data class Grades(
|
||||
val subjectWithGrades: Map<String, List<Grade>>? = null,
|
||||
val gradeTheme: String? = null,
|
||||
override val error: Throwable? = null,
|
||||
override val isLoading: Boolean = false
|
||||
) : DashboardItem(Type.GRADES) {
|
||||
|
||||
override val isDataLoaded get() = subjectWithGrades != null
|
||||
}
|
||||
|
||||
data class Lessons(
|
||||
val lessons: TimetableFull? = null,
|
||||
override val error: Throwable? = null,
|
||||
override val isLoading: Boolean = false
|
||||
) : DashboardItem(Type.LESSONS) {
|
||||
|
||||
override val isDataLoaded get() = lessons != null
|
||||
}
|
||||
|
||||
data class Homework(
|
||||
val homework: List<EntitiesHomework>? = null,
|
||||
override val error: Throwable? = null,
|
||||
override val isLoading: Boolean = false
|
||||
) : DashboardItem(Type.HOMEWORK) {
|
||||
|
||||
override val isDataLoaded get() = homework != null
|
||||
}
|
||||
|
||||
data class Announcements(
|
||||
val announcement: List<SchoolAnnouncement>? = null,
|
||||
override val error: Throwable? = null,
|
||||
override val isLoading: Boolean = false
|
||||
) : DashboardItem(Type.ANNOUNCEMENTS) {
|
||||
|
||||
override val isDataLoaded get() = announcement != null
|
||||
}
|
||||
|
||||
data class Exams(
|
||||
val exams: List<Exam>? = null,
|
||||
override val error: Throwable? = null,
|
||||
override val isLoading: Boolean = false
|
||||
) : DashboardItem(Type.EXAMS) {
|
||||
|
||||
override val isDataLoaded get() = exams != null
|
||||
}
|
||||
|
||||
data class Conferences(
|
||||
val conferences: List<Conference>? = null,
|
||||
override val error: Throwable? = null,
|
||||
override val isLoading: Boolean = false
|
||||
) : DashboardItem(Type.CONFERENCES) {
|
||||
|
||||
override val isDataLoaded get() = conferences != null
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
ACCOUNT,
|
||||
HORIZONTAL_GROUP,
|
||||
LESSONS,
|
||||
GRADES,
|
||||
HOMEWORK,
|
||||
ANNOUNCEMENTS,
|
||||
EXAMS,
|
||||
CONFERENCES,
|
||||
ADS
|
||||
}
|
||||
|
||||
enum class Tile {
|
||||
ACCOUNT,
|
||||
LUCKY_NUMBER,
|
||||
MESSAGES,
|
||||
ATTENDANCE,
|
||||
LESSONS,
|
||||
GRADES,
|
||||
HOMEWORK,
|
||||
ANNOUNCEMENTS,
|
||||
EXAMS,
|
||||
CONFERENCES,
|
||||
ADS
|
||||
}
|
||||
}
|
||||
|
||||
fun DashboardItem.Tile.toDashboardItemType() = when (this) {
|
||||
DashboardItem.Tile.ACCOUNT -> DashboardItem.Type.ACCOUNT
|
||||
DashboardItem.Tile.LUCKY_NUMBER -> DashboardItem.Type.HORIZONTAL_GROUP
|
||||
DashboardItem.Tile.MESSAGES -> DashboardItem.Type.HORIZONTAL_GROUP
|
||||
DashboardItem.Tile.ATTENDANCE -> DashboardItem.Type.HORIZONTAL_GROUP
|
||||
DashboardItem.Tile.LESSONS -> DashboardItem.Type.LESSONS
|
||||
DashboardItem.Tile.GRADES -> DashboardItem.Type.GRADES
|
||||
DashboardItem.Tile.HOMEWORK -> DashboardItem.Type.HOMEWORK
|
||||
DashboardItem.Tile.ANNOUNCEMENTS -> DashboardItem.Type.ANNOUNCEMENTS
|
||||
DashboardItem.Tile.EXAMS -> DashboardItem.Type.EXAMS
|
||||
DashboardItem.Tile.CONFERENCES -> DashboardItem.Type.CONFERENCES
|
||||
DashboardItem.Tile.ADS -> DashboardItem.Type.ADS
|
||||
}
|
@ -0,0 +1,684 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.enums.MessageFolder
|
||||
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
|
||||
import io.github.wulkanowy.data.repositories.ConferenceRepository
|
||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.calculatePercentage
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import javax.inject.Inject
|
||||
|
||||
class DashboardPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val luckyNumberRepository: LuckyNumberRepository,
|
||||
private val gradeRepository: GradeRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val attendanceSummaryRepository: AttendanceSummaryRepository,
|
||||
private val timetableRepository: TimetableRepository,
|
||||
private val homeworkRepository: HomeworkRepository,
|
||||
private val examRepository: ExamRepository,
|
||||
private val conferenceRepository: ConferenceRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val schoolAnnouncementRepository: SchoolAnnouncementRepository
|
||||
) : BasePresenter<DashboardView>(errorHandler, studentRepository) {
|
||||
|
||||
private val dashboardItemLoadedList = mutableListOf<DashboardItem>()
|
||||
|
||||
private val dashboardItemRefreshLoadedList = mutableListOf<DashboardItem>()
|
||||
|
||||
private lateinit var dashboardItemsToLoad: Set<DashboardItem.Type>
|
||||
|
||||
private var dashboardTilesToLoad: Set<DashboardItem.Tile> = emptySet()
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
||||
override fun onAttachView(view: DashboardView) {
|
||||
super.onAttachView(view)
|
||||
|
||||
with(view) {
|
||||
initView()
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
|
||||
preferencesRepository.selectedDashboardTilesFlow
|
||||
.onEach { loadData(tilesToLoad = it) }
|
||||
.launch("dashboard_pref")
|
||||
}
|
||||
|
||||
fun loadData(forceRefresh: Boolean = false, tilesToLoad: Set<DashboardItem.Tile>) {
|
||||
val oldDashboardDataToLoad = dashboardTilesToLoad
|
||||
|
||||
dashboardTilesToLoad = tilesToLoad
|
||||
dashboardItemsToLoad = dashboardTilesToLoad.map { it.toDashboardItemType() }.toSet()
|
||||
|
||||
removeUnselectedTiles()
|
||||
|
||||
val newTileList = generateTileListToLoad(oldDashboardDataToLoad, forceRefresh)
|
||||
loadTiles(forceRefresh, newTileList)
|
||||
}
|
||||
|
||||
private fun removeUnselectedTiles() {
|
||||
val isLuckyNumberToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.LUCKY_NUMBER }
|
||||
val isMessagesToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.MESSAGES }
|
||||
val isAttendanceToLoad =
|
||||
dashboardTilesToLoad.any { it == DashboardItem.Tile.ATTENDANCE }
|
||||
|
||||
dashboardItemLoadedList.removeAll { loadedTile -> dashboardItemsToLoad.none { it == loadedTile.type } }
|
||||
|
||||
val horizontalGroup =
|
||||
dashboardItemLoadedList.find { it is DashboardItem.HorizontalGroup } as DashboardItem.HorizontalGroup?
|
||||
|
||||
if (horizontalGroup != null) {
|
||||
val horizontalIndex = dashboardItemLoadedList.indexOf(horizontalGroup)
|
||||
dashboardItemLoadedList.remove(horizontalGroup)
|
||||
|
||||
var updatedHorizontalGroup = horizontalGroup
|
||||
|
||||
if (horizontalGroup.luckyNumber != null && !isLuckyNumberToLoad) {
|
||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(luckyNumber = null)
|
||||
}
|
||||
|
||||
if (horizontalGroup.attendancePercentage != null && !isAttendanceToLoad) {
|
||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(attendancePercentage = null)
|
||||
}
|
||||
|
||||
if (horizontalGroup.unreadMessagesCount != null && !isMessagesToLoad) {
|
||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(unreadMessagesCount = null)
|
||||
}
|
||||
|
||||
if (horizontalGroup.error != null) {
|
||||
updatedHorizontalGroup = updatedHorizontalGroup.copy(error = null, isLoading = true)
|
||||
}
|
||||
|
||||
dashboardItemLoadedList.add(horizontalIndex, updatedHorizontalGroup)
|
||||
}
|
||||
|
||||
view?.updateData(dashboardItemLoadedList)
|
||||
}
|
||||
|
||||
private fun loadTiles(forceRefresh: Boolean, tileList: List<DashboardItem.Tile>) {
|
||||
tileList.forEach {
|
||||
when (it) {
|
||||
DashboardItem.Tile.ACCOUNT -> loadCurrentAccount(forceRefresh)
|
||||
DashboardItem.Tile.LUCKY_NUMBER -> loadLuckyNumber(forceRefresh)
|
||||
DashboardItem.Tile.MESSAGES -> loadMessages(forceRefresh)
|
||||
DashboardItem.Tile.ATTENDANCE -> loadAttendance(forceRefresh)
|
||||
DashboardItem.Tile.LESSONS -> loadLessons(forceRefresh)
|
||||
DashboardItem.Tile.GRADES -> loadGrades(forceRefresh)
|
||||
DashboardItem.Tile.HOMEWORK -> loadHomework(forceRefresh)
|
||||
DashboardItem.Tile.ANNOUNCEMENTS -> loadSchoolAnnouncements(forceRefresh)
|
||||
DashboardItem.Tile.EXAMS -> loadExams(forceRefresh)
|
||||
DashboardItem.Tile.CONFERENCES -> loadConferences(forceRefresh)
|
||||
DashboardItem.Tile.ADS -> TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateTileListToLoad(
|
||||
oldDashboardTileToLoad: Set<DashboardItem.Tile>,
|
||||
forceRefresh: Boolean
|
||||
) = dashboardTilesToLoad.filter { newTileToLoad ->
|
||||
oldDashboardTileToLoad.none { it == newTileToLoad } || forceRefresh
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
Timber.i("Force refreshing the dashboard")
|
||||
loadData(true, preferencesRepository.selectedDashboardTiles)
|
||||
}
|
||||
|
||||
fun onRetry() {
|
||||
view?.run {
|
||||
showErrorView(false)
|
||||
showProgress(true)
|
||||
}
|
||||
loadData(true, preferencesRepository.selectedDashboardTiles)
|
||||
}
|
||||
|
||||
fun onViewReselected() {
|
||||
Timber.i("Dashboard view is reselected")
|
||||
view?.run {
|
||||
resetView()
|
||||
popViewToRoot()
|
||||
}
|
||||
}
|
||||
|
||||
fun onDetailsClick() {
|
||||
view?.showErrorDetailsDialog(lastError)
|
||||
}
|
||||
|
||||
fun onDashboardTileSettingsSelected(): Boolean {
|
||||
view?.showDashboardTileSettings(preferencesRepository.selectedDashboardTiles.toList())
|
||||
return true
|
||||
}
|
||||
|
||||
fun onDashboardTileSettingSelected(selectedItems: List<String>) {
|
||||
preferencesRepository.selectedDashboardTiles = selectedItems.map {
|
||||
DashboardItem.Tile.valueOf(it)
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
private fun loadCurrentAccount(forceRefresh: Boolean) {
|
||||
flowWithResource { studentRepository.getCurrentStudent(false) }
|
||||
.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard account data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(DashboardItem.Account(it.data, isLoading = true), forceRefresh)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard account result: Success")
|
||||
updateData(DashboardItem.Account(it.data), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard account result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Account(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}
|
||||
.launch("dashboard_account")
|
||||
}
|
||||
|
||||
private fun loadLuckyNumber(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
|
||||
luckyNumberRepository.getLuckyNumber(student, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard lucky number data started")
|
||||
if (forceRefresh) return@onEach
|
||||
processHorizontalGroupData(
|
||||
luckyNumber = it.data?.luckyNumber,
|
||||
isLoading = true,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard lucky number result: Success")
|
||||
processHorizontalGroupData(
|
||||
luckyNumber = it.data?.luckyNumber ?: -1,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard lucky number result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
processHorizontalGroupData(error = it.error, forceRefresh = forceRefresh)
|
||||
}
|
||||
}
|
||||
}.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)
|
||||
|
||||
gradeRepository.getGrades(student, semester, forceRefresh)
|
||||
}.map { originalResource ->
|
||||
val filteredSubjectWithGrades = originalResource.data?.first.orEmpty()
|
||||
.filter { grade ->
|
||||
grade.date.isAfter(LocalDate.now().minusDays(7))
|
||||
}
|
||||
.groupBy { grade -> grade.subject }
|
||||
.mapValues { entry ->
|
||||
entry.value
|
||||
.take(5)
|
||||
.sortedBy { grade -> grade.date }
|
||||
}
|
||||
.toList()
|
||||
.sortedBy { subjectWithGrades -> subjectWithGrades.second[0].date }
|
||||
.toMap()
|
||||
|
||||
Resource(
|
||||
status = originalResource.status,
|
||||
data = filteredSubjectWithGrades.takeIf { originalResource.data != null },
|
||||
error = originalResource.error
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard grades data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Grades(
|
||||
subjectWithGrades = it.data,
|
||||
gradeTheme = preferencesRepository.gradeColorTheme,
|
||||
isLoading = true
|
||||
), forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard grades result: Success")
|
||||
updateData(
|
||||
DashboardItem.Grades(
|
||||
subjectWithGrades = it.data,
|
||||
gradeTheme = preferencesRepository.gradeColorTheme
|
||||
), forceRefresh
|
||||
)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard grades result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Grades(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_grades")
|
||||
}
|
||||
|
||||
private fun loadLessons(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val date = LocalDate.now().nextOrSameSchoolDay
|
||||
|
||||
timetableRepository.getTimetable(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = date,
|
||||
end = date.plusDays(1),
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard lessons data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(DashboardItem.Lessons(it.data, isLoading = true), forceRefresh)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard lessons result: Success")
|
||||
updateData(DashboardItem.Lessons(it.data), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard lessons result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Lessons(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_lessons")
|
||||
}
|
||||
|
||||
private fun loadHomework(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val date = LocalDate.now().nextOrSameSchoolDay
|
||||
|
||||
homeworkRepository.getHomework(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = date,
|
||||
end = date,
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}.map { homeworkResource ->
|
||||
val currentDate = LocalDate.now()
|
||||
|
||||
val filteredHomework = homeworkResource.data?.filter {
|
||||
(it.date.isAfter(currentDate) || it.date == currentDate) && !it.isDone
|
||||
}
|
||||
|
||||
homeworkResource.copy(data = filteredHomework)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard homework data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Homework(it.data ?: emptyList(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard homework result: Success")
|
||||
updateData(DashboardItem.Homework(it.data ?: emptyList()), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard homework result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Homework(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_homework")
|
||||
}
|
||||
|
||||
private fun loadSchoolAnnouncements(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
|
||||
schoolAnnouncementRepository.getSchoolAnnouncements(student, forceRefresh)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard announcements data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Announcements(
|
||||
it.data ?: emptyList(),
|
||||
isLoading = true
|
||||
), forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard announcements result: Success")
|
||||
updateData(DashboardItem.Announcements(it.data ?: emptyList()), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard announcements result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Announcements(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_announcements")
|
||||
}
|
||||
|
||||
private fun loadExams(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
examRepository.getExams(
|
||||
student = student,
|
||||
semester = semester,
|
||||
start = LocalDate.now(),
|
||||
end = LocalDate.now().plusDays(7),
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard exams data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Exams(it.data.orEmpty(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard exams result: Success")
|
||||
updateData(DashboardItem.Exams(it.data ?: emptyList()), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard exams result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Exams(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.launch("dashboard_exams")
|
||||
}
|
||||
|
||||
private fun loadConferences(forceRefresh: Boolean) {
|
||||
flowWithResourceIn {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
|
||||
conferenceRepository.getConferences(
|
||||
student = student,
|
||||
semester = semester,
|
||||
forceRefresh = forceRefresh,
|
||||
startDate = LocalDateTime.now()
|
||||
)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> {
|
||||
Timber.i("Loading dashboard conferences data started")
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(
|
||||
DashboardItem.Conferences(it.data ?: emptyList(), isLoading = true),
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading dashboard conferences result: Success")
|
||||
updateData(DashboardItem.Conferences(it.data ?: emptyList()), forceRefresh)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading dashboard conferences result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
updateData(DashboardItem.Conferences(error = it.error), forceRefresh)
|
||||
}
|
||||
}
|
||||
}.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) {
|
||||
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
||||
|
||||
with(dashboardItemLoadedList) {
|
||||
removeAll { it.type == dashboardItem.type && !isForceRefreshError }
|
||||
if (!isForceRefreshError) add(dashboardItem)
|
||||
sortBy { tile -> dashboardItemsToLoad.single { it == tile.type }.ordinal }
|
||||
}
|
||||
|
||||
if (forceRefresh) {
|
||||
with(dashboardItemRefreshLoadedList) {
|
||||
removeAll { it.type == dashboardItem.type }
|
||||
add(dashboardItem)
|
||||
}
|
||||
}
|
||||
|
||||
dashboardItemLoadedList.sortBy { tile -> dashboardItemsToLoad.single { it == 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard
|
||||
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface DashboardView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<DashboardItem>)
|
||||
|
||||
fun showDashboardTileSettings(selectedItems: List<DashboardItem.Tile>)
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showRefresh(show: Boolean)
|
||||
|
||||
fun showErrorView(show: Boolean)
|
||||
|
||||
fun setErrorDetails(message: String)
|
||||
|
||||
fun resetView()
|
||||
|
||||
fun popViewToRoot()
|
||||
}
|
@ -33,7 +33,7 @@ import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardFragment
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||
@ -218,12 +218,12 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
|
||||
with(binding.mainBottomNav) {
|
||||
with(menu) {
|
||||
add(Menu.NONE, 0, Menu.NONE, R.string.grade_title)
|
||||
add(Menu.NONE, 0, Menu.NONE, R.string.dashboard_title)
|
||||
.setIcon(R.drawable.ic_main_dashboard)
|
||||
add(Menu.NONE, 1, Menu.NONE, R.string.grade_title)
|
||||
.setIcon(R.drawable.ic_main_grade)
|
||||
add(Menu.NONE, 1, Menu.NONE, R.string.attendance_title)
|
||||
add(Menu.NONE, 2, Menu.NONE, R.string.attendance_title)
|
||||
.setIcon(R.drawable.ic_main_attendance)
|
||||
add(Menu.NONE, 2, Menu.NONE, R.string.exam_title)
|
||||
.setIcon(R.drawable.ic_main_exam)
|
||||
add(Menu.NONE, 3, Menu.NONE, R.string.timetable_title)
|
||||
.setIcon(R.drawable.ic_main_timetable)
|
||||
add(Menu.NONE, 4, Menu.NONE, R.string.more_title)
|
||||
@ -256,9 +256,9 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
}
|
||||
fragmentHideStrategy = HIDE
|
||||
rootFragments = listOf(
|
||||
DashboardFragment.newInstance(),
|
||||
GradeFragment.newInstance(),
|
||||
AttendanceFragment.newInstance(),
|
||||
ExamFragment.newInstance(),
|
||||
TimetableFragment.newInstance(),
|
||||
MoreFragment.newInstance()
|
||||
)
|
||||
|
@ -9,15 +9,15 @@ import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.FragmentMoreBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||
import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment
|
||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
|
||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||
import io.github.wulkanowy.utils.getCompatDrawable
|
||||
import javax.inject.Inject
|
||||
@ -48,9 +48,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
||||
override val noteRes: Pair<String, Drawable?>?
|
||||
get() = context?.run { getString(R.string.note_title) to getCompatDrawable(R.drawable.ic_more_note) }
|
||||
|
||||
override val luckyNumberRes: Pair<String, Drawable?>?
|
||||
get() = context?.run { getString(R.string.lucky_number_title) to getCompatDrawable(R.drawable.ic_more_lucky_number) }
|
||||
|
||||
override val conferencesRes: Pair<String, Drawable?>?
|
||||
get() = context?.run { getString(R.string.conferences_title) to getCompatDrawable(R.drawable.ic_more_conferences) }
|
||||
|
||||
@ -66,6 +63,9 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
||||
override val settingsRes: Pair<String, Drawable?>?
|
||||
get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) }
|
||||
|
||||
override val examRes: Pair<String, Drawable?>?
|
||||
get() = context?.run { getString(R.string.exam_title) to getCompatDrawable(R.drawable.ic_main_exam) }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentMoreBinding.bind(view)
|
||||
@ -104,10 +104,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
||||
(activity as? MainActivity)?.pushView(NoteFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun openLuckyNumberView() {
|
||||
(activity as? MainActivity)?.pushView(LuckyNumberFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun openSchoolAnnouncementView() {
|
||||
(activity as? MainActivity)?.pushView(SchoolAnnouncementFragment.newInstance())
|
||||
}
|
||||
@ -128,6 +124,10 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
||||
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun openExamView() {
|
||||
(activity as? MainActivity)?.pushView(ExamFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun popView(depth: Int) {
|
||||
(activity as? MainActivity)?.popView(depth)
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ class MorePresenter @Inject constructor(
|
||||
view?.run {
|
||||
when (title) {
|
||||
messagesRes?.first -> openMessagesView()
|
||||
examRes?.first -> openExamView()
|
||||
homeworkRes?.first -> openHomeworkView()
|
||||
noteRes?.first -> openNoteView()
|
||||
luckyNumberRes?.first -> openLuckyNumberView()
|
||||
conferencesRes?.first -> openConferencesView()
|
||||
schoolAnnouncementRes?.first -> openSchoolAnnouncementView()
|
||||
schoolAndTeachersRes?.first -> openSchoolAndTeachersView()
|
||||
@ -45,9 +45,9 @@ class MorePresenter @Inject constructor(
|
||||
view?.run {
|
||||
updateData(listOfNotNull(
|
||||
messagesRes,
|
||||
examRes,
|
||||
homeworkRes,
|
||||
noteRes,
|
||||
luckyNumberRes,
|
||||
conferencesRes,
|
||||
schoolAnnouncementRes,
|
||||
schoolAndTeachersRes,
|
||||
|
@ -11,8 +11,6 @@ interface MoreView : BaseView {
|
||||
|
||||
val noteRes: Pair<String, Drawable?>?
|
||||
|
||||
val luckyNumberRes: Pair<String, Drawable?>?
|
||||
|
||||
val conferencesRes: Pair<String, Drawable?>?
|
||||
|
||||
val schoolAnnouncementRes: Pair<String, Drawable?>?
|
||||
@ -23,6 +21,8 @@ interface MoreView : BaseView {
|
||||
|
||||
val settingsRes: Pair<String, Drawable?>?
|
||||
|
||||
val examRes: Pair<String, Drawable?>?
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<Pair<String, Drawable?>>)
|
||||
@ -37,8 +37,6 @@ interface MoreView : BaseView {
|
||||
|
||||
fun openNoteView()
|
||||
|
||||
fun openLuckyNumberView()
|
||||
|
||||
fun openSchoolAnnouncementView()
|
||||
|
||||
fun openConferencesView()
|
||||
@ -46,4 +44,6 @@ interface MoreView : BaseView {
|
||||
fun openSchoolAndTeachersView()
|
||||
|
||||
fun openMobileDevicesView()
|
||||
|
||||
fun openExamView()
|
||||
}
|
||||
|
@ -1,48 +1,46 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import java.text.SimpleDateFormat
|
||||
import java.time.DayOfWeek.FRIDAY
|
||||
import java.time.DayOfWeek.MONDAY
|
||||
import java.time.DayOfWeek.SATURDAY
|
||||
import java.time.DayOfWeek.SUNDAY
|
||||
import java.time.Instant.ofEpochMilli
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalDateTime.now
|
||||
import java.time.LocalDateTime.ofInstant
|
||||
import java.time.LocalTime
|
||||
import java.time.Month
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter.ofPattern
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.temporal.TemporalAdjusters.firstInMonth
|
||||
import java.time.temporal.TemporalAdjusters.next
|
||||
import java.time.temporal.TemporalAdjusters.previous
|
||||
import java.util.Locale
|
||||
|
||||
private const val DATE_PATTERN = "dd.MM.yyyy"
|
||||
private const val DEFAULT_DATE_PATTERN = "dd.MM.yyyy"
|
||||
|
||||
fun String.toLocalDate(format: String = DATE_PATTERN): LocalDate =
|
||||
LocalDate.parse(this, ofPattern(format))
|
||||
fun String.toLocalDate(format: String = DEFAULT_DATE_PATTERN): LocalDate =
|
||||
LocalDate.parse(this, DateTimeFormatter.ofPattern(format))
|
||||
|
||||
fun LocalDateTime.toTimestamp() =
|
||||
atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toInstant().toEpochMilli()
|
||||
|
||||
fun Long.toLocalDateTime(): LocalDateTime = ofInstant(ofEpochMilli(this), ZoneId.systemDefault())
|
||||
fun Long.toLocalDateTime(): LocalDateTime =
|
||||
LocalDateTime.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault())
|
||||
|
||||
fun LocalDate.toTimestamp() = atTime(LocalTime.now()).toTimestamp()
|
||||
|
||||
fun LocalDate.toFormattedString(format: String = DATE_PATTERN): String = format(ofPattern(format))
|
||||
fun LocalDate.toFormattedString(pattern: String = DEFAULT_DATE_PATTERN): String =
|
||||
format(DateTimeFormatter.ofPattern(pattern))
|
||||
|
||||
fun LocalDateTime.toFormattedString(format: String = DATE_PATTERN): String =
|
||||
format(ofPattern(format))
|
||||
fun LocalDateTime.toFormattedString(pattern: String = DEFAULT_DATE_PATTERN): String =
|
||||
format(DateTimeFormatter.ofPattern(pattern))
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
fun Month.getFormattedName(): String {
|
||||
val formatter = SimpleDateFormat("LLLL", Locale.getDefault())
|
||||
|
||||
val date = now().withMonth(value)
|
||||
val date = LocalDateTime.now().withMonth(value)
|
||||
return formatter.format(date.toInstant(ZoneOffset.UTC).toEpochMilli()).capitalise()
|
||||
}
|
||||
|
||||
@ -85,7 +83,7 @@ inline val LocalDate.previousOrSameSchoolDay: LocalDate
|
||||
}
|
||||
|
||||
inline val LocalDate.weekDayName: String
|
||||
get() = format(ofPattern("EEEE", Locale.getDefault()))
|
||||
get() = format(DateTimeFormatter.ofPattern("EEEE", Locale.getDefault()))
|
||||
|
||||
inline val LocalDate.monday: LocalDate
|
||||
get() = with(MONDAY)
|
||||
|
9
app/src/main/res/drawable/ic_main_dashboard.xml
Normal file
9
app/src/main/res/drawable/ic_main_dashboard.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,5v2h-4L15,5h4M9,5v6L5,11L5,5h4m10,8v6h-4v-6h4M9,17v2L5,19v-2h4M21,3h-8v6h8L21,3zM11,3L3,3v10h8L11,3zM21,11h-8v10h8L21,11zM11,15L3,15v6h8v-6z" />
|
||||
</vector>
|
82
app/src/main/res/layout/fragment_dashboard.xml
Normal file
82
app/src/main/res/layout/fragment_dashboard.xml
Normal file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/dashboard_swipe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dashboard_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/dashboard_error_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:ignore="UseCompoundDrawables"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
app:srcCompat="@drawable/ic_error"
|
||||
app:tint="?colorOnBackground"
|
||||
tools:ignore="contentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_error_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center"
|
||||
android:padding="8dp"
|
||||
android:text="@string/error_unknown"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/dashboard_error_details"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:text="@string/all_details" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/dashboard_error_retry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/all_retry" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
59
app/src/main/res/layout/item_dashboard_account.xml
Normal file
59
app/src/main/res/layout/item_dashboard_account.xml
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginVertical="6dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/dashboard_account_item_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dashboard_account_item_avatar"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_account_item_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_account_item_avatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="John Smith" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_account_item_school_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_account_item_avatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_account_item_name"
|
||||
tools:text="Szkoła Wulkanowego " />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_account_item_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
120
app/src/main/res/layout/item_dashboard_announcements.xml
Normal file
120
app/src/main/res/layout/item_dashboard_announcements.xml
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginVertical="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?selectableItemBackground"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_announcements_item_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_announcements_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:drawableStartCompat="@drawable/ic_all_about"
|
||||
app:drawableTint="?colorOnSurface"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dashboard_announcements_item_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_announcements_item_title"
|
||||
app:layout_constraintVertical_bias="0"
|
||||
tools:itemCount="2"
|
||||
tools:listitem="@layout/subitem_dashboard_announcements"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dashboard_announcements_item_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?colorDivider"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_announcements_item_recycler" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_announcements_item_more"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
tools:visibility="visible"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_announcements_item_divider"
|
||||
tools:text="Jeszcze 5 ogłoszeń więcej" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_announcements_item_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/dashboard_announcements_no_announcements"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_announcements_item_title"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_announcements_item_error"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_announcements_error"
|
||||
android:textColor="?colorError"
|
||||
android:textSize="14sp"
|
||||
tools:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/ic_error"
|
||||
app:drawableTint="?colorError"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_announcements_item_title" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_announcements_item_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_announcements_item_title" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
118
app/src/main/res/layout/item_dashboard_conferences.xml
Normal file
118
app/src/main/res/layout/item_dashboard_conferences.xml
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginVertical="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?selectableItemBackground"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_conferences_item_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_conferences_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:drawableStartCompat="@drawable/ic_more_conferences"
|
||||
app:drawableTint="?colorOnSurface"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dashboard_conferences_item_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_conferences_item_title"
|
||||
app:layout_constraintVertical_bias="0"
|
||||
tools:itemCount="2"
|
||||
tools:listitem="@layout/subitem_dashboard_exams" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dashboard_conferences_item_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?colorDivider"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_conferences_item_recycler" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_conferences_item_more"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_conferences_item_divider"
|
||||
tools:text="Jeszcze 5 zebrań więcej" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_conferences_item_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/dashboard_conferences_no_conferences"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_conferences_item_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_conferences_item_error"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_conferences_error"
|
||||
android:textColor="?colorError"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:drawableStartCompat="@drawable/ic_error"
|
||||
app:drawableTint="?colorError"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_conferences_item_title" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_conferences_item_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_conferences_item_title" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
118
app/src/main/res/layout/item_dashboard_exams.xml
Normal file
118
app/src/main/res/layout/item_dashboard_exams.xml
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginVertical="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?selectableItemBackground"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_exams_item_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_exams_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:drawableStartCompat="@drawable/ic_main_exam"
|
||||
app:drawableTint="?colorOnSurface"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dashboard_exams_item_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_exams_item_title"
|
||||
app:layout_constraintVertical_bias="0"
|
||||
tools:itemCount="2"
|
||||
tools:listitem="@layout/subitem_dashboard_exams" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dashboard_exams_item_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?colorDivider"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_exams_item_recycler" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_exams_item_more"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_exams_item_divider"
|
||||
tools:text="Jeszcze 5 sprawdzianów więcej" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_exams_item_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/dashboard_exams_no_exams"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_exams_item_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_exams_item_error"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/dashboard_exams_error"
|
||||
android:textColor="?colorError"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/ic_error"
|
||||
app:drawableTint="?colorError"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_exams_item_title" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_exams_item_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_exams_item_title" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
96
app/src/main/res/layout/item_dashboard_grades.xml
Normal file
96
app/src/main/res/layout/item_dashboard_grades.xml
Normal file
@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginVertical="6dp"
|
||||
android:foreground="?selectableItemBackground"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_grades_item_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_grade_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:drawableStartCompat="@drawable/ic_main_grade"
|
||||
app:drawableTint="?colorOnSurface"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dashboard_grades_item_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none"
|
||||
android:nestedScrollingEnabled="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_grades_item_title"
|
||||
tools:itemCount="3"
|
||||
tools:listitem="@layout/subitem_dashboard_grades" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_grades_item_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/dashboard_grade_no_grade"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_grades_item_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_grades_item_error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_grade_error"
|
||||
android:textColor="?colorError"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
android:gravity="center_vertical"
|
||||
app:drawableStartCompat="@drawable/ic_error"
|
||||
app:drawableTint="?colorError"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_grades_item_title" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_grades_item_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_grades_item_title" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
118
app/src/main/res/layout/item_dashboard_homework.xml
Normal file
118
app/src/main/res/layout/item_dashboard_homework.xml
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginVertical="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?selectableItemBackground"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_item_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_homework_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:drawableStartCompat="@drawable/ic_more_homework"
|
||||
app:drawableTint="?colorOnSurface"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dashboard_homework_item_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_homework_item_title"
|
||||
app:layout_constraintVertical_bias="0"
|
||||
tools:itemCount="5"
|
||||
tools:listitem="@layout/subitem_dashboard_homework" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dashboard_homework_item_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="?colorDivider"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_homework_item_recycler" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_item_more"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_homework_item_divider"
|
||||
tools:text="Jeszcze 5 zadań więcej" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_item_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/dashboard_homework_no_homework"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_homework_item_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_item_error"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_homework_error"
|
||||
android:textColor="?colorError"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/ic_error"
|
||||
app:drawableTint="?colorError"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_homework_item_title" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_homework_item_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_homework_item_title" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
218
app/src/main/res/layout/item_dashboard_horizontal_group.xml
Normal file
218
app/src/main/res/layout/item_dashboard_horizontal_group.xml
Normal file
@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginVertical="2dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/dashboard_horizontal_group_item_lucky_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_horizontal_group_item_message_container"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dashboard_horizontal_group_item_lucky_icon"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:src="@drawable/ic_more_lucky_number"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_horizontal_group_item_lucky_value"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?colorOnSurface"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_horizontal_group_item_lucky_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_horizontal_group_item_lucky_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="16" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/dashboard_horizontal_group_item_message_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_horizontal_group_item_attendance_container"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_horizontal_group_item_lucky_container"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_goneMarginStart="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dashboard_horizontal_group_item_message_icon"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:src="@drawable/ic_more_messages"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_horizontal_group_item_message_value"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?colorOnSurface"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_horizontal_group_item_message_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:includeFontPadding="false"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_horizontal_group_item_message_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="16" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/dashboard_horizontal_group_item_attendance_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_horizontal_group_item_message_container"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_percent="0.40">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dashboard_horizontal_group_item_attendance_icon"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:src="@drawable/ic_main_attendance"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_horizontal_group_item_attendance_value"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?colorOnSurface"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_horizontal_group_item_attendance_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:includeFontPadding="false"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_horizontal_group_item_attendance_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="99,00%" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/dashboard_horizontal_group_item_info_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:visibility="gone"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_horizontal_group_item_message_container"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_percent="0.40">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_horizontal_group_item_info_error_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/dashboard_horizontal_group_error"
|
||||
android:textColor="?colorError"
|
||||
android:textSize="14sp"
|
||||
app:drawableStartCompat="@drawable/ic_error"
|
||||
app:drawableTint="?colorError"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_title"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_horizontal_group_item_info_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:indeterminate="true"
|
||||
app:indicatorSize="28dp" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
253
app/src/main/res/layout/item_dashboard_lessons.xml
Normal file
253
app/src/main/res/layout/item_dashboard_lessons.xml
Normal file
@ -0,0 +1,253 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginVertical="6dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?selectableItemBackground"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_timetable_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:drawableStartCompat="@drawable/ic_main_timetable"
|
||||
app:drawableTint="?colorOnSurface"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_title_tomorrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="@string/dashboard_timetable_title_tomorrow"
|
||||
android:textColor="?colorOnSurface"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/dashboard_lessons_item_title"
|
||||
app:layout_constraintBottom_toBottomOf="@id/dashboard_lessons_item_title"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_lessons_item_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_first_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_title"
|
||||
tools:text="Teraz:" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_first_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_lessons_item_first_time_barrier"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_lessons_item_first_title"
|
||||
app:layout_constraintTop_toTopOf="@id/dashboard_lessons_item_first_title"
|
||||
tools:text="Matematyka, Sala 28" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/dashboard_lessons_item_first_time_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="start"
|
||||
app:constraint_referenced_ids="dashboard_lessons_item_first_time, dashboard_lessons_item_first_time_range" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_first_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/background_timetable_time_left"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:paddingBottom="1dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="13sp"
|
||||
app:backgroundTint="?colorPrimary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/dashboard_lessons_item_first_title"
|
||||
tools:text="jeszcze 15 minut" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_first_time_range"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/dashboard_lessons_item_first_title"
|
||||
tools:text="10:45 - 11:45"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_second_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/dashboard_timetable_second_lessons_title"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_first_value" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_second_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_lessons_item_second_time"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_lessons_item_second_title"
|
||||
app:layout_constraintTop_toTopOf="@id/dashboard_lessons_item_second_title"
|
||||
app:layout_constraintVertical_bias="0"
|
||||
tools:text="Matematyka (28)" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_second_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/dashboard_lessons_item_second_title"
|
||||
tools:text="10:45 - 11:45" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dashboard_lessons_item_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?colorDivider"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_second_value" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_third_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/dashboard_timetable_third_title"
|
||||
android:textSize="13sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_divider"
|
||||
tools:text="Poźniej" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_third_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:textSize="13sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_lessons_item_third_time"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_lessons_item_third_title"
|
||||
app:layout_constraintTop_toTopOf="@id/dashboard_lessons_item_third_title"
|
||||
tools:text="jeszcze 5 kolejnych lekcji" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_third_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textSize="13sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/dashboard_lessons_item_third_title"
|
||||
tools:text="do 15:55" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/dashboard_timetable_no_lessons"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_day_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_title"
|
||||
tools:text="@tools:sample/lorem"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_lessons_item_error"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="@string/dashboard_timetable_error"
|
||||
android:textColor="?colorError"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/ic_error"
|
||||
app:drawableTint="?colorError"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_title" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/dashboard_lessons_item_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dashboard_lessons_item_title" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
33
app/src/main/res/layout/subitem_dashboard_announcements.xml
Normal file
33
app/src/main/res/layout/subitem_dashboard_announcements.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_subitem_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_homework_subitem_time"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Dzień wolny od zajęć dydaktycznych" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_subitem_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="02.11.2020" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
32
app/src/main/res/layout/subitem_dashboard_conferences.xml
Normal file
32
app/src/main/res/layout/subitem_dashboard_conferences.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_subitem_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="Spotaknie z rodzicami/opiekunami"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_homework_subitem_time"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_subitem_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="17:00 02.11.2020"
|
||||
android:textSize="13sp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
33
app/src/main/res/layout/subitem_dashboard_exams.xml
Normal file
33
app/src/main/res/layout/subitem_dashboard_exams.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_subitem_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
tools:text="Sprawdzian - Matematyka"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_homework_subitem_time"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_subitem_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
tools:text="02.11"
|
||||
android:textSize="13sp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
30
app/src/main/res/layout/subitem_dashboard_grades.xml
Normal file
30
app/src/main/res/layout/subitem_dashboard_grades.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_grades_subitem_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Urządzenia techniki kompu..." />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/dashboard_grades_subitem_grade_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/dashboard_grades_subitem_title"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="UselessLeaf" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
32
app/src/main/res/layout/subitem_dashboard_homework.xml
Normal file
32
app/src/main/res/layout/subitem_dashboard_homework.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_subitem_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/dashboard_homework_subitem_time"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Język polski - Zadanie z podręcznika str.107-108" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dashboard_homework_subitem_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:textSize="13sp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="do 18.05" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
15
app/src/main/res/layout/subitem_dashboard_small_grade.xml
Normal file
15
app/src/main/res/layout/subitem_dashboard_small_grade.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/dashboard_small_grade_subitem_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:background="@color/grade_material_default"
|
||||
android:gravity="center"
|
||||
android:maxLength="5"
|
||||
android:minWidth="20dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="6" />
|
11
app/src/main/res/menu/action_menu_dashboard.xml
Normal file
11
app/src/main/res/menu/action_menu_dashboard.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/dashboard_menu_tiles"
|
||||
android:icon="@drawable/ic_more_settings"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/pref_dashboard_appearance_tiles_title"
|
||||
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
@ -40,7 +40,7 @@
|
||||
<item>https://vulcan.net.pl/?login</item>
|
||||
<item>https://vulcan.net.pl/?login</item>
|
||||
<item>https://vulcan.net.pl/?login</item>
|
||||
<item>http://fakelog.tk/?email</item>
|
||||
<item>http://fakelog.cf/?email</item>
|
||||
</string-array>
|
||||
<string-array name="hosts_symbols">
|
||||
<item>Default</item>
|
||||
|
@ -25,4 +25,12 @@
|
||||
<bool name="pref_default_homework_fullscreen">false</bool>
|
||||
<bool name="pref_default_subjects_without_grades">false</bool>
|
||||
<bool name="pref_default_optional_arithmetic_average">false</bool>
|
||||
<string-array name="pref_default_dashboard_tiles">
|
||||
<item>LUCKY_NUMBER</item>
|
||||
<item>MESSAGES</item>
|
||||
<item>ATTENDANCE</item>
|
||||
<item>LESSONS</item>
|
||||
<item>GRADES</item>
|
||||
<item>ANNOUNCEMENTS</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
@ -3,6 +3,7 @@
|
||||
<string name="pref_key_start_menu">start_menu</string>
|
||||
<string name="pref_key_attendance_present">attendance_present</string>
|
||||
<string name="pref_key_app_theme">app_theme</string>
|
||||
<string name="pref_key_dashboard_tiles">dashboard_tiles</string>
|
||||
<string name="pref_key_grade_color_scheme">grade_color_scheme</string>
|
||||
<string name="pref_key_expand_grade">expand_grade</string>
|
||||
<string name="pref_key_grade_average_mode">grade_average_mode</string>
|
||||
|
@ -109,4 +109,27 @@
|
||||
<item>both_semesters</item>
|
||||
<item>all_year</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Lucky number</item>
|
||||
<item>Unread messages</item>
|
||||
<item>Attendance</item>
|
||||
<item>Lessons</item>
|
||||
<item>Grades</item>
|
||||
<item>Homework</item>
|
||||
<item>School announcements</item>
|
||||
<item>Exams</item>
|
||||
<item>Conferences</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_values" translatable="false">
|
||||
<item>LUCKY_NUMBER</item>
|
||||
<item>MESSAGES</item>
|
||||
<item>ATTENDANCE</item>
|
||||
<item>LESSONS</item>
|
||||
<item>GRADES</item>
|
||||
<item>HOMEWORK</item>
|
||||
<item>ANNOUNCEMENTS</item>
|
||||
<item>EXAMS</item>
|
||||
<item>CONFERENCES</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
@ -23,6 +23,7 @@
|
||||
<string name="account_quick_title">Select account</string>
|
||||
<string name="account_details_title">Account details</string>
|
||||
<string name="student_info_title">Student info</string>
|
||||
<string name="dashboard_title">Dashboard</string>
|
||||
|
||||
|
||||
<!--Subtitles-->
|
||||
@ -469,6 +470,74 @@
|
||||
<string name="logviewer_refresh">Refresh</string>
|
||||
|
||||
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Lessons</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Tomorrow)</string>
|
||||
<string name="dashboard_timetable_lesson_value">%1$s (%2$s)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">In a moment:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Soon:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">First:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_now">Now:</string>
|
||||
<plurals name="dashboard_timetable_first_lesson_time_in_minutes">
|
||||
<item quantity="one">in %1$d minute</item>
|
||||
<item quantity="other">in %1$d minutes</item>
|
||||
</plurals>
|
||||
<plurals name="dashboard_timetable_first_lesson_time_more_minutes">
|
||||
<item quantity="one">%1$d more minute</item>
|
||||
<item quantity="other">%1$d more minutes</item>
|
||||
</plurals>
|
||||
<string name="dashboard_timetable_second_lesson_value_end">End of lessons</string>
|
||||
<string name="dashboard_timetable_second_lessons_title">Next:</string>
|
||||
<string name="dashboard_timetable_third_title">Later:</string>
|
||||
<plurals name="dashboard_timetable_third_value">
|
||||
<item quantity="one">%1$d more lesson</item>
|
||||
<item quantity="other">%1$d more lessons</item>
|
||||
</plurals>
|
||||
<string name="dashboard_timetable_third_time">until %1$s</string>
|
||||
<string name="dashboard_timetable_no_lessons">No lessons</string>
|
||||
<string name="dashboard_timetable_error">An error occurred while loading the lesson</string>
|
||||
|
||||
<string name="dashboard_homework_title">Homework</string>
|
||||
<string name="dashboard_homework_no_homework">No homework</string>
|
||||
<string name="dashboard_homework_error">An error occurred while loading the homework</string>
|
||||
<plurals name="dashboard_homework_more">
|
||||
<item quantity="one">%1$d more homework</item>
|
||||
<item quantity="other">%1$d more homework</item>
|
||||
</plurals>
|
||||
<string name="dashboard_homework_time">due %1$s</string>
|
||||
|
||||
<string name="dashboard_grade_title">Last grades</string>
|
||||
<string name="dashboard_grade_no_grade">No new grades</string>
|
||||
<string name="dashboard_grade_error">An error occurred while loading the grades</string>
|
||||
|
||||
<string name="dashboard_announcements_title">School announcements</string>
|
||||
<string name="dashboard_announcements_no_announcements">No announcements</string>
|
||||
<string name="dashboard_announcements_error">An error occurred while loading the announcements</string>
|
||||
<plurals name="dashboard_announcements_more">
|
||||
<item quantity="one">%1$d more announcement</item>
|
||||
<item quantity="other">%1$d more announcements</item>
|
||||
</plurals>
|
||||
|
||||
<string name="dashboard_exams_title">Exams</string>
|
||||
<string name="dashboard_exams_no_exams">No exams</string>
|
||||
<string name="dashboard_exams_error">An error occurred while loading the exams</string>
|
||||
<plurals name="dashboard_exams_more">
|
||||
<item quantity="one">%1$d more exam</item>
|
||||
<item quantity="other">%1$d more exams</item>
|
||||
</plurals>
|
||||
|
||||
<string name="dashboard_conferences_title">Conferences</string>
|
||||
<string name="dashboard_conferences_no_conferences">No conferences</string>
|
||||
<string name="dashboard_conferences_error">An error occurred while loading the conferences</string>
|
||||
<plurals name="dashboard_conference_more">
|
||||
<item quantity="one">%1$d more conference</item>
|
||||
<item quantity="other">%1$d more conferences</item>
|
||||
</plurals>
|
||||
|
||||
<string name="dashboard_horizontal_group_error">An error occurred while loading data</string>
|
||||
<string name="dashboard_horizontal_group_no_lukcy_number">No</string>
|
||||
|
||||
|
||||
<!--Error dialog-->
|
||||
<string name="dialog_error_check_update">Check for updates</string>
|
||||
<string name="dialog_error_check_update_message">Before reporting a bug, check first if an update with the bug fix is available</string>
|
||||
@ -552,6 +621,8 @@
|
||||
<string name="pref_settings_sync_title">Synchronization</string>
|
||||
|
||||
<string name="pref_grades_appearance_header">Grades</string>
|
||||
<string name="pref_dashboard_appearance_header">Dashboard</string>
|
||||
<string name="pref_dashboard_appearance_tiles_title">Tiles visibility</string>
|
||||
<string name="pref_attendance_appearance_view">Attendance</string>
|
||||
<string name="pref_timetable_appearance_view">Timetable</string>
|
||||
<string name="pref_grades_advanced_header">Grades</string>
|
||||
|
@ -29,6 +29,17 @@
|
||||
app:title="@string/pref_view_list"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref_dashboard_appearance_header">
|
||||
<MultiSelectListPreference
|
||||
app:entries="@array/dashboard_tile_entries"
|
||||
app:entryValues="@array/dashboard_tile_values"
|
||||
app:iconSpaceReserved="false"
|
||||
app:defaultValue="@array/pref_default_dashboard_tiles"
|
||||
app:key="@string/pref_key_dashboard_tiles"
|
||||
app:title="@string/pref_dashboard_appearance_tiles_title" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref_grades_appearance_header">
|
||||
@ -38,8 +49,7 @@
|
||||
app:entryValues="@array/grade_color_scheme_values"
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="@string/pref_key_grade_color_scheme"
|
||||
app:title="@string/pref_view_grade_color_scheme"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
app:title="@string/pref_view_grade_color_scheme" />
|
||||
<SwitchPreferenceCompat
|
||||
app:defaultValue="@bool/pref_default_expand_grade"
|
||||
app:iconSpaceReserved="false"
|
||||
|
Loading…
x
Reference in New Issue
Block a user