Skip to content

Commit

Permalink
General: Release 1.2.0 - Merge pull request #154
Browse files Browse the repository at this point in the history
  • Loading branch information
anian03 authored Aug 25, 2024
2 parents 43091d8 + 8134e54 commit b0082ff
Show file tree
Hide file tree
Showing 39 changed files with 1,443 additions and 426 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/ls1intum/artemis-ios-core-modules",
"state" : {
"revision" : "ce0d4e6e74cbb9c55e9dbc8f9ec2d15a8bd1c233",
"version" : "13.2.0"
"revision" : "b6456ffac746054f34e53a3ea42987b3c06e7c70",
"version" : "14.0.3"
}
},
{
Expand All @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0",
"version" : "1.8.2"
"revision" : "678d442c6f7828def400a70ae15968aef67ef52d",
"version" : "1.8.3"
}
},
{
Expand Down Expand Up @@ -122,17 +122,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/gonzalezreal/swift-markdown-ui",
"state" : {
"revision" : "9a8119b37e09a770367eeb26e05267c75d854053",
"version" : "2.3.1"
"revision" : "55441810c0f678c78ed7e2ebd46dde89228e02fc",
"version" : "2.4.0"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "303e5c5c36d6a558407d364878df131c3546fad8",
"version" : "510.0.2"
"revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82",
"version" : "510.0.3"
}
},
{
Expand Down Expand Up @@ -194,8 +194,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"state" : {
"revision" : "9234124cff5e22e178988c18d8b95a8ae8007f76",
"version" : "5.1.2"
"revision" : "3036ba9d69cf1fd04d433527bc339dc0dc75433d",
"version" : "5.1.3"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion Artemis/Supporting/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.1.0</string>
<string>1.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
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: "13.2.0")),
.package(url: "https://github.com/ls1intum/artemis-ios-core-modules", .upToNextMajor(from: "14.0.3")),
.package(url: "https://github.com/mac-cain13/R.swift.git", from: "7.0.0")
],
targets: [
Expand Down
14 changes: 14 additions & 0 deletions ArtemisKit/Sources/CourseView/ExerciseTab/ExerciseDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public struct ExerciseDetailView: View {
}
.task {
await viewModel.loadExercise()
await viewModel.loadAssociatedChannel()
}
.refreshable {
await viewModel.refreshExercise()
Expand Down Expand Up @@ -218,6 +219,19 @@ private extension ExerciseDetailView {
}
}
}

if let channel = viewModel.channel.value {
Divider()
.frame(height: 1.0)
.overlay(Color.Artemis.artemisBlue)

ExerciseDetailCell(descriptionText: R.string.localizable.communication() + ":") {
NavigationLink(value: ConversationPath(conversation: .channel(conversation: channel),
coursePath: .init(id: viewModel.courseId))) {
Text("\(channel.conversationName) \(Image(systemName: "chevron.forward"))")
}
}
}
}
.background {
RoundedRectangle(cornerRadius: 3.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ final class ExerciseDetailViewModel {
let exerciseId: Int

var exercise: DataState<Exercise>
var channel: DataState<Channel> = .loading

var isFeedbackPresented = false
var latestResultId: Int?
Expand Down Expand Up @@ -77,6 +78,10 @@ final class ExerciseDetailViewModel {
webViewId = UUID()
}

func loadAssociatedChannel() async {
channel = await ExerciseChannelServiceFactory.shared.getAssociatedChannel(for: exerciseId, in: courseId)
}

private func setParticipationAndResultId(from exercise: Exercise) {
isWebViewLoading = true

Expand Down
47 changes: 47 additions & 0 deletions ArtemisKit/Sources/CourseView/LectureTab/LectureDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Common
import SharedModels
import ArtemisMarkdown
import DesignLibrary
import Navigation

public struct LectureDetailView: View {

Expand Down Expand Up @@ -58,11 +59,23 @@ public struct LectureDetailView: View {
AttachmentCell(attachment: attachment)
}
}
if let channel = viewModel.channel.value {
Text(R.string.localizable.communication())
.font(.headline)
ChannelCell(courseId: viewModel.courseId, channel: channel)
}
Spacer()
}
Spacer()
}.padding(.l)
}
.onChange(of: viewModel.course.value, initial: true) { _, newValue in
if newValue != nil {
Task {
await viewModel.loadAssociatedChannel()
}
}
}
}
.navigationTitle(viewModel.lecture.value?.title ?? R.string.localizable.loading())
.navigationBarTitleDisplayMode(.inline)
Expand All @@ -73,6 +86,40 @@ public struct LectureDetailView: View {
}
}

private struct ChannelCell: View {

@EnvironmentObject var navigationController: NavigationController
let courseId: Int
let channel: Channel

var body: some View {
Button {
navigationController.path.append(ConversationPath(id: channel.id, coursePath: CoursePath(id: courseId)))
} label: {
HStack {
VStack(alignment: .leading, spacing: .l) {
Label {
Text(channel.conversationName)
} icon: {
channel.icon
}
.font(.title3)

if let description = channel.description {
Text(description)
}
}
.foregroundColor(Color.Artemis.primaryLabel)
Spacer()
Image(systemName: "chevron.forward")
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.l)
.cardModifier(backgroundColor: .Artemis.exerciseCardBackgroundColor, cornerRadius: .m)
}
}
}

private struct AttachmentCell: View {

let attachment: Attachment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class LectureDetailViewModel: BaseViewModel {

@Published var lecture: DataState<Lecture> = .loading
@Published var course: DataState<Course> = .loading
@Published var channel: DataState<Channel> = .loading

let lectureId: Int
let courseId: Int
Expand Down Expand Up @@ -55,6 +56,13 @@ class LectureDetailViewModel: BaseViewModel {
}
}

func loadAssociatedChannel() async {
// We only have a channel if communication is enabled
guard course.value?.courseInformationSharingConfiguration != .disabled else { return }

channel = await LectureServiceFactory.shared.getAssociatedChannel(for: lectureId, in: courseId)
}

func updateLectureUnitCompletion(lectureUnit: LectureUnit, completed: Bool) async -> LectureUnit {
let result = await LectureServiceFactory.shared.updateLectureUnitCompletion(lectureId: lectureId,
lectureUnitId: lectureUnit.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,4 @@
"lectureUnits" = "Lecture Units";
"lecturesGroupTitle" = "%s (Lectures: %i)";
"attachments" = "Attachments";
"communication" = "Communication";
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// ExerciseChannelService.swift
//
//
// Created by Anian Schleyer on 18.08.24.
//

import Foundation
import Common
import SharedModels

protocol ExerciseChannelService {
func getAssociatedChannel(for exerciseId: Int, in courseId: Int) async -> DataState<Channel>
}

enum ExerciseChannelServiceFactory {
static let shared: ExerciseChannelService = ExerciseChannelServiceImpl()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// ExerciseChannelServiceImpl.swift
//
//
// Created by Anian Schleyer on 18.08.24.
//

import APIClient
import Common
import SharedModels

struct ExerciseChannelServiceImpl: ExerciseChannelService {

let client = APIClient()

struct GetExerciseChannelRequest: APIRequest {
typealias Response = Channel

let courseId: Int
let exerciseId: Int

var method: HTTPMethod {
.get
}

var resourceName: String {
"api/courses/\(courseId)/exercises/\(exerciseId)/channel"
}
}

func getAssociatedChannel(for exerciseId: Int, in courseId: Int) async -> DataState<Channel> {
let result = await client.sendRequest(GetExerciseChannelRequest(courseId: courseId, exerciseId: exerciseId))

switch result {
case let .success((response, _)):
return .done(response: response)
case let .failure(error):
return .failure(error: UserFacingError(error: error))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ protocol LectureService {
func getLectureDetails(lectureId: Int) async -> DataState<Lecture>
func getAttachmentFile(link: String) async -> DataState<URL>
func updateLectureUnitCompletion(lectureId: Int, lectureUnitId: Int64, completed: Bool) async -> NetworkResponse
func getAssociatedChannel(for lectureId: Int, in courseId: Int) async -> DataState<Channel>
}

enum LectureServiceFactory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,30 @@ class LectureServiceImpl: LectureService {
return .failure(error: UserFacingError(title: error.localizedDescription))
}
}

struct GetLectureChannelRequest: APIRequest {
typealias Response = Channel

let courseId: Int
let lectureId: Int

var method: HTTPMethod {
.get
}

var resourceName: String {
"api/courses/\(courseId)/lectures/\(lectureId)/channel"
}
}

func getAssociatedChannel(for lectureId: Int, in courseId: Int) async -> DataState<Channel> {
let result = await client.sendRequest(GetLectureChannelRequest(courseId: courseId, lectureId: lectureId))

switch result {
case let .success((response, _)):
return .done(response: response)
case let .failure(error):
return .failure(error: UserFacingError(error: error))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,38 @@ private let MAX_MINUTES_FOR_GROUPING_MESSAGES = 5

extension BaseMessage {
/// Whether the same author messaged multiple times within 5 minutes.
func isContinuation(of message: some BaseMessage) -> Bool {
guard author == message.author,
func isContinuation(of message: BaseMessage?) -> Bool {
guard let message,
author == message.author,
let lhs = creationDate,
let rhs = message.creationDate else {
return false
}

// Don't merge pinned messages
if (message as? Message)?.displayPriority == .pinned {
return false
}
if (self as? Message)?.displayPriority == .pinned {
return false
}

// Don't merge resolving answers
if (message as? AnswerMessage)?.resolvesPost ?? false {
return false
}
if (self as? AnswerMessage)?.resolvesPost ?? false {
return false
}

return lhs < rhs.addingTimeInterval(TimeInterval(MAX_MINUTES_FOR_GROUPING_MESSAGES * 60))
}
}

// https://stackoverflow.com/a/30593673
extension Collection {
/// Returns the element at the specified index if it is within bounds, otherwise nil.
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct OfflineMessageOrAnswer: BaseMessage {
var updatedDate: Date?
var content: String?
var tokenizedContent: String?
var authorRoleTransient: UserRole?
var authorRole: UserRole?
var reactions: [Reaction]?
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public struct NavigationDestinationThreadViewModifier: ViewModifier {

public func body(content: Content) -> some View {
content.navigationDestination(for: MessagePath.self) { messagePath in
MessageDetailView(viewModel: messagePath.conversationViewModel, message: messagePath.message)
MessageDetailView(viewModel: messagePath.conversationViewModel, message: messagePath.message, presentKeyboardOnAppear: messagePath.presentKeyboardOnAppear)
}
}
}
Loading

0 comments on commit b0082ff

Please sign in to comment.