Skip to content

Commit

Permalink
Merge pull request #102 from ls1intum/develop
Browse files Browse the repository at this point in the history
`Development`: Release
  • Loading branch information
nityanandaz authored May 29, 2024
2 parents c7946f2 + 2f6b6ce commit b4c3077
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/ls1intum/apollon-ios-module",
"state" : {
"revision" : "424631162a5f05bcb0278d59ffb8f9b6f9d9c6ca",
"version" : "1.0.8"
"revision" : "5e4b1223bf33b542bcef2b844f7c451ac0ed7a9e",
"version" : "1.0.9"
}
},
{
"identity" : "artemis-ios-core-modules",
"kind" : "remoteSourceControl",
"location" : "https://github.com/ls1intum/artemis-ios-core-modules",
"state" : {
"revision" : "969303b0a2ab90a4a7150accc3d18764b9bde37f",
"version" : "10.0.0"
"revision" : "9c70eae3336c21f9de1e84ae7d25134d019b4dac",
"version" : "11.0.0"
}
},
{
Expand All @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c",
"version" : "1.8.1"
"revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0",
"version" : "1.8.2"
}
},
{
Expand Down Expand Up @@ -95,8 +95,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/SourceKitten.git",
"state" : {
"revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56",
"version" : "0.34.1"
"revision" : "fd4df99170f5e9d7cf9aa8312aa8506e0e7a44e7",
"version" : "0.35.0"
}
},
{
Expand All @@ -111,10 +111,10 @@
{
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"location" : "https://github.com/apple/swift-argument-parser",
"state" : {
"revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531",
"version" : "1.2.3"
"revision" : "46989693916f56d1186bd59ac15124caef896560",
"version" : "1.3.1"
}
},
{
Expand All @@ -131,17 +131,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
"version" : "509.0.2"
"revision" : "303e5c5c36d6a558407d364878df131c3546fad8",
"version" : "510.0.2"
}
},
{
"identity" : "swiftlint",
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/SwiftLint.git",
"state" : {
"revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee",
"version" : "0.54.0"
"revision" : "b515723b16eba33f15c4677ee65f3fef2ce8c255",
"version" : "0.55.1"
}
},
{
Expand Down Expand Up @@ -194,8 +194,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"state" : {
"revision" : "8a835d918245ca22f36663dd3862138805d7f707",
"version" : "5.1.0"
"revision" : "9234124cff5e22e178988c18d8b95a8ae8007f76",
"version" : "5.1.2"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion ArtemisKit/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ let package = Package(
.package(url: "https://github.com/daltoniam/Starscream.git", exact: "4.0.4"),
.package(url: "https://github.com/Kelvas09/EmojiPicker.git", from: "1.0.0"),
.package(url: "https://github.com/ls1intum/apollon-ios-module", .upToNextMajor(from: "1.0.2")),
.package(url: "https://github.com/ls1intum/artemis-ios-core-modules", .upToNextMajor(from: "10.0.0")),
.package(url: "https://github.com/ls1intum/artemis-ios-core-modules", .upToNextMajor(from: "11.0.0")),
.package(url: "https://github.com/mac-cain13/R.swift.git", from: "7.0.0")
],
targets: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public struct ExerciseDetailView: View {
private let exerciseId: Int
private let courseId: Int

@State private var webViewId = UUID()

public init(course: Course, exercise: Exercise) {
self._exercise = State(wrappedValue: .done(response: exercise))
self._urlRequest = State(wrappedValue: URLRequest(url: URL(string: "/courses/\(course.id)/exercises/\(exercise.id)/problem-statement", relativeTo: UserSession.shared.institution?.baseURL)!))
Expand Down Expand Up @@ -217,9 +219,12 @@ public struct ExerciseDetailView: View {

ArtemisWebView(urlRequest: $urlRequest,
contentHeight: $webViewHeight,
isLoading: $isWebViewLoading)
isLoading: $isWebViewLoading,
customJSHeightQuery: webViewContentJS)
.frame(height: webViewHeight)
.allowsHitTesting(false)
.loadingIndicator(isLoading: $isWebViewLoading)
.id(webViewId)
}
}
.toolbar {
Expand Down Expand Up @@ -258,6 +263,8 @@ public struct ExerciseDetailView: View {
if let exercise = self.exercise.value {
setParticipationAndResultId(from: exercise)
}
// Force WebView to reload
webViewId = UUID()
}

private func setParticipationAndResultId(from exercise: Exercise) {
Expand All @@ -273,6 +280,17 @@ public struct ExerciseDetailView: View {

urlRequest = URLRequest(url: URL(string: "/courses/\(courseId)/exercises/\(exercise.id)/problem-statement/\(participationId?.description ?? "")", relativeTo: UserSession.shared.institution?.baseURL)!)
}

/// JavaScript to reduce visible content in WebView to just problem statement
private let webViewContentJS = """
if (document.querySelector("jhi-course-overview") != null
&& document.querySelector("jhi-programming-exercise-instructions") != null
&& document.querySelector("jhi-problem-statement").innerText.length > 10) {
document.querySelector("jhi-course-overview").innerHTML = document.querySelector("jhi-programming-exercise-instructions").innerHTML;
document.querySelector("#programming-exercise-instructions-content").setAttribute("style", "overflow: unset");
}
document.querySelector(".instructions__content").scrollHeight
"""
}

private struct ExerciseDetailCell<Content: View>: View {
Expand Down
106 changes: 57 additions & 49 deletions ArtemisKit/Sources/CourseView/ExerciseTab/ExerciseListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ struct ExerciseListView: View {
ScrollViewReader { value in
List {
if searchText.isEmpty {
ForEach(weeklyExercises) { weeklyExercise in
ExerciseListSection(course: viewModel.course, weeklyExercise: weeklyExercise)
.id(weeklyExercise.id)
if weeklyExercises.isEmpty {
ContentUnavailableView(R.string.localizable.exercisesUnavailable(), systemImage: "list.bullet.clipboard")
.listRowSeparator(.hidden)
} else {
ForEach(weeklyExercises) { weeklyExercise in
ExerciseListSection(course: viewModel.course, weeklyExercise: weeklyExercise)
.id(weeklyExercise.id)
}
}
} else {
if searchResults.isEmpty {
Expand All @@ -30,6 +35,9 @@ struct ExerciseListView: View {
}
}
.listStyle(.plain)
.refreshable {
await viewModel.refreshCourse()
}
.onChange(of: weeklyExercises) { _, newValue in
withAnimation {
if let id = newValue.first(where: { $0.exercises.first?.baseExercise.dueDate ?? .tomorrow > .now })?.id {
Expand All @@ -38,9 +46,6 @@ struct ExerciseListView: View {
}
}
}
.refreshable {
await viewModel.refreshCourse()
}
}
}

Expand Down Expand Up @@ -137,53 +142,56 @@ struct ExerciseListCell: View {
]

var body: some View {
VStack(alignment: .leading, spacing: .m) {
HStack(spacing: .l) {
exercise.image
.renderingMode(.template)
.resizable()
.scaledToFit()
.foregroundColor(Color.Artemis.primaryLabel)
.frame(width: .smallImage)
Text(exercise.baseExercise.title ?? "")
.font(.title3)
Spacer()
}
if let dueDate = exercise.baseExercise.dueDate {
Text(R.string.localizable.dueDate(dueDate.relative ?? "?"))
} else {
Text(R.string.localizable.noDueDate())
}
SubmissionResultStatusView(exercise: exercise)
ScrollView(.horizontal) {
LazyHGrid(rows: rows, spacing: .s) {
if let releaseDate = exercise.baseExercise.releaseDate,
releaseDate > .now {
Chip(
text: R.string.localizable.notReleased(),
backgroundColor: Color.Artemis.badgeWarningColor)
}
ForEach(exercise.baseExercise.categories ?? [], id: \.category) { category in
Chip(text: category.category, backgroundColor: UIColor(hexString: category.colorCode).suColor)
}
// TODO: maybe add isActiveQuiz in presentationMode badge
if let difficulty = exercise.baseExercise.difficulty {
Chip(text: difficulty.description, backgroundColor: difficulty.color)
}
if exercise.baseExercise.includedInOverallScore != .includedCompletely {
Chip(
text: exercise.baseExercise.includedInOverallScore.description,
backgroundColor: exercise.baseExercise.includedInOverallScore.color)
Button {
navigationController.path.append(ExercisePath(exercise: exercise, coursePath: CoursePath(course: course)))
} label: {
VStack(alignment: .leading, spacing: .m) {
HStack(spacing: .l) {
exercise.image
.renderingMode(.template)
.resizable()
.scaledToFit()
.foregroundColor(Color.Artemis.primaryLabel)
.frame(width: .smallImage)
Text(exercise.baseExercise.title ?? "")
.font(.title3)
Spacer()
}
if let dueDate = exercise.baseExercise.dueDate {
Text(R.string.localizable.dueDate(dueDate.relative ?? "?"))
} else {
Text(R.string.localizable.noDueDate())
}
SubmissionResultStatusView(exercise: exercise)
ScrollView(.horizontal) {
LazyHGrid(rows: rows, spacing: .s) {
if let releaseDate = exercise.baseExercise.releaseDate,
releaseDate > .now {
Chip(
text: R.string.localizable.notReleased(),
backgroundColor: Color.Artemis.badgeWarningColor)
}
ForEach(exercise.baseExercise.categories ?? [], id: \.category) { category in
Chip(text: category.category, backgroundColor: UIColor(hexString: category.colorCode).suColor)
}
// TODO: maybe add isActiveQuiz in presentationMode badge
if let difficulty = exercise.baseExercise.difficulty {
Chip(text: difficulty.description, backgroundColor: difficulty.color)
}
if exercise.baseExercise.includedInOverallScore != .includedCompletely {
Chip(
text: exercise.baseExercise.includedInOverallScore.description,
backgroundColor: exercise.baseExercise.includedInOverallScore.color)
}
}
}
}
.frame(maxWidth: .infinity)
.padding(.l)
.artemisStyleCard()
}
.frame(maxWidth: .infinity)
.padding(.l)
.artemisStyleCard()
.onTapGesture {
navigationController.path.append(ExercisePath(exercise: exercise, coursePath: CoursePath(course: course)))
}
// Make button style explicit, otherwise, multiple cells may activate a navigation link.
.buttonStyle(.plain)
}
}

Expand Down
12 changes: 10 additions & 2 deletions ArtemisKit/Sources/CourseView/LectureTab/LectureListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ struct LectureListView: View {
ScrollViewReader { value in
List {
if searchText.isEmpty {
ForEach(weeklyLectures) { weeklyLecture in
LectureListSectionView(course: viewModel.course, weeklyLecture: weeklyLecture)
if weeklyLectures.isEmpty {
ContentUnavailableView(R.string.localizable.lecturesUnavailable(), systemImage: "character.book.closed")
.listRowSeparator(.hidden)
} else {
ForEach(weeklyLectures) { weeklyLecture in
LectureListSectionView(course: viewModel.course, weeklyLecture: weeklyLecture)
}
}
} else {
if searchResults.isEmpty {
Expand All @@ -34,6 +39,9 @@ struct LectureListView: View {
}
}
.listStyle(.plain)
.refreshable {
await viewModel.refreshCourse()
}
.onChange(of: weeklyLectures) { _, newValue in
withAnimation {
let lecture = newValue.first {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"exercisesTabLabel" = "Exercises";
"lectureTabLabel" = "Lectures";
"messagesTabLabel" = "Messages";
"exercisesUnavailable" = "No Exercises";
"lecturesUnavailable" = "No Lectures";

// MARK: SubmissionResultStatusView
"userNotAssignedToTeam" = "You have not been assigned to a team yet.";
Expand Down
16 changes: 9 additions & 7 deletions ArtemisKit/Sources/Dashboard/CourseGridCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,20 @@ struct CourseGridCell: View {
var nextExercise: Exercise? {
// filters out every already successful (100%) exercise, only exercises left that still need work
let exercisesWithOpenTasks = courseForDashboard.course.upcomingExercises.filter { exercise in
guard let participation = exercise.baseExercise.studentParticipations?.first,
let submission = participation.baseParticipation.submissions?.first,
let result = submission.baseSubmission.results?.first else {
return false
if let participation = exercise.baseExercise.studentParticipations?.first,
let submission = participation.baseParticipation.submissions?.first,
let result = submission.baseSubmission.results?.first,
let success = result?.successful {
return !success
}
return !(result?.successful ?? false)
return true
}
return exercisesWithOpenTasks.first
}

var body: some View {
Button {
navigationController.path.append(CoursePath(course: courseForDashboard.course))
navigationController.path.append(CoursePath(id: courseForDashboard.id))
} label: {
VStack(alignment: .leading, spacing: 0) {
header
Expand Down Expand Up @@ -66,7 +67,8 @@ private extension CourseGridCell {
.multilineTextAlignment(.leading)
.lineLimit(2)
Text(R.string.localizable.dashboardExercisesLabel(courseForDashboard.course.exercises?.count ?? 0))
Text(R.string.localizable.dashboardLecturesLabel(courseForDashboard.course.lectures?.count ?? 0))
let numberOfLectures = courseForDashboard.course.numberOfLectures ?? courseForDashboard.course.lectures?.count ?? 0
Text(R.string.localizable.dashboardLecturesLabel(numberOfLectures))
}
.foregroundStyle(.white)
.padding(.m)
Expand Down
5 changes: 4 additions & 1 deletion ArtemisKit/Sources/Messages/Models/Schema/SchemaV1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ enum SchemaV1: VersionedSchema {
@Attribute(.unique)
var host: String

var lastAccessDate: Date

@Relationship(deleteRule: .cascade, inverse: \Course.server)
var courses: [Course]

init(host: String, courses: [Course] = []) {
init(host: String, lastAccessDate: Date, courses: [Course] = []) {
self.host = host
self.lastAccessDate = lastAccessDate
self.courses = courses
}
}
Expand Down
Loading

0 comments on commit b4c3077

Please sign in to comment.