Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions Core/Core/Features/Notifications/API/APIActivity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ public struct APIActivity: Codable {
let context_type: String?
let course_id: ID?
let group_id: ID?
let score: Double?
let grade: String?
let read_state: Bool?
let notification_category: String?
}

#if DEBUG
Expand All @@ -55,7 +59,11 @@ extension APIActivity {
type: ActivityType = .message,
context_type: String = ContextType.course.rawValue,
course_id: ID? = "1",
group_id: ID? = nil
group_id: ID? = nil,
score: Double? = nil,
grade: String? = "12",
read_state: Bool? = true,
notification_category: String? = "Due Date"
) -> APIActivity {
return APIActivity(
id: id,
Expand All @@ -67,7 +75,11 @@ extension APIActivity {
type: type,
context_type: context_type,
course_id: course_id,
group_id: group_id
group_id: group_id,
score: score,
grade: grade,
read_state: read_state,
notification_category: notification_category
)
}
}
Expand All @@ -76,18 +88,29 @@ extension APIActivity {
public struct GetActivitiesRequest: APIRequestable {
public typealias Response = [APIActivity]
let perPage: Int?
let onlyActiveCourses: Bool

public init(perPage: Int? = nil) {
public init(perPage: Int? = nil, onlyActiveCourses: Bool = true) {
self.perPage = perPage
self.onlyActiveCourses = onlyActiveCourses
}

public var path: String {
let context = Context(.user, id: "self")
return "\(context.pathComponent)/activity_stream"
}

public var query: [APIQueryItem] {[
.value("only_active_courses", "true"),
.perPage(perPage)
]}
public var query: [APIQueryItem] {
var items: [APIQueryItem] = []

if onlyActiveCourses {
items.append(.value("only_active_courses", "true"))
}

if let perPage = perPage {
items.append(.perPage(perPage))
}

return items
}
}
15 changes: 14 additions & 1 deletion Core/Core/Features/Notifications/CoreData/Activity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public final class Activity: NSManagedObject, WriteableModel {
@NSManaged public var typeRaw: String
@NSManaged public var htmlURL: URL?
@NSManaged public var canvasContextIDRaw: String?
@NSManaged public var score: String?
@NSManaged public var grade: String?
@NSManaged public var notification_category: String?
@NSManaged public var context_type: String?
@NSManaged public var course_id: String?
@NSManaged public var read_state: Bool

public var context: Context? {
get { return Context(canvasContextID: canvasContextIDRaw ?? "") }
Expand All @@ -52,13 +58,20 @@ public final class Activity: NSManagedObject, WriteableModel {
model.htmlURL = item.html_url
model.typeRaw = item.type.rawValue
model.updatedAt = item.updated_at

model.grade = item.grade
model.notification_category = item.notification_category
model.context_type = item.context_type
model.read_state = item.read_state ?? true
if let score = item.score {
model.score = String(score)
}
if let rawValue = item.context_type, let contextType = ContextType(rawValue: rawValue.lowercased()) {
var context: Context?
switch contextType {
case .course:
if let id = item.course_id?.value {
context = Context(contextType, id: id)
model.course_id = id
}
case .group:
if let id = item.group_id?.value {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ public class GetActivities: CollectionUseCase {
public typealias Response = Request.Response

private let context: Context?
public init(context: Context? = nil) {
private let onlyActiveCourses: Bool
public init(
context: Context? = nil,
onlyActiveCourses: Bool = true
) {
self.context = context
self.onlyActiveCourses = onlyActiveCourses
}

public var cacheKey: String? {
Expand All @@ -50,6 +55,6 @@ public class GetActivities: CollectionUseCase {
}

public var request: GetActivitiesRequest {
return GetActivitiesRequest()
return GetActivitiesRequest(onlyActiveCourses: onlyActiveCourses)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@
</entity>
<entity name="Activity" representedClassName=".Activity" syncable="YES">
<attribute name="canvasContextIDRaw" optional="YES" attributeType="String"/>
<attribute name="context_type" optional="YES" attributeType="String"/>
<attribute name="course_id" optional="YES" attributeType="String"/>
<attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="grade" optional="YES" attributeType="String"/>
<attribute name="htmlURL" optional="YES" attributeType="URI"/>
<attribute name="id" optional="YES" attributeType="String"/>
<attribute name="message" optional="YES" attributeType="String"/>
<attribute name="notification_category" optional="YES" attributeType="String"/>
<attribute name="read_state" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="score" optional="YES" attributeType="String"/>
<attribute name="title" optional="YES" attributeType="String"/>
<attribute name="typeRaw" optional="YES" attributeType="String"/>
<attribute name="updatedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
Expand Down
30 changes: 30 additions & 0 deletions Horizon/Horizon/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
},
"-" : {

},
"'s score is now available" : {

},
"'s score weight was changed " : {

},
"%@ %@" : {
"localizations" : {
Expand Down Expand Up @@ -74,6 +80,9 @@
},
"Amsterdam (+01:00/+02:00)" : {

},
"Announcement from" : {

},
"Announcements and Messages" : {

Expand All @@ -98,6 +107,9 @@
},
"Assignment Name" : {

},
"Assignment Scored" : {

},
"Assignment Successfully Submitted!" : {

Expand Down Expand Up @@ -272,6 +284,9 @@
},
"Due Date" : {

},
"Due Date Changed" : {

},
"Due Date: %@" : {

Expand Down Expand Up @@ -413,6 +428,9 @@
},
"Irkutsk (+08:00/+08:00)" : {

},
"is due on " : {

},
"Islamabad (+05:00)" : {

Expand Down Expand Up @@ -581,6 +599,9 @@
},
"No" : {

},
"No notification activity yet." : {

},
"Norfolk Island (+11:00/+12:00)" : {

Expand Down Expand Up @@ -734,6 +755,9 @@
},
"Scores" : {

},
"Scoring Weight Changed" : {

},
"Select a Submission Type" : {

Expand Down Expand Up @@ -857,6 +881,12 @@
},
"Ulaanbaatar (+08:00/+08:00)" : {

},
"Unknown Course" : {

},
"Unknown date" : {

},
"Unlimited" : {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ struct DashboardView: View {
HorizonUI.NavigationBar.Trailing {
viewModel.notebookDidTap(viewController: viewController)
} onNotificationDidTap: {
viewModel.notificationsDidTap()
viewModel.notificationsDidTap(viewController: viewController)
} onMailDidTap: {
viewModel.mailDidTap(viewController: viewController)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ class DashboardViewModel {
router.route(to: "/notebook", from: viewController)
}

func notificationsDidTap() {}
func notificationsDidTap(viewController: WeakViewController) {
router.show(NotificationAssembly.makeView(), from: viewController)
}

func mailDidTap(viewController: WeakViewController) {
router.route(to: "/conversations", from: viewController)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// This file is part of Canvas.
// Copyright (C) 2025-present Instructure, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import Core
import Foundation

struct HActivity: Identifiable, Equatable {
let id: String
let title: String
let message: String?
let date: Date?
let grade: String?
let score: String?
let type: ActivityType?
let contextType: String?
let notificationCategory: String?
let courseId: String?
let isRead: Bool

init(
id: String,
title: String,
message: String?,
date: Date? = nil,
grade: String? = nil,
score: String? = nil,
type: ActivityType? = nil,
contextType: String? = nil,
notificationCategory: String? = nil,
courseId: String? = nil,
isRead: Bool = true
) {
self.id = id
self.title = title
self.message = message
self.date = date
self.grade = grade
self.score = score
self.type = type
self.contextType = contextType
self.notificationCategory = notificationCategory
self.courseId = courseId
self.isRead = isRead
}

init(from entity: Activity) {
self.id = entity.id
self.title = entity.title ?? ""
self.message = entity.message
self.date = entity.updatedAt
self.grade = entity.grade
self.score = entity.score
self.type = entity.type
self.contextType = entity.context_type
self.notificationCategory = entity.notification_category
self.courseId = entity.course_id
self.isRead = entity.read_state
}

var dateFormatted: String {
date?.formatted(format: "MMM d") ?? ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// This file is part of Canvas.
// Copyright (C) 2025-present Instructure, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

struct NotificationModel: Identifiable, Equatable {
let id: String
let category: String
let title: String
let date: String
let isRead: Bool
}
Loading