Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Communication: Show profile picture #111

Merged
merged 45 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a07b44e
added lectureMarkdownPattern to markdown transformer
julian-wls Oct 24, 2024
31d6c5b
fixed links not opening inside the app
julian-wls Oct 27, 2024
4435755
Merge branch 'develop' into bugfix/communication/attachments-rendering
julian-wls Nov 13, 2024
8fddcb2
changed regex to distinguish between images and other files
julian-wls Nov 14, 2024
95120ee
added DefaultImageProvider to create ImageRequests and markdown Image…
julian-wls Nov 15, 2024
92f76c7
changed ImageRequest in DragAndDropWorkArea to use DefaultImageProvider
julian-wls Nov 15, 2024
0fcec6e
resolved merge conflict
julian-wls Nov 15, 2024
b8008a3
Merge branch 'develop' into bugfix/communication/attachments-rendering
julian-wls Nov 16, 2024
a7f37e7
changed parameters to only pass imageLoader down
julian-wls Nov 16, 2024
1732191
changes to add fixed size to images
julian-wls Nov 18, 2024
0f2b510
resolved some of the issues mentioned
julian-wls Nov 19, 2024
9f68876
fixed image sizing
julian-wls Nov 19, 2024
9c6ac81
resolved merge confict
julian-wls Nov 26, 2024
8f83931
minor changes
julian-wls Nov 26, 2024
cbd5289
minor changes
julian-wls Nov 26, 2024
ae42d96
Added authorImageUrl to posts
FelberMartin Nov 16, 2024
8801742
Started with compose impl
FelberMartin Nov 16, 2024
d6aa2fe
Add author_image_url to database queries
FelberMartin Nov 17, 2024
6a489ae
Showing profile pictures in chatlist
FelberMartin Nov 17, 2024
9ee564e
Added profile pictures to thread ui
FelberMartin Nov 17, 2024
f907a70
Add test for displaying profile picture
FelberMartin Nov 18, 2024
cf92ff0
Added role icon
FelberMartin Nov 18, 2024
63a5c44
Renaming
FelberMartin Nov 18, 2024
9159639
Created string resources for create_reply
FelberMartin Nov 19, 2024
f9935f9
Fixed merge issues
FelberMartin Nov 20, 2024
c0473c4
Addressing small change requests
FelberMartin Nov 26, 2024
715d199
Merge remote-tracking branch 'origin/bugfix/communication/attachments…
FelberMartin Nov 26, 2024
29389c4
Started using CompositionLocal; introduced ArtemisImageProvider
FelberMartin Nov 26, 2024
b3e3668
Merge branch 'develop' into bugfix/communication/attachments-rendering
FelberMartin Nov 28, 2024
944415e
Providing compositionLocals in MainActivity
FelberMartin Nov 28, 2024
1c0a4b7
remember imagerequest
FelberMartin Nov 28, 2024
5c17f3f
Introduced ProfilePictureData.Unknown
FelberMartin Nov 28, 2024
c8723c4
Remove authorImageUrl from posts
FelberMartin Nov 28, 2024
157cb1a
Updated tests + addressed remaining comments
FelberMartin Nov 29, 2024
62842d0
Merge branch 'develop' into bugfix/communication/attachments-rendering
FelberMartin Nov 29, 2024
75e2513
Merge branch 'develop' into bugfix/communication/attachments-rendering
FelberMartin Nov 29, 2024
edc6183
Merge remote-tracking branch 'origin/develop' into feature/communicat…
FelberMartin Nov 29, 2024
5ed6040
Merge branch 'develop' into bugfix/communication/attachments-rendering
FelberMartin Nov 29, 2024
5f8717a
Merge branch 'bugfix/communication/attachments-rendering' into featur…
FelberMartin Nov 30, 2024
4c9eb09
Fix empty username crash
FelberMartin Nov 30, 2024
fe7b816
Fix merge bug
FelberMartin Nov 30, 2024
37d2d02
Merge remote-tracking branch 'origin/develop' into feature/communicat…
FelberMartin Dec 5, 2024
75395d3
Update database schema version to 12
FelberMartin Dec 5, 2024
2e4f53b
Fix tests
FelberMartin Dec 5, 2024
02479e1
Merge branch 'develop' into feature/communication/show-profile-picture
FelberMartin Dec 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import de.tum.informatics.www1.artemis.native_app.feature.push.communication_not
CommunicationMessageEntity::class
],
exportSchema = true,
version = 11,
version = 12,
)
@TypeConverters(RoomTypeConverters::class)
abstract class AppDatabase : RoomDatabase() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import de.tum.informatics.www1.artemis.native_app.core.ui.LocalLinkOpener
import de.tum.informatics.www1.artemis.native_app.core.ui.LocalWindowSizeClassProvider
import de.tum.informatics.www1.artemis.native_app.core.ui.WindowSizeClassProvider
import de.tum.informatics.www1.artemis.native_app.core.ui.alert.TextAlertDialog
import de.tum.informatics.www1.artemis.native_app.core.ui.remote_images.LocalArtemisImageProvider
import de.tum.informatics.www1.artemis.native_app.feature.courseregistration.courseRegistration
import de.tum.informatics.www1.artemis.native_app.feature.courseregistration.navigateToCourseRegistration
import de.tum.informatics.www1.artemis.native_app.feature.courseview.ui.course_overview.course
Expand All @@ -53,7 +54,7 @@ import de.tum.informatics.www1.artemis.native_app.feature.lectureview.navigateTo
import de.tum.informatics.www1.artemis.native_app.feature.login.LoginScreen
import de.tum.informatics.www1.artemis.native_app.feature.login.loginScreen
import de.tum.informatics.www1.artemis.native_app.feature.login.navigateToLogin
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.ProvideLocalVisibleMetisContextManager
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.LocalVisibleMetisContextManager
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.VisibleMetisContext
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.VisibleMetisContextManager
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.VisibleMetisContextReporter
Expand All @@ -73,6 +74,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.koin.android.ext.android.get
import org.koin.compose.koinInject

/**
* Main and only activity used in the android app.
Expand Down Expand Up @@ -134,8 +136,8 @@ class MainActivity : AppCompatActivity(),

setContent {
AppTheme {
ProvideLocalVisibleMetisContextManager(
visibleMetisContextManager = visibleMetisContextManager
CompositionLocalProvider(
LocalVisibleMetisContextManager provides visibleMetisContextManager,
) {
val navController = rememberNavController()

Expand Down Expand Up @@ -251,7 +253,8 @@ class MainActivity : AppCompatActivity(),

CompositionLocalProvider(
LocalWindowSizeClassProvider provides windowSizeClassProvider,
LocalLinkOpener provides linkOpener
LocalLinkOpener provides linkOpener,
LocalArtemisImageProvider provides koinInject()
) {
// Use jetpack compose navigation for the navigation logic.
NavHost(navController = navController, startDestination = startDestination) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package de.tum.informatics.www1.artemis.native_app.core.ui.common

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp

val TextUnit.nonScaledSp
@Composable
get() = (this.value / LocalDensity.current.fontScale).sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package de.tum.informatics.www1.artemis.native_app.core.ui.remote_images

import androidx.compose.runtime.Composable
import androidx.compose.runtime.compositionLocalOf
import coil.compose.AsyncImagePainter
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest


val LocalArtemisImageProvider = compositionLocalOf<ArtemisImageProvider> { error("No ArtemisImageProvider provided") }

/**
* Provides a way to load images from the Artemis server. This interface implementation takes care
* of authentication and the applicable Artemis server URL.
*/
interface ArtemisImageProvider {

@Composable
fun rememberArtemisImageRequest(
imagePath: String,
): ImageRequest

@Composable
fun rememberArtemisAsyncImagePainter(
imagePath: String,
): AsyncImagePainter = rememberAsyncImagePainter(model = rememberArtemisImageRequest(imagePath))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package de.tum.informatics.www1.artemis.native_app.core.ui.remote_images

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import coil.request.ImageRequest
import de.tum.informatics.www1.artemis.native_app.core.datastore.AccountService
import de.tum.informatics.www1.artemis.native_app.core.datastore.ServerConfigurationService
import de.tum.informatics.www1.artemis.native_app.core.datastore.authToken

class ArtemisImageProviderImpl(
private val accountService: AccountService,
private val serverConfigurationService: ServerConfigurationService,
) : ArtemisImageProvider {

private val imageProvider = BaseImageProviderImpl()

@Composable
override fun rememberArtemisImageRequest(imagePath: String): ImageRequest {
val serverUrl by serverConfigurationService.serverUrl.collectAsState(initial = "")
val authToken by accountService.authToken.collectAsState(initial = "")

val context = LocalContext.current
return remember(serverUrl, authToken, imagePath) {
imageProvider.createImageRequest(
context = context,
imagePath = imagePath,
serverUrl = serverUrl,
authorizationToken = authToken,
memoryCacheKey = serverUrl + imagePath
)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package de.tum.informatics.www1.artemis.native_app.core.ui.remote_images

import android.content.Context
import coil.ImageLoader
import coil.request.ImageRequest
import io.ktor.http.HttpHeaders
import io.ktor.http.URLBuilder
import io.ktor.http.appendPathSegments

class BaseImageProviderImpl : BaseImageProvider {
override fun createImageRequest(
context: Context,
imagePath: String,
serverUrl: String,
authorizationToken: String,
memoryCacheKey: String?
): ImageRequest {
val imageUrl = URLBuilder(serverUrl).appendPathSegments(imagePath).buildString()

val builder = ImageRequest.Builder(context)
.addHeader(HttpHeaders.Cookie, "jwt=$authorizationToken")
.data(imageUrl)
// The following line is needed to for the AsyncImagePainter to work correctly, see:
// https://stackoverflow.com/a/74705550/13366254
.size(coil.size.Size.ORIGINAL)

memoryCacheKey?.let {
builder.memoryCacheKey(it)
}
return builder.build()
}

override fun createImageLoader(
context: Context,
authorizationToken: String
): ImageLoader {
return ImageLoader.Builder(context)
.okHttpClient {
okhttp3.OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.addHeader(HttpHeaders.Cookie, "jwt=$authorizationToken")
.build()
chain.proceed(request)
}
.build()
}
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface CourseImageProvider {
}

private object DefaultCourseImageProvider : CourseImageProvider {
private val imageProvider = DefaultImageProvider()
private val imageProvider = BaseImageProviderImpl()

@Composable
override fun rememberCourseImagePainter(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package de.tum.informatics.www1.artemis.native_app.core.ui

import de.tum.informatics.www1.artemis.native_app.core.ui.remote_images.ArtemisImageProvider
import de.tum.informatics.www1.artemis.native_app.core.ui.remote_images.ArtemisImageProviderImpl
import org.koin.dsl.module

val uiModule = module {
single<ArtemisImageProvider> { ArtemisImageProviderImpl(get(), get()) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
Expand Down Expand Up @@ -37,7 +38,7 @@ import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.d
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.conversation.OneToOneChat
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.db.pojo.PostPojo
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.ui.humanReadableName
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.ProvideLocalVisibleMetisContextManager
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.LocalVisibleMetisContextManager
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.VisibleMetisContext
import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.visiblemetiscontextreporter.VisibleMetisContextManager
import kotlinx.coroutines.CompletableDeferred
Expand Down Expand Up @@ -195,6 +196,15 @@ fun `Metis - Conversation Channel`() {
),
).reversed()

val visibleMetisContextManagerStub = object : VisibleMetisContextManager {
override fun registerMetisContext(metisContext: VisibleMetisContext) =
Unit

override fun unregisterMetisContext(metisContext: VisibleMetisContext) =
Unit
}

// TODO: Provide artemis image provider
ScreenshotFrame(title = "Send and receive messages directly from the app") {
CourseUiScreen(
modifier = Modifier.fillMaxSize(),
Expand All @@ -204,14 +214,8 @@ fun `Metis - Conversation Channel`() {
exerciseTabContent = { },
lectureTabContent = { },
communicationTabContent = {
ProvideLocalVisibleMetisContextManager(
visibleMetisContextManager = object : VisibleMetisContextManager {
override fun registerMetisContext(metisContext: VisibleMetisContext) =
Unit

override fun unregisterMetisContext(metisContext: VisibleMetisContext) =
Unit
}
CompositionLocalProvider(
LocalVisibleMetisContextManager provides visibleMetisContextManagerStub,
) {
ConversationChatListScreen(
modifier = Modifier.fillMaxSize(),
Expand Down Expand Up @@ -284,6 +288,7 @@ private fun generateMessage(
authorName = name,
authorRole = UserRole.USER,
authorId = authorId,
authorImageUrl = null,
creationDate = time,
updatedDate = null,
resolved = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ internal class MetisStorageServiceImpl(
val user = MetisUserEntity(
serverId = serverId,
id = authorId,
displayName = author?.name ?: "NULL"
displayName = author?.name ?: "NULL",
imageUrl = author?.imageUrl
)

return Triple(basePost, answer, user)
Expand All @@ -138,7 +139,8 @@ internal class MetisStorageServiceImpl(
) to MetisUserEntity(
serverId = serverId,
id = userId,
displayName = user?.name ?: return null
imageUrl = user?.imageUrl,
displayName = user?.name ?: return null,
)
}

Expand Down Expand Up @@ -443,7 +445,8 @@ internal class MetisStorageServiceImpl(
val postingAuthor = MetisUserEntity(
serverId = host,
id = sp.author?.id ?: return null,
displayName = sp.author?.name ?: return null
displayName = sp.author?.name ?: return null,
imageUrl = sp.author?.imageUrl
)

val (standaloneBasePosting, standalonePosting) = sp.asDb(
Expand All @@ -466,7 +469,9 @@ internal class MetisStorageServiceImpl(
}

// First insert the users as they have no dependencies
metisDao.updateUsers(standalonePostReactionsUsers)
// TODO: Do not update existing users, as for the reactions we always get null as image_url
// Can be undone when https://github.com/ls1intum/Artemis/pull/9897 is merged.
// metisDao.updateUsers(standalonePostReactionsUsers)
metisDao.insertUsers(standalonePostReactionsUsers)

metisDao.insertOrUpdateUser(postingAuthor)
Expand Down Expand Up @@ -571,7 +576,10 @@ internal class MetisStorageServiceImpl(
val answerPostReactionUsers = answerPostReactionsWithUsers.map { it.second }

metisDao.insertOrUpdateUser(metisUserEntity)
metisDao.updateUsers(answerPostReactionUsers)

// TODO: Do not update existing users, as for the reactions we always get null as image_url
// Can be undone when https://github.com/ls1intum/Artemis/pull/9897 is merged.
// metisDao.updateUsers(answerPostReactionUsers)
metisDao.insertUsers(answerPostReactionUsers)

if (isNewPost) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import de.tum.informatics.www1.artemis.native_app.core.model.exercise.Programmin
import de.tum.informatics.www1.artemis.native_app.core.model.exercise.QuizExercise
import de.tum.informatics.www1.artemis.native_app.core.model.exercise.TextExercise
import de.tum.informatics.www1.artemis.native_app.core.model.exercise.UnknownExercise
import de.tum.informatics.www1.artemis.native_app.core.ui.remote_images.DefaultImageProvider
import de.tum.informatics.www1.artemis.native_app.core.ui.remote_images.BaseImageProviderImpl
import de.tum.informatics.www1.artemis.native_app.core.ui.serverUrlStateFlow
import de.tum.informatics.www1.artemis.native_app.core.websocket.WebsocketProvider
import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.R
Expand Down Expand Up @@ -710,7 +710,7 @@ internal open class ConversationViewModel(

fun createMarkdownImageLoader(context: Context): Deferred<ImageLoader> {
return viewModelScope.async(coroutineContext) {
val imageProvider = DefaultImageProvider()
val imageProvider = BaseImageProviderImpl()
val authorizationToken = accountService.authToken.first()
imageProvider.createImageLoader(context, authorizationToken)
}
Expand Down
Loading
Loading