mirror of
https://github.com/kickstarter/android-oss.git
synced 2026-03-13 09:11:01 +08:00
MBL-3085: Handle schema change for RichTextHeader (#2479)
In addition, refactor Rich Text transformers into extension functions and move them to a new file `RichTextTransformers.kt` within a new package at `../transformers/extensions`. Co-authored-by: Tony Teate <4317686+tonyteate@users.noreply.github.com>
This commit is contained in:
@@ -31,34 +31,7 @@ fragment storyRichTextComponentFragment on RichTextComponent {
|
||||
...richTextPhotoFragment
|
||||
}
|
||||
}
|
||||
... on RichTextHeader1 {
|
||||
__typename
|
||||
text
|
||||
link
|
||||
styles
|
||||
children {
|
||||
...richTextChildParagraphFragment
|
||||
}
|
||||
}
|
||||
... on RichTextHeader2 {
|
||||
__typename
|
||||
text
|
||||
link
|
||||
styles
|
||||
children {
|
||||
...richTextChildParagraphFragment
|
||||
}
|
||||
}
|
||||
... on RichTextHeader3 {
|
||||
__typename
|
||||
text
|
||||
link
|
||||
styles
|
||||
children {
|
||||
...richTextChildParagraphFragment
|
||||
}
|
||||
}
|
||||
... on RichTextHeader4 {
|
||||
... on RichTextHeader {
|
||||
__typename
|
||||
text
|
||||
link
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,10 +6,10 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.kickstarter.features.projectstory.data.StoriedProject
|
||||
import com.kickstarter.features.projectstory.data.transform
|
||||
import com.kickstarter.libs.Environment
|
||||
import com.kickstarter.libs.utils.extensions.isProjectUri
|
||||
import com.kickstarter.models.Project
|
||||
import com.kickstarter.services.transformers.extensions.toStoriedProject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -70,7 +70,7 @@ class ProjectStoryViewModel(
|
||||
_projectStoryUiState.value = ProjectStoryUiState(
|
||||
isLoading = false,
|
||||
error = null,
|
||||
storiedProject = transform(it?.projectStoryFragment)
|
||||
storiedProject = it?.projectStoryFragment.toStoriedProject()
|
||||
)
|
||||
Timber.d("storiedProject: ${projectStoryUiState.value.storiedProject}")
|
||||
}
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
package com.kickstarter.features.projectstory.data
|
||||
|
||||
import com.kickstarter.fragment.ProjectStoryFragment
|
||||
import com.kickstarter.fragment.RichTextChildParagraphFragment
|
||||
import com.kickstarter.fragment.RichTextPhotoFragment
|
||||
import com.kickstarter.fragment.StoryRichTextComponentFragment
|
||||
import com.kickstarter.libs.utils.extensions.isTrue
|
||||
import com.kickstarter.libs.utils.extensions.negate
|
||||
import com.kickstarter.models.Photo
|
||||
import com.kickstarter.models.Project
|
||||
import com.kickstarter.services.transformers.decodeRelayId
|
||||
import timber.log.Timber
|
||||
|
||||
data class StoriedProject(
|
||||
val project: Project,
|
||||
@@ -82,168 +73,3 @@ sealed interface RichTextItem {
|
||||
val _present: Boolean,
|
||||
) : RichTextItem
|
||||
}
|
||||
|
||||
fun transform(projectStoryFragment: ProjectStoryFragment?): StoriedProject {
|
||||
Timber.d("transform()")
|
||||
val id = decodeRelayId(projectStoryFragment?.id) ?: -1
|
||||
Timber.d("-- id: $id")
|
||||
Timber.d("-- _?.pid: ${projectStoryFragment?.pid}")
|
||||
val name = projectStoryFragment?.name
|
||||
val slug = projectStoryFragment?.slug
|
||||
val displayPrelaunch = (projectStoryFragment?.isLaunched ?: false).negate()
|
||||
/* from GraphQLTransformers.getPhoto() */
|
||||
val photo = projectStoryFragment?.imageUrl.let { photoUrl ->
|
||||
Photo.builder()
|
||||
.ed(photoUrl)
|
||||
.full(photoUrl)
|
||||
.little(photoUrl)
|
||||
.med(photoUrl)
|
||||
.small(photoUrl)
|
||||
.thumb(photoUrl)
|
||||
.altText(null)
|
||||
.build()
|
||||
}
|
||||
|
||||
val project = Project.builder()
|
||||
.displayPrelaunch(displayPrelaunch)
|
||||
.id(id)
|
||||
.name(name)
|
||||
.photo(photo) // - now we get the full size for field from GraphQL, but V1 provided several image sizes
|
||||
.slug(slug)
|
||||
.build()
|
||||
|
||||
val story =
|
||||
if (project.displayPrelaunch().isTrue())
|
||||
projectStoryFragment?.prelaunchStoryRichText?.storyRichTextComponentFragment?.let {
|
||||
transform(it)
|
||||
}
|
||||
else
|
||||
projectStoryFragment?.storyRichText?.storyRichTextComponentFragment?.let {
|
||||
transform(it)
|
||||
}
|
||||
|
||||
return StoriedProject(project, story)
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the use of `mapNotNull` to filter out `null` items everywhere. This may change.
|
||||
*/
|
||||
|
||||
fun transform(storyRichTextComponentFragment: StoryRichTextComponentFragment): RichTextComponent {
|
||||
val items: List<RichTextItem> = storyRichTextComponentFragment.items.mapNotNull { fragmentItem ->
|
||||
when {
|
||||
fragmentItem.onRichText != null -> {
|
||||
RichTextItem.Text.Paragraph(
|
||||
fragmentItem.onRichText.__typename,
|
||||
fragmentItem.onRichText.text,
|
||||
fragmentItem.onRichText.link,
|
||||
fragmentItem.onRichText.styles,
|
||||
children = fragmentItem.onRichText.children?.mapNotNull { fragmentItemChild ->
|
||||
when {
|
||||
fragmentItemChild.richTextChildParagraphFragment != null ->
|
||||
transform(fragmentItemChild.richTextChildParagraphFragment)
|
||||
fragmentItemChild.richTextPhotoFragment != null -> transform(fragmentItemChild.richTextPhotoFragment)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextHeader1 != null -> {
|
||||
RichTextItem.Text.Header(
|
||||
RichTextItem.Text.Header.Level.H1,
|
||||
fragmentItem.onRichTextHeader1.__typename,
|
||||
fragmentItem.onRichTextHeader1.text,
|
||||
fragmentItem.onRichTextHeader1.link,
|
||||
fragmentItem.onRichTextHeader1.styles,
|
||||
children = fragmentItem.onRichTextHeader1.children?.mapNotNull { fragmentItemChild ->
|
||||
fragmentItemChild.richTextChildParagraphFragment?.let(::transform)
|
||||
},
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextHeader2 != null -> {
|
||||
RichTextItem.Text.Header(
|
||||
RichTextItem.Text.Header.Level.H2,
|
||||
fragmentItem.onRichTextHeader2.__typename,
|
||||
fragmentItem.onRichTextHeader2.text,
|
||||
fragmentItem.onRichTextHeader2.link,
|
||||
fragmentItem.onRichTextHeader2.styles,
|
||||
children = fragmentItem.onRichTextHeader2.children?.mapNotNull { fragmentItemChild ->
|
||||
fragmentItemChild.richTextChildParagraphFragment?.let(::transform)
|
||||
},
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextHeader3 != null -> {
|
||||
RichTextItem.Text.Header(
|
||||
RichTextItem.Text.Header.Level.H3,
|
||||
fragmentItem.onRichTextHeader3.__typename,
|
||||
fragmentItem.onRichTextHeader3.text,
|
||||
fragmentItem.onRichTextHeader3.link,
|
||||
fragmentItem.onRichTextHeader3.styles,
|
||||
children = fragmentItem.onRichTextHeader3.children?.mapNotNull { fragmentItemChild ->
|
||||
fragmentItemChild.richTextChildParagraphFragment?.let(::transform)
|
||||
},
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextHeader4 != null -> {
|
||||
RichTextItem.Text.Header(
|
||||
RichTextItem.Text.Header.Level.H4,
|
||||
fragmentItem.onRichTextHeader4.__typename,
|
||||
fragmentItem.onRichTextHeader4.text,
|
||||
fragmentItem.onRichTextHeader4.link,
|
||||
fragmentItem.onRichTextHeader4.styles,
|
||||
children = fragmentItem.onRichTextHeader4.children?.mapNotNull { fragmentItemChild ->
|
||||
fragmentItemChild.richTextChildParagraphFragment?.let(::transform)
|
||||
},
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextListItem != null -> {
|
||||
RichTextItem.Text.ListItem(
|
||||
fragmentItem.onRichTextListItem.__typename,
|
||||
fragmentItem.onRichTextListItem.text,
|
||||
fragmentItem.onRichTextListItem.link,
|
||||
fragmentItem.onRichTextListItem.styles,
|
||||
children = fragmentItem.onRichTextListItem.children?.mapNotNull { fragmentItemChild ->
|
||||
fragmentItemChild.richTextChildParagraphFragment?.let(::transform)
|
||||
},
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextPhoto != null -> {
|
||||
transform(fragmentItem.onRichTextPhoto.richTextPhotoFragment)
|
||||
}
|
||||
fragmentItem.onRichTextOembed != null -> {
|
||||
RichTextItem.Oembed(
|
||||
fragmentItem.onRichTextOembed.__typename,
|
||||
fragmentItem.onRichTextOembed.type,
|
||||
fragmentItem.onRichTextOembed.iframeUrl
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
return RichTextComponent(items)
|
||||
}
|
||||
|
||||
fun transform(richTextChildParagraphFragment: RichTextChildParagraphFragment): RichTextItem.Text.ChildParagraph {
|
||||
return RichTextItem.Text.ChildParagraph(
|
||||
richTextChildParagraphFragment.__typename,
|
||||
richTextChildParagraphFragment.text,
|
||||
richTextChildParagraphFragment.link,
|
||||
richTextChildParagraphFragment.styles
|
||||
)
|
||||
}
|
||||
|
||||
fun transform(richTextPhotoFragment: RichTextPhotoFragment): RichTextItem.Photo {
|
||||
return RichTextItem.Photo(
|
||||
richTextPhotoFragment.__typename,
|
||||
richTextPhotoFragment.url,
|
||||
richTextPhotoFragment.altText,
|
||||
richTextPhotoFragment.caption,
|
||||
richTextPhotoFragment.asset?.let {
|
||||
RichTextItem.Photo.Asset(
|
||||
it.url,
|
||||
it.altText
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package com.kickstarter.services.transformers.extensions
|
||||
|
||||
import com.kickstarter.features.projectstory.data.RichTextComponent
|
||||
import com.kickstarter.features.projectstory.data.RichTextItem
|
||||
import com.kickstarter.features.projectstory.data.StoriedProject
|
||||
import com.kickstarter.fragment.ProjectStoryFragment
|
||||
import com.kickstarter.fragment.RichTextChildParagraphFragment
|
||||
import com.kickstarter.fragment.RichTextPhotoFragment
|
||||
import com.kickstarter.fragment.StoryRichTextComponentFragment
|
||||
import com.kickstarter.libs.utils.extensions.isTrue
|
||||
import com.kickstarter.libs.utils.extensions.negate
|
||||
import com.kickstarter.models.Photo
|
||||
import com.kickstarter.models.Project
|
||||
import com.kickstarter.services.transformers.decodeRelayId
|
||||
import timber.log.Timber
|
||||
|
||||
fun ProjectStoryFragment?.toStoriedProject(): StoriedProject {
|
||||
Timber.d("transform()")
|
||||
val id = decodeRelayId(this?.id) ?: -1
|
||||
Timber.d("-- id: $id")
|
||||
Timber.d("-- _?.pid: ${this?.pid}")
|
||||
val name = this?.name
|
||||
val slug = this?.slug
|
||||
val displayPrelaunch = (this?.isLaunched ?: false).negate()
|
||||
/* from GraphQLTransformers.getPhoto() */
|
||||
val photo = this?.imageUrl.let { photoUrl ->
|
||||
Photo.builder()
|
||||
.ed(photoUrl)
|
||||
.full(photoUrl)
|
||||
.little(photoUrl)
|
||||
.med(photoUrl)
|
||||
.small(photoUrl)
|
||||
.thumb(photoUrl)
|
||||
.altText(null)
|
||||
.build()
|
||||
}
|
||||
|
||||
val project = Project.builder()
|
||||
.displayPrelaunch(displayPrelaunch)
|
||||
.id(id)
|
||||
.name(name)
|
||||
.photo(photo) // - now we get the full size for field from GraphQL, but V1 provided several image sizes
|
||||
.slug(slug)
|
||||
.build()
|
||||
|
||||
val story =
|
||||
if (project.displayPrelaunch().isTrue())
|
||||
this?.prelaunchStoryRichText?.storyRichTextComponentFragment?.toRichTextComponent()
|
||||
else
|
||||
this?.storyRichText?.storyRichTextComponentFragment?.toRichTextComponent()
|
||||
|
||||
return StoriedProject(project, story)
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the use of `mapNotNull` to filter out `null` items everywhere. This may change.
|
||||
*/
|
||||
fun StoryRichTextComponentFragment.toRichTextComponent(): RichTextComponent {
|
||||
val items: List<RichTextItem> = this.items.mapNotNull { fragmentItem ->
|
||||
when {
|
||||
fragmentItem.onRichText != null -> {
|
||||
RichTextItem.Text.Paragraph(
|
||||
fragmentItem.onRichText.__typename,
|
||||
fragmentItem.onRichText.text,
|
||||
fragmentItem.onRichText.link,
|
||||
fragmentItem.onRichText.styles,
|
||||
children = fragmentItem.onRichText.children?.mapNotNull { fragmentItemChild ->
|
||||
when {
|
||||
fragmentItemChild.richTextChildParagraphFragment != null ->
|
||||
fragmentItemChild.richTextChildParagraphFragment.toChildParagraph()
|
||||
fragmentItemChild.richTextPhotoFragment != null ->
|
||||
fragmentItemChild.richTextPhotoFragment.toPhoto()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextHeader != null -> {
|
||||
val styles = fragmentItem.onRichTextHeader.styles.orEmpty()
|
||||
val level = when {
|
||||
"HEADING_1" in styles -> RichTextItem.Text.Header.Level.H1
|
||||
"HEADING_2" in styles -> RichTextItem.Text.Header.Level.H2
|
||||
"HEADING_3" in styles -> RichTextItem.Text.Header.Level.H3
|
||||
else -> RichTextItem.Text.Header.Level.H4 /* Least disruptive style */
|
||||
}
|
||||
RichTextItem.Text.Header(
|
||||
level,
|
||||
fragmentItem.onRichTextHeader.__typename,
|
||||
fragmentItem.onRichTextHeader.text,
|
||||
fragmentItem.onRichTextHeader.link,
|
||||
fragmentItem.onRichTextHeader.styles,
|
||||
children = fragmentItem.onRichTextHeader.children?.mapNotNull { fragmentItemChild ->
|
||||
fragmentItemChild.richTextChildParagraphFragment?.toChildParagraph()
|
||||
},
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextListItem != null -> {
|
||||
RichTextItem.Text.ListItem(
|
||||
fragmentItem.onRichTextListItem.__typename,
|
||||
fragmentItem.onRichTextListItem.text,
|
||||
fragmentItem.onRichTextListItem.link,
|
||||
fragmentItem.onRichTextListItem.styles,
|
||||
children = fragmentItem.onRichTextListItem.children?.mapNotNull { fragmentItemChild ->
|
||||
fragmentItemChild.richTextChildParagraphFragment?.toChildParagraph()
|
||||
},
|
||||
)
|
||||
}
|
||||
fragmentItem.onRichTextPhoto != null -> {
|
||||
fragmentItem.onRichTextPhoto.richTextPhotoFragment.toPhoto()
|
||||
}
|
||||
fragmentItem.onRichTextOembed != null -> {
|
||||
RichTextItem.Oembed(
|
||||
fragmentItem.onRichTextOembed.__typename,
|
||||
fragmentItem.onRichTextOembed.type,
|
||||
fragmentItem.onRichTextOembed.iframeUrl
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
return RichTextComponent(items)
|
||||
}
|
||||
|
||||
private fun RichTextChildParagraphFragment.toChildParagraph(): RichTextItem.Text.ChildParagraph {
|
||||
return RichTextItem.Text.ChildParagraph(
|
||||
__typename,
|
||||
text,
|
||||
link,
|
||||
styles
|
||||
)
|
||||
}
|
||||
|
||||
private fun RichTextPhotoFragment.toPhoto(): RichTextItem.Photo {
|
||||
return RichTextItem.Photo(
|
||||
__typename,
|
||||
url,
|
||||
altText,
|
||||
caption,
|
||||
asset?.let {
|
||||
RichTextItem.Photo.Asset(
|
||||
it.url,
|
||||
it.altText
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user