Skip to content

Commit

Permalink
Implemented copy feature (#1300)
Browse files Browse the repository at this point in the history
* Implemented copy feature

* Fixed : linting issues

* Fixed : detekt issues

* Implemented copy feature for request

* change copy icon color

* Change copy icon color

* refactor variable names

* refactor variable onCopyResp name
  • Loading branch information
A7ak authored Dec 8, 2024
1 parent 3e078d4 commit 8a65651
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.core.text.getSpans
import androidx.recyclerview.widget.RecyclerView
import com.chuckerteam.chucker.R
import com.chuckerteam.chucker.databinding.ChuckerTransactionItemBodyLineBinding
import com.chuckerteam.chucker.databinding.ChuckerTransactionItemCopyBinding
import com.chuckerteam.chucker.databinding.ChuckerTransactionItemHeadersBinding
import com.chuckerteam.chucker.databinding.ChuckerTransactionItemImageBinding
import com.chuckerteam.chucker.internal.support.ChessboardDrawable
Expand All @@ -24,7 +25,8 @@ import com.chuckerteam.chucker.internal.support.indicesOf
* We're using a [RecyclerView] to show the content of the body line by line to do not affect
* performances when loading big payloads.
*/
internal class TransactionBodyAdapter : RecyclerView.Adapter<TransactionPayloadViewHolder>() {
internal class TransactionBodyAdapter(private val onCopyBodyListener: () -> Unit) :
RecyclerView.Adapter<TransactionPayloadViewHolder>() {
private val items = arrayListOf<TransactionPayloadItem>()

fun setItems(bodyItems: List<TransactionPayloadItem>) {
Expand Down Expand Up @@ -58,6 +60,12 @@ internal class TransactionBodyAdapter : RecyclerView.Adapter<TransactionPayloadV
TransactionPayloadViewHolder.BodyLineViewHolder(bodyItemBinding)
}

TYPE_COPY -> {
val copyItemBinding =
ChuckerTransactionItemCopyBinding.inflate(inflater, parent, false)
TransactionPayloadViewHolder.CopyViewHolder(copyItemBinding, onCopyBodyListener)
}

else -> {
val imageItemBinding = ChuckerTransactionItemImageBinding.inflate(inflater, parent, false)
TransactionPayloadViewHolder.ImageViewHolder(imageItemBinding)
Expand All @@ -72,6 +80,7 @@ internal class TransactionBodyAdapter : RecyclerView.Adapter<TransactionPayloadV
is TransactionPayloadItem.HeaderItem -> TYPE_HEADERS
is TransactionPayloadItem.BodyLineItem -> TYPE_BODY_LINE
is TransactionPayloadItem.ImageItem -> TYPE_IMAGE
is TransactionPayloadItem.CopyItem -> TYPE_COPY
}
}

Expand Down Expand Up @@ -152,6 +161,7 @@ internal class TransactionBodyAdapter : RecyclerView.Adapter<TransactionPayloadV
private const val TYPE_HEADERS = 1
private const val TYPE_BODY_LINE = 2
private const val TYPE_IMAGE = 3
private const val TYPE_COPY = 4
}

/**
Expand Down Expand Up @@ -188,6 +198,20 @@ internal sealed class TransactionPayloadViewHolder(view: View) : RecyclerView.Vi
}
}

internal class CopyViewHolder(
private val copyBinding: ChuckerTransactionItemCopyBinding,
private val onCopyBodyListener: () -> Unit,
) : TransactionPayloadViewHolder(copyBinding.root) {
override fun bind(item: TransactionPayloadItem) {
if (item is TransactionPayloadItem.CopyItem) {
copyBinding.responseCopy.visibility = View.VISIBLE
copyBinding.responseCopy.setOnClickListener {
onCopyBodyListener.invoke()
}
}
}
}

internal class BodyLineViewHolder(
private val bodyBinding: ChuckerTransactionItemBodyLineBinding,
) : TransactionPayloadViewHolder(bodyBinding.root) {
Expand Down Expand Up @@ -237,6 +261,8 @@ internal sealed class TransactionPayloadViewHolder(view: View) : RecyclerView.Vi
internal sealed class TransactionPayloadItem {
internal class HeaderItem(val headers: Spanned) : TransactionPayloadItem()

internal class CopyItem(val copy: String) : TransactionPayloadItem()

internal class BodyLineItem(var line: SpannableStringBuilder) : TransactionPayloadItem()

internal class ImageItem(val image: Bitmap, val luminance: Double?) : TransactionPayloadItem()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package com.chuckerteam.chucker.internal.ui.transaction

import android.annotation.SuppressLint
import android.app.Activity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.graphics.Color
import android.os.Bundle
Expand Down Expand Up @@ -82,7 +84,7 @@ internal class TransactionPayloadFragment :
}

private lateinit var payloadBinding: ChuckerFragmentTransactionPayloadBinding
private val payloadAdapter = TransactionBodyAdapter()
private val payloadAdapter = TransactionBodyAdapter(::copyResponse)

private var backgroundSpanColor: Int = Color.YELLOW
private var foregroundSpanColor: Int = Color.RED
Expand Down Expand Up @@ -151,6 +153,45 @@ internal class TransactionPayloadFragment :
}
}

private fun copyResponse() {
val transaction = viewModel.transaction.value

when (payloadType.name) {
PayloadType.REQUEST.name -> {
transaction?.requestBody?.let { request ->
copyToClipboard(
request,
getString(R.string.chucker_request),
getString(R.string.chucker_request_copied),
)
}
}

PayloadType.RESPONSE.name -> {
transaction?.responseBody?.let { response ->
copyToClipboard(
response,
getString(R.string.chucker_response),
getString(R.string.chucker_response_copied),
)
}
}
}
}

private fun copyToClipboard(
payload: String,
payloadType: String,
toastSuccessMessage: String,
) {
val clipboard = activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(payloadType, payload)
clipboard.setPrimaryClip(clip)

Toast.makeText(activity, toastSuccessMessage, Toast.LENGTH_LONG)
.show()
}

private fun onSearchScrollerButtonClick(goNext: Boolean) {
// hide the keyboard if visible
val inputMethodManager = activity?.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
Expand Down Expand Up @@ -407,7 +448,10 @@ internal class TransactionPayloadFragment :
result.add(TransactionPayloadItem.BodyLineItem(SpannableStringBuilder.valueOf(text)))
}

else ->
else -> {
// adding copy item
result.add(TransactionPayloadItem.CopyItem(getString(R.string.chucker_copy_response)))

bodyString.lines().forEach {
result.add(
TransactionPayloadItem.BodyLineItem(
Expand All @@ -419,6 +463,7 @@ internal class TransactionPayloadFragment :
),
)
}
}
}
return@withContext result
}
Expand Down
12 changes: 12 additions & 0 deletions library/src/main/res/drawable/chucker_ic_copy.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="24"
android:viewportHeight="24">

<path
android:fillColor="@color/chucker_copy_icon_color"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z" />

</vector>
17 changes: 17 additions & 0 deletions library/src/main/res/layout/chucker_transaction_item_copy.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="end">

<ImageButton
android:id="@+id/responseCopy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/chucker_doub_grid"
android:layout_marginVertical="@dimen/chucker_half_grid"
android:background="@android:color/transparent"
android:contentDescription="@string/chucker_copy_response"
android:src="@drawable/chucker_ic_copy"/>
</LinearLayout>
3 changes: 3 additions & 0 deletions library/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,7 @@
<string name="chucker_graphql_operation_is_empty"> &lt;No se puede descubrir en nombre de la operación GrahpQL&gt;</string>
<string name="chucker_scroll_buttons_for_search">Botones para desplazarse en los resultados de la búsqueda</string>
<string name="chucker_search_results_title">Resultados de la búsqueda:</string>
<string name="chucker_copy_response">Copiar Respuesta</string>
<string name="chucker_response_copied">Respuesta Copiadad</string>
<string name="chucker_request_copied">Solicitud Copiadad</string>
</resources>
1 change: 1 addition & 0 deletions library/src/main/res/values-night/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@
<color name="chucker_json_elements_color">#777777</color>
<color name="chucker_json_boolean_color">#9FA162</color>

<color name="chucker_copy_icon_color">#CCFFFFFF</color>
</resources>
1 change: 1 addition & 0 deletions library/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@
<color name="chucker_json_elements_color">#474747</color>
<color name="chucker_json_boolean_color">#2F99AA</color>

<color name="chucker_copy_icon_color">#80474747</color>

</resources>
3 changes: 3 additions & 0 deletions library/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,7 @@
<string name="chucker_graphql_operation_is_empty"> &lt;Unable to discover GraphQL operation name&gt;</string>
<string name="chucker_scroll_buttons_for_search">Buttons to scroll the search items</string>
<string name="chucker_search_results_title">Search Results:</string>
<string name="chucker_copy_response">Copy Response</string>
<string name="chucker_response_copied">Response Copied</string>
<string name="chucker_request_copied">Request Copied</string>
</resources>

0 comments on commit 8a65651

Please sign in to comment.