Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eric/inbox middleware semaphore #719

Closed
wants to merge 17 commits into from
Closed
145 changes: 145 additions & 0 deletions Mlem.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@
"version" : "12.1.4"
}
},
{
"identity" : "semaphore",
"kind" : "remoteSourceControl",
"location" : "https://github.com/groue/Semaphore",
"state" : {
"revision" : "f1c4a0acabeb591068dea6cffdd39660b86dec28",
"version" : "0.0.8"
}
},
{
"identity" : "swift-clocks",
"kind" : "remoteSourceControl",
Expand Down
7 changes: 7 additions & 0 deletions Mlem/API/APIClient/APIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,19 @@ extension APIClient {
return try await perform(request: request).privateMessageReportView
}

@available(*, deprecated, message: "Use id-based sendPrivateMessage instead")
@discardableResult
func sendPrivateMessage(content: String, recipient: APIPerson) async throws -> PrivateMessageResponse {
let request = try CreatePrivateMessageRequest(session: session, content: content, recipient: recipient)
return try await perform(request: request)
}

@discardableResult
func sendPrivateMessage(content: String, recipientId: Int) async throws -> PrivateMessageResponse {
let request = try CreatePrivateMessageRequest(session: session, content: content, recipientId: recipientId)
return try await perform(request: request)
}

func markPrivateMessageRead(id: Int, isRead: Bool) async throws -> APIPrivateMessageView {
let request = try MarkPrivateMessageAsRead(session: session, privateMessageId: id, read: isRead)
return try await perform(request: request).privateMessageView
Expand Down
12 changes: 11 additions & 1 deletion Mlem/API/Requests/Messages/CreatePrivateMessageRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@ struct CreatePrivateMessageRequest: APIPostRequest {
let content: String
let recipient_id: Int
}


init(
session: APISession,
content: String,
recipientId: Int
) throws {
self.instanceURL = try session.instanceUrl
self.body = try .init(auth: session.token, content: content, recipient_id: recipientId)
}

@available(*, deprecated, message: "Use id-based initializer instead")
init(
session: APISession,
content: String,
Expand Down
5 changes: 3 additions & 2 deletions Mlem/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ struct ContentView: View {
// but when guest mode arrives we'll either omit these entirely, or replace them with a
// guest mode specific tab for sign in / change instance screen.
if let account = appState.currentActiveAccount {
InboxView()
// InboxView()
InboxViewNew()
.fancyTabItem(tag: TabSelection.inbox) {
FancyTabBarLabel(
tag: TabSelection.inbox,
Expand Down Expand Up @@ -157,7 +158,7 @@ struct ContentView: View {
}

func showAccountSwitcherDragCallback() {
if !homeButtonExists && allowTabBarSwipeUpGesture {
if !homeButtonExists, allowTabBarSwipeUpGesture {
isPresentingAccountSwitcher = true
}
}
Expand Down
19 changes: 19 additions & 0 deletions Mlem/Dependency/Repositories/InboxRepository+Dependency.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// InboxRepository+Dependency.swift
// Mlem
//
// Created by Eric Andrews on 2023-09-23.
//
import Dependencies
import Foundation

extension InboxRepository: DependencyKey {
static let liveValue = InboxRepository()
}

extension DependencyValues {
var inboxRepository: InboxRepository {
get { self[InboxRepository.self] }
set { self[InboxRepository.self] = newValue }
}
}
2 changes: 1 addition & 1 deletion Mlem/Enums/Content Type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
import Foundation

enum ContentType: Int, Codable {
case post, comment, community, user
case post, comment, community, user, message, mention, reply
}
16 changes: 16 additions & 0 deletions Mlem/Enums/LoadingState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// LoadingState.swift
// Mlem
//
// Created by Eric Andrews on 2023-10-12.
//

import Foundation

/// Enum of possible loading states that a standard tracker can be in.
/// - idle: not currently loading, but more posts available to load
/// - loading: currently loading more posts
/// - done: no more posts available to load
enum LoadingState {
case idle, loading, done
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// MessageModel+ChildTrackerItem.swift
// Mlem
//
// Created by Eric Andrews on 2023-10-16.
//

import Foundation

extension MessageModel: ChildTrackerItem {
typealias ParentType = InboxItemNew

func sortVal(sortType: TrackerSortType) -> TrackerSortVal {
switch sortType {
case .published:
return .published(privateMessage.published)
}
}

func toParent() -> ParentType {
.message(self)
}
}
23 changes: 23 additions & 0 deletions Mlem/Extensions/Tracker Items/ReplyModel+ChildTrackerItem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// ReplyModel+ChildTrackerItem.swift
// Mlem
//
// Created by Eric Andrews on 2023-10-16.
//

import Foundation

extension ReplyModel: ChildTrackerItem {
typealias ParentType = InboxItemNew

func toParent() -> ParentType {
.reply(self)
}

func sortVal(sortType: TrackerSortType) -> TrackerSortVal {
switch sortType {
case .published:
return .published(commentReply.published)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
import SwiftUI

struct ReplyToMessage: ResponseEditorModel {
@Dependency(\.apiClient) var apiClient
@Dependency(\.inboxRepository) var inboxRepository
@Dependency(\.hapticManager) var hapticManager

var id: Int { message.id }
Expand All @@ -26,7 +26,7 @@ struct ReplyToMessage: ResponseEditorModel {

func sendResponse(responseContents: String) async throws {
do {
try await apiClient.sendPrivateMessage(content: responseContents, recipient: message.creator)
_ = try await inboxRepository.sendMessage(content: responseContents, recipientId: message.creator.id)
hapticManager.play(haptic: .success, priority: .high)
} catch {
hapticManager.play(haptic: .failure, priority: .high)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
import SwiftUI

struct ReportMessage: ResponseEditorModel {
@Dependency(\.apiClient) var apiClient
@Dependency(\.inboxRepository) var inboxRepository
@Dependency(\.hapticManager) var hapticManager

var id: Int { message.id }
Expand All @@ -26,7 +26,7 @@ struct ReportMessage: ResponseEditorModel {

func sendResponse(responseContents: String) async throws {
do {
try await apiClient.reportPrivateMessage(id: message.id, reason: responseContents)
_ = try await inboxRepository.reportMessage(id: message.id, reason: responseContents)
hapticManager.play(haptic: .violentSuccess, priority: .high)
} catch {
hapticManager.play(haptic: .failure, priority: .high)
Expand Down
49 changes: 49 additions & 0 deletions Mlem/Models/Content/MentionModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// MentionModel.swift
// Mlem
//
// Created by Eric Andrews on 2023-09-23.
//
import Foundation

/// Internal representation of a person mention
struct MentionModel {
let personMention: APIPersonMention
let comment: APIComment
let creator: APIPerson
let post: APIPost
let community: APICommunity
let recipient: APIPerson
let counts: APICommentAggregates
let creatorBannedFromCommunity: Bool
let subscribed: APISubscribedStatus
let saved: Bool
let creatorBlocked: Bool
let myVote: ScoringOperation?

var uid: ContentModelIdentifier { .init(contentType: .mention, contentId: personMention.id) }
}

extension MentionModel: Hashable {
/// Hashes all fields for which state changes should trigger view updates.
func hash(into hasher: inout Hasher) {
hasher.combine(uid)
hasher.combine(personMention.read)
hasher.combine(comment.updated)
hasher.combine(comment.deleted)
hasher.combine(counts.upvotes)
hasher.combine(counts.downvotes)
hasher.combine(myVote)
hasher.combine(saved)
}
}

extension MentionModel: Identifiable {
var id: Int { hashValue }
}

extension MentionModel: Equatable {
static func == (lhs: MentionModel, rhs: MentionModel) -> Bool {
lhs.id == rhs.id
}
}
47 changes: 47 additions & 0 deletions Mlem/Models/Content/MessageModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// MessageModel.swift
// Mlem
//
// Created by Eric Andrews on 2023-09-23.
//
import Foundation

/**
Internal model to represent a private message.

Note: To make the transition to internal models smoother, this is currently identical to APIPrivateMessageView
*/
struct MessageModel: ContentIdentifiable {
let creator: APIPerson
let recipient: APIPerson
let privateMessage: APIPrivateMessage

var uid: ContentModelIdentifier { .init(contentType: .message, contentId: privateMessage.id) }

/// Creates a PrivateMessageModel from the raw APIPrivateMessageView returned by the Lemmy API
/// - Parameter from: APIPrivateMessageView returned by the Lemmy API
init(from apiPrivateMessageView: APIPrivateMessageView) {
self.creator = apiPrivateMessageView.creator
self.recipient = apiPrivateMessageView.recipient
self.privateMessage = apiPrivateMessageView.privateMessage
}
}

extension MessageModel: Hashable {
/// Hashes all fields for which state changes should trigger view updates.
func hash(into hasher: inout Hasher) {
hasher.combine(uid)
hasher.combine(privateMessage.read)
hasher.combine(privateMessage.updated)
}
}

extension MessageModel: Identifiable {
var id: Int { hashValue }
}

extension MessageModel: Equatable {
static func == (lhs: MessageModel, rhs: MessageModel) -> Bool {
lhs.id == rhs.id
}
}
63 changes: 63 additions & 0 deletions Mlem/Models/Content/ReplyModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// ReplyModel.swift
// Mlem
//
// Created by Eric Andrews on 2023-09-23.
//
import Foundation

/// Internal representation of a comment reply
struct ReplyModel {
let commentReply: APICommentReply
let comment: APIComment
let creator: APIPerson
let post: APIPost
let community: APICommunity
let recipient: APIPerson
let counts: APICommentAggregates
let creatorBannedFromCommunity: Bool
let subscribed: APISubscribedStatus
let saved: Bool
let creatorBlocked: Bool
let myVote: ScoringOperation?

var uid: ContentModelIdentifier { .init(contentType: .reply, contentId: commentReply.id) }

init(from replyView: APICommentReplyView) {
self.commentReply = replyView.commentReply
self.comment = replyView.comment
self.creator = replyView.creator
self.post = replyView.post
self.community = replyView.community
self.recipient = replyView.recipient
self.counts = replyView.counts
self.creatorBannedFromCommunity = replyView.creatorBannedFromCommunity
self.subscribed = replyView.subscribed
self.saved = replyView.saved
self.creatorBlocked = replyView.creatorBlocked
self.myVote = replyView.myVote
}
}

extension ReplyModel: Hashable {
/// Hashes all fields for which state changes should trigger view updates.
func hash(into hasher: inout Hasher) {
hasher.combine(uid)
hasher.combine(commentReply.read)
hasher.combine(comment.updated)
hasher.combine(counts.upvotes)
hasher.combine(counts.downvotes)
hasher.combine(myVote)
hasher.combine(saved)
}
}

extension ReplyModel: Identifiable {
var id: Int { hashValue }
}

extension ReplyModel: Equatable {
static func == (lhs: ReplyModel, rhs: ReplyModel) -> Bool {
lhs.id == rhs.id
}
}
Loading