AgentSkillsCN

search-guides

搜索应用分步指南——新增提供者(5 步)、添加设置(4 步)、添加设置界面(5 步)、Room 数据库迁移、常见文件路径表、命名规范、包结构组织,以及所采用的设计模式。

SKILL.md
--- frontmatter
name: search-guides
description: Search app step-by-step guides - adding new providers (5 steps), adding settings (4 steps), adding settings screens (5 steps), Room database migrations, common file locations table, naming conventions, package organization, and design patterns used.

Quick Reference Guides

Adding a New Provider

Step 1: Create Provider Class

code
app/src/main/java/com/mrndstvndv/search/provider/{type}/{Name}Provider.kt

Step 2: Implement Provider Interface

kotlin
class NewProvider(
    private val context: Context,
    private val settingsRepository: ProviderSettingsRepository
) : Provider {
    
    override val id = "new-provider"
    override val displayName = "New Provider"
    override val refreshSignal = MutableSharedFlow<Unit>()
    
    override fun initialize() { /* Heavy setup */ }
    
    override fun canHandle(query: Query): Boolean {
        return query.text.isNotBlank()
    }
    
    override suspend fun query(query: Query): List<ProviderResult> {
        // Return search results
    }
    
    override fun dispose() { /* Cleanup */ }
}

Step 3: Register in MainActivity (~line 150)

kotlin
val providers = remember {
    listOf(
        // ... existing providers
        NewProvider(context, settingsRepository)
    )
}

Step 4: Add Toggle in ProvidersSettingsScreen

kotlin
SettingsSwitch(
    title = "New Provider",
    checked = isEnabled,
    onCheckedChange = { /* save state */ }
)

Step 5: Add to DEFAULT_PROVIDER_ORDER

In ProviderRankingRepository:

kotlin
private val DEFAULT_PROVIDER_ORDER = listOf(
    // ... existing IDs
    "new-provider"
)

Adding a New Setting

Step 1: Add Key Constant

In ProviderSettingsRepository:

kotlin
private const val KEY_NEW_SETTING = "new_setting"

Step 2: Add StateFlow

kotlin
private val _newSetting = MutableStateFlow(loadNewSetting())
val newSetting: StateFlow<Boolean> = _newSetting.asStateFlow()

Step 3: Add Load/Save Methods

kotlin
private fun loadNewSetting(): Boolean {
    return prefs.getBoolean(KEY_NEW_SETTING, true)
}

fun setNewSetting(value: Boolean) {
    prefs.edit().putBoolean(KEY_NEW_SETTING, value).apply()
    _newSetting.value = value
}

Step 4: Add UI

In the appropriate settings screen:

kotlin
val newSetting by settingsRepository.newSetting.collectAsState()

SettingsSwitch(
    title = "New Setting",
    description = "Description of what this does",
    checked = newSetting,
    onCheckedChange = { settingsRepository.setNewSetting(it) }
)

Adding a New Settings Screen

Step 1: Create Screen File

code
app/src/main/java/com/mrndstvndv/search/ui/settings/NewSettingsScreen.kt

Step 2: Implement Composable

kotlin
@Composable
fun NewSettingsScreen(
    settingsRepository: ProviderSettingsRepository,
    onNavigateBack: () -> Unit
) {
    Column {
        // Back button header
        TopAppBar(
            title = { Text("New Settings") },
            navigationIcon = {
                IconButton(onClick = onNavigateBack) {
                    Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back")
                }
            }
        )
        
        // Settings content
        SettingsGroup(title = "Section") {
            // Settings components...
        }
    }
}

Step 3: Add to Screen Enum

In SettingsActivity.kt:

kotlin
private enum class Screen {
    // ... existing screens
    NewScreen
}

Step 4: Add Navigation Case

kotlin
Screen.NewScreen -> NewSettingsScreen(
    settingsRepository = settingsRepository,
    onNavigateBack = { currentScreen = Screen.Home }
)

Step 5: Add Navigation Row

In parent screen:

kotlin
SettingsNavigationRow(
    title = "New Settings",
    onClick = { onNavigate(Screen.NewScreen) }
)

Database Migrations (Room)

Step 1: Update Entity

In provider/files/index/:

kotlin
@Entity(tableName = "files")
data class FileEntity(
    @PrimaryKey val path: String,
    val name: String,
    val newColumn: String = ""  // Add new field
)

Step 2: Add Migration

In FileSearchDatabase:

kotlin
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL(
            "ALTER TABLE files ADD COLUMN newColumn TEXT NOT NULL DEFAULT ''"
        )
    }
}

Step 3: Increment Version and Add Migration

kotlin
@Database(entities = [FileEntity::class], version = 2)
abstract class FileSearchDatabase : RoomDatabase() {
    companion object {
        fun getInstance(context: Context) = Room.databaseBuilder(...)
            .addMigrations(MIGRATION_1_2)
            .build()
    }
}

Common File Locations

TaskLocation
Add new providerprovider/{type}/{Name}Provider.kt
Add provider settingssettings/ProviderSettingsRepository.kt
Add settings UIui/settings/{Name}SettingsScreen.kt
Add reusable componentui/components/{ComponentName}.kt
Modify themeui/theme/Theme.kt, Color.kt, Type.kt
Add permissionAndroidManifest.xml
Add dependencygradle/libs.versions.toml + app/build.gradle.kts
Modify file search indexprovider/files/index/

Naming Conventions

TypeConventionExample
Providers*Provider.ktAppListProvider.kt
Repositories*Repository.ktAliasRepository.kt
Settings Data*SettingsWebSearchSettings
ComposablesPascalCase functionsSearchField()
Screen files*Screen.ktGeneralSettingsScreen.kt
State variablescamelCase with prefixisLoading, hasError

Package Organization

code
provider/
├── Provider.kt           # Base interface
├── ProviderResult.kt     # Result model
├── model/                # Shared models (Query, etc.)
├── {type}/               # Provider implementation
│   ├── {Type}Provider.kt
│   └── {Type}Repository.kt (if needed)

ui/
├── theme/                # Design system
├── components/           # Reusable components
│   └── settings/         # Settings-specific components
└── settings/             # Settings screens

settings/                 # Non-UI settings utilities
├── ProviderSettingsRepository.kt
└── ProviderRankingRepository.kt

Design Patterns Used

PatternUsageLocation
Provider PatternUnified search source abstractionprovider/Provider.kt
Repository PatternData access abstraction*Repository.kt files
Singleton PatternHeavy shared resourcesFileSearchRepository
Observer PatternReactive settings via StateFlowAll repositories
Sealed ClassesType-safe result/target hierarchiesAliasTarget, ProviderResult
Fuzzy MatchingRaycast-style character matchingFuzzyMatcher.kt

Related Skills

  • search-overview - Project structure and architecture
  • search-provider - Provider interface details
  • search-repository - Repository patterns
  • search-ui - UI components and navigation
  • search-build - Build configuration