Skip to content

Commit

Permalink
Fix HTML Text rendering in course section and discussion (#357)
Browse files Browse the repository at this point in the history
* Store HTML text in models to be used in HTML Text Field

Also included is regex to append token to every URL present in the HTML text, as CMS requires for the token to be present as it starts downloading the resource from the URL.

* Render HTML text properly by using parseText from HTMLTextView
  • Loading branch information
JustAGhost23 committed Feb 25, 2024
1 parent 82f86cc commit a1855b6
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class CourseSectionDelegate(activity: Activity) : AdapterDelegate<List<CourseCon
val vh = holder as CourseSectionViewHolder
val section = items[position] as CourseSection
vh.sectionName.text = section.name
val summary = Utils.trimWhiteSpace(HtmlCompat.fromHtml(section.summary.trim { it <= ' ' },
val summary = Utils.trimWhiteSpace(HtmlCompat.fromHtml(section.summary,
HtmlCompat.FROM_HTML_MODE_COMPACT))
if (summary.isNotEmpty()) {
vh.sectionDescription.visibility = View.VISIBLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package crux.bphc.cms.fragments

import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand All @@ -24,9 +23,9 @@ import crux.bphc.cms.helper.CourseRequestHandler
import crux.bphc.cms.models.forum.Attachment
import crux.bphc.cms.models.forum.Discussion
import crux.bphc.cms.utils.Utils
import crux.bphc.cms.widgets.HtmlTextView
import crux.bphc.cms.widgets.PropertiesAlertDialog
import io.realm.Realm
import io.realm.RealmList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -92,7 +91,7 @@ class DiscussionFragment : Fragment() {
binding.subject.text = discussion.subject
binding.userName.text = discussion.userFullName
binding.modifiedTime.text = Utils.formatDate(discussion.timeModified)
binding.message.text = discussion.message
binding.message.text = HtmlTextView.parseHtml(discussion.message)
Glide.with(requireContext())
.load(Urls.getProfilePicUrl(discussion.userPictureUrl))
.into(binding.userPic)
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/crux/bphc/cms/fragments/ForumFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import crux.bphc.cms.helper.CourseRequestHandler
import crux.bphc.cms.interfaces.ClickListener
import crux.bphc.cms.models.forum.Discussion
import crux.bphc.cms.utils.Utils
import crux.bphc.cms.widgets.HtmlTextView
import io.realm.Realm
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -185,7 +186,7 @@ class ForumFragment : Fragment() {

itemBinding.subject.text = discussion.subject
itemBinding.userName.text = discussion.userFullName
itemBinding.message.text = discussion.message
itemBinding.message.text = HtmlTextView.parseHtml(discussion.message)
itemBinding.modifiedTime.text = Utils.formatDate(discussion.timeModified)

if (!discussion.isPinned) {
Expand Down
40 changes: 32 additions & 8 deletions app/src/main/java/crux/bphc/cms/models/course/CourseSection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package crux.bphc.cms.models.course
import androidx.core.text.HtmlCompat
import com.google.gson.annotations.SerializedName
import crux.bphc.cms.interfaces.CourseContent
import crux.bphc.cms.models.UserAccount
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import java.util.regex.Matcher
import java.util.regex.Pattern

/**
* @author Harshit Agarwal (17-Dec-2016)
Expand All @@ -15,24 +18,41 @@ open class CourseSection(
@PrimaryKey @SerializedName("id") var id: Int = 0,
name: String = "",
@SerializedName("section") var sectionNum: Int = 0,
@SerializedName("summary") var summary: String = "",
summary: String = "",
@SerializedName("modules") var modules: RealmList<Module> = RealmList<Module>(),
var courseId: Int = 0,
) : RealmObject(), CourseContent {

@SerializedName("name") var name: String = name
get() {
return HtmlCompat.fromHtml(field, HtmlCompat.FROM_HTML_MODE_COMPACT).toString()
.trim { it <= ' ' }
.trim { it <= ' ' }
}

@SerializedName("summary") var summary: String = summary
get() {
val pattern: Pattern = Pattern.compile(URL_REGEX)
val matcher: Matcher = pattern.matcher(field)

val summaryBuffer = StringBuffer(field.length)

while (matcher.find()) {
val foundLink = matcher.group(1)
val replaceWith = "<a href=\"$foundLink?token=${UserAccount.token}\">"
matcher.appendReplacement(summaryBuffer, replaceWith)
}
matcher.appendTail(summaryBuffer)

return summaryBuffer.toString().trim { it <= ' ' }
}

fun deepCopy(): CourseSection = CourseSection(
id,
name,
sectionNum,
summary,
RealmList<Module>(*modules.map { it.deepCopy() }.toTypedArray()),
courseId,
id,
name,
sectionNum,
summary,
RealmList<Module>(*modules.map { it.deepCopy() }.toTypedArray()),
courseId,
)

override fun equals(other: Any?): Boolean {
Expand All @@ -42,4 +62,8 @@ open class CourseSection(
override fun hashCode(): Int {
return id
}

companion object {
private const val URL_REGEX = "<a href=\"(.*?)\">"
}
}
68 changes: 46 additions & 22 deletions app/src/main/java/crux/bphc/cms/models/course/Module.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,31 @@ import androidx.core.text.HtmlCompat
import com.google.gson.annotations.SerializedName
import crux.bphc.cms.R
import crux.bphc.cms.interfaces.CourseContent
import crux.bphc.cms.models.UserAccount
import crux.bphc.cms.utils.FileUtils
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import java.util.*
import java.util.regex.Matcher
import java.util.regex.Pattern

/**
* @author Harshit Agarwal (16-Dec-2016)
* @author Abhijeet Viswa
*/
open class Module(
@PrimaryKey @SerializedName("id") var id: Int = 0,
@SerializedName("instance") var instance: Int = 0,
name: String = "",
@SerializedName("url") var url: String = "",
@SerializedName("modicon") var modIcon: String = "",
@SerializedName("modname") private var modName: String = "",
@SerializedName("description") var description: String = "",
@SerializedName("contents") var contents: RealmList<Content> = RealmList(),
var courseSectionId: Int = 0,
var isUnread: Boolean = false,
@PrimaryKey @SerializedName("id") var id: Int = 0,
@SerializedName("instance") var instance: Int = 0,
name: String = "",
@SerializedName("url") var url: String = "",
@SerializedName("modicon") var modIcon: String = "",
@SerializedName("modname") private var modName: String = "",
description: String = "",
@SerializedName("contents") var contents: RealmList<Content> = RealmList(),
var courseSectionId: Int = 0,
var isUnread: Boolean = false,
) : RealmObject(), CourseContent {
enum class Type {
RESOURCE, FORUM, LABEL, ASSIGNMENT, FOLDER, QUIZ, URL, PAGE, DEFAULT, BOOK
Expand All @@ -34,7 +37,24 @@ open class Module(
@SerializedName("name") var name: String = name
get() {
return HtmlCompat.fromHtml(field, HtmlCompat.FROM_HTML_MODE_COMPACT).toString()
.trim{ it <= ' ' }
.trim{ it <= ' ' }
}

@SerializedName("description") var description: String = description
get() {
val pattern: Pattern = Pattern.compile(URL_REGEX)
val matcher: Matcher = pattern.matcher(field)

val descriptionBuffer = StringBuffer(field.length)

while (matcher.find()) {
val foundLink = matcher.group(1)
val replaceWith = "<a href=\"$foundLink?token=${UserAccount.token}\">"
matcher.appendReplacement(descriptionBuffer, replaceWith)
}
matcher.appendTail(descriptionBuffer)

return descriptionBuffer.toString().trim { it <= ' ' }
}

@Ignore var modType: Type = Type.DEFAULT
Expand Down Expand Up @@ -67,20 +87,20 @@ open class Module(
}

fun deepCopy(): Module = Module(
id,
instance,
name,
url,
modIcon,
modName,
description,
RealmList<Content>(*contents.map { it.copy() }.toTypedArray()),
courseSectionId,
isUnread,
id,
instance,
name,
url,
modIcon,
modName,
description,
RealmList<Content>(*contents.map { it.copy() }.toTypedArray()),
courseSectionId,
isUnread,
)

private fun inferModuleTypeFromModuleName(): Type {
return when (modName.toLowerCase(Locale.ROOT)) {
return when (modName.lowercase(Locale.ROOT)) {
"resource" -> Type.RESOURCE
"forum" -> Type.FORUM
"label" -> Type.LABEL
Expand All @@ -100,4 +120,8 @@ open class Module(
override fun hashCode(): Int {
return id
}

companion object {
private const val URL_REGEX = "<a href=\"(.*?)\">"
}
}
Loading

0 comments on commit a1855b6

Please sign in to comment.