Files
RSSuper/android/src/main/java/com/rssuper/search/SearchService.kt
Michael Freno dd4e184600 Fix critical iOS notification service issues
- Fixed authorization handling in NotificationService
- Removed invalid icon and haptic properties
- Fixed deliveryDate API usage
- Removed invalid presentNotificationRequest call
- Fixed notification trigger initialization
- Simplified notification categories with delegate implementation
- Replaced UNNotificationBadgeManager with UIApplication.shared.applicationIconBadgeNumber
- Eliminated code duplication in badge update logic
- Fixed NotificationPreferencesStore JSON encoding/decoding
2026-03-30 23:54:39 -04:00

121 lines
4.0 KiB
Kotlin

package com.rssuper.search
import com.rssuper.database.daos.FeedItemDao
import com.rssuper.database.daos.SearchHistoryDao
import com.rssuper.database.entities.SearchHistoryEntity
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
/**
* SearchService - Provides search functionality with FTS
*/
class SearchService(
private val feedItemDao: FeedItemDao,
private val searchHistoryDao: SearchHistoryDao,
private val resultProvider: SearchResultProvider
) {
private data class CacheEntry(val results: List<SearchResult>, val timestamp: Long)
private val cache = object : LinkedHashMap<String, CacheEntry>(maxCacheSize, 0.75f, true) {
override fun removeEldestEntry(eldest: MutableEntry<String, CacheEntry>?): Boolean {
return size > maxCacheSize ||
eldest?.value?.let { isCacheEntryExpired(it) } ?: false
}
}
private val maxCacheSize = 100
private val cacheExpirationMs = 5 * 60 * 1000L // 5 minutes
private fun isCacheEntryExpired(entry: CacheEntry): Boolean {
return System.currentTimeMillis() - entry.timestamp > cacheExpirationMs
}
private fun cleanExpiredCacheEntries() {
val expiredKeys = cache.entries.filter { isCacheEntryExpired(it.value) }.map { it.key }
expiredKeys.forEach { cache.remove(it) }
}
fun search(query: String): Flow<List<SearchResult>> {
val validation = SearchResultProvider.validateQuery(query)
if (validation.isFailure) {
return flow { emit(emptyList()) }
}
val cacheKey = query.hashCode().toString()
// Clean expired entries periodically
if (cache.size > maxCacheSize / 2) {
cleanExpiredCacheEntries()
}
// Return cached results if available and not expired
cache[cacheKey]?.let { entry ->
if (!isCacheEntryExpired(entry)) {
return flow { emit(entry.results) }
}
}
return flow {
val result = resultProvider.search(query)
val results = result.getOrDefault(emptyList())
cache[cacheKey] = CacheEntry(results, System.currentTimeMillis())
emit(results)
}
}
fun searchBySubscription(query: String, subscriptionId: String): Flow<List<SearchResult>> {
val validation = SearchResultProvider.validateQuery(query)
if (validation.isFailure) {
return flow { emit(emptyList()) }
}
return flow {
val result = resultProvider.searchBySubscription(query, subscriptionId)
emit(result.getOrDefault(emptyList()))
}
}
suspend fun searchAndSave(query: String): List<SearchResult> {
val validation = SearchResultProvider.validateQuery(query)
if (validation.isFailure) {
return emptyList()
}
val result = resultProvider.search(query)
val results = result.getOrDefault(emptyList())
// Save to search history
saveSearchHistory(query)
return results
}
suspend fun saveSearchHistory(query: String) {
val searchHistory = SearchHistoryEntity(
id = System.currentTimeMillis().toString(),
query = query,
filtersJson = null,
timestamp = System.currentTimeMillis()
)
searchHistoryDao.insertSearchHistory(searchHistory)
}
fun getSearchHistory(): Flow<List<SearchHistoryEntity>> {
return searchHistoryDao.getAllSearchHistory()
}
suspend fun getRecentSearches(limit: Int = 10): List<SearchHistoryEntity> {
return searchHistoryDao.getRecentSearches(limit).firstOrNull() ?: emptyList()
}
suspend fun clearSearchHistory() {
searchHistoryDao.deleteAllSearchHistory()
}
fun getSearchSuggestions(query: String): Flow<List<SearchHistoryEntity>> {
return searchHistoryDao.searchHistory(query)
}
fun clearCache() {
cache.clear()
}
}