Skip to content

Commit d8a8980

Browse files
UI adjustments to align with iOS; exercise and lecture list item redesign (#43)
Co-authored-by: Martin Felber <[email protected]> Co-authored-by: Martin Felber <[email protected]>
1 parent 46eb330 commit d8a8980

File tree

7 files changed

+137
-68
lines changed

7 files changed

+137
-68
lines changed

app/src/main/java/de/tum/informatics/www1/artemis/native_app/android/ui/MainActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.content.Intent
55
import android.net.Uri
66
import android.os.Bundle
77
import androidx.activity.compose.setContent
8+
import androidx.activity.enableEdgeToEdge
89
import androidx.appcompat.app.AppCompatActivity
910
import androidx.browser.customtabs.CustomTabsIntent
1011
import androidx.compose.material3.windowsizeclass.WindowSizeClass
@@ -132,6 +133,7 @@ class MainActivity : AppCompatActivity(),
132133
}
133134

134135
setContent {
136+
enableEdgeToEdge()
135137
AppTheme {
136138
ProvideLocalVisibleMetisContextManager(
137139
visibleMetisContextManager = visibleMetisContextManager

core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/exercise/ExerciseCategoryChips.kt

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ fun ExerciseCategoryChipRow(modifier: Modifier, exercise: Exercise) {
4242

4343
@Composable
4444
fun ExerciseCategoryChipRow(modifier: Modifier, chips: List<ExerciseCategoryChipData>) {
45+
if (chips.isEmpty()) return
46+
4547
Row(
4648
modifier = modifier,
4749
horizontalArrangement = Arrangement.spacedBy(8.dp)
@@ -114,30 +116,6 @@ private fun collectExerciseCategoryChips(
114116
)
115117
) else emptyList()
116118

117-
val difficulty = exercise.difficulty
118-
val difficultyChips = if (difficulty != null) {
119-
val data = when (difficulty) {
120-
Exercise.Difficulty.EASY ->
121-
ExerciseCategoryChipData(
122-
context.getString(de.tum.informatics.www1.artemis.native_app.core.ui.R.string.exercise_difficulty_easy),
123-
Color(0xff28a745)
124-
)
125-
126-
Exercise.Difficulty.MEDIUM ->
127-
ExerciseCategoryChipData(
128-
context.getString(de.tum.informatics.www1.artemis.native_app.core.ui.R.string.exercise_difficulty_medium),
129-
Color(0xffffc107)
130-
)
131-
132-
Exercise.Difficulty.HARD ->
133-
ExerciseCategoryChipData(
134-
context.getString(de.tum.informatics.www1.artemis.native_app.core.ui.R.string.exercise_difficulty_hard),
135-
Color(0xffdc3545)
136-
)
137-
}
138-
listOf(data)
139-
} else emptyList()
140-
141119
val bonusChips =
142120
if (exercise.includedInOverallScore == Exercise.IncludedInOverallScore.INCLUDED_AS_BONUS) {
143121
listOf(
@@ -155,5 +133,5 @@ private fun collectExerciseCategoryChips(
155133
)
156134
}
157135

158-
return liveQuizChips + categoryChips + difficultyChips + bonusChips
136+
return liveQuizChips + categoryChips + bonusChips
159137
}

core/ui/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/core/ui/exercise/ExerciseListItem.kt

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package de.tum.informatics.www1.artemis.native_app.core.ui.exercise
22

3+
import androidx.compose.foundation.background
34
import androidx.compose.foundation.horizontalScroll
45
import androidx.compose.foundation.layout.Arrangement
56
import androidx.compose.foundation.layout.Box
67
import androidx.compose.foundation.layout.Column
8+
import androidx.compose.foundation.layout.IntrinsicSize
79
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.fillMaxHeight
811
import androidx.compose.foundation.layout.fillMaxSize
912
import androidx.compose.foundation.layout.fillMaxWidth
13+
import androidx.compose.foundation.layout.height
1014
import androidx.compose.foundation.layout.padding
1115
import androidx.compose.foundation.layout.size
16+
import androidx.compose.foundation.layout.width
1217
import androidx.compose.foundation.rememberScrollState
1318
import androidx.compose.material3.Card
1419
import androidx.compose.material3.Icon
@@ -24,6 +29,9 @@ import de.tum.informatics.www1.artemis.native_app.core.model.exercise.Exercise
2429
import de.tum.informatics.www1.artemis.native_app.core.ui.R
2530
import de.tum.informatics.www1.artemis.native_app.core.ui.date.getRelativeTime
2631
import de.tum.informatics.www1.artemis.native_app.core.ui.getWindowSizeClass
32+
import de.tum.informatics.www1.artemis.native_app.core.ui.material.easyColor
33+
import de.tum.informatics.www1.artemis.native_app.core.ui.material.hardColor
34+
import de.tum.informatics.www1.artemis.native_app.core.ui.material.mediumColor
2735

2836
/**
2937
* Display a single exercise.
@@ -41,54 +49,84 @@ fun ExerciseListItem(
4149
modifier = modifier,
4250
onClick = onClickExercise
4351
) {
44-
Column(
52+
Row(
4553
modifier = Modifier
4654
.fillMaxWidth()
47-
.padding(8.dp),
48-
verticalArrangement = Arrangement.spacedBy(8.dp)
55+
.height(IntrinsicSize.Min)
4956
) {
50-
Row(modifier = Modifier.fillMaxWidth()) {
51-
ExerciseTypeIcon(modifier = Modifier.size(80.dp), exercise = exercise)
57+
exercise.difficulty?.let { DifficultyRectangle(modifier = Modifier, difficulty = it)}
58+
59+
Column(
60+
modifier = Modifier
61+
.fillMaxWidth()
62+
.padding(16.dp),
63+
verticalArrangement = Arrangement.spacedBy(8.dp)
64+
) {
65+
Row(
66+
modifier = Modifier.fillMaxWidth(),
67+
verticalAlignment = Alignment.CenterVertically
68+
) {
69+
//Displays the icon of the exercise
70+
Icon(
71+
modifier = Modifier
72+
.size(40.dp)
73+
.padding(end = 8.dp)
74+
.fillMaxSize(),
75+
painter = getExerciseTypeIconPainter(exercise),
76+
contentDescription = null
77+
)
78+
79+
//Displays the title of the exercise
80+
Text(
81+
text = exercise.title.orEmpty(),
82+
style = MaterialTheme.typography.titleMedium
83+
)
84+
}
5285

5386
ExerciseDataText(
54-
modifier = Modifier
55-
.weight(1f)
56-
.padding(horizontal = 16.dp),
87+
modifier = Modifier,
5788
exercise = exercise,
5889
displayActionButtons = displayActionButtons,
5990
exerciseActions = exerciseActions
6091
)
61-
}
6292

63-
//Display a row of chips
64-
ExerciseCategoryChipRow(
65-
modifier = Modifier
66-
.fillMaxWidth()
67-
.horizontalScroll(rememberScrollState()),
68-
exercise = exercise
69-
)
93+
//Display a row of chips
94+
ExerciseCategoryChipRow(
95+
modifier = Modifier
96+
.fillMaxWidth()
97+
.horizontalScroll(rememberScrollState()),
98+
exercise = exercise
99+
)
100+
}
70101
}
71102
}
72103
}
73104

74105
/**
75-
* Displays the icon of the exercise within an outlined circle
106+
* Displays a rectangle next to the text to show the difficulty of the exercise.
76107
*/
77108
@Composable
78-
private fun ExerciseTypeIcon(modifier: Modifier, exercise: Exercise) {
79-
Box(modifier = modifier) {
80-
Icon(
81-
modifier = Modifier
82-
.fillMaxSize()
83-
.padding(8.dp),
84-
painter = getExerciseTypeIconPainter(exercise),
85-
contentDescription = null
109+
private fun DifficultyRectangle(modifier: Modifier, difficulty: Exercise.Difficulty) {
110+
Box(modifier = modifier
111+
.fillMaxHeight()
112+
.width(10.dp)
113+
.background(
114+
color = when (difficulty) {
115+
Exercise.Difficulty.EASY ->
116+
easyColor
117+
118+
Exercise.Difficulty.MEDIUM ->
119+
mediumColor
120+
121+
Exercise.Difficulty.HARD ->
122+
hardColor
123+
}
86124
)
87-
}
125+
)
88126
}
89127

90128
/**
91-
* Displays the exercise title, the due data and the participation info. The participation info is automatically updated.
129+
* Displays the exercise due data and the participation info. The participation info is automatically updated.
92130
*/
93131
@Composable
94132
private fun ExerciseDataText(
@@ -107,11 +145,6 @@ private fun ExerciseDataText(
107145
} else stringResource(id = R.string.exercise_item_due_date_not_set)
108146

109147
Column(modifier = modifier) {
110-
Text(
111-
text = exercise.title.orEmpty(),
112-
style = MaterialTheme.typography.titleMedium
113-
)
114-
115148
Text(
116149
text = formattedDueDate,
117150
style = MaterialTheme.typography.bodyMedium
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package de.tum.informatics.www1.artemis.native_app.core.ui.material
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.ui.graphics.Color
5+
6+
val hardColor: Color
7+
@Composable get() = Color(0xffdc3545)
8+
val mediumColor: Color
9+
@Composable get() = Color(0xffffc107)
10+
val easyColor: Color
11+
@Composable get() = Color(0xff28a745)

core/ui/src/main/res/values/exercise_strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<resources>
44

55
<string name="exercise_item_due_date_set">Due date: %1$s</string>
6-
<string name="exercise_item_due_date_not_set">No date associated</string>
6+
<string name="exercise_item_due_date_not_set">No due date</string>
77

88
<!-- Difficulty -->
99
<string name="exercise_difficulty_easy">Easy</string>

feature/course-view/src/main/kotlin/de/tum/informatics/www1/artemis/native_app/feature/courseview/ui/LectureListUi.kt

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package de.tum.informatics.www1.artemis.native_app.feature.courseview.ui
22

3-
import androidx.compose.foundation.clickable
4-
import androidx.compose.foundation.layout.Arrangement
53
import androidx.compose.foundation.layout.Box
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.fillMaxSize
67
import androidx.compose.foundation.layout.fillMaxWidth
78
import androidx.compose.foundation.layout.padding
8-
import androidx.compose.material3.ListItem
9+
import androidx.compose.foundation.layout.size
10+
import androidx.compose.material3.Card
11+
import androidx.compose.material3.Icon
912
import androidx.compose.material3.MaterialTheme
1013
import androidx.compose.material3.Text
1114
import androidx.compose.runtime.Composable
1215
import androidx.compose.ui.Alignment
1316
import androidx.compose.ui.Modifier
1417
import androidx.compose.ui.platform.testTag
18+
import androidx.compose.ui.res.painterResource
1519
import androidx.compose.ui.res.stringResource
1620
import androidx.compose.ui.text.style.TextAlign
1721
import androidx.compose.ui.unit.dp
@@ -40,12 +44,13 @@ internal fun LectureListUi(
4044
} else {
4145
WeeklyItemsLazyColumn(
4246
modifier = modifier.testTag(TEST_TAG_LECTURE_LIST),
43-
verticalArrangement = Arrangement.Top,
4447
weeklyItemGroups = lectures,
4548
getItemId = { id ?: 0L }
4649
) { lecture ->
4750
LectureListItem(
48-
modifier = Modifier.fillMaxWidth(),
51+
modifier = Modifier
52+
.fillMaxWidth()
53+
.padding(horizontal = 8.dp),
4954
lecture = lecture,
5055
onClick = { onClickLecture(lecture) }
5156
)
@@ -63,9 +68,39 @@ private fun LectureListItem(modifier: Modifier, lecture: Lecture, onClick: () ->
6368
)
6469
} else stringResource(id = R.string.course_ui_lecture_item_start_date_not_set)
6570

66-
ListItem(
67-
modifier = modifier.clickable(onClick = onClick),
68-
headlineContent = { Text(text = lecture.title) },
69-
supportingContent = { Text(text = startTimeText) }
70-
)
71+
Card(
72+
modifier = modifier,
73+
onClick = onClick
74+
) {
75+
Column(
76+
modifier = Modifier
77+
.fillMaxWidth()
78+
.padding(16.dp)
79+
) {
80+
Row(
81+
modifier = Modifier.fillMaxWidth(),
82+
verticalAlignment = Alignment.CenterVertically
83+
) {
84+
Icon(
85+
modifier = Modifier
86+
.size(40.dp)
87+
.padding(end = 8.dp)
88+
.fillMaxSize(),
89+
painter = painterResource(id = R.drawable.chalkboard_teacher),
90+
contentDescription = null
91+
)
92+
93+
Text(
94+
text = lecture.title,
95+
style = MaterialTheme.typography.titleMedium
96+
)
97+
}
98+
99+
Text(
100+
modifier = Modifier,
101+
text = startTimeText,
102+
style = MaterialTheme.typography.bodyMedium
103+
)
104+
}
105+
}
71106
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!--! Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. -->
2+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:width="640dp"
4+
android:height="512dp"
5+
android:viewportWidth="640"
6+
android:viewportHeight="512">
7+
<path
8+
android:fillColor="#FF000000"
9+
android:pathData="M208 352c-2.4 0-4.8 .4-7.1 1.1C188 357.3 174.4 360 160 360c-14.4 0-28-2.7-41-6.9-2.3-.7-4.7-1.1-7.1-1.1C49.9 352-.3 402.5 0 464.6 .1 490.9 21.7 512 48 512h224c26.3 0 47.9-21.1 48-47.4 .3-62.1-49.9-112.6-112-112.6zm-48-32c53 0 96-43 96-96s-43-96-96-96-96 43-96 96 43 96 96 96zM592 0H208c-26.5 0-48 22.3-48 49.6V96c23.4 0 45.1 6.8 64 17.8V64h352v288h-64v-64H384v64h-76.2c19.1 16.7 33.1 38.7 39.7 64H592c26.5 0 48-22.3 48-49.6V49.6C640 22.3 618.5 0 592 0z"/>
10+
</vector>

0 commit comments

Comments
 (0)