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
Expand Up @@ -21,7 +21,7 @@ internal class DebugPanelInstance(
private var pluginManager: PluginManager? = null
private val eventLiveData: MutableLiveData<DebugEvent> = MutableLiveData()
private val eventSharedFlow: MutableSharedFlow<DebugEvent> = MutableSharedFlow(
extraBufferCapacity = 1,
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
private val themeDataStore by lazy {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.redmadrobot.debug.plugin.aboutapp

import android.content.Context
import java.util.UUID

/**
* No-op declaration of [AboutAppAction] for release builds.
*/
@Suppress("UnusedPrivateProperty")
public sealed interface AboutAppAction {
public val id: String
public val title: String

public class Direct(
override val title: String,
public val onClick: (Context) -> Unit,
override val id: String = UUID.randomUUID().toString(),
) : AboutAppAction

public class Event(
override val title: String,
override val id: String = UUID.randomUUID().toString(),
) : AboutAppAction
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ package com.redmadrobot.debug.plugin.aboutapp
*/
@Suppress("UnusedPrivateProperty")
public class AboutAppPlugin(
private val appInfoList: List<AboutAppInfo>
private val appInfoList: List<AboutAppInfo>,
private val actions: List<AboutAppAction> = emptyList(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,41 @@ import androidx.compose.runtime.Composable
import com.redmadrobot.debug.core.internal.CommonContainer
import com.redmadrobot.debug.core.internal.PluginDependencyContainer
import com.redmadrobot.debug.core.plugin.Plugin
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppAction
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.
* Accepts an arbitrary list of "title -- value" pairs which will be shown as a list,
* plus an optional list of custom action buttons rendered below the info section.
*
* @param appInfoList list of information entries to display.
* Must contain at least one element.
* @throws IllegalStateException if [appInfoList] is empty
* @param actions list of custom action buttons rendered below the info section.
* @throws IllegalStateException if both [appInfoList] and [actions] are empty
*
* @see AboutAppInfo
* @see AboutAppAction
*/
public class AboutAppPlugin(
private val appInfoList: List<AboutAppInfo>
private val appInfoList: List<AboutAppInfo>,
private val actions: List<AboutAppAction> = emptyList(),
) : Plugin() {
init {
appInfoList.firstOrNull()
?: error("AboutAppPlugin can't be initialized. At least one information block must be set.")
check(appInfoList.isNotEmpty() || actions.isNotEmpty()) {
"AboutAppPlugin can't be initialized. " +
"At least one information block or one action must be set."
}
}

override fun getPluginContainer(commonContainer: CommonContainer): PluginDependencyContainer {
return AboutAppPluginContainer(appInfoList = appInfoList, commonContainer = commonContainer)
return AboutAppPluginContainer(
appInfoList = appInfoList,
actions = actions,
commonContainer = commonContainer,
pushEvent = ::pushEvent,
)
}

override fun getName(): String = NAME
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
package com.redmadrobot.debug.plugin.aboutapp

import com.redmadrobot.debug.core.DebugEvent
import com.redmadrobot.debug.core.internal.CommonContainer
import com.redmadrobot.debug.core.internal.PluginDependencyContainer
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppAction
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppInfo
import com.redmadrobot.debug.plugin.aboutapp.ui.AboutAppViewModel
import com.redmadrobot.debug.plugin.aboutapp.utils.ClipboardProvider

internal class AboutAppPluginContainer(
private val appInfoList: List<AboutAppInfo>,
private val commonContainer: CommonContainer
private val actions: List<AboutAppAction>,
private val commonContainer: CommonContainer,
private val pushEvent: (DebugEvent) -> Unit,
) : PluginDependencyContainer {
fun createAboutAppViewModel(): AboutAppViewModel {
val clipboardProvider = ClipboardProvider(context = commonContainer.context)

return AboutAppViewModel(appInfoList = appInfoList, clipboardProvider = clipboardProvider)
return AboutAppViewModel(
appInfoList = appInfoList,
actions = actions,
context = commonContainer.context,
clipboardProvider = clipboardProvider,
pushEvent = pushEvent,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.redmadrobot.debug.plugin.aboutapp.model

import android.content.Context
import com.redmadrobot.debug.core.DebugEvent
import com.redmadrobot.debug.plugin.aboutapp.AboutAppPlugin
import java.util.UUID

/**
* Custom action button displayed in [AboutAppPlugin] under the application info section.
*
* Library consumers should use [Event]: clicks are published on the debug panel event bus as the provided [DebugEvent].
*
* [Direct] is intended for the library's own built-in actions that can be handled with application context only (e.g., copy a token, clear cache).
* It is not part of the recommended public usage — prefer [Event] in application code.
*/
public sealed interface AboutAppAction {
/**
* Stable identifier used as a `LazyColumn` key. Auto-generated by default;
* override only if you need a deterministic key (e.g., for UI tests).
*/
public val id: String

/** Button label. */
public val title: String

/**
* Library-internal action whose [onClick] handler is invoked directly inside the plugin with the application context.
* Reserved for built-in actions shipped with the library. Application code should use [Event] instead.
*/
public class Direct(
override val title: String,
public val onClick: (Context) -> Unit,
override val id: String = UUID.randomUUID().toString(),
) : AboutAppAction

/**
* Action that, when clicked, publishes [debugEvent] on the debug panel event bus.
*/
public class Event(
override val title: String,
public val debugEvent: DebugEvent,
override val id: String = UUID.randomUUID().toString(),
) : AboutAppAction
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import com.redmadrobot.debug.plugin.aboutapp.R
import com.redmadrobot.debug.uikit.theme.DebugPanelShapes
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme

private const val ITEM_ACTIONS_HEADER_KEY = "actions_header"

@Composable
internal fun AboutAppScreen(
viewModel: AboutAppViewModel = provideViewModel {
Expand Down Expand Up @@ -75,6 +77,18 @@ internal fun AboutAppScreen(
},
)
}

if (state.actions.isNotEmpty()) {
item(key = ITEM_ACTIONS_HEADER_KEY) {
AboutAppActionsHeader()
}
items(items = state.actions, key = { it.id }) { action ->
AboutAppAction(
title = action.title,
onActionClick = { viewModel.onActionClicked(action) }
)
}
}
}
}
}
Expand Down Expand Up @@ -112,3 +126,33 @@ private fun InfoRow(
)
}
}

@Composable
private fun AboutAppActionsHeader(modifier: Modifier = Modifier) {
Text(
text = stringResource(id = R.string.about_app_actions_title),
style = DebugPanelTheme.typography.labelLarge,
color = DebugPanelTheme.colors.content.tertiary,
modifier = modifier
.fillMaxWidth()
.padding(top = 20.dp, bottom = 8.dp)
.padding(horizontal = 12.dp),
)
}

@Composable
private fun AboutAppAction(
title: String,
onActionClick: () -> Unit,
modifier: Modifier = Modifier
) {
Text(
modifier = modifier
.padding(horizontal = 12.dp, vertical = 8.dp)
.clickable { onActionClick.invoke() },
text = title,
overflow = TextOverflow.Ellipsis,
style = DebugPanelTheme.typography.bodyLarge,
color = DebugPanelTheme.colors.content.accent,
)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.redmadrobot.debug.plugin.aboutapp.ui

import android.content.Context
import androidx.lifecycle.viewModelScope
import com.redmadrobot.debug.core.DebugEvent
import com.redmadrobot.debug.core.internal.PluginViewModel
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppAction
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppInfo
import com.redmadrobot.debug.plugin.aboutapp.utils.ClipboardProvider
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -15,9 +17,14 @@ import kotlinx.coroutines.launch

internal class AboutAppViewModel(
appInfoList: List<AboutAppInfo>,
actions: List<AboutAppAction>,
private val context: Context,
private val clipboardProvider: ClipboardProvider,
private val pushEvent: (DebugEvent) -> Unit,
) : PluginViewModel() {
private val _state = MutableStateFlow(value = AboutAppViewState(appInfoList = appInfoList))
private val _state = MutableStateFlow(
value = AboutAppViewState(appInfoList = appInfoList, actions = actions),
)
val state: StateFlow<AboutAppViewState> = _state.asStateFlow()

private val _events = MutableSharedFlow<AppInfoSelectionEvent>()
Expand All @@ -29,6 +36,13 @@ internal class AboutAppViewModel(
_events.emit(AppInfoSelectionEvent(message = message, item = item))
}
}

fun onActionClicked(action: AboutAppAction) {
when (action) {
is AboutAppAction.Direct -> action.onClick(context)
is AboutAppAction.Event -> pushEvent(action.debugEvent)
}
}
}

internal data class AppInfoSelectionEvent(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.redmadrobot.debug.plugin.aboutapp.ui

import androidx.compose.runtime.Immutable
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppAction
import com.redmadrobot.debug.plugin.aboutapp.model.AboutAppInfo

@Immutable
internal data class AboutAppViewState(
val appInfoList: List<AboutAppInfo>
val appInfoList: List<AboutAppInfo>,
val actions: List<AboutAppAction>,
)
1 change: 1 addition & 0 deletions plugins/plugin-about-app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about_app_copied">«%s» is copied</string>
<string name="about_app_actions_title">Debug actions</string>
</resources>
Loading