ADB-based RIPDPI device/emulator debugging: build/install/launch, logcat filtering, fixture port-forwarding, instrumented tests, crash/ANR triage. Use when debugging on a real device or emulator.
中文简介正在准备中。当前显示原文说明。
RIPDPI's own Compose conventions: ViewModel pattern, Route/Screen split, DataStore->StateFlow, RipDpiThemeTokens. Use for how this app does Compose, not generic Compose API questions (see compose).
中文简介正在准备中。当前显示原文说明。
查看安装方法安装前可以查看交给 AI 代理的指令内容。
RIPDPI uses Jetpack Compose with Material 3 and a sealed-class navigation system. State flows from DataStore through ViewModels to Composables via StateFlow + collectAsStateWithLifecycle().
Diagnostics UI is a current hotspot in this repo. It layers internal UI models over shared diagnostics contracts, exposes stable automation tags through RipDpiTestTags, and routes callback-style actions such as opening Advanced Settings or candidate-detail sheets through screen-level parameters.
DataStore (proto) -> ViewModel (StateFlow + combine) -> Composable (collectAsStateWithLifecycle)
User action -> ViewModel method -> DataStore.updateData { } or ServiceManager.start/stop
One-shot effects -> Channel<Effect> -> receiveAsFlow() -> LaunchedEffect collector
Routes are defined as a sealed class in app/.../ui/navigation/Route.kt.
Route sealed class with route string, @StringRes titleRes, optional iconRoute.topLevel listRoute.all listcomposable(Route.YourRoute.route) { ... } in RipDpiNavHost.ktnavController.navigate(Route.YourRoute.route) { launchSingleTop = true; restoreState = true }launchSingleTop = true and restoreState = true for all navigationsisTopLevelDestination() routesclass ExampleViewModel(application: Application) : AndroidViewModel(application) {
// State: combine multiple sources into single UI state
val uiState: StateFlow<UiState> = combine(
application.settingsStore.data,
_localState,
) { settings, local -> UiState(/*...*/) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), UiState())
// Effects: one-shot events (navigation, snackbar, permission requests)
private val _effects = Channel<Effect>(Channel.BUFFERED)
val effects = _effects.receiveAsFlow()
// Actions: public methods called by Composables
fun onAction() { viewModelScope.launch { /* ... */ } }
}
SharingStarted.WhileSubscribed(5_000) for all StateFlow exportsAndroidViewModel (not plain ViewModel) when DataStore access neededMutex for thread-safe state transitions (see MainViewModel.toggleService)Channel<Effect> for one-shot UI events, collected via LaunchedEffect// Route composable: connects ViewModel to screen
@Composable
fun ExampleRoute(viewModel: ExampleViewModel, navController: NavController) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
ExampleScreen(uiState = uiState, onAction = viewModel::onAction)
}
// Screen composable: pure UI, no ViewModel reference
@Composable
fun ExampleScreen(uiState: UiState, onAction: () -> Unit) { /* ... */ }
collectAsStateWithLifecycle() (not collectAsState())RipDpiThemeTokens for colors, spacing, typography| ViewModel | Location | Purpose |
|---|---|---|
MainViewModel | activities/MainViewModel.kt | Connection state, VPN/proxy toggle, metrics |
ConfigViewModel | activities/ConfigViewModel.kt | Proxy config presets, draft editing, validation |
SettingsViewModel | activities/SettingsViewModel.kt | App settings, theme, DataStore persistence |
DiagnosticsViewModel | activities/DiagnosticsViewModel.kt | Diagnostics scan orchestration, history, export/share state, and strategy-probe presentation |
activities/DiagnosticsUi* support files instead of recomputing report metadata directly in composables.app/src/main/kotlin/com/poyka/ripdpi/ui/testing/RipDpiTestTags.kt for any new externally exercised UI.onOpenAdvancedSettings, onSelectCandidate, and sheet-dismiss actions through Route/Screen parameters rather than letting deep child composables navigate directly.| Mistake | Fix |
|---|---|
Using collectAsState() | Use collectAsStateWithLifecycle() for lifecycle awareness |
| Passing ViewModel to Screen composable | Pass uiState and callbacks; keep Screen stateless |
| Hardcoding colors/spacing | Use RipDpiThemeTokens and Material 3 theme |
Missing WhileSubscribed(5_000) | Required for proper lifecycle handling in all StateFlow exports |
| Creating ViewModel in Composable | Use viewModel() in Route composable or pass from NavHost |
compose (.agents/skills/compose/SKILL.md):
General Jetpack Compose API reference (guidance docs plus a live-fetch index into the
actual androidx source) and the scored RIPDPI Compose quality audit.
Use for questions about how Compose APIs work internally, correct API usage patterns,
recomposition mechanics, Modifier ordering, side-effects, performance, or accessibility.还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
ADB-based RIPDPI device/emulator debugging: build/install/launch, logcat filtering, fixture port-forwarding, instrumented tests, crash/ANR triage. Use when debugging on a real device or emulator.
中文简介正在准备中。当前显示原文说明。
RIPDPI Appium launch-contract reference: start routes and permission/service/data presets. Use when a test launches to the wrong screen or a new automation route is added. General flakiness: appium-test-debug.
中文简介正在准备中。当前显示原文说明。
RIPDPI Appium test authoring: page objects, resource-id locators, assertions, wait tiers. Use when writing a new Appium test or page object, or adding coverage for a new screen.
中文简介正在准备中。当前显示原文说明。
RIPDPI Appium failure triage: flaky tests, locator/session/wait issues, screenshot and element-tree debugging. Use when an Appium test fails or is flaky.
中文简介正在准备中。当前显示原文说明。
Add or modify a GitHub Actions job. Use when editing a file under .github/workflows/. Not for running a workflow locally (local-ci-act) or release signing (release-signing).
中文简介正在准备中。当前显示原文说明。
Conservative review of end-user legal exposure from diagnostics targets and probe hosts, by jurisdiction. Use when shipping or editing diagnostics target lists, probe hosts, or bootstrap endpoints.
中文简介正在准备中。当前显示原文说明。