From 7a458dab7afc1e4b215588666027206e2f7cf34b Mon Sep 17 00:00:00 2001 From: Martin Felber <45291671+FelberMartin@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:10:24 +0100 Subject: [PATCH 01/22] Add PR template (#116) --- .github/pull_request_template.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..e06b7b0f9 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ + + +### Problem Description + + +### Changes + + + +### Steps for testing + + +### Screenshots From 1e24253ede18ea0a32a3022f57da541578a4136c Mon Sep 17 00:00:00 2001 From: Martin Felber <45291671+FelberMartin@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:30:18 +0100 Subject: [PATCH 02/22] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 60cb29409..e52a0b2c2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,7 +7,7 @@ assignees: '' --- -**Describe the bug** +### Describe the bug A clear and concise description of what the bug is. **To Reproduce** @@ -20,8 +20,8 @@ Steps to reproduce the behavior: **Expected behavior** A clear and concise description of what you expected to happen. -**Screenshots** +### Screenshots If applicable, add screenshots to help explain your problem. -**Additional context** +### Additional context Add any other context about the problem here. From ea12b02b93de446998ff843384044bd8d06c792d Mon Sep 17 00:00:00 2001 From: Martin Felber <45291671+FelberMartin@users.noreply.github.com> Date: Tue, 19 Nov 2024 22:16:56 +0100 Subject: [PATCH 03/22] `Chore`: Display server url in settings (#122) --- .../artemis/native_app/feature/settings/SettingsScreen.kt | 8 ++++++++ feature/settings/src/main/res/values/settings_strings.xml | 1 + 2 files changed, 9 insertions(+) diff --git a/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/SettingsScreen.kt b/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/SettingsScreen.kt index e17afc751..dfba46ced 100644 --- a/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/SettingsScreen.kt +++ b/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/SettingsScreen.kt @@ -207,6 +207,7 @@ private fun SettingsScreen( AboutSection( modifier = Modifier.fillMaxWidth(), hasUserSelectedInstance = hasUserSelectedInstance, + serverUrl = serverUrl, onOpenPrivacyPolicy = { val link = URLBuilder(serverUrl).appendPathSegments("privacy").buildString() @@ -334,6 +335,7 @@ private fun NotificationSection(modifier: Modifier, onOpenNotificationSettings: private fun AboutSection( modifier: Modifier, hasUserSelectedInstance: Boolean, + serverUrl: String, onRequestSelectServerInstance: () -> Unit, onOpenPrivacyPolicy: () -> Unit, onOpenImprint: () -> Unit, @@ -352,6 +354,12 @@ private fun AboutSection( } if (hasUserSelectedInstance) { + PreferenceEntry( + modifier = Modifier.fillMaxWidth(), + text = stringResource(R.string.settings_server_url, serverUrl), + onClick = {} + ) + PreferenceEntry( modifier = Modifier.fillMaxWidth(), text = stringResource(id = R.string.settings_about_privacy_policy), diff --git a/feature/settings/src/main/res/values/settings_strings.xml b/feature/settings/src/main/res/values/settings_strings.xml index 3954c4b7c..ec4a71b13 100644 --- a/feature/settings/src/main/res/values/settings_strings.xml +++ b/feature/settings/src/main/res/values/settings_strings.xml @@ -12,6 +12,7 @@ About Imprint and privacy policy depend on the server you have currently selected. + Server URL: %1$s Imprint and privacy policy are unavailable as you have not yet selected a server instance. Please select a server instance to view their privacy policy and imprint. Select instance Privacy policy From 5e0e7763a7f44f79aa78a8597274ffd6433ff630 Mon Sep 17 00:00:00 2001 From: Martin Felber <45291671+FelberMartin@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:29:39 +0100 Subject: [PATCH 04/22] Fix answer post got duplicated (#96) --- feature/metis/conversation/build.gradle.kts | 8 +- .../storage/impl/MetisStorageServiceImpl.kt | 16 +- ...geServiceImplTestUpgradeLocalAnswerPost.kt | 207 ++++++++++++++++++ .../feature/metis/shared/db/MetisDao.kt | 2 +- gradle/libs.versions.toml | 2 + 5 files changed, 228 insertions(+), 7 deletions(-) create mode 100644 feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/service/storage/impl/MetisStorageServiceImplTestUpgradeLocalAnswerPost.kt diff --git a/feature/metis/conversation/build.gradle.kts b/feature/metis/conversation/build.gradle.kts index 498c87285..c83ed2e88 100644 --- a/feature/metis/conversation/build.gradle.kts +++ b/feature/metis/conversation/build.gradle.kts @@ -20,6 +20,7 @@ dependencies { implementation(project(":core:device")) implementation(project(":feature:metis:shared")) + testImplementation(project(":feature:metis-test")) implementation(libs.androidx.paging.runtime) implementation(libs.androidx.paging.compose) @@ -33,10 +34,9 @@ dependencies { implementation(libs.androidx.work.runtime.ktx) implementation(libs.androidx.dataStore.preferences) - - testImplementation(project(":feature:metis-test")) - implementation("androidx.paging:paging-common:3.2.1") - + implementation(libs.androidx.paging.common) + + testImplementation(libs.androidx.paging.testing) testImplementation(libs.mockk.android) testImplementation(libs.mockk.agent) } diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/service/storage/impl/MetisStorageServiceImpl.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/service/storage/impl/MetisStorageServiceImpl.kt index da80b42be..d9bca3b4a 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/service/storage/impl/MetisStorageServiceImpl.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/service/storage/impl/MetisStorageServiceImpl.kt @@ -2,9 +2,9 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.se import androidx.paging.PagingSource import androidx.room.withTransaction -import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.MetisContext import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.storage.MetisStorageService import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.MetisDatabaseProvider +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.MetisContext import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.AnswerPost import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.BasePost import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.CourseWideContext @@ -336,6 +336,19 @@ internal class MetisStorageServiceImpl( val metisDao = databaseProvider.metisDao databaseProvider.database.withTransaction { + val doesPostAnswerAlreadyExist = metisDao.isPostPresentInContext( + serverId = host, + serverPostId = post.id ?: return@withTransaction, + courseId = metisContext.courseId, + conversationId = metisContext.conversationId + ) + + // In rare cases, the websocket connection already inserted the post answer. In that case, we can delete the client side post. + if (doesPostAnswerAlreadyExist) { + metisDao.deletePostingWithClientSideId(clientPostId = clientSidePostId) + return@withTransaction + } + metisDao.upgradePost( clientSidePostId = clientSidePostId, serverSidePostId = post.id ?: return@withTransaction @@ -502,7 +515,6 @@ internal class MetisStorageServiceImpl( answerServerIds = sp.answers.orEmpty().mapNotNull { it.id } ) } - for (ap in sp.answers.orEmpty()) { val answerPostId = ap.id ?: continue diff --git a/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/service/storage/impl/MetisStorageServiceImplTestUpgradeLocalAnswerPost.kt b/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/service/storage/impl/MetisStorageServiceImplTestUpgradeLocalAnswerPost.kt new file mode 100644 index 000000000..cbe8a8b9a --- /dev/null +++ b/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/service/storage/impl/MetisStorageServiceImplTestUpgradeLocalAnswerPost.kt @@ -0,0 +1,207 @@ +package de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.storage.impl + +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingSource +import androidx.paging.testing.asSnapshot +import androidx.test.platform.app.InstrumentationRegistry +import de.tum.informatics.www1.artemis.native_app.core.common.test.UnitTest +import de.tum.informatics.www1.artemis.native_app.core.model.account.User +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.MetisContext +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.AnswerPost +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.StandalonePost +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.UserRole +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.AnswerPostPojo +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.db.pojo.PostPojo +import de.tum.informatics.www1.artemis.native_app.feature.metistest.MetisDatabaseProviderMock +import kotlinx.coroutines.test.runTest +import kotlinx.datetime.Clock +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.experimental.categories.Category +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@Category(UnitTest::class) +@RunWith(RobolectricTestRunner::class) +class MetisStorageServiceImplUpgradeLocalAnswerPostTest { + + private val databaseProviderMock = MetisDatabaseProviderMock(InstrumentationRegistry.getInstrumentation().context) + private val sut = MetisStorageServiceImpl(databaseProviderMock) + + private val host = "host" + + private val author = User(id = 20, name = "AuthorName") + private val parentClientPostId = "parent-client-id-0" + private val answerClientPostId = "answer-client-id-0" + + private val course: MetisContext.Course = MetisContext.Course(courseId = 1) + private val conversation = OneToOneChat(id = 2) + private val metisContext = MetisContext.Conversation(course.courseId, conversation.id) + + private val localAnswerPojo = AnswerPostPojo( + parentPostId = parentClientPostId, + postId = answerClientPostId, + resolvesPost = false, + basePostingCache = AnswerPostPojo.BasePostingCache( + serverPostId = 0, + authorId = author.id, + creationDate = Clock.System.now(), + updatedDate = null, + content = "Answer post content 0", + authorRole = UserRole.USER, + authorName = author.name!! + ), + reactions = emptyList(), + serverPostIdCache = AnswerPostPojo.ServerPostIdCache( + serverPostId = null // Only local answer post, no server id + ) + ) + + private val basePostPojo = PostPojo( + clientPostId = parentClientPostId, + serverPostId = 0, + content = "Base post content", + resolved = false, + updatedDate = null, + creationDate = Clock.System.now(), + authorId = author.id, + title = null, + authorName = author.name!!, + authorRole = UserRole.USER, + courseWideContext = null, + tags = emptyList(), + answers = emptyList(), + reactions = emptyList() + ) + + private val basePost = StandalonePost(basePostPojo, conversation) + private val localAnswer = AnswerPost(localAnswerPojo, basePost) + + private lateinit var basePostUpdated: StandalonePost + private lateinit var answerUpdated: AnswerPost + + @Test + fun testInsertClientSidePost() = runTest { + // GIVEN: A base post + sut.insertOrUpdatePosts( + host = host, + metisContext = metisContext, + posts = listOf(basePost), + ) + + // WHEN: Inserting a client side answer post + sut.insertClientSidePost( + host = host, + metisContext = metisContext, + post = localAnswer, + clientSidePostId = answerClientPostId + ) + + // THEN: Both the base post and the answer post are stored + assertStoredContentIsTheSame() + } + + @Test + fun testUpgradeClientSideAnswerPost() = runTest { + // GIVEN: A post with a new only local answer post + setupPostWithLocalAnswer() + + // WHEN: insertOrUpdatePosts is called before upgradeClientSideAnswerPost. + updateAnswerPostWithServerId() + + // Called by the WebSocket + sut.updatePost( + host = host, + metisContext = metisContext, + post = basePostUpdated + ) + + // Called by SendConversationPostWorker + sut.upgradeClientSideAnswerPost( + host = host, + metisContext = metisContext, + clientSidePostId = answerClientPostId, + post = answerUpdated + ) + + // THEN: Content stays the same and the upgrade is successful + assertStoredContentIsTheSame() + assertUpgradeSuccessful() + } + + @Test + fun testUpgradeClientSideAnswerPost2() = runTest { + // GIVEN: A post with a new only local answer post + setupPostWithLocalAnswer() + + // WHEN: upgradeClientSideAnswerPost is called before updatePost. + updateAnswerPostWithServerId() + + // Called by SendConversationPostWorker + sut.upgradeClientSideAnswerPost( + host = host, + metisContext = metisContext, + clientSidePostId = answerClientPostId, + post = answerUpdated + ) + + // Called by the WebSocket + sut.updatePost( + host = host, + metisContext = metisContext, + post = basePostUpdated + ) + + // THEN: Content stays the same and the upgrade is successful + assertStoredContentIsTheSame() + assertUpgradeSuccessful() + } + + private suspend fun setupPostWithLocalAnswer() { + sut.insertOrUpdatePosts( + host = host, + metisContext = metisContext, + posts = listOf(basePost) + ) + sut.insertClientSidePost( + host = host, + metisContext = metisContext, + clientSidePostId = answerClientPostId, + post = localAnswer + ) + } + + + private fun updateAnswerPostWithServerId() { + val answerPojoUpdated = localAnswerPojo.copy(serverPostIdCache = localAnswerPojo.serverPostIdCache.copy(serverPostId = 1)) + basePostUpdated = StandalonePost(basePostPojo, conversation) + answerUpdated = AnswerPost(answerPojoUpdated, basePostUpdated) + basePostUpdated = basePostUpdated.copy(answers = listOf(answerUpdated)) + } + + private suspend fun assertStoredContentIsTheSame() { + val posts = getStoredPosts() + assertEquals(1, posts.size) + assertEquals(basePostPojo.content, posts.first().content) + assertEquals(1, posts.first().answers.size) + assertEquals(localAnswerPojo.content, posts.first().answers.first().content) + } + + private suspend fun assertUpgradeSuccessful() { + val posts = getStoredPosts() + assertEquals(answerUpdated.serverPostId, posts.first().answers.first().serverPostId) + } + + private suspend fun getStoredPosts() = sut.getStoredPosts( + serverId = host, + metisContext = metisContext + ).loadAsList() + + private suspend fun PagingSource.loadAsList(): List { + return Pager(PagingConfig(pageSize = 10), pagingSourceFactory = { this }).flow.asSnapshot { + scrollTo(50) + } + } +} \ No newline at end of file diff --git a/feature/metis/shared/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/shared/db/MetisDao.kt b/feature/metis/shared/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/shared/db/MetisDao.kt index 73207808a..c82654043 100644 --- a/feature/metis/shared/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/shared/db/MetisDao.kt +++ b/feature/metis/shared/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/shared/db/MetisDao.kt @@ -140,7 +140,7 @@ interface MetisDao { postingType: BasePostingEntity.PostingType = BasePostingEntity.PostingType.STANDALONE ) - @Query("delete from metis_post_context where client_post_id = :clientPostId") + @Query("delete from postings where id = :clientPostId") suspend fun deletePostingWithClientSideId( clientPostId: String ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1b8007277..7b14ab928 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -72,6 +72,8 @@ androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "li androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidxNavigation" } androidx-paging-runtime = { group = "androidx.paging", name = "paging-runtime", version.ref = "androidxPaging" } androidx-paging-compose = { group = "androidx.paging", name = "paging-compose", version.ref = "androidxPagingCompose" } +androidx-paging-common = { group = "androidx.paging", name = "paging-common", version.ref = "androidxPaging" } +androidx-paging-testing = { group = "androidx.paging", name = "paging-testing", version.ref = "androidxPaging" } androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } androidx-room-paging = { group = "androidx.room", name = "room-paging", version.ref = "room" } From d8cb940c1713d0ca6f61f0a5bdd43dd8cb13da2e Mon Sep 17 00:00:00 2001 From: Julian Waluschyk <37155504+julian-wls@users.noreply.github.com> Date: Wed, 20 Nov 2024 15:08:34 +0100 Subject: [PATCH 05/22] Display content edge-to-edge (#91) Co-authored-by: Martin Felber <45291671+FelberMartin@users.noreply.github.com> --- .../native_app/android/ui/MainActivity.kt | 1 + .../core/ui/common/course/CourseListUi.kt | 14 ++- .../courseregistration/RegisterForCourseUi.kt | 8 +- .../feature/courseview/ui/WeeklyItemsUi.kt | 12 +- .../ui/course_overview/CourseUiScreen.kt | 6 +- .../feature/dashboard/CoursesOverview.kt | 8 +- .../feature/lectureview/AttachmentsTab.kt | 11 +- .../feature/lectureview/LectureScreenUi.kt | 2 +- .../feature/lectureview/OverviewTab.kt | 10 +- .../native_app/feature/login/AccountUi.kt | 15 ++- .../feature/login/NotificationSettingsUi.kt | 6 +- .../InstanceSelectionScreen.kt | 8 +- .../native_app/feature/login/login/LoginUi.kt | 1 + .../feature/login/register/RegisterUi.kt | 3 +- .../feature/login/RegisterEndToEndTest.kt | 2 + .../codeofconduct/ui/AcceptCodeOfConductUi.kt | 9 +- .../ui/ConversationChatListScreen.kt | 12 +- .../ui/ConversationThreadScreen.kt | 6 +- .../conversation/ui/chatlist/MetisChatList.kt | 4 +- .../ui/post/PostContextBottomSheet.kt | 3 + .../conversation/ui/thread/MetisThreadUi.kt | 7 +- .../metis/conversation/BaseThreadUITest.kt | 97 +++++++++++++++ .../ConversationAnswerMessagesUITest.kt | 115 ++---------------- .../reply/ReplyTextFieldVisibilityUITest.kt | 85 +++++++++++++ .../browse_channels/BrowseChannelsScreen.kt | 6 +- .../create_channel/CreateChannelScreen.kt | 2 + .../CreatePersonalConversationScreen.kt | 2 + .../overview/ConversationOverviewBody.kt | 17 ++- .../members/ConversationMembersScreen.kt | 5 +- .../overview/ConversationSettingsBody.kt | 6 +- .../overview/ConversationSettingsScreen.kt | 8 +- .../PushNotificationSettingsScreen.kt | 8 +- .../feature/settings/SettingsScreen.kt | 8 +- 33 files changed, 372 insertions(+), 135 deletions(-) create mode 100644 feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/BaseThreadUITest.kt create mode 100644 feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/reply/ReplyTextFieldVisibilityUITest.kt diff --git a/app/src/main/java/de/tum/informatics/www1/artemis/native_app/android/ui/MainActivity.kt b/app/src/main/java/de/tum/informatics/www1/artemis/native_app/android/ui/MainActivity.kt index ce578fb53..e7903bcba 100644 --- a/app/src/main/java/de/tum/informatics/www1/artemis/native_app/android/ui/MainActivity.kt +++ b/app/src/main/java/de/tum/informatics/www1/artemis/native_app/android/ui/MainActivity.kt @@ -91,6 +91,7 @@ class MainActivity : AppCompatActivity(), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() // When the user is logged in, immediately display the course overview. val startDestination = runBlocking { diff --git a/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/common/course/CourseListUi.kt b/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/common/course/CourseListUi.kt index 661e46bde..bef41c94c 100644 --- a/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/common/course/CourseListUi.kt +++ b/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/common/course/CourseListUi.kt @@ -9,12 +9,22 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.ime +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeContent +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridItemScope import androidx.compose.foundation.lazy.grid.LazyVerticalGrid @@ -71,7 +81,9 @@ fun CourseItemGrid( columns = GridCells.Fixed(columnCount), verticalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), - contentPadding = PaddingValues(bottom = 90.dp) + contentPadding = PaddingValues( + bottom = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding() + ) ) { items(courses, key = { it.course.id ?: 0L }) { course -> courseItem(course, courseItemModifier, isCompact) diff --git a/feature/course-registration/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseregistration/RegisterForCourseUi.kt b/feature/course-registration/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseregistration/RegisterForCourseUi.kt index c3c8d6fa2..44d0a3a63 100644 --- a/feature/course-registration/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseregistration/RegisterForCourseUi.kt +++ b/feature/course-registration/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseregistration/RegisterForCourseUi.kt @@ -6,9 +6,13 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.LazyVerticalGrid @@ -140,7 +144,8 @@ internal fun RegisterForCourseScreen( RegisterForCourseContent( modifier = Modifier .fillMaxSize() - .padding(padding) + .padding(top = padding.calculateTopPadding()) + .consumeWindowInsets(WindowInsets.systemBars) .padding(horizontal = 8.dp), courses = courses, serverUrl = properServerUrl, @@ -235,6 +240,7 @@ private fun RegisterForCourseContent( .fillMaxSize() .testTag(TEST_TAG_REGISTRABLE_COURSE_LIST), columns = GridCells.Fixed(columnCount), + contentPadding = WindowInsets.systemBars.asPaddingValues(), verticalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { diff --git a/feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/WeeklyItemsUi.kt b/feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/WeeklyItemsUi.kt index 9f641b192..40f93d56b 100644 --- a/feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/WeeklyItemsUi.kt +++ b/feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/WeeklyItemsUi.kt @@ -3,9 +3,13 @@ package de.tum.informatics.www1.artemis.native_app.feature.courseview.ui import android.os.Parcelable import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons @@ -71,7 +75,13 @@ internal fun WeeklyItemsLazyColumn( } } - LazyColumn(modifier = modifier, verticalArrangement = verticalArrangement) { + LazyColumn( + modifier = modifier, + verticalArrangement = verticalArrangement, + contentPadding = PaddingValues( + bottom = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding() + ) + ) { weeklyItemGroups.forEachIndexed { index, weeklyItems -> item { WeeklyItemsSectionHeader( diff --git a/feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/course_overview/CourseUiScreen.kt b/feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/course_overview/CourseUiScreen.kt index c2eedf643..557480740 100644 --- a/feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/course_overview/CourseUiScreen.kt +++ b/feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/course_overview/CourseUiScreen.kt @@ -6,8 +6,11 @@ import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -331,7 +334,8 @@ internal fun CourseUiScreen( BasicDataStateUi( modifier = Modifier .fillMaxSize() - .padding(padding), + .padding(top = padding.calculateTopPadding()) + .consumeWindowInsets(WindowInsets.systemBars), dataState = courseDataState, loadingText = stringResource(id = R.string.course_ui_loading_course_loading), failureText = stringResource(id = R.string.course_ui_loading_course_failed), diff --git a/feature/dashboard/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/dashboard/CoursesOverview.kt b/feature/dashboard/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/dashboard/CoursesOverview.kt index 1436d7c7b..dc93016f4 100644 --- a/feature/dashboard/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/dashboard/CoursesOverview.kt +++ b/feature/dashboard/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/dashboard/CoursesOverview.kt @@ -8,10 +8,15 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -188,7 +193,8 @@ internal fun CoursesOverview( BasicDataStateUi( modifier = Modifier .fillMaxSize() - .padding(padding), + .padding(top = padding.calculateTopPadding()) + .consumeWindowInsets(WindowInsets.systemBars), dataState = coursesDataState, loadingText = stringResource(id = R.string.courses_loading_loading), failureText = stringResource(id = R.string.courses_loading_failure), diff --git a/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/AttachmentsTab.kt b/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/AttachmentsTab.kt index 64ba8bc73..0e01ea757 100644 --- a/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/AttachmentsTab.kt +++ b/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/AttachmentsTab.kt @@ -2,9 +2,13 @@ package de.tum.informatics.www1.artemis.native_app.feature.lectureview import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons @@ -31,7 +35,12 @@ internal fun AttachmentsTab( onClickOpenLinkAttachment: (Attachment) -> Unit ) { if (attachments.isNotEmpty()) { - LazyColumn(modifier = modifier) { + LazyColumn( + modifier = modifier, + contentPadding = PaddingValues( + bottom = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding() + ) + ) { items(attachments) { attachment -> AttachmentItem( modifier = Modifier.fillMaxWidth(), diff --git a/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/LectureScreenUi.kt b/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/LectureScreenUi.kt index 8a6787be9..3e693705e 100644 --- a/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/LectureScreenUi.kt +++ b/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/LectureScreenUi.kt @@ -195,7 +195,7 @@ internal fun LectureScreen( ) { padding -> val bodyModifier = Modifier .fillMaxSize() - .padding(padding) + .padding(top = padding.calculateTopPadding()) contentBody( bodyModifier diff --git a/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/OverviewTab.kt b/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/OverviewTab.kt index 2da11137c..a53a80388 100644 --- a/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/OverviewTab.kt +++ b/feature/lecture-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/lectureview/OverviewTab.kt @@ -2,7 +2,12 @@ package de.tum.informatics.www1.artemis.native_app.feature.lectureview import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListState @@ -50,7 +55,10 @@ internal fun OverviewTab( LazyColumn( modifier = modifier.testTag(TEST_TAG_OVERVIEW_LIST), verticalArrangement = Arrangement.spacedBy(16.dp), - state = state + state = state, + contentPadding = PaddingValues( + bottom = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding() + ) ) { if (description != null) { item { diff --git a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/AccountUi.kt b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/AccountUi.kt index a64be37e2..d5ab2fc50 100644 --- a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/AccountUi.kt +++ b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/AccountUi.kt @@ -10,10 +10,15 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.ClickableText import androidx.compose.foundation.verticalScroll @@ -273,7 +278,9 @@ private fun LoginUiScreen( NavHost( modifier = Modifier .fillMaxSize() - .padding(paddingValues), + .imePadding() + .consumeWindowInsets(WindowInsets.systemBars) + .padding(top = paddingValues.calculateTopPadding()), navController = nestedNavController, startDestination = if (hasSelectedInstance) NestedDestination.HOME.destination else NestedDestination.INSTANCE_SELECTION.destination ) { @@ -463,7 +470,11 @@ private fun AccountUi( ClickableText( modifier = Modifier .align(Alignment.CenterHorizontally) - .padding(bottom = 8.dp), + .padding( + bottom = WindowInsets.systemBars + .asPaddingValues() + .calculateBottomPadding() + ), text = AnnotatedString(stringResource(id = R.string.account_change_artemis_instance_label)), style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.linkTextColor), onClick = { onNavigateToInstanceSelection() } diff --git a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/NotificationSettingsUi.kt b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/NotificationSettingsUi.kt index 04f4ee1fd..40e576e96 100644 --- a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/NotificationSettingsUi.kt +++ b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/NotificationSettingsUi.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -88,8 +89,9 @@ internal fun NotificationSettingsUi(modifier: Modifier, onDone: () -> Unit) { Column( modifier = Modifier .fillMaxSize() - .padding(padding) - .padding(8.dp) + .imePadding() + .padding(top = padding.calculateTopPadding()) + .padding(horizontal = 8.dp) .verticalScroll(rememberScrollState()) ) { de.tum.informatics.www1.artemis.native_app.feature.push.ui.PushNotificationSettingsUi( diff --git a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/instance_selection/InstanceSelectionScreen.kt b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/instance_selection/InstanceSelectionScreen.kt index 686a22a61..0342ff367 100644 --- a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/instance_selection/InstanceSelectionScreen.kt +++ b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/instance_selection/InstanceSelectionScreen.kt @@ -4,10 +4,14 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items @@ -79,7 +83,9 @@ internal fun InstanceSelectionScreen( columns = GridCells.Fixed(columnCount), horizontalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp), - contentPadding = PaddingValues(bottom = 16.dp) + contentPadding = PaddingValues( + bottom = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding() + ) ) { items(availableInstances) { instance -> val item = GridCellItem.ArtemisInstanceGridCellItem( diff --git a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/login/LoginUi.kt b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/login/LoginUi.kt index 902aa9382..f38f78582 100644 --- a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/login/LoginUi.kt +++ b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/login/LoginUi.kt @@ -3,6 +3,7 @@ package de.tum.informatics.www1.artemis.native_app.feature.login.login import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState diff --git a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/register/RegisterUi.kt b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/register/RegisterUi.kt index 93dcbb6b2..fa7b7ed48 100644 --- a/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/register/RegisterUi.kt +++ b/feature/login/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/login/register/RegisterUi.kt @@ -4,6 +4,7 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Divider @@ -92,7 +93,7 @@ internal fun RegisterUi( } Column( - modifier = modifier, + modifier = modifier.imePadding(), verticalArrangement = Arrangement.spacedBy(16.dp) ) { val textFieldModifier = Modifier diff --git a/feature/login/src/test/java/de/tum/informatics/www1/artemis/native_app/feature/login/RegisterEndToEndTest.kt b/feature/login/src/test/java/de/tum/informatics/www1/artemis/native_app/feature/login/RegisterEndToEndTest.kt index dafc3c397..98015640b 100644 --- a/feature/login/src/test/java/de/tum/informatics/www1/artemis/native_app/feature/login/RegisterEndToEndTest.kt +++ b/feature/login/src/test/java/de/tum/informatics/www1/artemis/native_app/feature/login/RegisterEndToEndTest.kt @@ -1,6 +1,7 @@ package de.tum.informatics.www1.artemis.native_app.feature.login import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.ui.Modifier @@ -83,6 +84,7 @@ class RegisterEndToEndTest : BaseComposeTest() { RegisterUi( modifier = Modifier .fillMaxSize() + .imePadding() .verticalScroll(rememberScrollState()), viewModel = viewModel, onRegistered = { } diff --git a/feature/metis/code-of-conduct/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/codeofconduct/ui/AcceptCodeOfConductUi.kt b/feature/metis/code-of-conduct/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/codeofconduct/ui/AcceptCodeOfConductUi.kt index fb255be90..39a57b9a9 100644 --- a/feature/metis/code-of-conduct/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/codeofconduct/ui/AcceptCodeOfConductUi.kt +++ b/feature/metis/code-of-conduct/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/codeofconduct/ui/AcceptCodeOfConductUi.kt @@ -11,12 +11,15 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll @@ -125,7 +128,11 @@ fun AcceptCodeOfConductUi( Icon( modifier = Modifier .align(Alignment.BottomCenter) - .padding(bottom = 8.dp) + .padding( + bottom = WindowInsets.systemBars + .asPaddingValues() + .calculateBottomPadding() + ) .offset { val offsetInDp = 4.dp.toPx() IntOffset(0, (offsetInDp * additionalOffsetPercent).toInt()) diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationChatListScreen.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationChatListScreen.kt index a35aa4177..09a7be4ed 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationChatListScreen.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationChatListScreen.kt @@ -2,8 +2,14 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeContent +import androidx.compose.foundation.layout.safeContentPadding +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons @@ -29,6 +35,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.unit.dp import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems import de.tum.informatics.www1.artemis.native_app.core.data.isSuccess @@ -106,9 +113,10 @@ internal fun ConversationChatListScreen( MetisChatList( modifier = Modifier .fillMaxSize() - .padding(padding), + .imePadding() + .padding(bottom = padding.calculateBottomPadding()), viewModel = viewModel, - listContentPadding = PaddingValues(), + listContentPadding = PaddingValues(top = padding.calculateTopPadding()), onClickViewPost = onClickViewPost, isReplyEnabled = isReplyEnabled, state = chatListState, diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationThreadScreen.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationThreadScreen.kt index 4bf13c8d0..294d5f7cf 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationThreadScreen.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/ConversationThreadScreen.kt @@ -1,8 +1,10 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack @@ -58,13 +60,15 @@ internal fun ConversationThreadScreen( Column( modifier = Modifier .fillMaxSize() - .padding(padding) + .imePadding() + .padding(bottom = padding.calculateBottomPadding()) ) { CompositionLocalProvider(LocalReplyAutoCompleteHintProvider provides viewModel) { MetisThreadUi( modifier = Modifier .fillMaxWidth() .weight(1f), + listContentPadding = PaddingValues(top = padding.calculateTopPadding()), viewModel = viewModel ) } diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisChatList.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisChatList.kt index 235d245d9..82e6ad78f 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisChatList.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisChatList.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.paging.compose.LazyPagingItems import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.R +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.EmojiService import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.MetisModificationFailure import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.ConversationViewModel import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.post.DisplayPostOrder @@ -124,6 +125,7 @@ fun MetisChatList( serverUrl: String, courseId: Long, state: LazyListState, + emojiService: EmojiService = koinInject(), isReplyEnabled: Boolean, onCreatePost: () -> Deferred, onEditPost: (IStandalonePost, String) -> Deferred, @@ -155,7 +157,7 @@ fun MetisChatList( state = state, itemCount = posts.itemCount, order = DisplayPostOrder.REVERSED, - emojiService = koinInject(), + emojiService = emojiService, bottomItem = bottomItem ) { when (posts) { diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/post/PostContextBottomSheet.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/post/PostContextBottomSheet.kt index 474f6a443..f5d170c34 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/post/PostContextBottomSheet.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/post/PostContextBottomSheet.kt @@ -9,10 +9,12 @@ import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -75,6 +77,7 @@ internal fun PostContextBottomSheet( if (!displayAllEmojis) { ModalBottomSheet( modifier = Modifier.testTag(TEST_TAG_POST_CONTEXT_BOTTOM_SHEET), + windowInsets = WindowInsets.statusBars, sheetState = rememberModalBottomSheetState(), onDismissRequest = onDismissRequest ) { diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/thread/MetisThreadUi.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/thread/MetisThreadUi.kt index 8914c06db..6149d487d 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/thread/MetisThreadUi.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/thread/MetisThreadUi.kt @@ -66,6 +66,7 @@ internal fun testTagForAnswerPost(answerPostId: String) = "answerPost$answerPost @Composable internal fun MetisThreadUi( modifier: Modifier, + listContentPadding: PaddingValues, viewModel: ConversationViewModel ) { val postDataState: DataState by viewModel.threadUseCase.post.collectAsState() @@ -97,6 +98,7 @@ internal fun MetisThreadUi( postDataState = postDataState, isAtLeastTutorInCourse = isAtLeastTutorInCourse, hasModerationRights = hasModerationRights, + listContentPadding = listContentPadding, serverUrl = serverUrl, emojiService = koinInject(), clientId = clientId, @@ -142,6 +144,7 @@ internal fun MetisThreadUi( conversationDataState: DataState, hasModerationRights: Boolean, isAtLeastTutorInCourse: Boolean, + listContentPadding: PaddingValues, serverUrl: String, emojiService: EmojiService, initialReplyTextProvider: InitialReplyTextProvider, @@ -200,6 +203,7 @@ internal fun MetisThreadUi( post = post, hasModerationRights = hasModerationRights, isAtLeastTutorInCourse = isAtLeastTutorInCourse, + listContentPadding = listContentPadding, clientId = clientId, onRequestReactWithEmoji = onRequestReactWithEmojiDelegate, onRequestEdit = onEditPostDelegate, @@ -234,6 +238,7 @@ private fun PostAndRepliesList( post: PostPojo, hasModerationRights: Boolean, isAtLeastTutorInCourse: Boolean, + listContentPadding: PaddingValues, clientId: Long, onRequestEdit: (IBasePost) -> Unit, onRequestDelete: (IBasePost) -> Unit, @@ -270,7 +275,7 @@ private fun PostAndRepliesList( ProvideMarkwon { LazyColumn( modifier = modifier, - contentPadding = PaddingValues(vertical = 8.dp), + contentPadding = listContentPadding, verticalArrangement = Arrangement.spacedBy(8.dp), state = state ) { diff --git a/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/BaseThreadUITest.kt b/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/BaseThreadUITest.kt new file mode 100644 index 000000000..49db524f3 --- /dev/null +++ b/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/BaseThreadUITest.kt @@ -0,0 +1,97 @@ +package de.tum.informatics.www1.artemis.native_app.feature.metis.conversation + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import de.tum.informatics.www1.artemis.native_app.core.data.DataState +import de.tum.informatics.www1.artemis.native_app.core.model.Course +import de.tum.informatics.www1.artemis.native_app.core.test.BaseComposeTest +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.MetisModificationFailure +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.impl.EmojiServiceStub +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.thread.MetisThreadUi +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.IBasePost +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.UserRole +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.AnswerPostPojo +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.db.pojo.PostPojo +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.Deferred +import kotlinx.datetime.Clock + +abstract class BaseThreadUITest : BaseComposeTest() { + + val clientId = 20L + + val course: Course = Course(id = 1) + val conversation = OneToOneChat(id = 2) + + val answers = (0..2).map { index -> + AnswerPostPojo( + parentPostId = "client-id", + postId = "answer-client-id-$index", + resolvesPost = false, + basePostingCache = AnswerPostPojo.BasePostingCache( + serverPostId = index.toLong(), + authorId = clientId, + creationDate = Clock.System.now(), + updatedDate = null, + content = "Answer Post content $index", + authorRole = UserRole.USER, + authorName = "author name" + ), + reactions = emptyList(), + serverPostIdCache = AnswerPostPojo.ServerPostIdCache( + serverPostId = index.toLong() + ) + ) + } + + val posts = (0..2).map { index -> + PostPojo( + clientPostId = "client-id-$index", + serverPostId = index.toLong(), + content = "Post content $index", + resolved = false, + updatedDate = null, + creationDate = Clock.System.now(), + authorId = clientId, + title = null, + authorName = "author name", + authorRole = UserRole.USER, + courseWideContext = null, + tags = emptyList(), + answers = if (index == 0) answers else emptyList(), + reactions = emptyList() + ) + } + + fun setupThreadUi( + post: PostPojo, + onResolvePost: ((IBasePost) -> Deferred)? + ) { + composeTestRule.setContent { + MetisThreadUi( + modifier = Modifier.fillMaxSize(), + courseId = course.id!!, + clientId = clientId, + postDataState = DataState.Success(post), + conversationDataState = DataState.Success(conversation), + hasModerationRights = false, + isAtLeastTutorInCourse = false, + listContentPadding = PaddingValues(), + serverUrl = "", + emojiService = EmojiServiceStub, + initialReplyTextProvider = remember { TestInitialReplyTextProvider() }, + onCreatePost = { CompletableDeferred() }, + onEditPost = { _, _ -> CompletableDeferred() }, + onResolvePost = onResolvePost, + onDeletePost = { CompletableDeferred() }, + onRequestReactWithEmoji = { _, _, _ -> CompletableDeferred() }, + onRequestReload = {}, + onRequestRetrySend = { _, _ -> }, + ) + } + } + +} diff --git a/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ConversationAnswerMessagesUITest.kt b/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ConversationAnswerMessagesUITest.kt index da5f2f06d..b9a232f32 100644 --- a/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ConversationAnswerMessagesUITest.kt +++ b/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ConversationAnswerMessagesUITest.kt @@ -1,105 +1,37 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.conversation -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.SemanticsActions -import androidx.compose.ui.semantics.SemanticsProperties -import androidx.compose.ui.semantics.getOrNull -import androidx.compose.ui.test.SemanticsNodeInteraction import androidx.compose.ui.test.assert -import androidx.compose.ui.test.assertHasClickAction import androidx.compose.ui.test.hasAnyChild -import androidx.compose.ui.test.hasScrollAction -import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasText import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText -import androidx.compose.ui.test.onParent -import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performClick -import androidx.compose.ui.test.performScrollTo import androidx.compose.ui.test.performScrollToIndex import androidx.compose.ui.test.performSemanticsAction -import androidx.compose.ui.test.printToLog -import de.tum.informatics.www1.artemis.native_app.core.common.test.EndToEndTest -import de.tum.informatics.www1.artemis.native_app.core.data.DataState -import de.tum.informatics.www1.artemis.native_app.core.model.Course -import de.tum.informatics.www1.artemis.native_app.core.test.BaseComposeTest -import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.MetisModificationFailure -import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.impl.EmojiServiceStub -import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.thread.MetisThreadUi +import de.tum.informatics.www1.artemis.native_app.core.common.test.UnitTest import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.thread.TEST_TAG_THREAD_LIST import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.IBasePost -import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.content.dto.UserRole -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.AnswerPostPojo -import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.db.pojo.PostPojo import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.runBlocking -import kotlinx.datetime.Clock import org.junit.Test import org.junit.experimental.categories.Category import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner -@Category(EndToEndTest::class) +@Category(UnitTest::class) @RunWith(RobolectricTestRunner::class) -class ConversationAnswerMessagesUITest : BaseComposeTest() { - - private val clientId = 20L - - private val course: Course = Course(id = 1) - private val conversation = OneToOneChat(id = 2) - - private val answers = (0..2).map { index -> - AnswerPostPojo( - parentPostId = "client-id", - postId = "answer-client-id-$index", - resolvesPost = false, - basePostingCache = AnswerPostPojo.BasePostingCache( - serverPostId = index.toLong(), - authorId = clientId, - creationDate = Clock.System.now(), - updatedDate = null, - content = "Answer Post content $index", - authorRole = UserRole.USER, - authorName = "author name" - ), - reactions = emptyList(), - serverPostIdCache = AnswerPostPojo.ServerPostIdCache( - serverPostId = index.toLong() - ) - ) - } - - private val post = PostPojo( - clientPostId = "client-id", - serverPostId = 12, - content = "Post content", - resolved = false, - updatedDate = null, - creationDate = Clock.System.now(), - authorId = clientId, - title = null, - authorName = "author name", - authorRole = UserRole.USER, - courseWideContext = null, - tags = emptyList(), - answers = answers, - reactions = emptyList() - ) +class ConversationAnswerMessagesUITest : BaseThreadUITest() { private fun testTagForAnswerPost(answerPostId: String) = "answerPost$answerPostId" + private val post = posts[0] + @Test fun `test GIVEN post is not resolved WHEN resolving the post THEN the post is resolved with the first answer post`() { var resolvedPost: IBasePost? = null - setupUi(post) { post -> + setupThreadUi(post) { post -> resolvedPost = post CompletableDeferred() } @@ -118,7 +50,7 @@ class ConversationAnswerMessagesUITest : BaseComposeTest() { fun `test GIVEN post is not resolved WHEN resolving the post THEN the post is resolved with the third answer post`() { var resolvedPost: IBasePost? = null - setupUi(post) { post -> + setupThreadUi(post) { post -> resolvedPost = post CompletableDeferred() } @@ -145,7 +77,7 @@ class ConversationAnswerMessagesUITest : BaseComposeTest() { var unresolvedPost: IBasePost? = null - setupUi(resolvedPost) { post -> + setupThreadUi(resolvedPost) { post -> unresolvedPost = post CompletableDeferred() } @@ -162,7 +94,7 @@ class ConversationAnswerMessagesUITest : BaseComposeTest() { @Test fun `test GIVEN the post is not resolved and no answer post is resolving THEN the post is shown as not resolved and no answer post is shown as resolving`() { - setupUi(post) { CompletableDeferred() } + setupThreadUi(post) { CompletableDeferred() } composeTestRule.onNodeWithText(post.content).assertExists() for (answer in answers) { @@ -185,7 +117,7 @@ class ConversationAnswerMessagesUITest : BaseComposeTest() { answers = modifiedAnswers ) - setupUi(resolvedPost) { CompletableDeferred() } + setupThreadUi(resolvedPost) { CompletableDeferred() } val resolvesAssertion = hasAnyChild(hasText(context.getString(R.string.post_resolves))) @@ -199,31 +131,4 @@ class ConversationAnswerMessagesUITest : BaseComposeTest() { .assert(if (i == resolvingIndex) resolvesAssertion else resolvesAssertion.not()) } } - - private fun setupUi( - post: PostPojo, - onResolvePost: ((IBasePost) -> Deferred)? - ) { - composeTestRule.setContent { - MetisThreadUi( - modifier = Modifier.fillMaxSize(), - courseId = course.id!!, - clientId = clientId, - postDataState = DataState.Success(post), - conversationDataState = DataState.Success(conversation), - hasModerationRights = false, - isAtLeastTutorInCourse = false, - serverUrl = "", - emojiService = EmojiServiceStub, - initialReplyTextProvider = remember { TestInitialReplyTextProvider() }, - onCreatePost = { CompletableDeferred() }, - onEditPost = { _, _ -> CompletableDeferred() }, - onResolvePost = onResolvePost, - onDeletePost = { CompletableDeferred() }, - onRequestReactWithEmoji = { _, _, _ -> CompletableDeferred() }, - onRequestReload = {}, - onRequestRetrySend = { _, _ -> }, - ) - } - } } \ No newline at end of file diff --git a/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/reply/ReplyTextFieldVisibilityUITest.kt b/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/reply/ReplyTextFieldVisibilityUITest.kt new file mode 100644 index 000000000..0ad718440 --- /dev/null +++ b/feature/metis/conversation/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/reply/ReplyTextFieldVisibilityUITest.kt @@ -0,0 +1,85 @@ +package de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.reply + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import de.tum.informatics.www1.artemis.native_app.core.common.test.EndToEndTest +import de.tum.informatics.www1.artemis.native_app.core.common.test.UnitTest +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.BaseThreadUITest +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.TestInitialReplyTextProvider +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.impl.EmojiServiceStub +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.chatlist.ChatListItem +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.chatlist.MetisChatList +import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.ui.chatlist.PostsDataState +import de.tum.informatics.www1.artemis.native_app.feature.metis.shared.db.pojo.PostPojo +import junit.framework.TestCase.assertTrue +import kotlinx.coroutines.CompletableDeferred +import org.junit.Test +import org.junit.experimental.categories.Category +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@Category(UnitTest::class) +@RunWith(RobolectricTestRunner::class) +class ReplyTextFieldVisibilityUITest : BaseThreadUITest() { + + @Test + fun `test GIVEN the thread view is shown containing one post and three answer posts WHEN the markdown text field is clicked THEN the keyboard is shown below the markdown text field`() { + setupThreadUi(posts[0]) { CompletableDeferred() } + runTest() + } + + @Test + fun `test GIVEN the chat list containing three posts is shown WHEN the markdown text field is clicked THEN the keyboard is shown below the markdown text field`() { + setupChatUi(posts) + runTest() + } + + private fun runTest() { + val markdownTextField = composeTestRule.onNodeWithTag(TEST_TAG_CAN_CREATE_REPLY) + val initialPosition = markdownTextField.fetchSemanticsNode().positionInRoot.y + + markdownTextField.performClick() + composeTestRule.waitForIdle() + + val newPosition = markdownTextField.fetchSemanticsNode().positionInRoot.y + + markdownTextField + .assertExists() + .assertIsDisplayed() + assertTrue("Text field should move up when the keyboard appears", newPosition < initialPosition) + } + + private fun setupChatUi(posts: List) { + composeTestRule.setContent { + val list = posts.map { post -> ChatListItem.PostChatListItem(post) }.toMutableList() + MetisChatList( + modifier = Modifier.fillMaxSize(), + initialReplyTextProvider = remember { TestInitialReplyTextProvider() }, + posts = PostsDataState.Loaded.WithList(list, PostsDataState.NotLoading), + clientId = clientId, + hasModerationRights = false, + isAtLeastTutorInCourse = false, + listContentPadding = PaddingValues(), + serverUrl = "", + courseId = course.id!!, + state = rememberLazyListState(), + emojiService = EmojiServiceStub, + bottomItem = posts.lastOrNull(), + isReplyEnabled = true, + onCreatePost = { CompletableDeferred() }, + onEditPost = { _, _ -> CompletableDeferred() }, + onDeletePost = { CompletableDeferred() }, + onRequestReactWithEmoji = { _, _, _ -> CompletableDeferred() }, + onClickViewPost = {}, + onRequestRetrySend = { _ -> }, + title = "Title" + ) + } + } +} diff --git a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/browse_channels/BrowseChannelsScreen.kt b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/browse_channels/BrowseChannelsScreen.kt index 15463df2f..61a95fb97 100644 --- a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/browse_channels/BrowseChannelsScreen.kt +++ b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/browse_channels/BrowseChannelsScreen.kt @@ -3,9 +3,12 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.manageconversat import androidx.compose.foundation.background import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -103,7 +106,8 @@ internal fun BrowseChannelsScreen( BasicDataStateUi( modifier = Modifier .fillMaxSize() - .padding(padding), + .padding(top = padding.calculateTopPadding()) + .consumeWindowInsets(WindowInsets.systemBars), dataState = channelsDataState, loadingText = stringResource(id = R.string.browse_channel_list_loading), failureText = stringResource(id = R.string.browse_channel_list_failure), diff --git a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/create_channel/CreateChannelScreen.kt b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/create_channel/CreateChannelScreen.kt index 6f209ac66..0091182bd 100644 --- a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/create_channel/CreateChannelScreen.kt +++ b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/create_channel/CreateChannelScreen.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -92,6 +93,7 @@ internal fun CreateChannelScreen( Column( modifier = Modifier .fillMaxSize() + .imePadding() .padding(paddingValues) .verticalScroll(rememberScrollState()) .padding(horizontal = Spacings.ScreenHorizontalSpacing), diff --git a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/create_personal_conversation/CreatePersonalConversationScreen.kt b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/create_personal_conversation/CreatePersonalConversationScreen.kt index 1fe03354b..816af3a5d 100644 --- a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/create_personal_conversation/CreatePersonalConversationScreen.kt +++ b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/create_personal_conversation/CreatePersonalConversationScreen.kt @@ -1,6 +1,7 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.manageconversations.ui.conversation.create_personal_conversation import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack @@ -87,6 +88,7 @@ internal fun CreatePersonalConversationScreen( MemberSelection( modifier = Modifier .fillMaxSize() + .imePadding() .padding(padding) .padding(horizontal = Spacings.ScreenHorizontalSpacing), viewModel = viewModel diff --git a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/overview/ConversationOverviewBody.kt b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/overview/ConversationOverviewBody.kt index 960a3b505..cfed38cbc 100644 --- a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/overview/ConversationOverviewBody.kt +++ b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/overview/ConversationOverviewBody.kt @@ -7,10 +7,15 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -155,7 +160,8 @@ fun ConversationOverviewBody( Box( modifier = Modifier .fillMaxWidth() - .padding(top = 16.dp) + .padding(16.dp) + .padding(bottom = 24.dp) ) { TextButton( modifier = Modifier.align(Alignment.Center), @@ -184,6 +190,7 @@ fun ConversationOverviewBody( if (showCodeOfConduct) { ModalBottomSheet( + windowInsets = WindowInsets.statusBars, onDismissRequest = { showCodeOfConduct = false } ) { CodeOfConductUi( @@ -210,7 +217,13 @@ fun ConversationFabMenu( Box( modifier = Modifier .fillMaxSize() - .padding(16.dp), + .padding( + bottom = WindowInsets.systemBars + .asPaddingValues() + .calculateBottomPadding() + 8.dp, + end = 16.dp + ) + .imePadding(), contentAlignment = Alignment.BottomEnd ) { Box { diff --git a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/members/ConversationMembersScreen.kt b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/members/ConversationMembersScreen.kt index 662c1a63a..eb6bdec30 100644 --- a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/members/ConversationMembersScreen.kt +++ b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/members/ConversationMembersScreen.kt @@ -1,7 +1,10 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.manageconversations.ui.conversation.settings.members +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar @@ -61,7 +64,7 @@ fun ConversationMembersScreen( ConversationMembersBody( modifier = Modifier .fillMaxSize() - .padding(padding) + .consumeWindowInsets(WindowInsets.systemBars) .padding(top = 16.dp), courseId = courseId, conversationId = conversationId diff --git a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/overview/ConversationSettingsBody.kt b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/overview/ConversationSettingsBody.kt index cc5136014..db639141c 100644 --- a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/overview/ConversationSettingsBody.kt +++ b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/overview/ConversationSettingsBody.kt @@ -2,9 +2,12 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.manageconversat import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme @@ -136,7 +139,8 @@ internal fun ConversationSettingsBody( Column( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()), + .verticalScroll(rememberScrollState()) + .padding(bottom = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()), verticalArrangement = Arrangement.spacedBy(16.dp) ) { ConversationInfoSettings( diff --git a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/overview/ConversationSettingsScreen.kt b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/overview/ConversationSettingsScreen.kt index 795755ce1..e87e15fdc 100644 --- a/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/overview/ConversationSettingsScreen.kt +++ b/feature/metis/manage-conversations/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/ui/conversation/settings/overview/ConversationSettingsScreen.kt @@ -1,7 +1,11 @@ package de.tum.informatics.www1.artemis.native_app.feature.metis.manageconversations.ui.conversation.settings.overview +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.Icon @@ -121,7 +125,9 @@ internal fun ConversationSettingsScreen( ConversationSettingsBody( modifier = Modifier .fillMaxSize() - .padding(paddingValues), + .imePadding() + .padding(top = paddingValues.calculateTopPadding()) + .consumeWindowInsets(WindowInsets.systemBars), viewModel = viewModel, onRequestViewAllMembers = onRequestViewAllMembers, onRequestAddMembers = onRequestAddMembers, diff --git a/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/PushNotificationSettingsScreen.kt b/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/PushNotificationSettingsScreen.kt index 28bcd23f3..c6b216307 100644 --- a/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/PushNotificationSettingsScreen.kt +++ b/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/PushNotificationSettingsScreen.kt @@ -1,7 +1,10 @@ package de.tum.informatics.www1.artemis.native_app.feature.settings +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -67,9 +70,10 @@ internal fun PushNotificationSettingsScreen(modifier: Modifier, onNavigateBack: PushNotificationSettingsUi( modifier = Modifier .fillMaxSize() - .padding(padding) + .padding(top = padding.calculateTopPadding()) .padding(horizontal = 8.dp) - .verticalScroll(rememberScrollState()), + .verticalScroll(rememberScrollState()) + .padding(bottom = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()), viewModel = viewModel ) diff --git a/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/SettingsScreen.kt b/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/SettingsScreen.kt index dfba46ced..00e78af6d 100644 --- a/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/SettingsScreen.kt +++ b/feature/settings/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/settings/SettingsScreen.kt @@ -6,9 +6,12 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -175,8 +178,9 @@ private fun SettingsScreen( Column( modifier = Modifier .fillMaxSize() - .padding(padding) - .verticalScroll(rememberScrollState()), + .padding(top = padding.calculateTopPadding()) + .verticalScroll(rememberScrollState()) + .padding(bottom = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()), verticalArrangement = Arrangement.spacedBy(16.dp) ) { if (authToken != null) { From d89336f36247f532fd1d117cd846f47f76e98f15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 15:12:38 +0100 Subject: [PATCH 06/22] Bump sentry-android from 6.22.0 to 7.17.0 (#113) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Felber Co-authored-by: Martin Felber <45291671+FelberMartin@users.noreply.github.com> --- .github/workflows/e2e-test.yml | 5 +++++ .github/workflows/unit-test.yml | 5 +++++ gradle/libs.versions.toml | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 7194207da..0277a2045 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -8,6 +8,11 @@ on: pull_request: workflow_dispatch: +permissions: + id-token: write + contents: read + checks: write + jobs: end-to-end-tests: name: E2E Tests diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index f560eef1f..5a444809f 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -8,6 +8,11 @@ on: pull_request: workflow_dispatch: +permissions: + id-token: write + contents: read + checks: write + jobs: jUnit: name: JUnit Tests diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7b14ab928..852573e89 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ mockk = "1.13.8" ossLicensesPlugin = "0.10.6" placeholderMaterial = "1.0.1" room = "2.6.0" -sentry-android = "6.22.0" +sentry-android = "7.17.0" work = "2.9.0" # Used indirecly in the build config -> Do not remove without double checking. From b69876651f63eeb782b53332ffd33816df053077 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:02:09 +0100 Subject: [PATCH 07/22] Bump ktor from 2.3.7 to 2.3.12 (#112) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Felber --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 852573e89..fb40cd9a7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ kotlinxSerializationJson = "1.5.1" koin = "3.5.3" koinAndroidxCompose = "3.4.5" kover = "0.7.2" -ktor = "2.3.7" +ktor = "2.3.12" krossbow = "5.2.0" markwon = "4.6.2" mockk = "1.13.8" From 0ae3b859def5b2d6e5d44cbcf5c0d68b694acb09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 17:35:54 +0100 Subject: [PATCH 08/22] Bump plugin.serialization from 1.8.10 to 2.0.21 (#50) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Felber <45291671+FelberMartin@users.noreply.github.com> --- buildSrc/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index e3f9e9cd6..0b1e201ba 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,7 +1,7 @@ plugins { `kotlin-dsl` kotlin("jvm") version "1.8.10" - kotlin("plugin.serialization") version "1.8.10" + kotlin("plugin.serialization") version "2.0.21" // id("java-gradle-plugin") } From 964e5b9787baa4492c83e8e8b8ccd89808c44573 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:34:27 +0100 Subject: [PATCH 09/22] Bump kotlinxCoroutines from 1.7.3 to 1.9.0 (#45) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Felber <45291671+FelberMartin@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fb40cd9a7..ff8fb54e2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ androidxPagingCompose = "3.2.1" coil = "2.4.0" emoji2 = "1.4.0" kotlin = "1.9.25" -kotlinxCoroutines = "1.7.3" +kotlinxCoroutines = "1.9.0" kotlinxDatetime = "0.4.0" kotlinxSerializationJson = "1.5.1" koin = "3.5.3" From 27853fce6e1c8034423608ab00cf3d40fbd648c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:34:57 +0100 Subject: [PATCH 10/22] Bump androidx.work:work-runtime-ktx from 2.9.0 to 2.10.0 (#129) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ff8fb54e2..7d4df60a4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ ossLicensesPlugin = "0.10.6" placeholderMaterial = "1.0.1" room = "2.6.0" sentry-android = "7.17.0" -work = "2.9.0" +work = "2.10.0" # Used indirecly in the build config -> Do not remove without double checking. androidxComposeCompiler = "1.5.15" From 98e93fd8c3f89848185971db10132a6beb88ffc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:35:09 +0100 Subject: [PATCH 11/22] Bump androidxDataStore from 1.0.0 to 1.1.1 (#131) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7d4df60a4..e56b6383c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ androidxComposeBom = "2023.10.01" androidxLifecycle = "2.6.2" androidxNavigation = "2.7.5" androidGradlePlugin = "8.7.0" -androidxDataStore = "1.0.0" +androidxDataStore = "1.1.1" androidxPaging = "3.2.1" androidxPagingCompose = "3.2.1" coil = "2.4.0" From 9457e86129aaf326a8ab244f858c7f563bba97a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:48:14 +0100 Subject: [PATCH 12/22] Bump androidxPaging from 3.2.1 to 3.3.4 (#132) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Felber <45291671+FelberMartin@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e56b6383c..5d0170b43 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,8 +12,8 @@ androidxComposeBom = "2023.10.01" androidxLifecycle = "2.6.2" androidxNavigation = "2.7.5" androidGradlePlugin = "8.7.0" +androidxPaging = "3.3.4" androidxDataStore = "1.1.1" -androidxPaging = "3.2.1" androidxPagingCompose = "3.2.1" coil = "2.4.0" emoji2 = "1.4.0" From 1e520ed93d5f337c06dedf47a376faa00352ecd4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:01:43 +0100 Subject: [PATCH 13/22] Bump io.github.fornewid:placeholder-material3 from 1.0.1 to 2.0.0 (#130) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Felber Co-authored-by: Martin Felber <45291671+FelberMartin@users.noreply.github.com> --- .../core/test/test_setup/TestVariables.kt | 2 +- .../ConversationMemberSettingsE2eTest.kt | 25 +++++++------------ gradle/libs.versions.toml | 4 +-- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/core/core-test/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/test/test_setup/TestVariables.kt b/core/core-test/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/test/test_setup/TestVariables.kt index dbc20f4f4..af73193f5 100644 --- a/core/core-test/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/test/test_setup/TestVariables.kt +++ b/core/core-test/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/test/test_setup/TestVariables.kt @@ -1,3 +1,3 @@ package de.tum.informatics.www1.artemis.native_app.core.test.test_setup -val DefaultTimeoutMillis: Long get() = System.getenv("DEFAULT_TIMEOUT")?.toLong() ?: 10000L \ No newline at end of file +val DefaultTimeoutMillis: Long get() = System.getenv("DEFAULT_TIMEOUT")?.toLong() ?: 15000L \ No newline at end of file diff --git a/feature/metis/manage-conversations/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/members/ConversationMemberSettingsE2eTest.kt b/feature/metis/manage-conversations/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/members/ConversationMemberSettingsE2eTest.kt index b51c8f4e9..18223e902 100644 --- a/feature/metis/manage-conversations/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/members/ConversationMemberSettingsE2eTest.kt +++ b/feature/metis/manage-conversations/src/test/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/manageconversations/members/ConversationMemberSettingsE2eTest.kt @@ -6,7 +6,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assert import androidx.compose.ui.test.hasAnyAncestor -import androidx.compose.ui.test.hasAnyDescendant import androidx.compose.ui.test.hasContentDescription import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasText @@ -15,10 +14,10 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performScrollTo import androidx.lifecycle.SavedStateHandle -import de.tum.informatics.www1.artemis.native_app.core.common.test.EndToEndTest import de.tum.informatics.www1.artemis.native_app.core.common.test.DefaultTestTimeoutMillis -import de.tum.informatics.www1.artemis.native_app.core.test.test_setup.DefaultTimeoutMillis +import de.tum.informatics.www1.artemis.native_app.core.common.test.EndToEndTest import de.tum.informatics.www1.artemis.native_app.core.common.test.testServerUrl +import de.tum.informatics.www1.artemis.native_app.core.test.test_setup.DefaultTimeoutMillis import de.tum.informatics.www1.artemis.native_app.feature.login.test.user1Username import de.tum.informatics.www1.artemis.native_app.feature.login.test.user2Username import de.tum.informatics.www1.artemis.native_app.feature.login.test.user3Username @@ -83,28 +82,24 @@ class ConversationMemberSettingsE2eTest : ConversationBaseTest() { composeTestRule .onNodeWithTag(testTagForMember(user1Username)) .performScrollTo() - .assert( - hasAnyDescendant(hasText(user1Username)) and hasAnyDescendant( - hasContentDescription(context.getString(R.string.conversation_members_content_description_moderator)) - ) - ) + .assert(hasText(user1Username)) + .assert(hasContentDescription(context.getString(R.string.conversation_members_content_description_moderator)) + ) composeTestRule .onNodeWithTag(testTagForMember(user2Username)) .performScrollTo() .assert( - hasAnyDescendant(hasText(user2Username)) and !hasAnyDescendant( + hasText(user2Username) and ! hasContentDescription(context.getString(R.string.conversation_members_content_description_moderator)) - ) ) composeTestRule .onNodeWithTag(testTagForMember(user2Username)) .performScrollTo() .assert( - hasAnyDescendant(hasText(user2Username)) and !hasAnyDescendant( + hasText(user2Username) and ! hasContentDescription(context.getString(R.string.conversation_members_content_description_moderator)) - ) ) } @@ -186,10 +181,8 @@ class ConversationMemberSettingsE2eTest : ConversationBaseTest() { ) .performClick() - val isModeratorCheck = hasAnyDescendant( - hasContentDescription( - context.getString(R.string.conversation_members_content_description_moderator) - ) + val isModeratorCheck = hasContentDescription( + context.getString(R.string.conversation_members_content_description_moderator) ) composeTestRule.waitUntilExactlyOneExists( diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5d0170b43..fc668c6d8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ accompanist = "0.30.1" androidDesugarJdkLibs = "2.0.4" androidxActivity = "1.8.1" androidxAppCompat = "1.6.1" -androidxComposeBom = "2023.10.01" +androidxComposeBom = "2024.06.00" androidxLifecycle = "2.6.2" androidxNavigation = "2.7.5" androidGradlePlugin = "8.7.0" @@ -29,7 +29,7 @@ krossbow = "5.2.0" markwon = "4.6.2" mockk = "1.13.8" ossLicensesPlugin = "0.10.6" -placeholderMaterial = "1.0.1" +placeholderMaterial = "2.0.0" room = "2.6.0" sentry-android = "7.17.0" work = "2.10.0" From fd3dfbcc5f87a11afcc34e89cae944d22ceb9412 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 07:52:54 +0100 Subject: [PATCH 14/22] Bump emoji2 from 1.4.0 to 1.5.0 (#138) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fc668c6d8..3f996b422 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ androidxPaging = "3.3.4" androidxDataStore = "1.1.1" androidxPagingCompose = "3.2.1" coil = "2.4.0" -emoji2 = "1.4.0" +emoji2 = "1.5.0" kotlin = "1.9.25" kotlinxCoroutines = "1.9.0" kotlinxDatetime = "0.4.0" From 63e45eacff43cd2312187e34be5ed95bf8c79c70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 07:53:48 +0100 Subject: [PATCH 15/22] Bump room from 2.6.0 to 2.6.1 (#136) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3f996b422..560c66603 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ markwon = "4.6.2" mockk = "1.13.8" ossLicensesPlugin = "0.10.6" placeholderMaterial = "2.0.0" -room = "2.6.0" +room = "2.6.1" sentry-android = "7.17.0" work = "2.10.0" From b70948a4e3193acfb2ed645803e671b10a043009 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:23:28 +0100 Subject: [PATCH 16/22] Bump io.coil-kt:coil-compose from 2.4.0 to 2.7.0 (#137) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Felber <45291671+FelberMartin@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 560c66603..e455469b8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ androidGradlePlugin = "8.7.0" androidxPaging = "3.3.4" androidxDataStore = "1.1.1" androidxPagingCompose = "3.2.1" -coil = "2.4.0" +coil = "2.7.0" emoji2 = "1.5.0" kotlin = "1.9.25" kotlinxCoroutines = "1.9.0" From 180670a4a6d3ba68134a605cd04405686ed3116d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 10:26:16 +0100 Subject: [PATCH 17/22] Bump ktor from 2.3.12 to 2.3.13 (#141) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e455469b8..196176725 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ kotlinxSerializationJson = "1.5.1" koin = "3.5.3" koinAndroidxCompose = "3.4.5" kover = "0.7.2" -ktor = "2.3.12" +ktor = "2.3.13" krossbow = "5.2.0" markwon = "4.6.2" mockk = "1.13.8" From 11b990b1b530caa8c9ebc7c2740f4a467e7a76bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 10:26:27 +0100 Subject: [PATCH 18/22] Bump com.google.android.gms:play-services-oss-licenses from 17.0.1 to 17.1.0 (#142) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 196176725..7f58a8eab 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -123,7 +123,7 @@ noties-markwon-simple-ext = { group = "io.noties.markwon", name = "simple-ext", noties-markwon-image-coil = { group = "io.noties.markwon", name = "image-coil", version.ref = "markwon" } oss-licenses-plugin = { module = "com.google.android.gms:oss-licenses-plugin", version.ref = "ossLicensesPlugin" } placeholder-material = { group = "io.github.fornewid", name = "placeholder-material3", version.ref = "placeholderMaterial" } -play-services-oss-licences = { group = "com.google.android.gms", name = "play-services-oss-licenses", version = "17.0.1" } +play-services-oss-licences = { group = "com.google.android.gms", name = "play-services-oss-licenses", version = "17.1.0" } robolectric = { group = "org.robolectric", name = "robolectric", version = "4.13" } sentry-android = { group = "io.sentry", name = "sentry-android", version.ref = "sentry-android" } sentry-compose-android = { group = "io.sentry", name = "sentry-compose-android", version.ref = "sentry-android" } From 372ba2382d95f15a1e073542466bfc3937c37127 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 10:26:37 +0100 Subject: [PATCH 19/22] Bump androidxLifecycle from 2.6.2 to 2.8.7 (#143) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7f58a8eab..47c21103c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ androidDesugarJdkLibs = "2.0.4" androidxActivity = "1.8.1" androidxAppCompat = "1.6.1" androidxComposeBom = "2024.06.00" -androidxLifecycle = "2.6.2" +androidxLifecycle = "2.8.7" androidxNavigation = "2.7.5" androidGradlePlugin = "8.7.0" androidxPaging = "3.3.4" From a8098e9c25697660a502f64845c9fa027f9a0fb7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 10:42:26 +0100 Subject: [PATCH 20/22] Bump com.google.firebase.appdistribution from 4.0.1 to 5.0.0 (#144) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Felber <45291671+FelberMartin@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 47c21103c..57393bb45 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -139,6 +139,6 @@ android-library = { id = "com.android.library", version.ref = "androidGradlePlug kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } google-services = { id = "com.google.gms.google-services", version = "4.4.2" } -google-firebase-appdistribution = { id = "com.google.firebase.appdistribution", version = "4.0.1" } +google-firebase-appdistribution = { id = "com.google.firebase.appdistribution", version = "5.0.0" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } google-ksp = { id = "com.google.devtools.ksp", version = "1.9.25-1.0.20" } From 8f8393180bbac26ed15c9e7732701bf64b72a450 Mon Sep 17 00:00:00 2001 From: Julian Waluschyk Date: Tue, 26 Nov 2024 14:15:21 +0100 Subject: [PATCH 21/22] minor changes --- .../courseview/MessagingScreenshots.kt | 1 - .../conversation/ui/chatlist/MetisChatList.kt | 50 +++++------ .../ui/chatlist/MetisPostListHandler.kt | 9 +- .../conversation/ui/thread/MetisThreadUi.kt | 87 +++++++++---------- 4 files changed, 70 insertions(+), 77 deletions(-) diff --git a/feature/course-view/src/debug/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/MessagingScreenshots.kt b/feature/course-view/src/debug/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/MessagingScreenshots.kt index cb0fc96cd..05ede95c2 100644 --- a/feature/course-view/src/debug/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/MessagingScreenshots.kt +++ b/feature/course-view/src/debug/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/MessagingScreenshots.kt @@ -247,7 +247,6 @@ fun `Metis - Conversation Channel`() { listContentPadding = PaddingValues(), serverUrl = "", courseId = 0, - markdownImageLoader = null, state = rememberLazyListState(), isReplyEnabled = true, onCreatePost = { CompletableDeferred() }, diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisChatList.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisChatList.kt index b42c7d421..900010940 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisChatList.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisChatList.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.paging.compose.LazyPagingItems import coil.ImageLoader +import de.tum.informatics.www1.artemis.native_app.core.ui.markdown.ProvideMarkwon import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.R import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.EmojiService import de.tum.informatics.www1.artemis.native_app.feature.metis.conversation.service.MetisModificationFailure @@ -91,7 +92,7 @@ internal fun MetisChatList( val context = LocalContext.current var imageLoader: ImageLoader? by remember { mutableStateOf(null) } - LaunchedEffect(rememberCoroutineScope()) { + LaunchedEffect(true) { imageLoader = viewModel.createMarkdownImageLoader(context).await() } @@ -101,28 +102,29 @@ internal fun MetisChatList( } } - MetisChatList( - modifier = modifier, - initialReplyTextProvider = viewModel, - posts = posts.asPostsDataState(), - clientId = clientId, - hasModerationRights = hasModerationRights, - isAtLeastTutorInCourse = isAtLeastTutorInCourse, - listContentPadding = listContentPadding, - serverUrl = serverUrl, - courseId = viewModel.courseId, - markdownImageLoader = imageLoader, - state = state, - bottomItem = bottomItem, - isReplyEnabled = isReplyEnabled, - onCreatePost = viewModel::createPost, - onEditPost = viewModel::editPost, - onDeletePost = viewModel::deletePost, - onRequestReactWithEmoji = viewModel::createOrDeleteReaction, - onClickViewPost = onClickViewPost, - onRequestRetrySend = viewModel::retryCreatePost, - title = updatedTitle - ) + ProvideMarkwon(imageLoader) { + MetisChatList( + modifier = modifier, + initialReplyTextProvider = viewModel, + posts = posts.asPostsDataState(), + clientId = clientId, + hasModerationRights = hasModerationRights, + isAtLeastTutorInCourse = isAtLeastTutorInCourse, + listContentPadding = listContentPadding, + serverUrl = serverUrl, + courseId = viewModel.courseId, + state = state, + bottomItem = bottomItem, + isReplyEnabled = isReplyEnabled, + onCreatePost = viewModel::createPost, + onEditPost = viewModel::editPost, + onDeletePost = viewModel::deletePost, + onRequestReactWithEmoji = viewModel::createOrDeleteReaction, + onClickViewPost = onClickViewPost, + onRequestRetrySend = viewModel::retryCreatePost, + title = updatedTitle + ) + } } @Composable @@ -137,7 +139,6 @@ fun MetisChatList( listContentPadding: PaddingValues, serverUrl: String, courseId: Long, - markdownImageLoader: ImageLoader?, state: LazyListState, emojiService: EmojiService = koinInject(), isReplyEnabled: Boolean, @@ -172,7 +173,6 @@ fun MetisChatList( itemCount = posts.itemCount, order = DisplayPostOrder.REVERSED, emojiService = emojiService, - markdownImageLoader = markdownImageLoader, bottomItem = bottomItem ) { when (posts) { diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisPostListHandler.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisPostListHandler.kt index c63ee04c0..b9d51bfd8 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisPostListHandler.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/chatlist/MetisPostListHandler.kt @@ -42,7 +42,6 @@ internal fun MetisPostListHandler( itemCount: Int, bottomItem: T?, order: DisplayPostOrder, - markdownImageLoader: ImageLoader?, emojiService: EmojiService, content: @Composable BoxScope.() -> Unit ) { @@ -119,11 +118,9 @@ internal fun MetisPostListHandler( PostArtemisMarkdownTransformer(serverUrl = strippedServerUrl, courseId = courseId) } - ProvideMarkwon(markdownImageLoader) { - ProvideEmojis(emojiService) { - CompositionLocalProvider(LocalMarkdownTransformer provides markdownTransformer) { - content() - } + ProvideEmojis(emojiService) { + CompositionLocalProvider(LocalMarkdownTransformer provides markdownTransformer) { + content() } } } diff --git a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/thread/MetisThreadUi.kt b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/thread/MetisThreadUi.kt index f2f2f1656..90cb8b9e4 100644 --- a/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/thread/MetisThreadUi.kt +++ b/feature/metis/conversation/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/metis/conversation/ui/thread/MetisThreadUi.kt @@ -84,7 +84,7 @@ internal fun MetisThreadUi( val context = LocalContext.current var imageLoader: ImageLoader? by remember { mutableStateOf(null) } - LaunchedEffect(rememberCoroutineScope()) { + LaunchedEffect(true) { imageLoader = viewModel.createMarkdownImageLoader(context).await() } @@ -101,50 +101,51 @@ internal fun MetisThreadUi( val conversationDataState by viewModel.conversation.collectAsState() - MetisThreadUi( - modifier = modifier, - courseId = viewModel.courseId, - initialReplyTextProvider = viewModel, - conversationDataState = conversationDataState, - postDataState = postDataState, - isAtLeastTutorInCourse = isAtLeastTutorInCourse, - hasModerationRights = hasModerationRights, - listContentPadding = listContentPadding, - serverUrl = serverUrl, - emojiService = koinInject(), - clientId = clientId, - markdownImageLoader = imageLoader, - onCreatePost = viewModel::createReply, - onEditPost = { post, newText -> - val parentPost = postDataState.orNull() + ProvideMarkwon(imageLoader) { + MetisThreadUi( + modifier = modifier, + courseId = viewModel.courseId, + initialReplyTextProvider = viewModel, + conversationDataState = conversationDataState, + postDataState = postDataState, + isAtLeastTutorInCourse = isAtLeastTutorInCourse, + hasModerationRights = hasModerationRights, + listContentPadding = listContentPadding, + serverUrl = serverUrl, + emojiService = koinInject(), + clientId = clientId, + onCreatePost = viewModel::createReply, + onEditPost = { post, newText -> + val parentPost = postDataState.orNull() + + when (post) { + is AnswerPostPojo -> { + if (parentPost == null) CompletableDeferred( + MetisModificationFailure.UPDATE_POST + ) else viewModel.editAnswerPost(parentPost, post, newText) + } - when (post) { - is AnswerPostPojo -> { + is PostPojo -> viewModel.editPost(post, newText) + else -> throw NotImplementedError() + } + }, + onResolvePost = { post -> + val parentPost = postDataState.orNull() + + if (post is AnswerPostPojo) { if (parentPost == null) CompletableDeferred( MetisModificationFailure.UPDATE_POST - ) else viewModel.editAnswerPost(parentPost, post, newText) + ) else viewModel.toggleResolvePost(parentPost, post) + } else { + throw NotImplementedError() } - - is PostPojo -> viewModel.editPost(post, newText) - else -> throw NotImplementedError() - } - }, - onResolvePost = { post -> - val parentPost = postDataState.orNull() - - if (post is AnswerPostPojo) { - if (parentPost == null) CompletableDeferred( - MetisModificationFailure.UPDATE_POST - ) else viewModel.toggleResolvePost(parentPost, post) - } else { - throw NotImplementedError() - } - }, - onDeletePost = viewModel::deletePost, - onRequestReactWithEmoji = viewModel::createOrDeleteReaction, - onRequestReload = viewModel::requestReload, - onRequestRetrySend = viewModel::retryCreateReply - ) + }, + onDeletePost = viewModel::deletePost, + onRequestReactWithEmoji = viewModel::createOrDeleteReaction, + onRequestReload = viewModel::requestReload, + onRequestRetrySend = viewModel::retryCreateReply + ) + } } @Composable @@ -159,7 +160,6 @@ internal fun MetisThreadUi( listContentPadding: PaddingValues, serverUrl: String, emojiService: EmojiService, - markdownImageLoader: ImageLoader?, initialReplyTextProvider: InitialReplyTextProvider, onCreatePost: () -> Deferred, onEditPost: (IBasePost, String) -> Deferred, @@ -206,7 +206,6 @@ internal fun MetisThreadUi( state = listState, itemCount = post.orderedAnswerPostings.size, order = DisplayPostOrder.REGULAR, - markdownImageLoader = markdownImageLoader, emojiService = emojiService, bottomItem = post.orderedAnswerPostings.lastOrNull() ) { @@ -219,7 +218,6 @@ internal fun MetisThreadUi( isAtLeastTutorInCourse = isAtLeastTutorInCourse, listContentPadding = listContentPadding, clientId = clientId, - markdownImageLoader = markdownImageLoader, onRequestReactWithEmoji = onRequestReactWithEmojiDelegate, onRequestEdit = onEditPostDelegate, onRequestDelete = onDeletePostDelegate, @@ -255,7 +253,6 @@ private fun PostAndRepliesList( isAtLeastTutorInCourse: Boolean, listContentPadding: PaddingValues, clientId: Long, - markdownImageLoader: ImageLoader?, onRequestEdit: (IBasePost) -> Unit, onRequestDelete: (IBasePost) -> Unit, onRequestResolve: (IBasePost) -> Unit, From cbd528978977c7d2a51d840987118e99be1fb399 Mon Sep 17 00:00:00 2001 From: Julian Waluschyk Date: Tue, 26 Nov 2024 15:43:40 +0100 Subject: [PATCH 22/22] minor changes --- .../www1/artemis/native_app/core/ui/markdown/LocalMarkwon.kt | 1 - .../native_app/core/ui/remote_images/DefaultImageProvider.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/markdown/LocalMarkwon.kt b/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/markdown/LocalMarkwon.kt index 92473eb9b..ec5e2efd3 100644 --- a/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/markdown/LocalMarkwon.kt +++ b/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/markdown/LocalMarkwon.kt @@ -18,7 +18,6 @@ fun ProvideMarkwon(imageLoader: ImageLoader? = null, content: @Composable () -> val imageWith = context.resources.displayMetrics.widthPixels val markdownRender: Markwon = remember(imageLoader) { - println(imageWith) createMarkdownRender(context, imageLoader, imageWith) } diff --git a/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/remote_images/DefaultImageProvider.kt b/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/remote_images/DefaultImageProvider.kt index ea4f89c7a..c581e33ae 100644 --- a/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/remote_images/DefaultImageProvider.kt +++ b/core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/remote_images/DefaultImageProvider.kt @@ -27,7 +27,6 @@ class DefaultImageProvider : BaseImageProvider { return builder.build() } - override fun createImageLoader( context: Context, authorizationToken: String