diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugEvent.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugEvent.kt index 38b7cb61..e3d9df2e 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugEvent.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugEvent.kt @@ -1,3 +1,17 @@ package com.redmadrobot.debug.core +/** + * Marker interface for events emitted by plugins. + * + * Plugins send events via [com.redmadrobot.debug.core.plugin.Plugin.pushEvent], + * consumers subscribe via [DebugPanel.subscribeToEvents] or [DebugPanel.observeEvents]. + * + * Example: + * ``` + * data class ServerSelectedEvent(val server: DebugServer) : DebugEvent + * ``` + * + * @see com.redmadrobot.debug.core.plugin.Plugin.pushEvent + * @see DebugPanel.observeEvents + */ public interface DebugEvent diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugPanel.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugPanel.kt index b659fdfe..7aa98903 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugPanel.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugPanel.kt @@ -12,13 +12,41 @@ import com.redmadrobot.debug.core.util.ApplicationLifecycleHandler import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow +/** + * Main entry point for working with the debug panel. + * + * Before use, [initialize] must be called in [Application.onCreate]. + * + * Initialization example: + * ``` + * DebugPanel.initialize( + * application = this, + * plugins = listOf( + * ServersPlugin(preInstalledServers), + * KonfeaturePlugin(interceptor, konfeature), + * ) + * ) + * ``` + * + * @see Plugin + */ @OptIn(DebugPanelInternal::class) public object DebugPanel { @Volatile private var instance: DebugPanelInstance? = null + + /** Returns `true` if the panel has been initialized via [initialize]. */ public val isInitialized: Boolean get() = instance != null + /** + * Initializes the debug panel with the provided set of plugins. + * + * Must be called **once** in [Application.onCreate]. + * + * @param application the [Application] instance + * @param plugins list of plugins to be displayed in the panel + */ public fun initialize( application: Application, plugins: List, @@ -27,14 +55,32 @@ public object DebugPanel { ApplicationLifecycleHandler(application).start() } + /** + * Subscribes to plugin events with lifecycle binding. + * + * @param lifecycleOwner lifecycle owner (Activity, Fragment) + * @param onEvent callback invoked when an event is received + */ public fun subscribeToEvents(lifecycleOwner: LifecycleOwner, onEvent: (DebugEvent) -> Unit) { instance?.getEventLiveData()?.observe(lifecycleOwner, Observer { onEvent.invoke(it) }) } + /** + * Returns a [Flow] of events from plugins. + * + * If the panel is not initialized, returns an empty Flow. + */ public fun observeEvents(): Flow { return instance?.getEventFlow() ?: emptyFlow() } + /** + * Opens the Activity containing the debug panel. + * + * Does nothing if the panel has not been initialized. + * + * @param activity the Activity from which the panel will be launched + */ public fun showPanel(activity: Activity) { if (isInitialized) { openDebugPanel(activity) diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/annotation/DebugPanelInternal.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/annotation/DebugPanelInternal.kt index 1a34aa25..ec6a654a 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/annotation/DebugPanelInternal.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/annotation/DebugPanelInternal.kt @@ -1,5 +1,12 @@ package com.redmadrobot.debug.core.annotation +/** + * Marks an API as internal to the debug panel. + * + * Entities with this annotation are intended for use only within the library's modules and may change without notice. + * + * Using a marked API outside the library will produce a compilation error. + */ @RequiresOptIn( level = RequiresOptIn.Level.ERROR, message = "This is an internal part of DebugPanel. You shouldn't use it, cause it can be changed in future" diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/data/DebugDataProvider.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/data/DebugDataProvider.kt index 080f503f..a41e5315 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/data/DebugDataProvider.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/data/DebugDataProvider.kt @@ -1,5 +1,22 @@ package com.redmadrobot.debug.core.data +/** + * Functional interface for lazy data supply to plugins. + * + * Allows passing data into a plugin through a provider rather than directly, + * which is useful when data is produced lazily. + * + * Example usage with [com.redmadrobot.debug.plugin.servers.ServersPlugin]: + * ``` + * val provider = DebugDataProvider> { + * listOf(DebugServer("Prod", "https://api.example.com", isDefault = true)) + * } + * ServersPlugin(preInstalledServers = provider) + * ``` + * + * @param T type of provided data + */ public interface DebugDataProvider { + /** Returns data of type [T]. */ public fun provideData(): T } diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/extension/CoroutinesExtension.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/extension/CoroutinesExtension.kt index 3c6d9b6f..e6f44678 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/extension/CoroutinesExtension.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/extension/CoroutinesExtension.kt @@ -6,8 +6,13 @@ import kotlinx.coroutines.launch import timber.log.Timber /** - * Запуск корутины с встроенной обработкой ошибки - * */ + * Launches a coroutine with error handling. + * + * Catches all exceptions except [CancellationException], logs them via Timber. + * + * @param block suspend block to execute + * @param onError callback invoked when an error occurs + */ @Suppress("TooGenericExceptionCaught") public fun CoroutineScope.safeLaunch( block: suspend CoroutineScope.() -> Unit, @@ -26,8 +31,13 @@ public fun CoroutineScope.safeLaunch( } /** - * Запуск корутины с встроенным логированием ошибки - * */ + * Launches a coroutine with error logging. + * + * Equivalent to [safeLaunch] with an empty error handler -- + * exceptions are only logged via Timber. + * + * @param block suspend block to execute + */ public fun CoroutineScope.safeLaunch( block: suspend CoroutineScope.() -> Unit ) { diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/extension/PluginsExt.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/extension/PluginsExt.kt index 6d95bcd3..6813a387 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/extension/PluginsExt.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/extension/PluginsExt.kt @@ -14,6 +14,12 @@ internal fun getAllPlugins(): List { return DebugPanel.getInstance()?.getPluginManager()?.plugins ?: emptyList() } +/** + * Returns the registered plugin of the specified type. + * + * @throws IllegalArgumentException if the plugin is not found in the registry + * @see DebugPanel + */ @DebugPanelInternal public inline fun getPlugin(): T { val plugin = getPlugin(T::class.java.name) diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/CommonContainer.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/CommonContainer.kt index 8de611e1..cf74980c 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/CommonContainer.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/CommonContainer.kt @@ -3,5 +3,13 @@ package com.redmadrobot.debug.core.internal import android.content.Context import com.redmadrobot.debug.core.annotation.DebugPanelInternal +/** + * Container with shared dependencies, available to all plugins. + * + * Passed into [com.redmadrobot.debug.core.plugin.Plugin.getPluginContainer] + * when a plugin is initialized. + * + * @property context application context + */ @DebugPanelInternal public class CommonContainer(public val context: Context) : PluginDependencyContainer diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/EditablePlugin.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/EditablePlugin.kt index ef09c048..99e9dbae 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/EditablePlugin.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/EditablePlugin.kt @@ -4,10 +4,18 @@ import androidx.compose.runtime.Composable import com.redmadrobot.debug.core.annotation.DebugPanelInternal /** - * Plugin that will be displayed when opening the settings + * Interface for plugins providing a settings screen. + * + * A plugin implementing this interface will be displayed + * in the settings section of the debug panel. + * + * @see com.redmadrobot.debug.plugin.servers.ServersPlugin -- example implementation */ @DebugPanelInternal public interface EditablePlugin { + /** + * Composable function rendering the plugin's settings UI. + */ @Suppress("TopLevelComposableFunctions", "ComposableFunctionName") @Composable public fun settingsContent() { diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/PluginDependencyContainer.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/PluginDependencyContainer.kt index 05d32966..4a6072a0 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/PluginDependencyContainer.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/internal/PluginDependencyContainer.kt @@ -2,5 +2,13 @@ package com.redmadrobot.debug.core.internal import com.redmadrobot.debug.core.annotation.DebugPanelInternal +/** + * Marker interface for plugin dependency containers. + * + * Each plugin implements its own container, extending this interface, to hold repositories, interactors, and other dependencies. + * + * @see com.redmadrobot.debug.core.plugin.Plugin.getPluginContainer + * @see CommonContainer + */ @DebugPanelInternal public interface PluginDependencyContainer diff --git a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/plugin/Plugin.kt b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/plugin/Plugin.kt index a8494c92..9375f643 100644 --- a/panel-core/src/main/kotlin/com/redmadrobot/debug/core/plugin/Plugin.kt +++ b/panel-core/src/main/kotlin/com/redmadrobot/debug/core/plugin/Plugin.kt @@ -6,6 +6,18 @@ import com.redmadrobot.debug.core.DebugPanel import com.redmadrobot.debug.core.internal.CommonContainer import com.redmadrobot.debug.core.internal.PluginDependencyContainer +/** + * Base class for all debug panel plugins. + * + * Each plugin is an isolated module with its own UI and dependencies. + * To create a plugin, you need to: + * 1. Extend [Plugin] + * 2. Implement [getName] and [getPluginContainer] + * 3. Override [content] to render the UI + * + * @see DebugPanel.initialize + * @see PluginDependencyContainer + */ public abstract class Plugin { private lateinit var pluginContainer: PluginDependencyContainer @@ -14,18 +26,46 @@ public abstract class Plugin { return this } + /** + * Sends an event to the debug panel's shared event bus. + * + * Subscribers will receive the event via [DebugPanel.subscribeToEvents] or [DebugPanel.observeEvents]. + * + * @param debugEvent event to send + */ public fun pushEvent(debugEvent: DebugEvent) { DebugPanel.getInstance()?.pushEvent(debugEvent) } + /** + * Returns the plugin's dependency container, cast to type [T]. + * + * @throws ClassCastException if the container does not match the requested type + */ public fun getContainer(): T = pluginContainer as T + /** + * Composable function that renders the plugin's main UI in the debug panel. + */ @Suppress("TopLevelComposableFunctions", "ComposableFunctionName") @Composable public open fun content() { } + /** + * Creates and returns the plugin's dependency container. + * + * Called during plugin initialization. Use [commonContainer] to access shared dependencies (e.g., [android.content.Context]). + * + * @param commonContainer container with the panel's shared dependencies + * @return the dependency container for this plugin + */ public abstract fun getPluginContainer(commonContainer: CommonContainer): PluginDependencyContainer + /** + * Returns the plugin's unique name. + * + * Used to identify the plugin in the registry. + */ public abstract fun getName(): String } diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/DebugDataProvider.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/DebugDataProvider.kt index 080f503f..a7064c00 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/DebugDataProvider.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/DebugDataProvider.kt @@ -1,5 +1,8 @@ package com.redmadrobot.debug.core.data +/** + * No-op declaration of [DebugDataProvider] for release builds. + */ public interface DebugDataProvider { public fun provideData(): T } diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/core/DebugEvent.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/core/DebugEvent.kt index f4057a00..6ab28c18 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/core/DebugEvent.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/core/DebugEvent.kt @@ -1,3 +1,6 @@ package com.redmadrobot.debug.core.internal +/** + * No-op declaration of [DebugEvent] for release builds. + */ public interface DebugEvent diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/core/DebugPanel.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/core/DebugPanel.kt index 1390d573..7562bfee 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/core/DebugPanel.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/core/DebugPanel.kt @@ -8,6 +8,11 @@ import com.redmadrobot.debug.core.internal.DebugEvent import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow +/** + * No-op implementation of [DebugPanel] for release builds. + * + * All methods are empty stubs and perform no actions. + */ @Suppress("UnusedParameter", "OptionalUnit") public object DebugPanel { public fun initialize(application: Application, plugins: List): Unit = Unit diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/aboutapp/AboutAppInfo.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/aboutapp/AboutAppInfo.kt index 819dc408..d20a0c9c 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/aboutapp/AboutAppInfo.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/aboutapp/AboutAppInfo.kt @@ -1,5 +1,8 @@ package com.redmadrobot.debug.plugin.aboutapp +/** + * No-op declaration of [AboutAppInfo] for release builds. + */ public data class AboutAppInfo( val title: String, val value: String diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/aboutapp/AboutAppPlugin.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/aboutapp/AboutAppPlugin.kt index 12a446fc..2f7671bc 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/aboutapp/AboutAppPlugin.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/aboutapp/AboutAppPlugin.kt @@ -1,5 +1,10 @@ package com.redmadrobot.debug.plugin.aboutapp +/** + * No-op implementation of [AboutAppPlugin] for release builds. + * + * Performs no actions; only mirrors the public constructor signature. + */ @Suppress("UnusedPrivateProperty") public class AboutAppPlugin( private val appInfoList: List diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/konfeature/KonfeatureDebugPanelInterceptor.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/konfeature/KonfeatureDebugPanelInterceptor.kt index ae2fd343..34e46a23 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/konfeature/KonfeatureDebugPanelInterceptor.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/konfeature/KonfeatureDebugPanelInterceptor.kt @@ -4,6 +4,11 @@ import android.content.Context import com.redmadrobot.konfeature.source.FeatureValueSource import com.redmadrobot.konfeature.source.Interceptor +/** + * No-op implementation of [KonfeatureDebugPanelInterceptor] for release builds. + * + * [intercept] always returns `null`, so no flag overrides are applied. + */ @Suppress("UnusedPrivateProperty") public class KonfeatureDebugPanelInterceptor(context: Context) : Interceptor { override val name: String = "NoopDebugPanelInterceptor" diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/konfeature/KonfeaturePlugin.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/konfeature/KonfeaturePlugin.kt index b1dc8daa..0736427b 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/konfeature/KonfeaturePlugin.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/konfeature/KonfeaturePlugin.kt @@ -2,6 +2,11 @@ package com.redmadrobot.debug.plugin.konfeature import com.redmadrobot.konfeature.Konfeature +/** + * No-op implementation of [KonfeaturePlugin] for release builds. + * + * Performs no actions; only mirrors the public constructor signature. + */ @Suppress("UnusedPrivateProperty") public class KonfeaturePlugin( private val debugPanelInterceptor: KonfeatureDebugPanelInterceptor, diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/DebugServer.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/DebugServer.kt index 13c3b3d7..dce7dad5 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/DebugServer.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/DebugServer.kt @@ -1,5 +1,8 @@ package com.redmadrobot.debug.plugin.servers.data.model +/** + * No-op declaration of [DebugServer] for release builds. + */ public data class DebugServer( val name: String, val url: String, diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/ServerSelectedEvent.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/ServerSelectedEvent.kt index a7860da9..344eb79b 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/ServerSelectedEvent.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/ServerSelectedEvent.kt @@ -3,4 +3,7 @@ package com.redmadrobot.debug.plugin.servers import com.redmadrobot.debug.core.internal.DebugEvent import com.redmadrobot.debug.plugin.servers.data.model.DebugServer +/** + * No-op declaration of [ServerSelectedEvent] for release builds. + */ public data class ServerSelectedEvent(val debugServer: DebugServer) : DebugEvent diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/ServersPlugin.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/ServersPlugin.kt index 5fec7820..084d92ef 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/ServersPlugin.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/ServersPlugin.kt @@ -4,6 +4,11 @@ import com.redmadrobot.debug.core.data.DebugDataProvider import com.redmadrobot.debug.plugin.servers.data.model.DebugServer import java.util.Collections.emptyList +/** + * No-op implementation of [ServersPlugin] for release builds. + * + * Performs no actions; only mirrors the public constructor signatures. + */ public class ServersPlugin( private val preInstalledServers: List = emptyList() ) { diff --git a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/interceptor/DebugServerInterceptor.kt b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/interceptor/DebugServerInterceptor.kt index d8ca1182..815d174a 100644 --- a/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/interceptor/DebugServerInterceptor.kt +++ b/panel-no-op/src/main/kotlin/com/redmadrobot/debug/noop/plugin/servers/interceptor/DebugServerInterceptor.kt @@ -5,6 +5,11 @@ import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response +/** + * No-op implementation of [DebugServerInterceptor] for release builds. + * + * Passes every request through unchanged. + */ public class DebugServerInterceptor : Interceptor { @Suppress("UnusedParameter") public fun modifyRequest(block: (Request, DebugServer) -> Request): DebugServerInterceptor { diff --git a/plugins/plugin-about-app/src/main/kotlin/com/redmadrobot/debug/plugin/aboutapp/AboutAppPlugin.kt b/plugins/plugin-about-app/src/main/kotlin/com/redmadrobot/debug/plugin/aboutapp/AboutAppPlugin.kt index 3b5b0e9d..4e1aa4a9 100644 --- a/plugins/plugin-about-app/src/main/kotlin/com/redmadrobot/debug/plugin/aboutapp/AboutAppPlugin.kt +++ b/plugins/plugin-about-app/src/main/kotlin/com/redmadrobot/debug/plugin/aboutapp/AboutAppPlugin.kt @@ -7,6 +7,18 @@ import com.redmadrobot.debug.core.plugin.Plugin import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppInfo import com.redmadrobot.debug.plugin.aboutapp.ui.AboutAppScreen +/** + * Plugin that displays information about the application in the debug panel. + * + * Accepts an arbitrary list of "title -- value" pairs + * which will be shown as a list. + * + * @param appInfoList list of information entries to display. + * Must contain at least one element. + * @throws IllegalStateException if [appInfoList] is empty + * + * @see AboutAppInfo + */ public class AboutAppPlugin( private val appInfoList: List ) : Plugin() { diff --git a/plugins/plugin-about-app/src/main/kotlin/com/redmadrobot/debug/plugin/aboutapp/model/AboutAppInfo.kt b/plugins/plugin-about-app/src/main/kotlin/com/redmadrobot/debug/plugin/aboutapp/model/AboutAppInfo.kt index dfee542f..ff8d84c3 100644 --- a/plugins/plugin-about-app/src/main/kotlin/com/redmadrobot/debug/plugin/aboutapp/model/AboutAppInfo.kt +++ b/plugins/plugin-about-app/src/main/kotlin/com/redmadrobot/debug/plugin/aboutapp/model/AboutAppInfo.kt @@ -2,6 +2,12 @@ package com.redmadrobot.debug.plugin.aboutapp.model import java.util.UUID +/** + * Information entry for [com.redmadrobot.debug.plugin.aboutapp.AboutAppPlugin]. + * + * @property title parameter name (e.g., "Version", "Build type") + * @property value parameter value (e.g., "1.2.3", "debug") + */ public data class AboutAppInfo( val title: String, val value: String, diff --git a/plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/KonfeatureDebugPanelInterceptor.kt b/plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/KonfeatureDebugPanelInterceptor.kt index 50904f87..27057085 100644 --- a/plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/KonfeatureDebugPanelInterceptor.kt +++ b/plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/KonfeatureDebugPanelInterceptor.kt @@ -18,6 +18,27 @@ import kotlinx.coroutines.sync.withLock import org.json.JSONObject import timber.log.Timber +/** + * [Interceptor] for Konfeature that allows overriding feature flag values through the debug panel. + * + * Overridden values are stored in SharedPreferences and applied each time a flag is read through Konfeature. + * + * Must be passed to the [KonfeaturePlugin] constructor and also registered in Konfeature during its configuration. + * + * Example: + * ``` + * val interceptor = KonfeatureDebugPanelInterceptor(context) + * + * val konfeature = konfeature { + * addInterceptor(interceptor) + * // ... + * } + * + * KonfeaturePlugin(interceptor, konfeature) + * ``` + * + * @param context context for accessing SharedPreferences + */ public class KonfeatureDebugPanelInterceptor(context: Context) : Interceptor { private val preferences by lazy { context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE) diff --git a/plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/KonfeaturePlugin.kt b/plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/KonfeaturePlugin.kt index 5cb65c13..3987ea54 100644 --- a/plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/KonfeaturePlugin.kt +++ b/plugins/plugin-konfeature/src/main/kotlin/com/redmadrobot/debug/plugin/konfeature/KonfeaturePlugin.kt @@ -7,6 +7,17 @@ import com.redmadrobot.debug.core.plugin.Plugin import com.redmadrobot.debug.plugin.konfeature.ui.KonfeatureScreen import com.redmadrobot.konfeature.Konfeature +/** + * Plugin for viewing and overriding feature flags from the Konfeature library. + * + * Allows changing feature flag values at runtime without rebuilding the app. + * Overridden values are stored in SharedPreferences and survive app restarts. + * + * @param debugPanelInterceptor interceptor through which overrides are applied + * @param konfeature Konfeature instance used to obtain the list of features + * + * @see KonfeatureDebugPanelInterceptor + */ public class KonfeaturePlugin( private val debugPanelInterceptor: KonfeatureDebugPanelInterceptor, private val konfeature: Konfeature, diff --git a/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/ServerSelectedEvent.kt b/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/ServerSelectedEvent.kt index a35d0527..d5b72eaa 100644 --- a/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/ServerSelectedEvent.kt +++ b/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/ServerSelectedEvent.kt @@ -3,4 +3,11 @@ package com.redmadrobot.debug.plugin.servers import com.redmadrobot.debug.core.DebugEvent import com.redmadrobot.debug.plugin.servers.data.model.DebugServer +/** + * Event emitted when a server is selected in [ServersPlugin]. + * + * Subscribe via [com.redmadrobot.debug.core.DebugPanel.observeEvents] to react to environment changes. + * + * @property debugServer the selected server + */ public data class ServerSelectedEvent(val debugServer: DebugServer) : DebugEvent diff --git a/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/ServersPlugin.kt b/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/ServersPlugin.kt index b65bbd27..924e503c 100644 --- a/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/ServersPlugin.kt +++ b/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/ServersPlugin.kt @@ -11,6 +11,21 @@ import com.redmadrobot.debug.plugin.servers.data.model.DebugServer import com.redmadrobot.debug.plugin.servers.ui.ServersScreen import kotlinx.coroutines.runBlocking +/** + * Plugin for switching between servers (environments) at runtime. + * + * When a server is selected, a [ServerSelectedEvent] is emitted. + * For automatic URL substitution in OkHttp, use + * [com.redmadrobot.debug.plugin.servers.interceptor.DebugServerInterceptor]. + * + * At least one server in the list must be marked as [DebugServer.isDefault]. + * + * @param preInstalledServers list of pre-installed servers + * @throws IllegalStateException if no server is marked as default + * + * @see com.redmadrobot.debug.plugin.servers.interceptor.DebugServerInterceptor + * @see ServerSelectedEvent + */ public class ServersPlugin( private val preInstalledServers: List = emptyList(), ) : Plugin(), EditablePlugin { @@ -19,6 +34,9 @@ public class ServersPlugin( ?: error("ServersPlugin can't be initialized. At least one server must be default") } + /** + * Alternative constructor accepting a [DebugDataProvider] for lazy supply of the server list. + */ public constructor(preInstalledServers: DebugDataProvider>) : this( preInstalledServers = preInstalledServers.provideData() ) @@ -42,12 +60,25 @@ public class ServersPlugin( public companion object { internal const val NAME = "SERVERS" + /** + * Returns the currently selected server. + * + * Blocking call -- use only off the main thread + * or in places where blocking is acceptable (e.g., an OkHttp interceptor). + * + * @throws IllegalArgumentException if [ServersPlugin] is not registered + */ public fun getSelectedServer(): DebugServer { return runBlocking { getPlugin().getContainer().serversRepository.getSelectedServer() } } + /** + * Returns the server marked as default. + * + * @throws IllegalArgumentException if [ServersPlugin] is not registered + */ public fun getDefaultServer(): DebugServer { return getPlugin().getContainer().serversRepository.getDefault() } diff --git a/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/data/model/DebugServer.kt b/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/data/model/DebugServer.kt index a9c58e74..2a9988c0 100644 --- a/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/data/model/DebugServer.kt +++ b/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/data/model/DebugServer.kt @@ -2,6 +2,13 @@ package com.redmadrobot.debug.plugin.servers.data.model import kotlinx.serialization.Serializable +/** + * Server (environment) model for [com.redmadrobot.debug.plugin.servers.ServersPlugin]. + * + * @property name display name of the server + * @property url base URL of the server (e.g., `https://api.example.com`) + * @property isDefault `true` if the server is used by default. + */ @Serializable public data class DebugServer( val name: String, diff --git a/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/interceptor/DebugServerInterceptor.kt b/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/interceptor/DebugServerInterceptor.kt index f41046b6..2f84d80f 100644 --- a/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/interceptor/DebugServerInterceptor.kt +++ b/plugins/plugin-servers/src/main/kotlin/com/redmadrobot/debug/plugin/servers/interceptor/DebugServerInterceptor.kt @@ -12,6 +12,22 @@ import okhttp3.Request import okhttp3.Response import java.net.URI +/** + * OkHttp [Interceptor] that replaces the host and scheme of requests + * with values of the currently selected server from [ServersPlugin]. + * + * If the debug panel is not initialized, requests pass through unchanged. + * + * Example wiring: + * ``` + * OkHttpClient.Builder() + * .addInterceptor(DebugServerInterceptor()) + * .build() + * ``` + * + * @see ServersPlugin + * @see DebugServer + */ public class DebugServerInterceptor : Interceptor { private var requestModifier: ((Request, DebugServer) -> Request?)? = null @@ -22,8 +38,13 @@ public class DebugServerInterceptor : Interceptor { } /** - * Additional request modification - * */ + * Adds an additional request modification after the host substitution. + * + * Allows, for example, adding headers specific to a particular server. + * + * @param block modification function taking the current request and the selected server + * @return this interceptor for call chaining (builder pattern) + */ public fun modifyRequest(block: (Request, DebugServer) -> Request): DebugServerInterceptor { this.requestModifier = block return this