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

Use Flow of phrases from Room rather than a one shot #570

Merged
merged 1 commit into from
Jun 12, 2024
Merged
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
3 changes: 1 addition & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ dependencies {
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'android.arch.lifecycle:viewmodel:1.1.1'

implementation 'io.insert-koin:koin-core:3.1.5'
implementation 'io.insert-koin:koin-android:3.1.5'
implementation(libs.koin.android)

implementation "androidx.room:room-runtime:2.5.2"
kapt "androidx.room:room-compiler:2.5.2"
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ val vocableKoinModule = module {
single<VocableEnvironment> { VocableEnvironmentImpl() }
viewModel { PresetsViewModel(get(), get(), get(named<PresetsViewModel>())) }
viewModel { EditCategoriesViewModel(get()) }
viewModel { EditCategoryPhrasesViewModel(get(), get()) }
viewModel { EditCategoryPhrasesViewModel(get(), get(), get()) }
viewModel { AddUpdateCategoryViewModel(get(), get(), get()) }
viewModel { EditCategoryMenuViewModel(get()) }
}
3 changes: 3 additions & 0 deletions app/src/main/java/com/willowtree/vocable/IPhrasesUseCase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package com.willowtree.vocable

import com.willowtree.vocable.presets.Phrase
import com.willowtree.vocable.utils.locale.LocalesWithText
import kotlinx.coroutines.flow.Flow

interface IPhrasesUseCase {

suspend fun getPhrasesForCategory(categoryId: String): List<Phrase>

fun getPhrasesForCategoryFlow(categoryId: String): Flow<List<Phrase>>

suspend fun updatePhraseLastSpokenTime(phraseId: String)

suspend fun deletePhrase(phraseId: String)
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/java/com/willowtree/vocable/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koin.androidx.scope.ScopeActivity
import org.koin.androidx.viewmodel.ViewModelOwner
import org.koin.androidx.viewmodel.scope.getViewModel
import org.koin.androidx.viewmodel.ext.android.getViewModel

class MainActivity : ScopeActivity() {

Expand All @@ -41,7 +40,7 @@ class MainActivity : ScopeActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

faceTrackingViewModel = scope.getViewModel(owner = { ViewModelOwner.from(this) })
faceTrackingViewModel = getViewModel()

binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
Expand Down
47 changes: 36 additions & 11 deletions app/src/main/java/com/willowtree/vocable/PhrasesUseCase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import com.willowtree.vocable.utils.DateProvider
import com.willowtree.vocable.utils.UUIDProvider
import com.willowtree.vocable.utils.locale.LocaleProvider
import com.willowtree.vocable.utils.locale.LocalesWithText
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine

class PhrasesUseCase(
private val legacyPhrasesRepository: ILegacyCategoriesAndPhrasesRepository,
Expand All @@ -31,6 +33,23 @@ class PhrasesUseCase(
presetPhrasesRepository.getPhrasesForCategory(categoryId)
}

override fun getPhrasesForCategoryFlow(categoryId: String): Flow<List<Phrase>> {
return combine(
presetPhrasesRepository.getRecentPhrasesFlow(),
storedPhrasesRepository.getRecentPhrasesFlow(),
storedPhrasesRepository.getPhrasesForCategoryFlow(categoryId),
presetPhrasesRepository.getPhrasesForCategoryFlow(categoryId)
) { recentPresets, recentStored, stored, presets ->
if (categoryId == PresetCategories.RECENTS.id) {
(recentPresets + recentStored)
.sortedByDescending { it.lastSpokenDate }
.take(8)
} else {
stored + presets
}
}
}

override suspend fun updatePhraseLastSpokenTime(phraseId: String) {
storedPhrasesRepository.updatePhraseLastSpokenTime(phraseId)
presetPhrasesRepository.updatePhraseLastSpokenTime(phraseId)
Expand All @@ -54,6 +73,7 @@ class PhrasesUseCase(
localizedUtterance = localizedUtterance,
)
}

is PresetPhrase -> {
presetPhrasesRepository.deletePhrase(phraseId = phraseId)
// add a custom phrase to "shadow" over the preset
Expand All @@ -69,24 +89,29 @@ class PhrasesUseCase(
)

}

null -> throw IllegalArgumentException("Phrase with id $phraseId not found")
}
}

override suspend fun addPhrase(localizedUtterance: LocalesWithText, parentCategoryId: String) {
if (parentCategoryId != PresetCategories.RECENTS.id) {
storedPhrasesRepository.addPhrase(PhraseDto(
phraseId = uuidProvider.randomUUIDString(),
parentCategoryId = parentCategoryId,
creationDate = dateProvider.currentTimeMillis(),
lastSpokenDate = null,
localizedUtterance = localizedUtterance,
sortOrder = legacyPhrasesRepository.getPhrasesForCategory(parentCategoryId).size
))
storedPhrasesRepository.addPhrase(
PhraseDto(
phraseId = uuidProvider.randomUUIDString(),
parentCategoryId = parentCategoryId,
creationDate = dateProvider.currentTimeMillis(),
lastSpokenDate = null,
localizedUtterance = localizedUtterance,
sortOrder = legacyPhrasesRepository.getPhrasesForCategory(parentCategoryId).size
)
)
} else {
throw Exception("The 'Recents' category is not a true category -" +
" it is a filter applied to true categories. Therefore, saving phrases from " +
"the Recents 'category' is not supported.")
throw Exception(
"The 'Recents' category is not a true category -" +
" it is a filter applied to true categories. Therefore, saving phrases from " +
"the Recents 'category' is not supported."
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ import com.willowtree.vocable.customviews.CategoryButton
import com.willowtree.vocable.customviews.PointerListener
import com.willowtree.vocable.databinding.CategoriesFragmentBinding
import com.willowtree.vocable.databinding.CategoryButtonBinding
import org.koin.androidx.viewmodel.ViewModelOwner
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.androidx.viewmodel.ext.android.activityViewModel

class CategoriesFragment : BaseFragment<CategoriesFragmentBinding>() {

Expand All @@ -35,9 +34,7 @@ class CategoriesFragment : BaseFragment<CategoriesFragmentBinding>() {
override val bindingInflater: BindingInflater<CategoriesFragmentBinding> =
CategoriesFragmentBinding::inflate

private val viewModel: PresetsViewModel by viewModel(owner = {
ViewModelOwner.from(requireActivity())
})
private val viewModel: PresetsViewModel by activityViewModel()
private val allViews = mutableListOf<View>()
private var maxCategories = 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@ import com.willowtree.vocable.R
import com.willowtree.vocable.databinding.FragmentPhrasesBinding
import com.willowtree.vocable.presets.adapter.PhraseAdapter
import com.willowtree.vocable.utils.ItemOffsetDecoration
import org.koin.androidx.viewmodel.ViewModelOwner
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.androidx.viewmodel.ext.android.activityViewModel

class PhrasesFragment : BaseFragment<FragmentPhrasesBinding>() {
private val presetsViewModel: PresetsViewModel by viewModel(owner = {
ViewModelOwner.from(requireActivity())
})
private val presetsViewModel: PresetsViewModel by activityViewModel()

companion object {
private const val KEY_PHRASES = "KEY_PHRASES"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import com.willowtree.vocable.databinding.FragmentPresetsBinding
import com.willowtree.vocable.utils.SpokenText
import com.willowtree.vocable.utils.VocableFragmentStateAdapter
import com.willowtree.vocable.utils.VocableTextToSpeech
import org.koin.androidx.viewmodel.ViewModelOwner
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.androidx.viewmodel.ext.android.activityViewModel

class PresetsFragment : BaseFragment<FragmentPresetsBinding>() {

Expand All @@ -34,9 +33,7 @@ class PresetsFragment : BaseFragment<FragmentPresetsBinding>() {
private var isPortraitMode = true
private var isTabletMode = false

private val presetsViewModel: PresetsViewModel by viewModel(owner = {
ViewModelOwner.from(requireActivity())
})
private val presetsViewModel: PresetsViewModel by activityViewModel()
private lateinit var categoriesAdapter: CategoriesPagerAdapter
private lateinit var phrasesAdapter: PhrasesPagerAdapter

Expand Down
14 changes: 13 additions & 1 deletion app/src/main/java/com/willowtree/vocable/room/PhraseDao.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package com.willowtree.vocable.room

import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import kotlinx.coroutines.flow.Flow

@Dao
interface PhraseDao {
Expand All @@ -26,9 +32,15 @@ interface PhraseDao {
@Query("SELECT * FROM Phrase WHERE last_spoken_date IS NOT NULL ORDER BY last_spoken_date DESC LIMIT 8")
suspend fun getRecentPhrases(): List<PhraseDto>

@Query("SELECT * FROM Phrase WHERE last_spoken_date IS NOT NULL ORDER BY last_spoken_date DESC LIMIT 8")
fun getRecentPhrasesFlow(): Flow<List<PhraseDto>>

@Query("SELECT * FROM Phrase WHERE parent_category_id == :categoryId")
suspend fun getPhrasesForCategory(categoryId: String): List<PhraseDto>

@Query("SELECT * FROM Phrase WHERE parent_category_id == :categoryId")
fun getPhrasesForCategoryFlow(categoryId: String): Flow<List<PhraseDto>>

@Query("SELECT * FROM Phrase WHERE phrase_id == :phraseId")
suspend fun getPhrase(phraseId: String): PhraseDto?
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import kotlinx.coroutines.flow.Flow

@Dao
interface PresetPhrasesDao {
Expand All @@ -21,9 +22,15 @@ interface PresetPhrasesDao {
@Query("SELECT * FROM PresetPhrase WHERE last_spoken_date IS NOT NULL ORDER BY last_spoken_date DESC LIMIT 8")
suspend fun getRecentPhrases(): List<PresetPhraseDto>

@Query("SELECT * FROM PresetPhrase WHERE last_spoken_date IS NOT NULL ORDER BY last_spoken_date DESC LIMIT 8")
fun getRecentPhrasesFlow(): Flow<List<PresetPhraseDto>>

@Query("SELECT * FROM PresetPhrase WHERE parent_category_id = :categoryId")
suspend fun getPhrasesForCategory(categoryId: String): List<PresetPhraseDto>

@Query("SELECT * FROM PresetPhrase WHERE parent_category_id = :categoryId")
fun getPhrasesForCategoryFlow(categoryId: String): Flow<List<PresetPhraseDto>>

@Query("SELECT * FROM PresetPhrase WHERE phrase_id = :phraseId")
suspend fun getPhrase(phraseId: String): PresetPhraseDto?

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.willowtree.vocable.room

import com.willowtree.vocable.presets.PresetPhrase
import kotlinx.coroutines.flow.Flow

interface PresetPhrasesRepository {
suspend fun populateDatabase()
suspend fun getAllPresetPhrases(): List<PresetPhrase>
suspend fun updatePhraseLastSpokenTime(phraseId: String)
suspend fun getRecentPhrases() : List<PresetPhrase>
fun getRecentPhrasesFlow(): Flow<List<PresetPhrase>>
suspend fun getPhrasesForCategory(categoryId: String): List<PresetPhrase>
fun getPhrasesForCategoryFlow(categoryId: String): Flow<List<PresetPhrase>>
suspend fun getPhrase(phraseId: String): PresetPhrase?
suspend fun deletePhrase(phraseId: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import com.willowtree.vocable.presets.PresetCategories
import com.willowtree.vocable.presets.PresetPhrase
import com.willowtree.vocable.presets.asPhrase
import com.willowtree.vocable.utils.DateProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.koin.core.context.GlobalContext.get
Expand Down Expand Up @@ -37,7 +39,12 @@ class RoomPresetPhrasesRepository(
override suspend fun getRecentPhrases(): List<PresetPhrase> {
return presetPhrasesDao.getRecentPhrases()
.filterDeletedPresets()
.map { it.asPhrase()}
.map { it.asPhrase() }
}

override fun getRecentPhrasesFlow(): Flow<List<PresetPhrase>> {
return presetPhrasesDao.getRecentPhrasesFlow()
.map { phraseList -> phraseList.filterDeletedPresets().map { it.asPhrase() } }
}

override suspend fun getPhrasesForCategory(categoryId: String): List<PresetPhrase> {
Expand All @@ -46,6 +53,11 @@ class RoomPresetPhrasesRepository(
.map { it.asPhrase() }
}

override fun getPhrasesForCategoryFlow(categoryId: String): Flow<List<PresetPhrase>> {
return presetPhrasesDao.getPhrasesForCategoryFlow(categoryId)
.map { phraseList -> phraseList.filterDeletedPresets().map { it.asPhrase() } }
}

override suspend fun getPhrase(phraseId: String): PresetPhrase? {
return presetPhrasesDao.getPhrase(phraseId)?.asPhrase()
}
Expand All @@ -54,7 +66,7 @@ class RoomPresetPhrasesRepository(
presetPhrasesDao.deletePhrase(phraseId, deleted = true)
}

private fun List<PresetPhraseDto>.filterDeletedPresets() : List<PresetPhraseDto> {
private fun List<PresetPhraseDto>.filterDeletedPresets(): List<PresetPhraseDto> {
return filterNot { it.deleted }
}

Expand Down
Loading
Loading