Skip to content

Commit

Permalink
Feature: Add basic FAQ functionality (#403)
Browse files Browse the repository at this point in the history
  • Loading branch information
FelberMartin authored Feb 14, 2025
1 parent 7d027a8 commit a429a9c
Show file tree
Hide file tree
Showing 38 changed files with 1,264 additions and 199 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ dependencies {
implementation(project(":feature:quiz"))
implementation(project(":feature:push"))
implementation(project(":feature:metis"))
implementation(project(":feature:faq"))

kover(project(":core:common"))
kover(project(":core:data"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import de.tum.informatics.www1.artemis.native_app.feature.courseregistration.cou
import de.tum.informatics.www1.artemis.native_app.feature.courseview.courseViewModule
import de.tum.informatics.www1.artemis.native_app.feature.dashboard.dashboardModule
import de.tum.informatics.www1.artemis.native_app.feature.exerciseview.exerciseModule
import de.tum.informatics.www1.artemis.native_app.feature.faq.faqModule
import de.tum.informatics.www1.artemis.native_app.feature.lectureview.lectureModule
import de.tum.informatics.www1.artemis.native_app.feature.login.loginModule
import de.tum.informatics.www1.artemis.native_app.feature.metis.communicationModule
Expand All @@ -33,6 +34,7 @@ val appModule = module { includes(
quizParticipationModule,
settingsModule,
lectureModule,
faqModule,
pushModule,
dbModule
)}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import de.tum.informatics.www1.artemis.native_app.feature.exerciseview.ExerciseV
import de.tum.informatics.www1.artemis.native_app.feature.exerciseview.ExerciseViewUi
import de.tum.informatics.www1.artemis.native_app.feature.exerciseview.exercise
import de.tum.informatics.www1.artemis.native_app.feature.exerciseview.navigateToExercise
import de.tum.informatics.www1.artemis.native_app.feature.faq.ui.detail.faqDetail
import de.tum.informatics.www1.artemis.native_app.feature.faq.ui.detail.navigateToFaqDetail
import de.tum.informatics.www1.artemis.native_app.feature.lectureview.lecture
import de.tum.informatics.www1.artemis.native_app.feature.lectureview.navigateToLecture
import de.tum.informatics.www1.artemis.native_app.feature.login.LoginScreen
Expand Down Expand Up @@ -127,6 +129,9 @@ fun NavGraphBuilder.rootNavGraph(
lectureId = lectureId
) { }
},
onNavigateToFaq = { courseId, faqId ->
navController.navigateToFaqDetail(courseId, faqId) { }
},
onNavigateBack = navController::navigateUp
)

Expand All @@ -152,6 +157,10 @@ fun NavGraphBuilder.rootNavGraph(
onClickViewQuizResults = onClickViewQuizResults
)

faqDetail(
onNavigateBack = navController::navigateUp
)

quizParticipation(
onLeaveQuiz = {
val previousBackStackEntry = navController.previousBackStackEntry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,8 @@ package de.tum.informatics.www1.artemis.native_app.core.common.markdown

abstract class ArtemisMarkdownTransformer {

/**
* Empty markdown transformer.
*/
companion object : ArtemisMarkdownTransformer() {
override fun transformExerciseMarkdown(title: String, url: String, type: String): String =
""

override fun transformUserMentionMarkdown(
text: String,
fullName: String,
userName: String
): String = ""

override fun transformChannelMentionMarkdown(
channelName: String,
conversationId: Long
): String = ""

override fun transformLectureContentMarkdown(
type: String,
fileName: String,
url: String
) : String = ""

override fun transformFileUploadMessageMarkdown(
isImage: Boolean,
fileName: String,
filePath: String,
) : String = ""
companion object {
val Default = object : ArtemisMarkdownTransformer() {}
}

private val exerciseMarkdownPattern =
Expand Down Expand Up @@ -92,32 +65,32 @@ abstract class ArtemisMarkdownTransformer {
}
}

protected abstract fun transformExerciseMarkdown(
protected open fun transformExerciseMarkdown(
title: String,
url: String,
type: String
): String
): String = "$type: $title"

protected abstract fun transformUserMentionMarkdown(
protected open fun transformUserMentionMarkdown(
text: String,
fullName: String,
userName: String
): String
): String = "@$userName"

protected abstract fun transformChannelMentionMarkdown(
protected open fun transformChannelMentionMarkdown(
channelName: String,
conversationId: Long
): String
): String = "#$channelName"

protected abstract fun transformLectureContentMarkdown(
protected open fun transformLectureContentMarkdown(
type: String,
fileName: String,
url: String
): String
): String = "$type: $fileName"

protected abstract fun transformFileUploadMessageMarkdown(
protected open fun transformFileUploadMessageMarkdown(
isImage: Boolean,
fileName: String,
filePath: String
): String
): String = fileName
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ data class Course(
val teachingAssistantGroupName: String = "",
val editorGroupName: String = "",
val testCourse: Boolean = false,
val courseInformationSharingMessagingCodeOfConduct: String = ""
val courseInformationSharingMessagingCodeOfConduct: String = "",
val faqEnabled: Boolean = false,
) {
enum class CourseInformationSharingConfiguration(val supportsMessaging: Boolean) {
COMMUNICATION_AND_MESSAGING(true),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ val LocalMarkwon: ProvidableCompositionLocal<Markwon?> =
compositionLocalOf { null }

@Composable
fun ProvideMarkwon(content: @Composable () -> Unit) {
fun ProvideMarkwon(
useOriginalImageSize: Boolean = false,
content: @Composable () -> Unit
) {
val imageLoader = LocalArtemisImageProvider.current.rememberArtemisImageLoader()
val linkResolver = LocalMarkdownLinkResolver.current.rememberMarkdownLinkResolver()
val context = LocalContext.current

val imageWidth = context.resources.displayMetrics.widthPixels
val markdownRender: Markwon = remember(imageLoader, linkResolver) {
createMarkdownRender(context, imageLoader, linkResolver, imageWidth)
val markdownRender: Markwon = remember(imageLoader, linkResolver, useOriginalImageSize) {
MarkdownRenderFactory.create(context, imageLoader, linkResolver, useOriginalImageSize)
}

CompositionLocalProvider(LocalMarkwon provides markdownRender) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package de.tum.informatics.www1.artemis.native_app.core.ui.markdown

import android.content.Context
import coil.ImageLoader
import coil.request.Disposable
import coil.request.ImageRequest
import coil.size.Scale
import de.tum.informatics.www1.artemis.native_app.core.common.R
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.LinkResolver
import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonConfiguration
import io.noties.markwon.MarkwonVisitor
import io.noties.markwon.core.MarkwonTheme
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin
import io.noties.markwon.ext.tables.TablePlugin
import io.noties.markwon.html.HtmlPlugin
import io.noties.markwon.image.AsyncDrawable
import io.noties.markwon.image.coil.CoilImagesPlugin
import io.noties.markwon.linkify.LinkifyPlugin
import org.commonmark.node.SoftLineBreak

private const val DEFAULT_IMAGE_HEIGHT = 800
private const val LINK_TYPE_HINT_ICON_HEIGHT = 52

object MarkdownRenderFactory {

fun create(
context: Context,
imageLoader: ImageLoader?,
linkResolver: LinkResolver?,
useOriginalImageSize: Boolean = false,
): Markwon {
val imagePlugin: CoilImagesPlugin? = createImagePlugin(imageLoader, context, useOriginalImageSize)
val linkHighlightPlugin = createLinkHighlightPlugin(context)
val softLineBreakPlugin = createSoftLineBreakPlugin()
val linkResolverPlugin: AbstractMarkwonPlugin? = createLinkResolverPlugin(linkResolver)

return Markwon.builder(context)
.usePlugin(HtmlPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(TablePlugin.create(context))
.usePlugin(LinkifyPlugin.create())
.usePlugin(linkHighlightPlugin)
.usePlugin(softLineBreakPlugin)
.apply {
if (imagePlugin != null) {
usePlugin(imagePlugin)
}
if (linkResolverPlugin != null) {
usePlugin(linkResolverPlugin)
}
}
.build()
}


private fun createImagePlugin(
imageLoader: ImageLoader?,
context: Context,
useOriginalImageSize: Boolean,
): CoilImagesPlugin? {
if (imageLoader == null) return null

val displayWidth = context.resources.displayMetrics.widthPixels
val coilStore = object : CoilImagesPlugin.CoilStore {
override fun load(drawable: AsyncDrawable): ImageRequest {
var height = DEFAULT_IMAGE_HEIGHT
if (drawable.destination.contains(TYPE_ICON_RESOURCE_PATH)) {
height = LINK_TYPE_HINT_ICON_HEIGHT
}

val builder = ImageRequest.Builder(context)
.defaults(imageLoader.defaults)
.data(drawable.destination)
.crossfade(true)

if (!useOriginalImageSize) {
builder.apply {
size(displayWidth, height) // We set a fixed height and set the width of the image to the screen width.
scale(Scale.FIT)
}
}

return builder.build()
}

override fun cancel(disposable: Disposable) {
disposable.dispose()
}
}

return CoilImagesPlugin.create(coilStore, imageLoader)
}

private fun createSoftLineBreakPlugin() = object : AbstractMarkwonPlugin() {
override fun configureVisitor(builder: MarkwonVisitor.Builder) {
builder.on(SoftLineBreak::class.java) { visitor, _ ->
visitor.forceNewLine()
}
}
}

private fun createLinkHighlightPlugin(context: Context) =
object : AbstractMarkwonPlugin() {
override fun configureTheme(builder: MarkwonTheme.Builder) {
builder
.linkColor(context.getColor(R.color.link_color))
.isLinkUnderlined(false)
}
}

private fun createLinkResolverPlugin(linkResolver: LinkResolver?): AbstractMarkwonPlugin? {
if (linkResolver == null) return null

return object : AbstractMarkwonPlugin() {
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
builder.linkResolver(linkResolver)
}
}
}
}
Loading

0 comments on commit a429a9c

Please sign in to comment.