Skip to content
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
35 changes: 35 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,41 @@ on:
- main

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout source (with submodules)
uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive

- name: Install JBR 25
run: |
curl -L -o jbr.tar.gz "https://cache-redirector.jetbrains.com/intellij-jbr/jbrsdk-25.0.1-linux-x64-b268.52.tar.gz"
mkdir -p "$RUNNER_TEMP/jbr"
tar -xzf jbr.tar.gz -C "$RUNNER_TEMP/jbr"
JBR_DIR=$(find "$RUNNER_TEMP/jbr" -mindepth 1 -maxdepth 1 -type d -name "jbr*" -o -name "jbrsdk*" | head -n 1)
echo "JAVA_HOME=$JBR_DIR" >> "$GITHUB_ENV"
echo "$JBR_DIR/bin" >> "$GITHUB_PATH"

- name: Setup Gradle
uses: gradle/gradle-build-action@v3

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Run SeforimApp tests
run: ./gradlew :SeforimApp:jvmTest --no-daemon

- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports
path: '**/build/reports/tests/'
retention-days: 7

build:
runs-on: ${{ matrix.os }}
strategy:
Expand Down
3 changes: 3 additions & 0 deletions SeforimApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ kotlin {
implementation(libs.lucene.core)
implementation(libs.reorderable)

// SeforimLibrary search module
implementation("io.github.kdroidfilter.seforimlibrary:search")

implementation(libs.commons.compress)

// HTML sanitization for search snippets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.lifecycle.viewModelScope
import io.github.kdroidfilter.seforim.tabs.TabsViewModel
import io.github.kdroidfilter.seforim.tabs.TabsDestination
import io.github.kdroidfilter.seforimlibrary.dao.repository.SeforimRepository
import io.github.kdroidfilter.seforimapp.framework.search.LuceneSearchService
import io.github.kdroidfilter.seforimlibrary.search.SearchEngine
import io.github.kdroidfilter.seforimapp.framework.search.LuceneLookupSearchService
import io.github.kdroidfilter.seforimlibrary.core.models.Book
import io.github.kdroidfilter.seforimlibrary.core.models.Category
Expand Down Expand Up @@ -64,7 +64,7 @@ class SearchHomeViewModel(
private val tabsViewModel: TabsViewModel,
private val persistedStore: TabPersistedStateStore,
private val repository: SeforimRepository,
private val lucene: LuceneSearchService,
private val searchEngine: SearchEngine,
private val lookup: LuceneLookupSearchService,
private val settings: Settings
) : ViewModel() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import io.github.kdroidfilter.seforimapp.core.settings.AppSettings
import io.github.kdroidfilter.seforimapp.features.bookcontent.state.StateKeys
import io.github.kdroidfilter.seforimapp.features.search.domain.BuildSearchTreeUseCase
import io.github.kdroidfilter.seforimapp.features.search.domain.GetBreadcrumbPiecesUseCase
import io.github.kdroidfilter.seforimapp.framework.search.LuceneSearchService
import io.github.kdroidfilter.seforimlibrary.search.SearchEngine
import io.github.kdroidfilter.seforimlibrary.search.SearchSession
import io.github.kdroidfilter.seforimlibrary.search.LineHit
import io.github.kdroidfilter.seforimapp.framework.di.AppScope
import io.github.kdroidfilter.seforimapp.framework.session.SearchPersistedState
import io.github.kdroidfilter.seforimapp.framework.session.TabPersistedStateStore
Expand Down Expand Up @@ -63,7 +65,7 @@ class SearchResultViewModel(
@Assisted savedStateHandle: SavedStateHandle,
private val persistedStore: TabPersistedStateStore,
private val repository: SeforimRepository,
private val lucene: LuceneSearchService,
private val lucene: SearchEngine,
private val titleUpdateManager: TabTitleUpdateManager,
private val tabsViewModel: TabsViewModel
) : ViewModel() {
Expand Down Expand Up @@ -952,28 +954,28 @@ class SearchResultViewModel(
fetchCategoryId: Long?,
fetchBookId: Long?,
fetchTocId: Long?
): Pair<LuceneSearchService.SearchSession, Set<Long>>? {
): Pair<SearchSession, Set<Long>>? {
var tocAllowedLineIds: Set<Long> = emptySet()
val session: LuceneSearchService.SearchSession? = when {
val session: SearchSession? = when {
fetchTocId != null -> {
val toc = repository.getTocEntry(fetchTocId) ?: return null
ensureTocCountingCaches(toc.bookId)
val lineIds = collectLineIdsForTocSubtree(toc.id, toc.bookId)
tocAllowedLineIds = lineIds
lucene.openSearchSession(query, DEFAULT_NEAR, lineIds = lineIds)
lucene.openSession(query, DEFAULT_NEAR, lineIds = lineIds)
}
fetchBookId != null -> lucene.openSearchSession(query, DEFAULT_NEAR, bookIds = listOf(fetchBookId))
fetchBookId != null -> lucene.openSession(query, DEFAULT_NEAR, bookIds = listOf(fetchBookId))
fetchCategoryId != null -> {
val books = collectBookIdsUnderCategory(fetchCategoryId)
lucene.openSearchSession(query, DEFAULT_NEAR, bookIds = books)
lucene.openSession(query, DEFAULT_NEAR, bookIds = books)
}
else -> {
val extendedGlobal = _uiState.value.globalExtended
val baseOnlyBookIds: List<Long>? = if (!extendedGlobal) runCatching { repository.getBaseBookIds() }.getOrNull() else null
when {
baseOnlyBookIds != null && baseOnlyBookIds.isEmpty() -> null
baseOnlyBookIds != null -> lucene.openSearchSession(query, DEFAULT_NEAR, bookIds = baseOnlyBookIds)
else -> lucene.openSearchSession(query, DEFAULT_NEAR)
baseOnlyBookIds != null -> lucene.openSession(query, DEFAULT_NEAR, bookIds = baseOnlyBookIds)
else -> lucene.openSession(query, DEFAULT_NEAR)
}
}
}
Expand All @@ -982,7 +984,7 @@ class SearchResultViewModel(
}

private fun hitsToResults(
hits: List<LuceneSearchService.LineHit>,
hits: List<LineHit>,
rawQuery: String
): List<SearchResult> {
if (hits.isEmpty()) return emptyList()
Expand Down Expand Up @@ -1494,7 +1496,7 @@ class SearchResultViewModel(
return result
}

private suspend fun updateAggregatesForHits(hits: List<LuceneSearchService.LineHit>) {
private suspend fun updateAggregatesForHits(hits: List<LineHit>) {
countsMutex.withLock {
for (hit in hits) {
val book = bookCache[hit.bookId] ?: repository.getBookCore(hit.bookId)?.also { bookCache[hit.bookId] = it } ?: continue
Expand All @@ -1514,7 +1516,7 @@ class SearchResultViewModel(
}
}

private suspend fun updateTocCountsForHits(hits: List<LuceneSearchService.LineHit>, scopeBookId: Long) {
private suspend fun updateTocCountsForHits(hits: List<LineHit>, scopeBookId: Long) {
val subset = hits.filter { it.bookId == scopeBookId }
if (subset.isEmpty()) return
ensureTocCountingCaches(scopeBookId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import io.github.kdroidfilter.seforimapp.features.onboarding.data.OnboardingProc
import io.github.kdroidfilter.seforimapp.features.search.SearchHomeViewModel
import io.github.kdroidfilter.seforimapp.framework.session.TabPersistedStateStore
import io.github.kdroidfilter.seforimlibrary.dao.repository.SeforimRepository
import io.github.kdroidfilter.seforimapp.framework.search.LuceneSearchService
import io.github.kdroidfilter.seforimlibrary.search.SearchEngine

/**
* Metro DI graph: provider functions annotated with @Provides.
Expand All @@ -29,7 +29,7 @@ abstract class AppGraph : ViewModelGraph {
abstract val settings: Settings
abstract val categoryDisplaySettingsStore: CategoryDisplaySettingsStore
abstract val repository: SeforimRepository
abstract val luceneSearchService: LuceneSearchService
abstract val searchEngine: SearchEngine
abstract val tabsViewModel: TabsViewModel
abstract val searchHomeViewModel: SearchHomeViewModel

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import io.github.kdroidfilter.seforimapp.framework.database.getUserSettingsDatab
import io.github.kdroidfilter.seforimapp.framework.di.AppScope
import io.github.kdroidfilter.seforimapp.framework.session.TabPersistedStateStore
import io.github.kdroidfilter.seforimlibrary.dao.repository.SeforimRepository
import io.github.kdroidfilter.seforimapp.framework.search.LuceneSearchService
import io.github.kdroidfilter.seforimlibrary.search.LuceneSearchEngine
import io.github.kdroidfilter.seforimlibrary.search.SearchEngine
import io.github.kdroidfilter.seforimapp.framework.search.LuceneLookupSearchService
import io.github.kdroidfilter.seforimapp.framework.search.AcronymFrequencyCache
import io.github.kdroidfilter.seforimapp.framework.search.RepositorySnippetSourceProvider
Expand Down Expand Up @@ -65,11 +66,12 @@ object AppCoreBindings {

@Provides
@SingleIn(AppScope::class)
fun provideLuceneSearchService(repository: SeforimRepository): LuceneSearchService {
fun provideSearchEngine(repository: SeforimRepository): SearchEngine {
val dbPath = getDatabasePath()
val indexPath = if (dbPath.endsWith(".db")) "$dbPath.lucene" else "$dbPath.luceneindex"
val snippetSourceProvider = RepositorySnippetSourceProvider(repository)
return LuceneSearchService(Paths.get(indexPath), snippetSourceProvider)
val indexPath = Paths.get(if (dbPath.endsWith(".db")) "$dbPath.lucene" else "$dbPath.luceneindex")
val dictionaryPath = indexPath.resolveSibling("lexical.db")
val snippetProvider = RepositorySnippetSourceProvider(repository)
return LuceneSearchEngine(indexPath, snippetProvider, dictionaryPath = dictionaryPath)
}

@Provides
Expand Down Expand Up @@ -107,14 +109,14 @@ object AppCoreBindings {
tabsViewModel: TabsViewModel,
persistedStore: TabPersistedStateStore,
repository: SeforimRepository,
lucene: LuceneSearchService,
searchEngine: SearchEngine,
lookup: LuceneLookupSearchService,
settings: Settings
): SearchHomeViewModel = SearchHomeViewModel(
tabsViewModel = tabsViewModel,
persistedStore = persistedStore,
repository = repository,
lucene = lucene,
searchEngine = searchEngine,
lookup = lookup,
settings = settings
)
Expand Down
Loading
Loading