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 @@ -185,6 +185,7 @@ class ActivityLogDetailFragment : Fragment(R.layout.activity_log_item_detail) {
setActorIcon(activityLogModel?.actorIconUrl, activityLogModel?.showJetpackIcon)
uiHelpers.setTextOrHide(activityActorName, activityLogModel?.actorName)
uiHelpers.setTextOrHide(activityActorRole, activityLogModel?.actorRole)
uiHelpers.setTextOrHide(activityActorMetadata, activityLogModel?.actorMetadata)

val spannable = activityLogModel?.content?.let {
notificationsUtilsWrapper.getSpannableContentForRanges(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ data class ActivityLogDetailModel(
val isRewindButtonVisible: Boolean,
val actorName: String? = null,
val actorRole: String? = null,
val actorMetadata: String? = null,
val content: FormattableContent? = null,
val summary: String? = null,
val createdDate: String = "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ class ActivityLogAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ActivityLogViewHolder {
return when (viewType) {
ViewType.PROGRESS.id -> ProgressItemViewHolder(parent)
ViewType.EVENT.id -> EventItemViewHolder(parent, itemClickListener, secondaryActionClickListener)
ViewType.EVENT.id -> EventItemViewHolder(
parent, itemClickListener, secondaryActionClickListener, uiHelpers
)
ViewType.HEADER.id -> HeaderItemViewHolder(parent)
ViewType.FOOTER.id -> FooterItemViewHolder(parent)
ViewType.LOADING.id -> LoadingItemViewHolder(parent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ sealed class ActivityLogListItem(val type: ViewType) {
val date: Date,
override val isButtonVisible: Boolean,
val buttonIcon: Icon,
val isRestoreHidden: Boolean
val isRestoreHidden: Boolean,
val actorMetadata: String? = null
) : ActivityLogListItem(EVENT), IActionableItem {
val formattedDate: String = date.toFormattedDateString()
val icon = Icon.fromValue(gridIcon)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,23 @@ import android.widget.TextView
import org.wordpress.android.R
import org.wordpress.android.ui.activitylog.list.ActivityLogListItem.Event
import org.wordpress.android.ui.activitylog.list.ActivityLogListItem.SecondaryAction
import org.wordpress.android.ui.utils.UiHelpers
import org.wordpress.android.util.ColorUtils
import org.wordpress.android.util.extensions.getColorResIdFromAttribute

class EventItemViewHolder(
parent: ViewGroup,
private val itemClickListener: (ActivityLogListItem) -> Unit,
private val secondaryActionClickListener: (SecondaryAction, ActivityLogListItem) -> Boolean
private val secondaryActionClickListener: (SecondaryAction, ActivityLogListItem) -> Boolean,
private val uiHelpers: UiHelpers
) : ActivityLogViewHolder(parent, R.layout.activity_log_list_event_item) {
private val summary: TextView = itemView.findViewById(R.id.action_summary)
private val text: TextView = itemView.findViewById(R.id.action_text)
private val thumbnail: ImageView = itemView.findViewById(R.id.action_icon)
private val container: View = itemView.findViewById(R.id.activity_content_container)
private val actionButton: ImageButton = itemView.findViewById(R.id.action_button)
private val metadataSeparator: TextView = itemView.findViewById(R.id.action_metadata_separator)
private val metadata: TextView = itemView.findViewById(R.id.action_metadata)

override fun updateChanges(bundle: Bundle) {
if (bundle.containsKey(ActivityLogDiffCallback.LIST_ITEM_BUTTON_VISIBILITY_KEY)) {
Expand All @@ -41,6 +45,11 @@ class EventItemViewHolder(
summary.text = activity.title
text.text = activity.description

uiHelpers.setTextOrHide(metadata, activity.actorMetadata)
uiHelpers.updateVisibility(
metadataSeparator, activity.actorMetadata != null
)

ColorUtils.setImageResourceWithTint(
actionButton,
activity.buttonIcon.drawable,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.wordpress.android.viewmodel.activitylog

import org.wordpress.android.R
import org.wordpress.android.fluxc.model.activity.ActivityLogModel
import org.wordpress.android.viewmodel.ResourceProvider

fun ActivityLogModel.ActivityActor.formattedMcpMetadata(
resourceProvider: ResourceProvider
): String? {
val client = mcpClient
return if (isMCPAgent && !client.isNullOrEmpty()) {
resourceProvider.getString(
R.string.activity_log_mcp_agent_label, client
)
} else {
null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class ActivityLogDetailViewModel @Inject constructor(
?.toActivityLogDetailModel()
?.let {
_item.value = it
}?: findAndPostActivityLogItemDetailViaDashboardCardsIfNeeded()
} ?: findAndPostActivityLogItemDetailViaDashboardCardsIfNeeded()
}

private fun findAndPostActivityLogItemDetailViaDashboardCardsIfNeeded() {
Expand All @@ -138,20 +138,23 @@ class ActivityLogDetailViewModel @Inject constructor(
}
}

private fun ActivityLogModel.toActivityLogDetailModel() =
ActivityLogDetailModel(
private fun ActivityLogModel.toActivityLogDetailModel(): ActivityLogDetailModel {
val actorSnapshot = actor
return ActivityLogDetailModel(
activityID = activityID,
rewindId = rewindID,
actorIconUrl = actor?.avatarURL,
showJetpackIcon = actor?.showJetpackIcon(),
actorIconUrl = actorSnapshot?.avatarURL,
showJetpackIcon = actorSnapshot?.showJetpackIcon(),
isRewindButtonVisible = rewindable ?: false,
actorName = actor?.displayName,
actorRole = actor?.role,
actorName = actorSnapshot?.displayName,
actorRole = actorSnapshot?.role,
actorMetadata = actorSnapshot?.formattedMcpMetadata(resourceProvider),
content = content,
summary = summary,
createdDate = published.toFormattedDateString(),
createdTime = published.toFormattedTimeString()
)
}

private fun getMultisiteMessage(): SpannableString {
val clickableText = resourceProvider.getString(R.string.activity_log_visit_our_documentation_page)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,14 @@ class ActivityLogViewModel @Inject constructor(
model = model,
rewindDisabled = withRestoreProgressItem || withBackupDownloadProgressItem,
isRestoreHidden = restoreEvent.isRestoreHidden
)
).let { event ->
val metadata = model.actor?.formattedMcpMetadata(resourceProvider)
if (metadata != null) {
event.copy(actorMetadata = metadata)
} else {
event
}
}
val lastItem = items.lastOrNull() as? ActivityLogListItem.Event
if (lastItem == null || lastItem.formattedDate != currentItem.formattedDate) {
items.add(ActivityLogListItem.Header(currentItem.formattedDate))
Expand Down
14 changes: 12 additions & 2 deletions WordPress/src/main/res/layout/activity_log_item_detail.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@

<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">

<org.wordpress.android.widgets.WPTextView
Expand All @@ -61,6 +60,17 @@
android:textAppearance="?attr/textAppearanceCaption"
tools:text="Administrator" />

<org.wordpress.android.widgets.WPTextView
android:id="@+id/activityActorMetadata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:textAppearance="?attr/textAppearanceCaption"
android:visibility="gone"
tools:text="via Claude"
tools:visibility="visible" />

</LinearLayout>

<LinearLayout
Expand Down
44 changes: 37 additions & 7 deletions WordPress/src/main/res/layout/activity_log_list_event_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,44 @@
android:textAppearance="?attr/textAppearanceSubtitle1"
tools:text="Comment by oguzkocer on Android Studio 3.1 Configuration Issue: I think the bigger problem for me was the lack of make option, so hopefully at least that'll work." />

<org.wordpress.android.widgets.WPTextView
android:id="@+id/action_summary"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceCaption"
tools:text="Comment posted" />
android:orientation="horizontal">

<org.wordpress.android.widgets.WPTextView
android:id="@+id/action_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceCaption"
tools:text="Comment posted" />

<org.wordpress.android.widgets.WPTextView
android:id="@+id/action_metadata_separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:text="@string/activity_log_metadata_separator"
android:textAppearance="?attr/textAppearanceCaption"
android:visibility="gone"
tools:visibility="visible" />

<org.wordpress.android.widgets.WPTextView
android:id="@+id/action_metadata"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceCaption"
android:visibility="gone"
tools:text="via Claude"
tools:visibility="visible" />

</LinearLayout>

</LinearLayout>

Expand Down
3 changes: 3 additions & 0 deletions WordPress/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,9 @@

<!-- activity log -->
<string name="activity_log">Activity Log</string>
<!-- Shows the MCP client used for an activity log entry. %1$s is the client name (e.g. Claude). -->
<string name="activity_log_mcp_agent_label">via %1$s</string>
<string name="activity_log_metadata_separator" translatable="false">\u00B7</string>
<string name="activity_log_icon">Activity icon</string>
<string name="activity_log_event">Event</string>
<string name="activity_log_button">Activity Log action button</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.wordpress.android.BaseUnitTest
import org.wordpress.android.R
import org.wordpress.android.fluxc.Dispatcher
import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.fluxc.model.activity.ActivityLogModel
Expand Down Expand Up @@ -461,6 +463,75 @@ class ActivityLogDetailViewModelTest : BaseUnitTest() {
}
}

@Test
fun `given mcp agent with client, when view model starts, then metadata is shown`() {
val mcpLabel = "via Claude"
val mcpActivity = activityLogModel.copy(
actor = activityLogModel.actor?.copy(
isMCPAgent = true,
mcpClient = "Claude"
)
)
whenever(activityLogStore.getActivityLogForSite(site))
.thenReturn(listOf(mcpActivity))
whenever(
resourceProvider.getString(
eq(R.string.activity_log_mcp_agent_label), any()
)
).thenReturn(mcpLabel)

startViewModel()

assertNotNull(lastEmittedItem)
assertEquals(mcpLabel, lastEmittedItem?.actorMetadata)
}

@Test
fun `given mcp agent with empty client, when view model starts, then metadata is null`() {
val mcpActivity = activityLogModel.copy(
actor = activityLogModel.actor?.copy(
isMCPAgent = true,
mcpClient = ""
)
)
whenever(activityLogStore.getActivityLogForSite(site))
.thenReturn(listOf(mcpActivity))

startViewModel()

assertNotNull(lastEmittedItem)
assertNull(lastEmittedItem?.actorMetadata)
}

@Test
fun `given non-mcp agent with client, when view model starts, then metadata is null`() {
val mcpActivity = activityLogModel.copy(
actor = activityLogModel.actor?.copy(
isMCPAgent = false,
mcpClient = "Claude"
)
)
whenever(activityLogStore.getActivityLogForSite(site))
.thenReturn(listOf(mcpActivity))

startViewModel()

assertNotNull(lastEmittedItem)
assertNull(lastEmittedItem?.actorMetadata)
}

@Test
fun `given no actor, when view model starts, then metadata is null`() {
val noActorActivity = activityLogModel.copy(actor = null)
whenever(activityLogStore.getActivityLogForSite(site))
.thenReturn(listOf(noActorActivity))

startViewModel()

assertNotNull(lastEmittedItem)
assertNull(lastEmittedItem?.actorMetadata)
}

private fun startViewModel(
site: SiteModel = this.site,
activityID: String = this.activityID,
Expand Down
Loading
Loading