- 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
121 lines
4.0 KiB
Kotlin
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()
|
|
}
|
|
}
|