Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve reading plan UI #2095

Draft
wants to merge 6 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import net.bible.android.control.readingplan.ReadingPlanControl
import net.bible.android.control.search.SearchControl
import net.bible.android.control.speak.SpeakControl
import net.bible.android.control.versification.BibleTraverser
import net.bible.android.view.activity.readingplan.actionbar.ReadingPlanActionBarManager
import net.bible.android.view.activity.search.searchresultsactionbar.SearchResultsActionBarManager
import net.bible.android.view.activity.speak.actionbarbuttons.SpeakActionBarButton
import net.bible.android.view.activity.speak.actionbarbuttons.SpeakStopActionBarButton
Expand Down Expand Up @@ -66,6 +65,5 @@ interface ApplicationComponent {

fun speakActionBarButton(): SpeakActionBarButton
fun speakStopActionBarButton(): SpeakStopActionBarButton
fun readingPlanActionBarManager(): ReadingPlanActionBarManager
fun searchResultsActionBarManager(): SearchResultsActionBarManager
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import net.bible.android.control.event.passage.BeforeCurrentPageChangeEvent
import net.bible.android.control.page.CurrentPageManager
import net.bible.android.control.page.window.WindowControl
import net.bible.android.control.speak.SpeakControl
import net.bible.android.view.activity.readingplan.model.DayBarItem
import net.bible.service.common.CommonUtils
import net.bible.service.db.ReadingPlansUpdatedViaSyncEvent
import net.bible.service.db.readingplan.ReadingPlanRepository
Expand Down Expand Up @@ -102,6 +103,20 @@ class ReadingPlanControl @Inject constructor(
val currentPlansReadingList: List<OneDaysReadingsDto>
get() = readingPlanTextDao.getReadingList(currentPlanCode)

val currentPlansReadingDayBarItems: List<DayBarItem>
get() {
val planCurrentDay = currentPlanDay
return readingPlanTextDao.getReadingList(currentPlanCode).map {
DayBarItem(
it.day,
it.readingDate,
it.day == planCurrentDay,
false, // TODO add functionality
it.day < planCurrentDay
)
}
}

val currentPlanExists: Boolean get() = try {
readingPlanTextDao.getReading(currentPlanCode, 1)
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ open class ReadingStatus(val planCode: String, val day: Int, private val numRead
setStatus(readingNo, false)
}

fun setStatus(readingNo: Int, read: Boolean, saveStatus: Boolean = true) {
private fun setStatus(readingNo: Int, read: Boolean) {
val chapterRead = status.chapterReadArray.find { it.readingNumber == readingNo }
if (chapterRead == null) {
status.chapterReadArray.add(ChapterRead(readingNo, read))
Expand All @@ -82,7 +82,7 @@ open class ReadingStatus(val planCode: String, val day: Int, private val numRead
}
status.chapterReadArray.sortBy { it.readingNumber }

if (saveStatus) saveStatus()
saveStatus()
}

open fun isRead(readingNo: Int): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import android.view.View
import android.widget.TableLayout
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.MenuCompat
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import net.bible.android.BibleApplication

import net.bible.android.activity.R
Expand All @@ -39,7 +42,7 @@ import net.bible.android.control.readingplan.ReadingStatus
import net.bible.android.view.activity.base.CustomTitlebarActivityBase
import net.bible.android.view.activity.base.Dialogs
import net.bible.android.view.activity.installzip.InstallZip
import net.bible.android.view.activity.readingplan.actionbar.ReadingPlanActionBarManager
import net.bible.android.view.activity.readingplan.model.DayBarItem
import net.bible.service.common.CommonUtils
import net.bible.service.db.ReadingPlansUpdatedViaSyncEvent
import net.bible.service.readingplan.OneDaysReadingsDto
Expand All @@ -50,11 +53,7 @@ import java.util.Calendar

import javax.inject.Inject

/** Allow user to enter search criteria
*
* @author Martin Denham [mjdenham at gmail dot com]
*/
class DailyReading : CustomTitlebarActivityBase(R.menu.reading_plan) {
class DailyReading : CustomTitlebarActivityBase() {

private lateinit var binding: ReadingPlanOneDayBinding

Expand All @@ -67,7 +66,6 @@ class DailyReading : CustomTitlebarActivityBase(R.menu.reading_plan) {
private lateinit var readingsDto: OneDaysReadingsDto

@Inject lateinit var readingPlanControl: ReadingPlanControl
@Inject lateinit var readingPlanActionBarManager: ReadingPlanActionBarManager

private var readingStatus: ReadingStatus? = null
private val getReadingStatus: ReadingStatus
Expand All @@ -88,15 +86,14 @@ class DailyReading : CustomTitlebarActivityBase(R.menu.reading_plan) {
binding = ReadingPlanOneDayBinding.inflate(layoutInflater)
setContentView(binding.root)

super.setActionBarManager(readingPlanActionBarManager)

if (!readingPlanControl.isReadingPlanSelected || !readingPlanControl.currentPlanExists) {
val intent = Intent(this, ReadingPlanSelectorList::class.java)
selectReadingPlan.launch(intent)
return
}

loadDailyReading(null, null)
setupRecycler()
ABEventBus.register(this)
}

Expand Down Expand Up @@ -131,8 +128,6 @@ class DailyReading : CustomTitlebarActivityBase(R.menu.reading_plan) {

planCodeLoaded = readingPlanControl.currentPlanCode

readingPlanActionBarManager.updateButtons()

// get readings for chosen day
readingsDto = readingPlanControl.getDaysReading(dayLoaded)

Expand Down Expand Up @@ -229,11 +224,41 @@ class DailyReading : CustomTitlebarActivityBase(R.menu.reading_plan) {

}

private lateinit var viewAdapter: DailyReadingDayBarAdapter
private fun setupRecycler() {
val days = readingPlanControl.currentPlansReadingDayBarItems
viewAdapter = DailyReadingDayBarAdapter(object : OnItemClickListener {
override fun onItemClick(item: DayBarItem) {
days.forEach { d -> if (d.dayActive) {
d.dayActive = false
viewAdapter.notifyItemChanged(days.indexOf(d))
} }
item.dayActive = true
loadDailyReading(planCodeLoaded, item.dayNumber)
viewAdapter.notifyItemChanged(days.indexOf(item))
}
})
viewAdapter.submitList(days)
binding.daysRecycler.apply {
layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
adapter = viewAdapter
}
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.reading_plan, menu)
MenuCompat.setGroupDividerEnabled(menu, true)
return super.onCreateOptionsMenu(menu)
}

override fun onPrepareOptionsMenu(menu: Menu): Boolean {
if (::readingsDto.isInitialized && readingsDto.isDateBasedPlan) {
menu.findItem(R.id.setCurrentDay).isVisible = false
menu.findItem(R.id.setStartDate).isVisible = false
}
return super.onPrepareOptionsMenu(menu)
}

/** user pressed read button by 1 reading
*/
private fun onRead(readingNo: Int) {
Expand Down Expand Up @@ -330,14 +355,6 @@ class DailyReading : CustomTitlebarActivityBase(R.menu.reading_plan) {
startActivity(intent)
}

override fun onPrepareOptionsMenu(menu: Menu): Boolean {
if (::readingsDto.isInitialized && readingsDto.isDateBasedPlan) {
menu.findItem(R.id.setCurrentDay).isVisible = false
menu.findItem(R.id.setStartDate).isVisible = false
}
return super.onPrepareOptionsMenu(menu)
}

/**
* on Click handlers
*/
Expand Down Expand Up @@ -441,7 +458,7 @@ class DailyReading : CustomTitlebarActivityBase(R.menu.reading_plan) {
}
}

val installZipLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
private val installZipLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
// TODO load imported plan if result is OK
// still need to set up "InstallZip" to return reading plan fileName (code)
}
Expand Down Expand Up @@ -495,7 +512,7 @@ class DailyReading : CustomTitlebarActivityBase(R.menu.reading_plan) {
val planDescription: String
)

val PLAN = "net.bible.android.view.activity.readingplan.Plan"
val DAY = "net.bible.android.view.activity.readingplan.Day"
const val PLAN = "net.bible.android.view.activity.readingplan.Plan"
const val DAY = "net.bible.android.view.activity.readingplan.Day"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2022 Martin Denham, Tuomas Airaksinen and the And Bible contributors.
*
* This file is part of And Bible (http://github.com/AndBible/and-bible).
*
* And Bible is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* And Bible is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with And Bible.
* If not, see http://www.gnu.org/licenses/.
*
*/

package net.bible.android.view.activity.readingplan

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import net.bible.android.activity.R
import net.bible.android.activity.databinding.ReadingDayBarBoxBinding
import net.bible.android.view.activity.readingplan.model.DayBarItem
import net.bible.service.common.CommonUtils.getResourceColor
import java.text.SimpleDateFormat
import java.util.Locale

interface OnItemClickListener {
fun onItemClick(item: DayBarItem)
}
class DailyReadingDayBarAdapter(private val itemClickListener: OnItemClickListener) : ListAdapter<DayBarItem, DailyReadingDayBarAdapter.ViewHolder>(DIFF_CALLBACK) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ReadingDayBarBoxBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position) ?: return
holder.itemView.setOnClickListener {
itemClickListener.onItemClick(item)
}
holder.binding.apply {
dayNumberView.text = item.dayNumber.toString()
dateView.text = SimpleDateFormat("MMM dd", Locale.getDefault()).format(item.date)

boxContainer.setBackgroundColor(
if (item.dayActive)
getResourceColor(R.color.sync_on_green)
else if (item.dayReadComplete)
getResourceColor(R.color.grey_700)
else
getResourceColor(R.color.grey_500)
)
}
}

inner class ViewHolder(val binding: ReadingDayBarBoxBinding) : RecyclerView.ViewHolder(binding.root)

companion object {
const val TAG = "DailyReadingDayBarAdapt"
val DIFF_CALLBACK: DiffUtil.ItemCallback<DayBarItem> = object: DiffUtil.ItemCallback<DayBarItem>() {
override fun areItemsTheSame(oldItem: DayBarItem, newItem: DayBarItem):Boolean {
// User properties may have changed if reloaded from the DB, but ID is fixed
return oldItem.dayNumber == newItem.dayNumber
}
override fun areContentsTheSame(oldItem: DayBarItem, newItem: DayBarItem):Boolean {
// NOTE: if you use equals, your object must properly override Object#equals()
// Incorrectly returning false here will result in too many animations.
return oldItem == newItem
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2022 Martin Denham, Tuomas Airaksinen and the And Bible contributors.
*
* This file is part of And Bible (http://github.com/AndBible/and-bible).
*
* And Bible is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* And Bible is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with And Bible.
* If not, see http://www.gnu.org/licenses/.
*
*/

package net.bible.android.view.activity.readingplan.model

import java.util.Date

data class DayBarItem (
val dayNumber: Int,
val date: Date,
/** This day's readings are being shown in daily reading */
var dayActive: Boolean,
var dayReadPartial: Boolean,
var dayReadComplete: Boolean,
) {

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as DayBarItem

if (dayNumber != other.dayNumber) return false
if (date != other.date) return false
if (dayActive != other.dayActive) return false
if (dayReadPartial != other.dayReadPartial) return false
if (dayReadComplete != other.dayReadComplete) return false

return true
}
override fun hashCode(): Int {
var result = dayNumber
result = 31 * result + date.hashCode()
result = 31 * result + dayActive.hashCode()
result = 31 * result + dayReadPartial.hashCode()
result = 31 * result + dayReadComplete.hashCode()
return result
}
}
Loading