Skip to content

Commit

Permalink
Merge pull request #572 from willowtreeapps/bugfix/568-phrase-added-f…
Browse files Browse the repository at this point in the history
…rom-home-screen-not-shown-2

Abstract the model for showing a Phrase on the home screen
  • Loading branch information
PaulKlauser authored Jun 12, 2024
2 parents f9e97fb + 88119ad commit f29d198
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 177 deletions.
2 changes: 1 addition & 1 deletion app/src/main/java/com/willowtree/vocable/AppKoinModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ val vocableKoinModule = module {
single { VocableDatabase.createVocableDatabase(get()) }
single { get<VocableDatabase>().presetPhrasesDao() }
single<VocableEnvironment> { VocableEnvironmentImpl() }
viewModel { PresetsViewModel(get(), get(), get(named<PresetsViewModel>())) }
viewModel { PresetsViewModel(get(), get(), get(named<PresetsViewModel>()), get()) }
viewModel { EditCategoriesViewModel(get()) }
viewModel { EditCategoryPhrasesViewModel(get(), get(), get()) }
viewModel { AddUpdateCategoryViewModel(get(), get(), get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class NumberPadFragment : BaseFragment<FragmentNumberPadBinding>() {
private const val KEY_PHRASES = "KEY_PHRASES"
const val MAX_PHRASES = 12

fun newInstance(phrases: List<Phrase?>) = NumberPadFragment().apply {
fun newInstance(phrases: List<PhraseGridItem>) = NumberPadFragment().apply {
arguments = bundleOf(KEY_PHRASES to ArrayList(phrases))
}
}
Expand All @@ -37,7 +37,7 @@ class NumberPadFragment : BaseFragment<FragmentNumberPadBinding>() {
val numColumns = resources.getInteger(R.integer.number_pad_columns)
val numRows = resources.getInteger(R.integer.number_pad_rows)

val phrases = arguments?.getParcelableArrayList<Phrase>(KEY_PHRASES)
val phrases = arguments?.getParcelableArrayList<PhraseGridItem>(KEY_PHRASES)

phrases?.let {
with(binding.phrasesContainer) {
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/com/willowtree/vocable/presets/PhraseGridItem.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.willowtree.vocable.presets

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
sealed class PhraseGridItem : Parcelable {

@Parcelize
data class Phrase(
val phraseId: String,
val text: String
) : PhraseGridItem()

@Parcelize
object AddPhrase : PhraseGridItem()
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class PhrasesFragment : BaseFragment<FragmentPhrasesBinding>() {
companion object {
private const val KEY_PHRASES = "KEY_PHRASES"

fun newInstance(phrases: List<Phrase?>): PhrasesFragment {
fun newInstance(phrases: List<PhraseGridItem>): PhrasesFragment {
return PhrasesFragment().apply {
arguments = Bundle().apply {
putParcelableArrayList(KEY_PHRASES, ArrayList(phrases))
Expand All @@ -41,7 +41,7 @@ class PhrasesFragment : BaseFragment<FragmentPhrasesBinding>() {
val numColumns = resources.getInteger(R.integer.phrases_columns)
val numRows = resources.getInteger(R.integer.phrases_rows)

val phrases = arguments?.getParcelableArrayList<Phrase?>(KEY_PHRASES)
val phrases = arguments?.getParcelableArrayList<PhraseGridItem>(KEY_PHRASES)
phrases?.let {
with(binding.phrasesContainer) {
layoutManager = GridLayoutManager(requireContext(), numColumns)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ class PresetsFragment : BaseFragment<FragmentPresetsBinding>() {
}
}

private fun handlePhrases(phrases: List<Phrase?>) {
private fun handlePhrases(phrases: List<PhraseGridItem>) {
binding.emptyPhrasesText.isVisible =
phrases.isEmpty() && !recentsCategorySelected && categoriesAdapter.getSize() > 0
binding.emptyAddPhraseButton.isVisible =
Expand Down Expand Up @@ -306,9 +306,9 @@ class PresetsFragment : BaseFragment<FragmentPresetsBinding>() {
}

inner class PhrasesPagerAdapter(fm: FragmentManager) :
VocableFragmentStateAdapter<Phrase?>(fm, viewLifecycleOwner.lifecycle) {
VocableFragmentStateAdapter<PhraseGridItem>(fm, viewLifecycleOwner.lifecycle) {

override fun setItems(items: List<Phrase?>) {
override fun setItems(items: List<PhraseGridItem>) {
super.setItems(items)
setPagingButtonsEnabled(phrasesAdapter.numPages > 1)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.willowtree.vocable.ICategoriesUseCase
import com.willowtree.vocable.IPhrasesUseCase
import com.willowtree.vocable.utils.ILocalizedResourceUtility
import com.willowtree.vocable.utils.IdlingResourceContainer
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
Expand All @@ -23,7 +25,8 @@ import kotlinx.coroutines.launch
class PresetsViewModel(
private val categoriesUseCase: ICategoriesUseCase,
private val phrasesUseCase: IPhrasesUseCase,
private val idlingResourceContainer: IdlingResourceContainer
private val idlingResourceContainer: IdlingResourceContainer,
private val localizedResourceUtility: ILocalizedResourceUtility
) : ViewModel() {

val categoryList: LiveData<List<Category>> = categoriesUseCase.categories()
Expand Down Expand Up @@ -53,24 +56,30 @@ class PresetsViewModel(
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), null)
val selectedCategoryLiveData: LiveData<Category?> = selectedCategory.asLiveData()

val currentPhrases: LiveData<List<Phrase?>> = selectedCategoryId
val currentPhrases: LiveData<List<PhraseGridItem>> = selectedCategoryId
.filterNotNull()
.flatMapLatest { categoryId ->
phrasesUseCase.getPhrasesForCategoryFlow(categoryId).map { phrases ->
val phrasesToReturn = phrases.run {
val phraseGridItems: List<PhraseGridItem> = phrases.run {
if (categoryId != PresetCategories.RECENTS.id) {
sortedBy { it.sortOrder }
} else {
this
}
}.toMutableList<Phrase?>()
}.map {
PhraseGridItem.Phrase(
it.phraseId,
localizedResourceUtility.getTextFromPhrase(it)
)
}
if (categoryId != PresetCategories.RECENTS.id && categoryId != PresetCategories.USER_KEYPAD.id && phrases.isNotEmpty()) {
//Add null to end of normal non empty category phrase list for the "+ Add Phrase" button
phrasesToReturn.add(null)
phraseGridItems + PhraseGridItem.AddPhrase
} else {
phraseGridItems
}
phrasesToReturn
}
}
.distinctUntilChanged()
.asLiveData()

private val liveNavToAddPhrase = MutableLiveData<Boolean>()
Expand All @@ -90,10 +99,10 @@ class PresetsViewModel(
selectedCategoryId.update { categoryId }
}

fun addToRecents(phrase: Phrase) {
fun addToRecents(phraseId: String) {
viewModelScope.launch {
idlingResourceContainer.run {
phrasesUseCase.updatePhraseLastSpokenTime(phrase.phraseId)
phrasesUseCase.updatePhraseLastSpokenTime(phraseId)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,51 @@ import androidx.recyclerview.widget.RecyclerView
import com.willowtree.vocable.R
import com.willowtree.vocable.databinding.PhraseButtonAddBinding
import com.willowtree.vocable.databinding.PhraseButtonBinding
import com.willowtree.vocable.presets.Phrase
import com.willowtree.vocable.utils.locale.LocalizedResourceUtility
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import com.willowtree.vocable.presets.PhraseGridItem
import java.util.Locale

class PhraseAdapter(
private val phrases: List<Phrase?>,
private val phrases: List<PhraseGridItem>,
private val numRows: Int,
private val phraseClickAction: ((Phrase) -> Unit)?,
private val phraseClickAction: ((String) -> Unit)?,
private val phraseAddClickAction: (() -> Unit)?
) :
RecyclerView.Adapter<PhraseAdapter.PhraseViewHolder>(), KoinComponent {
) : RecyclerView.Adapter<PhraseAdapter.PhraseViewHolder>() {

abstract inner class PhraseViewHolder(
itemView: View
) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(text: String, position: Int)
abstract fun bind(position: Int)
}

inner class PhraseItemViewHolder(itemView: View) : PhraseAdapter.PhraseViewHolder(itemView) {
inner class PhraseGridItemViewHolder(itemView: View) :
PhraseAdapter.PhraseViewHolder(itemView) {

override fun bind(text: String, position: Int) {
val binding = PhraseButtonBinding.bind(itemView)
binding.root.setText(text, Locale.getDefault())
binding.root.action = {
phrases[position]?.let { phraseClickAction?.invoke(it) }
}
}
}

inner class PhraseAddItemViewHolder(itemView: View) : PhraseAdapter.PhraseViewHolder(itemView) {
override fun bind(position: Int) {
when (val gridItem = phrases[position]) {
is PhraseGridItem.Phrase -> {
val binding = PhraseButtonBinding.bind(itemView)
binding.root.setText(gridItem.text, Locale.getDefault())
binding.root.action = {
phraseClickAction?.invoke(gridItem.phraseId)
}
}

override fun bind(text: String, position: Int) {
val binding = PhraseButtonAddBinding.bind(itemView)
binding.root.action = {
phraseAddClickAction?.invoke()
PhraseGridItem.AddPhrase -> {
val binding = PhraseButtonAddBinding.bind(itemView)
binding.root.action = {
phraseAddClickAction?.invoke()
}
}
}
}
}

private val localizedResourceUtility: LocalizedResourceUtility by inject()

private var _minHeight: Int? = null

override fun getItemViewType(position: Int): Int {
return if (phrases[position] == null) {
R.layout.phrase_button_add
} else {
R.layout.phrase_button
return when (phrases[position]) {
is PhraseGridItem.Phrase -> R.layout.phrase_button
PhraseGridItem.AddPhrase -> R.layout.phrase_button_add
}
}

Expand All @@ -74,16 +69,12 @@ class PhraseAdapter(
isInvisible = false
}
}
return if (viewType == R.layout.phrase_button_add) {
PhraseAddItemViewHolder(itemView)
} else {
PhraseItemViewHolder(itemView)
}

return PhraseGridItemViewHolder(itemView)
}

override fun onBindViewHolder(holder: PhraseAdapter.PhraseViewHolder, position: Int) {
val text = localizedResourceUtility.getTextFromPhrase(phrases[position])
holder.bind(text, position)
holder.bind(position)
}

private fun getMinHeight(parent: ViewGroup): Int {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.willowtree.vocable.utils

import com.willowtree.vocable.presets.Category
import com.willowtree.vocable.presets.Phrase

interface ILocalizedResourceUtility {
fun getTextFromCategory(category: Category?): String
fun getTextFromPhrase(phrase: Phrase?): String
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class LocalizedResourceUtility(
return category?.text(context) ?: ""
}

fun getTextFromPhrase(phrase: Phrase?): String {
override fun getTextFromPhrase(phrase: Phrase?): String {
return phrase?.text(context) ?: ""
}
}
Loading

0 comments on commit f29d198

Please sign in to comment.