From 68764c58a9cba7adc84bab3c11cc172cfd00bec2 Mon Sep 17 00:00:00 2001 From: pokeum <102505472+pokeum@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:04:59 +0900 Subject: [PATCH 1/3] add custom color --- app/build.gradle | 3 +- .../activity/JsonViewerActivity.kt | 3 +- .../adapter/BaseJsonViewerAdapter.kt | 29 +++++++++++++++++++ .../adapter/JsonViewerAdapter.kt | 2 +- .../pokeum/jsonviewer_xml/util/SpansUtils.kt | 9 +++--- .../pokeum/jsonviewer_xml/util/StyleUtils.kt | 17 +++++++++++ .../viewholder/JsonArrayViewHolder.kt | 13 +++++++++ .../viewholder/JsonNullViewHolder.kt | 8 +++++ .../viewholder/JsonObjectViewHolder.kt | 13 +++++++++ .../viewholder/JsonPrimitiveViewHolder.kt | 8 +++++ .../src/main/res/layout/item_json_array.xml | 3 +- .../src/main/res/layout/item_json_object.xml | 3 +- .../src/main/res/values-night/colors.xml | 3 -- jsonviewer/src/main/res/values/colors.xml | 3 -- 14 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/adapter/BaseJsonViewerAdapter.kt create mode 100644 jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/util/StyleUtils.kt diff --git a/app/build.gradle b/app/build.gradle index 4d3a949..75e08f5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -59,7 +59,8 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) - implementation 'com.github.pokeum:jsonviewer-xml:0.0.0' + //implementation 'com.github.pokeum:jsonviewer-xml:0.0.0' + implementation(project(":jsonviewer")) implementation stdlib.kotlin implementation androidx.core diff --git a/app/src/main/java/kr/pokeum/app/presentation/activity/JsonViewerActivity.kt b/app/src/main/java/kr/pokeum/app/presentation/activity/JsonViewerActivity.kt index 1e50df8..bd31a0c 100644 --- a/app/src/main/java/kr/pokeum/app/presentation/activity/JsonViewerActivity.kt +++ b/app/src/main/java/kr/pokeum/app/presentation/activity/JsonViewerActivity.kt @@ -41,7 +41,8 @@ class JsonViewerActivity : AppCompatActivity() { private fun initRecyclerView() { jsonElement?.let { - binding.jsonRecyclerView.adapter = JsonViewerAdapter(it) + val adapter = JsonViewerAdapter(it) + binding.jsonRecyclerView.adapter = adapter } } diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/adapter/BaseJsonViewerAdapter.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/adapter/BaseJsonViewerAdapter.kt new file mode 100644 index 0000000..6bd4df0 --- /dev/null +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/adapter/BaseJsonViewerAdapter.kt @@ -0,0 +1,29 @@ +package kr.pokeum.jsonviewer_xml.adapter + +import androidx.recyclerview.widget.RecyclerView +import kr.pokeum.jsonviewer_xml.util.JVColor + +abstract class BaseJsonViewerAdapter : RecyclerView.Adapter() +{ +// abstract fun expandAll() +// abstract fun collapseAll() + + fun setKeyColor(color: JVColor) { KEY_COLOR = color } + fun setValueColor(color: JVColor) { VALUE_COLOR = color } + fun setSplitterColor(color: JVColor) { SPLITTER_COLOR = color } + fun setTypeColor(color: JVColor) { TYPE_COLOR = color } + fun setArrowColor(color: JVColor) { ARROW_COLOR = color } + fun setBracketColor(color: JVColor) { BRACKET_COLOR = color } + fun setDividerColor(color: JVColor) { DIVIDER_COLOR = color } + + companion object { + internal var KEY_COLOR = JVColor(0xFF000000.toInt(), 0xFFFFFFFF.toInt()) + internal var VALUE_COLOR = JVColor(0xFF888888.toInt()) + internal var SPLITTER_COLOR = JVColor(0xFF000000.toInt(), 0xFFFFFFFF.toInt()) + internal var TYPE_COLOR = JVColor(0xFF2196F3.toInt()) + internal var ARROW_COLOR = JVColor(0xFFF44336.toInt()) + internal var BRACKET_COLOR = JVColor(0xFF4CAF50.toInt()) + internal var DIVIDER_COLOR = JVColor(0x1E000000.toInt(), 0x1EFFFFFF.toInt()) + } +} + diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/adapter/JsonViewerAdapter.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/adapter/JsonViewerAdapter.kt index 00a78ec..c75f6c8 100644 --- a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/adapter/JsonViewerAdapter.kt +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/adapter/JsonViewerAdapter.kt @@ -19,7 +19,7 @@ import kr.pokeum.jsonviewer_xml.viewholder.JsonPrimitiveViewHolder class JsonViewerAdapter( jsonElement: JsonElement? = null, recyclerViewPool: RecyclerView.RecycledViewPool? = null -) : RecyclerView.Adapter() { +) : BaseJsonViewerAdapter() { private val elements: MutableList private val recyclerViewPool: RecyclerView.RecycledViewPool diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/util/SpansUtils.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/util/SpansUtils.kt index 16fe5a3..7a88665 100644 --- a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/util/SpansUtils.kt +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/util/SpansUtils.kt @@ -6,8 +6,7 @@ import android.text.Html.FROM_HTML_MODE_LEGACY import android.text.Spanned import android.view.View import androidx.annotation.ColorInt -import androidx.core.content.ContextCompat -import kr.pokeum.jsonviewer_xml.R +import kr.pokeum.jsonviewer_xml.adapter.BaseJsonViewerAdapter internal fun fromHtml(htmlText: String): Spanned { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { @@ -21,9 +20,9 @@ internal fun keyValueHtmlGenerator( splitter: String, view: View, /* Support dark mode */ ): String { - return textColorHtmlGenerator(key, ContextCompat.getColor(view.context, R.color.jv_key_color)) + - textColorHtmlGenerator(splitter, ContextCompat.getColor(view.context, R.color.jv_splitter_color)) + - textColorHtmlGenerator(value, ContextCompat.getColor(view.context, R.color.jv_value_color)) + return textColorHtmlGenerator(key, BaseJsonViewerAdapter.KEY_COLOR.getColor(view)) + + textColorHtmlGenerator(splitter, BaseJsonViewerAdapter.SPLITTER_COLOR.getColor(view)) + + textColorHtmlGenerator(value, BaseJsonViewerAdapter.VALUE_COLOR.getColor(view)) } /** diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/util/StyleUtils.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/util/StyleUtils.kt new file mode 100644 index 0000000..4427310 --- /dev/null +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/util/StyleUtils.kt @@ -0,0 +1,17 @@ +package kr.pokeum.jsonviewer_xml.util + +import android.content.res.Configuration +import android.view.View +import androidx.annotation.ColorInt + +class JVColor( + @ColorInt private val default: Int, + @ColorInt private val night: Int +) { + constructor(@ColorInt default: Int) : this(default, default) + + internal fun getColor(view: View) = when (view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) { + Configuration.UI_MODE_NIGHT_YES -> night + else -> default + } +} \ No newline at end of file diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonArrayViewHolder.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonArrayViewHolder.kt index 5a549f5..0b4101a 100644 --- a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonArrayViewHolder.kt +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonArrayViewHolder.kt @@ -1,7 +1,9 @@ package kr.pokeum.jsonviewer_xml.viewholder +import android.annotation.SuppressLint import android.view.View import androidx.recyclerview.widget.RecyclerView +import kr.pokeum.jsonviewer_xml.adapter.BaseJsonViewerAdapter import kr.pokeum.jsonviewer_xml.adapter.JsonViewerAdapter import kr.pokeum.jsonviewer_xml.databinding.ItemJsonArrayBinding import kr.pokeum.jsonviewer_xml.model.JsonArray @@ -27,11 +29,14 @@ internal class JsonArrayViewHolder( binding.childRecyclerView.setRecycledViewPool(recycledViewPool) } + @SuppressLint("SetTextI18n") fun bind(jsonArray: JsonArray) { target = jsonArray expandableUI(jsonArray.isExpanded()) binding.keyLabel.text = "\"${jsonArray.key}\"" childAdapter.setElements(jsonArray.elements) + + setStyle() } private fun expandableUI(isExpanded: Boolean) { @@ -39,4 +44,12 @@ internal class JsonArrayViewHolder( binding.arrowImage.rotation = rotation binding.expandableLayout.visibility = if (isExpanded) View.VISIBLE else View.GONE } + + private fun setStyle() { + // COLOR + binding.arrowImage.setColorFilter(BaseJsonViewerAdapter.ARROW_COLOR.getColor(binding.root)) + binding.keyDescriptionLabel.setTextColor(BaseJsonViewerAdapter.BRACKET_COLOR.getColor(binding.root)) + binding.keyLabel.setTextColor(BaseJsonViewerAdapter.KEY_COLOR.getColor(binding.root)) + binding.divider.setBackgroundColor(BaseJsonViewerAdapter.DIVIDER_COLOR.getColor(binding.root)) + } } \ No newline at end of file diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonNullViewHolder.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonNullViewHolder.kt index ffab500..8372d3b 100644 --- a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonNullViewHolder.kt +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonNullViewHolder.kt @@ -2,6 +2,7 @@ package kr.pokeum.jsonviewer_xml.viewholder import android.view.View import androidx.recyclerview.widget.RecyclerView +import kr.pokeum.jsonviewer_xml.adapter.BaseJsonViewerAdapter import kr.pokeum.jsonviewer_xml.databinding.ItemJsonNullBinding import kr.pokeum.jsonviewer_xml.model.JsonNull import kr.pokeum.jsonviewer_xml.util.fromHtml @@ -22,6 +23,13 @@ internal class JsonNullViewHolder( view = binding.root ) ) + + setStyle() + } + + private fun setStyle() { + // COLOR + binding.keyDescriptionLabel.setTextColor(BaseJsonViewerAdapter.TYPE_COLOR.getColor(binding.root)) } companion object { diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonObjectViewHolder.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonObjectViewHolder.kt index cbe8798..312d173 100644 --- a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonObjectViewHolder.kt +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonObjectViewHolder.kt @@ -1,9 +1,11 @@ package kr.pokeum.jsonviewer_xml.viewholder +import android.annotation.SuppressLint import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import androidx.recyclerview.widget.RecyclerView +import kr.pokeum.jsonviewer_xml.adapter.BaseJsonViewerAdapter import kr.pokeum.jsonviewer_xml.adapter.JsonViewerAdapter import kr.pokeum.jsonviewer_xml.databinding.ItemJsonObjectBinding import kr.pokeum.jsonviewer_xml.model.JsonObject @@ -29,11 +31,14 @@ internal class JsonObjectViewHolder( binding.childRecyclerView.setRecycledViewPool(recycledViewPool) } + @SuppressLint("SetTextI18n") fun bind(jsonObject: JsonObject) { target = jsonObject expandableUI(jsonObject.isExpanded()) binding.keyLabel.text = "\"${jsonObject.key}\"" childAdapter.setElements(jsonObject.elements) + + setStyle() } private fun expandableUI(isExpanded: Boolean) { @@ -41,4 +46,12 @@ internal class JsonObjectViewHolder( binding.arrowImage.rotation = rotation binding.expandableLayout.visibility = if (isExpanded) VISIBLE else GONE } + + private fun setStyle() { + // COLOR + binding.arrowImage.setColorFilter(BaseJsonViewerAdapter.ARROW_COLOR.getColor(binding.root)) + binding.keyDescriptionLabel.setTextColor(BaseJsonViewerAdapter.BRACKET_COLOR.getColor(binding.root)) + binding.keyLabel.setTextColor(BaseJsonViewerAdapter.KEY_COLOR.getColor(binding.root)) + binding.divider.setBackgroundColor(BaseJsonViewerAdapter.DIVIDER_COLOR.getColor(binding.root)) + } } \ No newline at end of file diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonPrimitiveViewHolder.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonPrimitiveViewHolder.kt index 43bd5fb..af5c479 100644 --- a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonPrimitiveViewHolder.kt +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/viewholder/JsonPrimitiveViewHolder.kt @@ -2,6 +2,7 @@ package kr.pokeum.jsonviewer_xml.viewholder import android.view.View import androidx.recyclerview.widget.RecyclerView +import kr.pokeum.jsonviewer_xml.adapter.BaseJsonViewerAdapter import kr.pokeum.jsonviewer_xml.databinding.ItemJsonPrimitiveBinding import kr.pokeum.jsonviewer_xml.model.JsonPrimitive import kr.pokeum.jsonviewer_xml.util.fromHtml @@ -38,6 +39,13 @@ internal class JsonPrimitiveViewHolder( view = binding.root ) ) + + setStyle() + } + + private fun setStyle() { + // COLOR + binding.keyDescriptionLabel.setTextColor(BaseJsonViewerAdapter.TYPE_COLOR.getColor(binding.root)) } companion object { diff --git a/jsonviewer/src/main/res/layout/item_json_array.xml b/jsonviewer/src/main/res/layout/item_json_array.xml index daefb88..29954a0 100644 --- a/jsonviewer/src/main/res/layout/item_json_array.xml +++ b/jsonviewer/src/main/res/layout/item_json_array.xml @@ -53,7 +53,7 @@ android:layout_marginLeft="@dimen/json_key_margin_start" android:layout_marginStart="@dimen/json_key_margin_start" android:textSize="@dimen/json_key_label_size" - android:textColor="@color/jv_array_index_color" + android:textColor="@color/jv_key_color" android:textStyle="bold" tools:text="@string/json_key_label" app:layout_constrainedWidth="true" @@ -73,6 +73,7 @@ app:layout_constraintTop_toBottomOf="@+id/headerLayout" > @color/white @color/gray @color/white - - @color/light_gray - @color/light_gray \ No newline at end of file diff --git a/jsonviewer/src/main/res/values/colors.xml b/jsonviewer/src/main/res/values/colors.xml index 7c091ce..8d97f6b 100644 --- a/jsonviewer/src/main/res/values/colors.xml +++ b/jsonviewer/src/main/res/values/colors.xml @@ -17,7 +17,4 @@ @color/black @color/gray @color/black - - @color/dark_gray - @color/dark_gray \ No newline at end of file From 623d82d4471d1023aec257cd39a3939f6116571a Mon Sep 17 00:00:00 2001 From: pokeum <102505472+pokeum@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:53:32 +0900 Subject: [PATCH 2/3] add custom color --- .../pokeum/jsonviewer_xml/JsonRecyclerView.kt | 28 ++++++++++++++++++- .../src/main/res/layout/item_json_array.xml | 4 +-- .../src/main/res/layout/item_json_null.xml | 2 +- .../src/main/res/layout/item_json_object.xml | 4 +-- .../main/res/layout/item_json_primitive.xml | 2 +- .../src/main/res/values-night/colors.xml | 6 ++-- jsonviewer/src/main/res/values/attrs.xml | 7 +++++ jsonviewer/src/main/res/values/colors.xml | 6 ++-- 8 files changed, 48 insertions(+), 11 deletions(-) diff --git a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/JsonRecyclerView.kt b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/JsonRecyclerView.kt index 2f201a9..967e356 100644 --- a/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/JsonRecyclerView.kt +++ b/jsonviewer/src/main/java/kr/pokeum/jsonviewer_xml/JsonRecyclerView.kt @@ -5,7 +5,9 @@ import android.util.AttributeSet import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kr.pokeum.jsonviewer_xml.adapter.JsonViewerAdapter +import kr.pokeum.jsonviewer_xml.util.JVColor +@Suppress("DEPRECATION") class JsonRecyclerView @JvmOverloads constructor( @@ -15,12 +17,28 @@ constructor( private var text: String + private var keyColor: Int + private var valueColor: Int + private var splitterColor: Int + private var typeColor: Int + private var arrowColor: Int + private var bracketColor: Int + private var dividerColor: Int + init { val typedArray = context.obtainStyledAttributes( attrs, R.styleable.JsonRecyclerView, 0, 0 ) try { text = typedArray.getString(R.styleable.JsonRecyclerView_text) ?: DEFAULT_TEXT + + keyColor = typedArray.getColor(R.styleable.JsonRecyclerView_keyColor, resources.getColor(R.color.jv_key_color)) + valueColor = typedArray.getColor(R.styleable.JsonRecyclerView_valueColor, resources.getColor(R.color.jv_value_color)) + splitterColor = typedArray.getColor(R.styleable.JsonRecyclerView_splitterColor, resources.getColor(R.color.jv_splitter_color)) + typeColor = typedArray.getColor(R.styleable.JsonRecyclerView_typeColor, resources.getColor(R.color.jv_type_color)) + arrowColor = typedArray.getColor(R.styleable.JsonRecyclerView_arrowColor, resources.getColor(R.color.jv_arrow_color)) + bracketColor = typedArray.getColor(R.styleable.JsonRecyclerView_bracketColor, resources.getColor(R.color.jv_bracket_color)) + dividerColor = typedArray.getColor(R.styleable.JsonRecyclerView_dividerColor, resources.getColor(R.color.jv_divider_color)) } finally { typedArray.recycle() } @@ -36,7 +54,15 @@ constructor( jsonParser.parse(text) } catch (_: Throwable) { jsonParser.parse(DEFAULT_TEXT) - }) + }).apply { + setKeyColor(JVColor(keyColor)) + setValueColor(JVColor(valueColor)) + setSplitterColor(JVColor(splitterColor)) + setTypeColor(JVColor(typeColor)) + setArrowColor(JVColor(arrowColor)) + setBracketColor(JVColor(bracketColor)) + setDividerColor(JVColor(dividerColor)) + } } companion object { diff --git a/jsonviewer/src/main/res/layout/item_json_array.xml b/jsonviewer/src/main/res/layout/item_json_array.xml index 29954a0..16a3a95 100644 --- a/jsonviewer/src/main/res/layout/item_json_array.xml +++ b/jsonviewer/src/main/res/layout/item_json_array.xml @@ -21,7 +21,7 @@ android:layout_marginLeft="@dimen/json_key_margin_start" android:layout_marginStart="@dimen/json_key_margin_start" app:srcCompat="@drawable/ic_arrow_white_24dp" - app:tint="@color/red_500" + app:tint="@color/jv_arrow_color" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -41,7 +41,7 @@ android:layout_gravity="center" android:text="@string/json_array_key_description_label" android:textSize="@dimen/json_key_description_label_size" - android:textColor="@color/green_500" + android:textColor="@color/jv_bracket_color" android:textStyle="bold" /> diff --git a/jsonviewer/src/main/res/layout/item_json_null.xml b/jsonviewer/src/main/res/layout/item_json_null.xml index cbc50ea..100541d 100644 --- a/jsonviewer/src/main/res/layout/item_json_null.xml +++ b/jsonviewer/src/main/res/layout/item_json_null.xml @@ -23,7 +23,7 @@ android:layout_gravity="center" android:text="@string/json_null_key_description_label" android:textSize="@dimen/json_key_description_label_size" - android:textColor="@color/blue_500" + android:textColor="@color/jv_type_color" android:textStyle="bold" /> diff --git a/jsonviewer/src/main/res/layout/item_json_object.xml b/jsonviewer/src/main/res/layout/item_json_object.xml index 9363686..6cfc234 100644 --- a/jsonviewer/src/main/res/layout/item_json_object.xml +++ b/jsonviewer/src/main/res/layout/item_json_object.xml @@ -20,7 +20,7 @@ android:layout_marginLeft="@dimen/json_key_margin_start" android:layout_marginStart="@dimen/json_key_margin_start" app:srcCompat="@drawable/ic_arrow_white_24dp" - app:tint="@color/red_500" + app:tint="@color/jv_arrow_color" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -40,7 +40,7 @@ android:layout_gravity="center" android:text="@string/json_object_key_description_label" android:textSize="@dimen/json_key_description_label_size" - android:textColor="@color/green_500" + android:textColor="@color/jv_bracket_color" android:textStyle="bold" /> diff --git a/jsonviewer/src/main/res/layout/item_json_primitive.xml b/jsonviewer/src/main/res/layout/item_json_primitive.xml index c650cff..db42d04 100644 --- a/jsonviewer/src/main/res/layout/item_json_primitive.xml +++ b/jsonviewer/src/main/res/layout/item_json_primitive.xml @@ -24,7 +24,7 @@ android:layout_gravity="center" android:text="@string/json_number_key_description_label" android:textSize="@dimen/json_primitive_key_description_label_size" - android:textColor="@color/blue_500" + android:textColor="@color/jv_type_color" android:textStyle="bold" /> diff --git a/jsonviewer/src/main/res/values-night/colors.xml b/jsonviewer/src/main/res/values-night/colors.xml index 1eedaa0..6f9798d 100644 --- a/jsonviewer/src/main/res/values-night/colors.xml +++ b/jsonviewer/src/main/res/values-night/colors.xml @@ -12,9 +12,11 @@ #FF4CAF50 - #1EFFFFFF - @color/white @color/gray @color/white + @color/blue_500 + @color/red_500 + @color/green_500 + #1EFFFFFF \ No newline at end of file diff --git a/jsonviewer/src/main/res/values/attrs.xml b/jsonviewer/src/main/res/values/attrs.xml index b7bdca3..5077f25 100644 --- a/jsonviewer/src/main/res/values/attrs.xml +++ b/jsonviewer/src/main/res/values/attrs.xml @@ -2,5 +2,12 @@ + + + + + + + \ No newline at end of file diff --git a/jsonviewer/src/main/res/values/colors.xml b/jsonviewer/src/main/res/values/colors.xml index 8d97f6b..b69a4d7 100644 --- a/jsonviewer/src/main/res/values/colors.xml +++ b/jsonviewer/src/main/res/values/colors.xml @@ -12,9 +12,11 @@ #FF4CAF50 - #1E000000 - @color/black @color/gray @color/black + @color/blue_500 + @color/red_500 + @color/green_500 + #1E000000 \ No newline at end of file From 9079a03b3845bca9ea94f9cdf2a03cb5b8fc669c Mon Sep 17 00:00:00 2001 From: pokeum <102505472+pokeum@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:11:30 +0900 Subject: [PATCH 3/3] Update README.md --- README.md | 43 ++++++++++++++++++++++++++++++ image/screenshot/styles-color.png | Bin 0 -> 18242 bytes 2 files changed, 43 insertions(+) create mode 100644 image/screenshot/styles-color.png diff --git a/README.md b/README.md index 2527e5b..b81a2d2 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ https://github.com/pokeum/jsonviewer-xml/assets/102505472/e2f260f0-cc28-4607-9ec - [Usage](#usage) - [Basic](#basic) - [Advance](#advance) +- [Custom Styles](#styles) ## Installation @@ -150,3 +151,45 @@ implementation 'com.github.pokeum:jsonviewer-xml:0.0.0' } } ``` + +## Custom Styles + +### Color + +| | | +| -- | -- | +| Key | `"friends"`, `"0"`, `"name"`, `"age"` | +| Value | `"Alice"`, `28` | +| Splitter | `:` | +| Type | `ABC`, `123` | +| Arrow | `\/` | +| Bracket | `[ ]`, `{ }` | +| Divider | `│` | + +#### Use JsonRecyclerView + + ```xml + + ``` + +#### Use RecyclerView + + ```kotlin + recyclerView.adapter = JsonViewerAdapter(/* JsonElement */).apply { + setKeyColor(JVColor(/* Default Color[, Dark Mode Color] */)) + setValueColor(JVColor(/* ... */)) + setSplitterColor(JVColor(/* ... */)) + setTypeColor(JVColor(/* ... */)) + setArrowColor(JVColor(/* ... */)) + setBracketColor(JVColor(/* ... */)) + setDividerColor(JVColor(/* ... */)) + } + ``` diff --git a/image/screenshot/styles-color.png b/image/screenshot/styles-color.png new file mode 100644 index 0000000000000000000000000000000000000000..daba288ddc790d161bcbb071d2107d470c2b208e GIT binary patch literal 18242 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