Skip to content

Commit

Permalink
Add support for subscript and superscript rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
rafalniski committed Feb 1, 2023
1 parent 33eda9e commit f87a012
Show file tree
Hide file tree
Showing 16 changed files with 137 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import android.text.SpannableStringBuilder;
import android.text.style.BackgroundColorSpan;
import android.text.style.StyleSpan;
import android.text.style.SubscriptSpan;
import android.text.style.SuperscriptSpan;
import android.text.style.TextAppearanceSpan;
import android.text.style.UnderlineSpan;

import com.contentful.java.cda.rich.CDARichMark;
import com.contentful.java.cda.rich.CDARichMark.CDARichMarkBold;
import com.contentful.java.cda.rich.CDARichMark.CDARichMarkItalic;
Expand Down Expand Up @@ -67,10 +68,15 @@ public TextRenderer(@Nonnull AndroidProcessor<CharSequence> processor) {
if (mark instanceof CDARichMarkUnderline) {
result.setSpan(new UnderlineSpan(), 0, result.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}

if (mark instanceof CDARichMarkBold) {
result.setSpan(new StyleSpan(Typeface.BOLD), 0, result.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (mark instanceof CDARichMark.CDARichMarkSubscript) {
result.setSpan(new SubscriptSpan(), 0, result.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (mark instanceof CDARichMark.CDARichMarkSuperscript) {
result.setSpan(new SuperscriptSpan(), 0, result.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (mark instanceof CDARichMarkItalic) {
result.setSpan(new StyleSpan(Typeface.ITALIC), 0, result.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import android.graphics.Typeface;
import android.text.SpannableStringBuilder;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.StyleSpan;
import android.text.style.SubscriptSpan;
import android.text.style.SuperscriptSpan;
import android.text.style.TextAppearanceSpan;
import android.text.style.UnderlineSpan;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;

import com.contentful.java.cda.rich.CDARichHeading;
import com.contentful.java.cda.rich.CDARichMark;
import com.contentful.java.cda.rich.CDARichMark.CDARichMarkBold;
Expand Down Expand Up @@ -77,6 +77,12 @@ public TextRenderer(@Nonnull AndroidProcessor<View> processor) {
if (mark instanceof CDARichMarkBold) {
textContent.setSpan(new StyleSpan(Typeface.BOLD), 0, textContent.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (mark instanceof CDARichMark.CDARichMarkSuperscript) {
textContent.setSpan(new SuperscriptSpan(), 0, textContent.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (mark instanceof CDARichMark.CDARichMarkSubscript) {
textContent.setSpan(new SubscriptSpan(), 0, textContent.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (mark instanceof CDARichMarkItalic) {
textContent.setSpan(new StyleSpan(Typeface.ITALIC), 0, textContent.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
}
Expand Down
1 change: 1 addition & 0 deletions android/src/main/res/layout/rich_text_layout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
android:id="@id/rich_content"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:padding="5dp"
android:layout_height="wrap_content"
/>
23 changes: 13 additions & 10 deletions android_sample/build.gradle
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
plugins {
id("com.android.application")
id "org.jetbrains.kotlin.android" version "1.6.0-RC"
id("org.jetbrains.kotlin.android.extensions") version "1.5.30"
id "org.jetbrains.kotlin.android" version "1.8.0"
}

repositories {
maven { url 'https://jitpack.io' }
}

android {
compileSdkVersion 32
compileSdk 33
buildToolsVersion "30.0.3"


defaultConfig {
applicationId "com.contentful.rich.android.sample"
minSdkVersion 21
targetSdkVersion 32
targetSdkVersion 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

}

buildFeatures {
viewBinding = true
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility "11"
targetCompatibility "11"
}

buildTypes {
all {
configureEach {
buildConfigField("String", "SPACE_ID", "\"${System.getenv("RICH_TEXT_SPACE_ID")}\"")
buildConfigField("String", "DELIVERY_TOKEN", "\"${System.getenv("RICH_TEXT_DELIVERY_TOKEN")}\"")
buildConfigField("String", "ENVIRONMENT_ID", "\"${System.getenv("RICH_TEXT_ENVIRONMENT_ID")}\"")
Expand All @@ -49,13 +52,13 @@ dependencies {
implementation project(path: ':android')
implementation project(path: ':core')

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.20"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3"
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'androidx.appcompat:appcompat:1.6.0'

implementation "com.contentful.java:java-sdk:${project.contentful_version}"
implementation 'com.google.code.findbugs:jsr305:3.0.2'

implementation 'com.google.android.material:material:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import com.contentful.java.cda.CDAEntry
import com.contentful.java.cda.QueryOperation.Matches
import com.contentful.java.cda.rich.CDARichDocument
import com.contentful.java.cda.rich.CDARichParagraph
import com.contentful.rich.android.sample.databinding.ActivityMainBinding
import com.contentful.rich.core.simple.RemoveEmpties
import com.contentful.rich.core.simple.RemoveToDeepNesting
import com.contentful.rich.core.simple.Simplifier
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

private const val SPACE_ID = "i1ppeoxgdpvt"
private const val TOKEN = "MU0hFqSvQ7QdXT82RgduxtQCGQBckJqqZkPw3U6T-rY"
private const val TOKEN = "QuYNYLv6rVnCKOT4_-d3552xD4YIPFcKTWRb2Y227Ic"
private const val ENVIRONMENT = "master"

class MainActivity(
Expand All @@ -29,19 +29,23 @@ class MainActivity(
.build()
) : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)

setSupportActionBar(toolbar)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayShowTitleEnabled(false)

if (PAGES.last().name != "Contentful") {
spinner.prompt = "⌛ Loading from Contentful ⏳"
binding.spinner.prompt = "⌛ Loading from Contentful ⏳"
loadPageFromContentful()
}

spinner.onItemSelectedListener = object : OnItemSelectedListener {
binding.spinner.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, PageFragment.newInstance(position))
Expand All @@ -63,7 +67,11 @@ class MainActivity(
.entries()
.values
.map { entry ->
entry.getField<Any>("rich") as CDARichDocument
if(entry.getField<Any>("rich") != null) {
entry.getField<Any>("rich") as CDARichDocument
} else {
CDARichDocument()
}
}.reduce { a, b ->
val p = CDARichParagraph()
p.content.addAll(b.content)
Expand All @@ -80,8 +88,8 @@ class MainActivity(
)

runOnUiThread {
spinner.prompt = PAGES[0].name
spinner.adapter = PageAdapter(
binding.spinner.prompt = PAGES[0].name
binding.spinner.adapter = PageAdapter(
this@MainActivity,
PAGES.toTypedArray()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ val PAGES = mutableListOf(
text("Normal Text"),
text("BoldText", listOf(CDARichMarkBold())),
text("Italic", listOf(CDARichMarkItalic())),
text("Superscript", listOf(CDARichMarkSuperscript())),
text("Subscript", listOf(CDARichMarkSubscript())),
text("Underline", listOf(CDARichMarkUnderline())),
text("final String code;", listOf(CDARichMarkCode())),
text("CustomText", listOf(CDARichMarkCustom("custom"))),
Expand All @@ -24,6 +26,8 @@ val PAGES = mutableListOf(
listOf(
CDARichMarkCustom("custom"),
CDARichMarkItalic(),
CDARichMarkSubscript(),
CDARichMarkSubscript(),
CDARichMarkBold(),
CDARichMarkCode(),
CDARichMarkUnderline()
Expand Down Expand Up @@ -129,7 +133,9 @@ val PAGES = mutableListOf(
CDARichBlock().addAll(
text("Quotes from "),
text("Famous", listOf(CDARichMark.CDARichMarkBold())),
text(" People", listOf(CDARichMark.CDARichMarkItalic()))
text(" People", listOf(CDARichMark.CDARichMarkItalic())),
text(" Dogs", listOf(CDARichMark.CDARichMarkSuperscript())),
text(" Cats", listOf(CDARichMark.CDARichMarkSubscript())),
),
CDARichQuote().addAll(
text("You know you’re in love when you can’t fall asleep because reality is finally better than your dreams."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,37 @@ package com.contentful.rich.android.sample

import android.content.Context
import android.content.res.Resources
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.appcompat.widget.ThemedSpinnerAdapter
import kotlinx.android.synthetic.main.dropdown_item.view.*
import com.contentful.rich.android.sample.databinding.AppbarItemBinding
import com.contentful.rich.android.sample.databinding.DropdownItemBinding

class PageAdapter(context: Context, objects: Array<Page>) :
ArrayAdapter<Page>(context, R.layout.appbar_item, objects), ThemedSpinnerAdapter {

private val mDropDownHelper: ThemedSpinnerAdapter.Helper = ThemedSpinnerAdapter.Helper(context)

override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = if (convertView == null) {
val inflater = mDropDownHelper.dropDownViewInflater
inflater.inflate(R.layout.appbar_item, parent, false)
} else {
convertView
}
val binding: AppbarItemBinding =
if (convertView != null) AppbarItemBinding.bind(convertView)
else AppbarItemBinding.inflate(LayoutInflater.from(context), parent, false)

view.list_item_text.text = getItem(position)?.name ?: "null"
binding.listItemText.text = getItem(position)?.name ?: "null"

return view
return binding.root
}

override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = if (convertView == null) {
val inflater = mDropDownHelper.dropDownViewInflater
inflater.inflate(R.layout.dropdown_item, parent, false)
} else {
convertView
}
val binding: DropdownItemBinding =
if (convertView != null) DropdownItemBinding.bind(convertView)
else DropdownItemBinding.inflate(LayoutInflater.from(context), parent, false)

view.list_item_text.text = getItem(position)?.name ?: "null"
binding.listItemText.text = getItem(position)?.name ?: "null"

return view
return binding.root
}

override fun getDropDownViewTheme(): Resources.Theme? {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,59 @@
package com.contentful.rich.android.sample

import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.fragment_page.*
import kotlinx.android.synthetic.main.fragment_page.view.*
import com.contentful.rich.android.sample.databinding.FragmentPageBinding
import com.contentful.rich.android.sample.databinding.SampleItemBinding

class PageFragment : Fragment() {
class Holder(view: View) : RecyclerView.ViewHolder(view)
class Holder(private val binding: SampleItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(text: String) {
binding.sampleItemText.text = text
binding.sampleItemText.movementMethod = LinkMovementMethod.getInstance()
}
fun removeViews(view: View) {
binding.sampleItemCard.removeAllViews()
binding.sampleItemCard.addView(view)
}
}

private var _binding: FragmentPageBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val rootView = inflater.inflate(R.layout.fragment_page, container, false)
rootView.page_recycler.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
rootView.page_recycler.adapter =
_binding = FragmentPageBinding.inflate(inflater, container, false)
binding.pageRecycler.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
binding.pageRecycler.adapter =
RichCharSequenceAdapter(arguments?.getInt(ARG_PAGE_INDEX, 0)
?: 0, requireContext())

rootView.main_native_check.setOnCheckedChangeListener { _, isChecked ->
binding.mainNativeCheck.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
onNativeViewProcessingSelected()
} else {
onCharSequenceProcessingSelected()
}
}

return rootView
return binding.root
}

private fun onNativeViewProcessingSelected() {
fragment_page.page_recycler.adapter =
binding.pageRecycler.adapter =
RichNativeViewAdapter(
arguments?.getInt(ARG_PAGE_INDEX, 0) ?: 0,
requireContext())

}

private fun onCharSequenceProcessingSelected() {
fragment_page.page_recycler.adapter =
binding.pageRecycler.adapter =
RichCharSequenceAdapter(
arguments?.getInt(ARG_PAGE_INDEX, 0) ?: 0,
requireContext())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.contentful.rich.android.sample
import android.content.Context
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.view.LayoutInflater
import android.view.View
Expand All @@ -14,19 +13,18 @@ import com.contentful.java.cda.CDAEntry
import com.contentful.java.cda.rich.CDARichHyperLink
import com.contentful.rich.android.AndroidContext
import com.contentful.rich.android.AndroidProcessor
import kotlinx.android.synthetic.main.sample_item.view.*
import com.contentful.rich.android.sample.databinding.SampleItemBinding

class RichCharSequenceAdapter(pageIndex: Int, private val androidContext: Context) : RecyclerView.Adapter<PageFragment.Holder>() {
private val page: Page = PAGES[pageIndex]
private val inflater: LayoutInflater = LayoutInflater.from(androidContext)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageFragment.Holder =
PageFragment.Holder(inflater.inflate(R.layout.sample_item, parent, false))

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageFragment.Holder {
val itemBinding = SampleItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return PageFragment.Holder(itemBinding)
}
override fun onBindViewHolder(holder: PageFragment.Holder, position: Int) {
val item = page.document.content[position]
val context = AndroidContext(androidContext)

val processor = AndroidProcessor.creatingCharSequences()
processor.overrideRenderer(
{ _, node -> node is CDARichHyperLink && node.data is CDAEntry },
Expand Down Expand Up @@ -67,9 +65,7 @@ class RichCharSequenceAdapter(pageIndex: Int, private val androidContext: Contex
)

val text = processor.process(context, item) ?: "???"

holder.itemView.sample_item_text.text = text
holder.itemView.sample_item_text.movementMethod = LinkMovementMethod.getInstance()
holder.bind(text.toString())
}

override fun getItemCount(): Int = page.document.content.size
Expand Down
Loading

0 comments on commit f87a012

Please sign in to comment.