From e8e9f04050e19e3ba493dcb52863c5ea9d98c51b Mon Sep 17 00:00:00 2001 From: Antoni Czaplicki <56671347+Antoni-Czaplicki@users.noreply.github.com> Date: Wed, 22 Sep 2021 00:03:31 +0200 Subject: [PATCH] [UI] Show attendance info in timetable and lesson dialog. (#74) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Show attendance in timetable view * Optimize code and UX * Update some code * Update attendance layout * Fix timetable view * Bump iconics version * Change umbrella icon * Update app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableDayFragment.kt * Update app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableDayFragment.kt * Update app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableDayFragment.kt * Update app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableDayFragment.kt * Update lesson cell margins * Add attendance info in lesson dialog Co-authored-by: Kuba Szczodrzyński --- app/build.gradle | 6 +- .../edziennik/data/db/dao/AttendanceDao.kt | 2 + .../dialogs/timetable/LessonDetailsDialog.kt | 30 ++++++++++ .../modules/timetable/TimetableDayFragment.kt | 57 +++++++++++++++---- .../utils/managers/AttendanceManager.kt | 14 +++++ .../main/res/layout/dialog_lesson_details.xml | 57 ++++++++++++++++++- app/src/main/res/layout/timetable_lesson.xml | 30 ++++------ app/src/main/res/values/strings.xml | 1 + 8 files changed, 162 insertions(+), 35 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 62f4c95c..96bb1176 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -172,10 +172,10 @@ dependencies { kapt "eu.szkolny.selective-dao:codegen:27f8f3f194" // Iconics & related - implementation "com.mikepenz:iconics-core:5.3.0-b01" - implementation "com.mikepenz:iconics-views:5.3.0-b01" + implementation "com.mikepenz:iconics-core:5.3.1" + implementation "com.mikepenz:iconics-views:5.3.1" implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar" - implementation "eu.szkolny:szkolny-font:1.3" + implementation "eu.szkolny:szkolny-font:77e33acc2a" // Other dependencies implementation "cat.ereza:customactivityoncrash:2.3.0" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt index 3ffdc1b8..94be0c34 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt @@ -64,6 +64,8 @@ abstract class AttendanceDao : BaseDao { getRawNow("$QUERY WHERE notified = 0 $ORDER_BY") fun getNotNotifiedNow(profileId: Int) = getRawNow("$QUERY WHERE attendances.profileId = $profileId AND notified = 0 $ORDER_BY") + fun getAllByDateNow(profileId: Int, date: Date) = + getRawNow("$QUERY WHERE attendances.profileId = $profileId AND attendanceDate = '${date.stringY_m_d}' $ORDER_BY") // GET ONE - NOW fun getByIdNow(profileId: Int, id: Long) = diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/timetable/LessonDetailsDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/timetable/LessonDetailsDialog.kt index 9b43f9be..2df41c36 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/timetable/LessonDetailsDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/timetable/LessonDetailsDialog.kt @@ -8,15 +8,20 @@ import android.content.Intent import android.view.View import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.mikepenz.iconics.IconicsDrawable +import com.mikepenz.iconics.utils.colorInt +import com.mikepenz.iconics.utils.sizeDp import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.Lesson +import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding import pl.szczodrzynski.edziennik.onClick @@ -24,6 +29,7 @@ import pl.szczodrzynski.edziennik.setText import pl.szczodrzynski.edziennik.ui.dialogs.event.EventDetailsDialog import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog +import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceDetailsDialog import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment import pl.szczodrzynski.edziennik.utils.BetterLink import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration @@ -34,6 +40,7 @@ import kotlin.coroutines.CoroutineContext class LessonDetailsDialog( val activity: AppCompatActivity, val lesson: LessonFull, + val attendance: AttendanceFull? = null, val onShowListener: ((tag: String) -> Unit)? = null, val onDismissListener: ((tag: String) -> Unit)? = null ) : CoroutineScope { @@ -52,6 +59,8 @@ class LessonDetailsDialog( private lateinit var adapter: EventListAdapter private val manager get() = app.timetableManager + private val attendanceManager + get() = app.attendanceManager init { run { if (activity.isFinishing) @@ -170,6 +179,27 @@ class LessonDetailsDialog( b.teamName = lesson.teamName } + b.attendanceDivider.isVisible = attendance != null + b.attendanceLayout.isVisible = attendance != null + if (attendance != null) { + b.attendanceView.setAttendance(attendance, app.attendanceManager, bigView = true) + b.attendanceType.text = attendance.typeName + b.attendanceIcon.isVisible = attendance.let { + val icon = attendanceManager.getAttendanceIcon(it) ?: return@let false + val color = attendanceManager.getAttendanceColor(it) + b.attendanceIcon.setImageDrawable( + IconicsDrawable(activity, icon).apply { + colorInt = color + sizeDp = 24 + } + ) + true + } + b.attendanceDetails.onClick { + AttendanceDetailsDialog(activity, attendance, onShowListener, onDismissListener) + } + } + adapter = EventListAdapter( activity, showWeekDay = false, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableDayFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableDayFragment.kt index 00ce872e..5d13ee86 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableDayFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/timetable/TimetableDayFragment.kt @@ -9,19 +9,24 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.FrameLayout +import android.widget.LinearLayout import android.widget.TextView import androidx.asynclayoutinflater.view.AsyncLayoutInflater -import androidx.core.view.isVisible -import androidx.core.view.marginTop -import androidx.core.view.setPadding -import androidx.core.view.updateLayoutParams +import androidx.core.view.* import com.linkedin.android.tachyon.DayView import com.linkedin.android.tachyon.DayViewConfig +import com.mikepenz.iconics.IconicsDrawable +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import com.mikepenz.iconics.utils.colorInt +import com.mikepenz.iconics.utils.sizeDp +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask +import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Lesson +import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.TimetableDayFragmentBinding @@ -61,6 +66,8 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { private val manager get() = app.timetableManager + private val attendanceManager + get() = app.attendanceManager // find SwipeRefreshLayout in the hierarchy private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) } @@ -102,14 +109,17 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { val events = withContext(Dispatchers.Default) { app.db.eventDao().getAllByDateNow(App.profileId, date) } - processLessonList(lessons, events) + val attendanceList = withContext(Dispatchers.Default) { + app.db.attendanceDao().getAllByDateNow(App.profileId, date) + } + processLessonList(lessons, events, attendanceList) } } return true } - private fun processLessonList(lessons: List, events: List) { + private fun processLessonList(lessons: List, events: List, attendanceList: List) { // no lessons - timetable not downloaded yet if (lessons.isEmpty()) { inflater.inflate(R.layout.timetable_no_timetable, b.root) { view, _, _ -> @@ -172,10 +182,10 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { lessons.forEach { it.showAsUnseen = !it.seen } - buildLessonViews(lessons.filter { it.type != Lesson.TYPE_NO_LESSONS }, events) + buildLessonViews(lessons.filter { it.type != Lesson.TYPE_NO_LESSONS }, events, attendanceList) } - private fun buildLessonViews(lessons: List, events: List) { + private fun buildLessonViews(lessons: List, events: List, attendanceList: List) { if (!isAdded) return @@ -192,6 +202,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity) for (lesson in lessons) { + val attendance = attendanceList.find { it.startTime == lesson.startTime } val startTime = lesson.displayStartTime ?: continue val endTime = lesson.displayEndTime ?: continue @@ -208,11 +219,17 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { val lb = TimetableLessonBinding.bind(eventView) eventViews += eventView - eventView.tag = lesson + eventView.tag = lesson to attendance eventView.setOnClickListener { - if (isAdded && it.tag is LessonFull) - LessonDetailsDialog(activity, it.tag as LessonFull) + if (isAdded && it.tag is Pair<*, *>) { + val (lessonObj, attendanceObj) = it.tag as Pair<*, *> + LessonDetailsDialog( + activity = activity, + lesson = lessonObj as LessonFull, + attendance = attendanceObj as AttendanceFull? + ) + } } val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3) @@ -276,6 +293,18 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { lb.detailsFirst.text = listOfNotEmpty(timeRange, classroomInfo).concat(bullet) lb.detailsSecond.text = listOfNotEmpty(teacherInfo, teamInfo).concat(bullet) + lb.attendanceIcon.isVisible = attendance?.let { + val icon = attendanceManager.getAttendanceIcon(it) ?: return@let false + val color = attendanceManager.getAttendanceColor(it) + lb.attendanceIcon.setImageDrawable( + IconicsDrawable(activity, icon).apply { + colorInt = color + sizeDp = 24 + } + ) + true + } ?: false + lb.unread = lesson.type != Lesson.TYPE_NORMAL && lesson.showAsUnseen if (!lesson.seen) { manager.markAsSeen(lesson) @@ -283,6 +312,12 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { //lb.subjectName.typeface = Typeface.create("sans-serif-light", Typeface.BOLD) lb.annotationVisible = manager.getAnnotation(activity, lesson, lb.annotation) + val lessonNumberMargin = + if (lb.annotationVisible) (-8).dp + else 0 + lb.lessonNumberText.updateLayoutParams { + updateMargins(top = lessonNumberMargin, bottom = lessonNumberMargin) + } // The day view needs the event time ranges in the start minute/end minute format, // so calculate those here diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/AttendanceManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/AttendanceManager.kt index cd726797..77af40ed 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/AttendanceManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/AttendanceManager.kt @@ -4,6 +4,9 @@ package pl.szczodrzynski.edziennik.utils.managers +import com.mikepenz.iconics.typeface.IIcon +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -63,6 +66,17 @@ class AttendanceManager(val app: App) : CoroutineScope { else getAttendanceColor(attendance.baseType) } + fun getAttendanceIcon(attendance: Attendance): IIcon? = when (attendance.baseType) { + Attendance.TYPE_PRESENT, Attendance.TYPE_PRESENT_CUSTOM -> CommunityMaterial.Icon.cmd_check + Attendance.TYPE_ABSENT -> CommunityMaterial.Icon.cmd_close + Attendance.TYPE_ABSENT_EXCUSED -> CommunityMaterial.Icon3.cmd_progress_close + Attendance.TYPE_RELEASED -> CommunityMaterial.Icon.cmd_account_arrow_right_outline + Attendance.TYPE_BELATED -> CommunityMaterial.Icon.cmd_clock_alert_outline + Attendance.TYPE_BELATED_EXCUSED -> CommunityMaterial.Icon.cmd_clock_check_outline + Attendance.TYPE_DAY_FREE -> SzkolnyFont.Icon.szf_umbrella_beach_outline + else -> null + } + /* _ _ _____ _____ _ __ _ | | | |_ _| / ____| (_)/ _(_) | | | | | | | (___ _ __ ___ ___ _| |_ _ ___ diff --git a/app/src/main/res/layout/dialog_lesson_details.xml b/app/src/main/res/layout/dialog_lesson_details.xml index bf9cc40d..a304c641 100644 --- a/app/src/main/res/layout/dialog_lesson_details.xml +++ b/app/src/main/res/layout/dialog_lesson_details.xml @@ -134,7 +134,8 @@ android:layout_marginTop="8dp" android:baselineAligned="false" android:gravity="center_vertical" - android:orientation="horizontal"> + android:orientation="horizontal" + android:visibility="gone"> + + + + + + + + + + +