forked from github/wulkanowy-mirror
Add lucky number history (#1184)
This commit is contained in:
@ -13,4 +13,7 @@ interface LuckyNumberDao : BaseDao<LuckyNumber> {
|
||||
|
||||
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
|
||||
fun load(studentId: Int, date: LocalDate): Flow<LuckyNumber?>
|
||||
|
||||
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date >= :start AND date <= :end")
|
||||
fun getAll(studentId: Int, start: LocalDate, end: LocalDate): Flow<List<LuckyNumber>>
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import io.github.wulkanowy.utils.init
|
||||
import io.github.wulkanowy.utils.networkBoundResource
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDate.now
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -33,6 +34,9 @@ class LuckyNumberRepository @Inject constructor(
|
||||
}
|
||||
)
|
||||
|
||||
fun getLuckyNumberHistory(student: Student, start: LocalDate, end: LocalDate) =
|
||||
luckyNumberDb.getAll(student.studentId, start, end)
|
||||
|
||||
suspend fun getNotNotifiedLuckyNumber(student: Student) = luckyNumberDb.load(student.studentId, now()).map {
|
||||
if (it?.isNotified == false) it else null
|
||||
}.first()
|
||||
|
@ -9,6 +9,8 @@ import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.databinding.FragmentLuckyNumberBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.luckynumber.history.LuckyNumberHistoryFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import javax.inject.Inject
|
||||
@ -42,6 +44,7 @@ class LuckyNumberFragment :
|
||||
luckyNumberSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||
luckyNumberSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||
luckyNumberSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh))
|
||||
luckyNumberHistoryButton.setOnClickListener { openLuckyNumberHistory() }
|
||||
luckyNumberErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||
luckyNumberErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||
}
|
||||
@ -79,6 +82,10 @@ class LuckyNumberFragment :
|
||||
binding.luckyNumberContent.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun openLuckyNumberHistory() {
|
||||
(activity as? MainActivity)?.pushView(LuckyNumberHistoryFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
|
@ -24,4 +24,6 @@ interface LuckyNumberView : BaseView {
|
||||
fun enableSwipe(enable: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun openLuckyNumberHistory()
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.databinding.ItemLuckyNumberHistoryBinding
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.weekDayName
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
class LuckyNumberHistoryAdapter @Inject constructor() :
|
||||
RecyclerView.Adapter<LuckyNumberHistoryAdapter.ItemViewHolder>() {
|
||||
|
||||
var items = emptyList<LuckyNumber>()
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||
ItemLuckyNumberHistoryBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
with(holder.binding) {
|
||||
luckyNumberHistoryWeekName.text = item.date.weekDayName.capitalize()
|
||||
luckyNumberHistoryDate.text = item.date.toFormattedString()
|
||||
luckyNumberHistory.text = item.luckyNumber.toString()
|
||||
}
|
||||
}
|
||||
|
||||
class ItemViewHolder(val binding: ItemLuckyNumberHistoryBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.databinding.FragmentLuckyNumberHistoryBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchooldaysRangeLimiter
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class LuckyNumberHistoryFragment :
|
||||
BaseFragment<FragmentLuckyNumberHistoryBinding>(R.layout.fragment_lucky_number_history), LuckyNumberHistoryView,
|
||||
MainView.TitledView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: LuckyNumberHistoryPresenter
|
||||
|
||||
@Inject
|
||||
lateinit var luckyNumberHistoryAdapter: LuckyNumberHistoryAdapter
|
||||
|
||||
companion object {
|
||||
fun newInstance() = LuckyNumberHistoryFragment()
|
||||
}
|
||||
|
||||
override val titleStringId: Int
|
||||
get() = R.string.lucky_number_history_title
|
||||
|
||||
override val isViewEmpty get() = luckyNumberHistoryAdapter.items.isEmpty()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentLuckyNumberHistoryBinding.bind(view)
|
||||
messageContainer = binding.luckyNumberHistoryRecycler
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
with(binding.luckyNumberHistoryRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = luckyNumberHistoryAdapter
|
||||
addItemDecoration(DividerItemDecoration(context))
|
||||
}
|
||||
|
||||
with(binding) {
|
||||
luckyNumberHistoryNavDate.setOnClickListener { presenter.onPickDate() }
|
||||
luckyNumberHistoryErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||
luckyNumberHistoryErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||
|
||||
luckyNumberHistoryPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
|
||||
luckyNumberHistoryNextButton.setOnClickListener { presenter.onNextWeek() }
|
||||
|
||||
luckyNumberHistoryNavContainer.setElevationCompat(requireContext().dpToPx(8f))
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateData(data: List<LuckyNumber>) {
|
||||
with(luckyNumberHistoryAdapter) {
|
||||
items = data
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearData() {
|
||||
with(luckyNumberHistoryAdapter) {
|
||||
items = emptyList()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
binding.luckyNumberHistoryEmpty.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun showErrorView(show: Boolean) {
|
||||
binding.luckyNumberHistoryError.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun setErrorDetails(message: String) {
|
||||
binding.luckyNumberHistoryErrorMessage.text = message
|
||||
}
|
||||
|
||||
override fun updateNavigationWeek(date: String) {
|
||||
binding.luckyNumberHistoryNavDate.text = date
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
binding.luckyNumberHistoryProgress.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun showPreButton(show: Boolean) {
|
||||
binding.luckyNumberHistoryPreviousButton.visibility = if (show) VISIBLE else View.INVISIBLE
|
||||
}
|
||||
|
||||
override fun showNextButton(show: Boolean) {
|
||||
binding.luckyNumberHistoryNextButton.visibility = if (show) VISIBLE else View.INVISIBLE
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
|
||||
presenter.onDateSet(year, month + 1, dayOfMonth)
|
||||
}
|
||||
val datePickerDialog = DatePickerDialog.newInstance(dateSetListener,
|
||||
currentDate.year, currentDate.monthValue - 1, currentDate.dayOfMonth)
|
||||
|
||||
with(datePickerDialog) {
|
||||
setDateRangeLimiter(SchooldaysRangeLimiter())
|
||||
version = DatePickerDialog.Version.VERSION_2
|
||||
scrollOrientation = DatePickerDialog.ScrollOrientation.VERTICAL
|
||||
vibrate(false)
|
||||
show(this@LuckyNumberHistoryFragment.parentFragmentManager, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
binding.luckyNumberHistoryRecycler.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.github.wulkanowy.utils.previousOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.sunday
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
||||
class LuckyNumberHistoryPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val luckyNumberRepository: LuckyNumberRepository,
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<LuckyNumberHistoryView>(errorHandler, studentRepository) {
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
||||
var currentDate: LocalDate = LocalDate.now().previousOrSameSchoolDay
|
||||
|
||||
override fun onAttachView(view: LuckyNumberHistoryView) {
|
||||
super.onAttachView(view)
|
||||
view.run {
|
||||
initView()
|
||||
reloadNavigation()
|
||||
showContent(false)
|
||||
}
|
||||
Timber.i("Lucky number history view was initialized")
|
||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||
loadData()
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
flowWithResource {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
luckyNumberRepository.getLuckyNumberHistory(student, currentDate.monday, currentDate.sunday)
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Loading lucky number history started")
|
||||
Status.SUCCESS -> {
|
||||
if (!it.data?.first().isNullOrEmpty()) {
|
||||
Timber.i("Loading lucky number result: Success")
|
||||
view?.apply {
|
||||
updateData(it.data!!.first())
|
||||
showContent(true)
|
||||
showEmpty(false)
|
||||
showErrorView(false)
|
||||
showProgress(false)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_items",
|
||||
"type" to "lucky_number_history",
|
||||
"numbers" to it.data
|
||||
)
|
||||
} else {
|
||||
Timber.i("Loading lucky number history result: No lucky numbers found")
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showEmpty(true)
|
||||
showErrorView(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Loading lucky number history result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
}
|
||||
}
|
||||
}.afterLoading {
|
||||
view?.run {
|
||||
showProgress(false)
|
||||
}
|
||||
}.launch()
|
||||
}
|
||||
|
||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||
view?.run {
|
||||
if (isViewEmpty) {
|
||||
lastError = error
|
||||
setErrorDetails(message)
|
||||
showErrorView(true)
|
||||
showEmpty(false)
|
||||
} else showError(message, error)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadView(date: LocalDate) {
|
||||
currentDate = date
|
||||
Timber.i("Reload lucky number history view with the date ${currentDate.toFormattedString()}")
|
||||
view?.apply {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
showEmpty(false)
|
||||
showErrorView(false)
|
||||
clearData()
|
||||
reloadNavigation()
|
||||
}
|
||||
}
|
||||
|
||||
fun onRetry() {
|
||||
view?.run {
|
||||
showErrorView(false)
|
||||
showProgress(true)
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onDetailsClick() {
|
||||
view?.showErrorDetailsDialog(lastError)
|
||||
}
|
||||
|
||||
private fun reloadNavigation() {
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(7).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(7).isHolidays)
|
||||
updateNavigationWeek("${currentDate.monday.toFormattedString("dd.MM")} - " +
|
||||
currentDate.sunday.toFormattedString("dd.MM"))
|
||||
}
|
||||
}
|
||||
|
||||
fun onDateSet(year: Int, month: Int, day: Int) {
|
||||
reloadView(LocalDate.of(year, month, day))
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onPickDate() {
|
||||
view?.showDatePickerDialog(currentDate)
|
||||
}
|
||||
|
||||
fun onPreviousWeek() {
|
||||
reloadView(currentDate.minusDays(7))
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onNextWeek() {
|
||||
reloadView(currentDate.plusDays(7))
|
||||
loadData()
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber.history
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import java.time.LocalDate
|
||||
|
||||
interface LuckyNumberHistoryView : BaseView {
|
||||
|
||||
val isViewEmpty: Boolean
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<LuckyNumber>)
|
||||
|
||||
fun clearData()
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun showErrorView(show: Boolean)
|
||||
|
||||
fun setErrorDetails(message: String)
|
||||
|
||||
fun updateNavigationWeek(date: String)
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showPreButton(show: Boolean)
|
||||
|
||||
fun showNextButton(show: Boolean)
|
||||
|
||||
fun showDatePickerDialog(currentDate: LocalDate)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun onDestroyView()
|
||||
}
|
Reference in New Issue
Block a user