Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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<Plugin>,
Expand All @@ -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<DebugEvent> {
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -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<List<DebugServer>> {
* listOf(DebugServer("Prod", "https://api.example.com", isDefault = true))
* }
* ServersPlugin(preInstalledServers = provider)
* ```
*
* @param T type of provided data
*/
public interface DebugDataProvider<T> {
/** Returns data of type [T]. */
public fun provideData(): T
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ internal fun getAllPlugins(): List<Plugin> {
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 <reified T : Plugin> getPlugin(): T {
val plugin = getPlugin(T::class.java.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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 <T> 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
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.redmadrobot.debug.core.data

/**
* No-op declaration of [DebugDataProvider] for release builds.
*/
public interface DebugDataProvider<T> {
public fun provideData(): T
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
package com.redmadrobot.debug.core.internal

/**
* No-op declaration of [DebugEvent] for release builds.
*/
public interface DebugEvent
Original file line number Diff line number Diff line change
Expand Up @@ -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<Any>): Unit = Unit
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<AboutAppInfo>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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<Any> = emptyList()
) {
Expand Down
Loading
Loading