Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…into mauroromito/knock_requests_list_screen
  • Loading branch information
Velin92 committed Nov 21, 2024
2 parents 6e9a339 + 7e1476d commit 6b00b9b
Show file tree
Hide file tree
Showing 31 changed files with 382 additions and 144 deletions.
91 changes: 51 additions & 40 deletions ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,18 @@ private enum PresentationAction: Hashable {
var focusedEvent: FocusEvent? {
switch self {
case .eventFocus(let focusEvent):
return focusEvent
focusEvent
default:
return nil
nil
}
}

var sharedText: String? {
switch self {
case .share(.text(_, let text)):
text
default:
nil
}
}
}
Expand Down Expand Up @@ -196,11 +205,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
roomScreenCoordinator?.focusOnEvent(.init(eventID: eventID, shouldSetPin: false))
}
case .share(let payload):
guard case let .mediaFile(roomID, _) = payload else {
return
}

guard let roomID, roomID == self.roomID else {
guard let roomID = payload.roomID, roomID == self.roomID else {
fatalError("Navigation route doesn't belong to this room flow.")
}

Expand Down Expand Up @@ -625,41 +630,68 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
case .eventFocus(let focusedEvent):
roomScreenCoordinator?.focusOnEvent(focusedEvent)
case .share(.mediaFile(_, let mediaFile)):
stateMachine.tryEvent(.presentMediaUploadPreview(fileURL: mediaFile.url))
default:
stateMachine.tryEvent(.presentMediaUploadPreview(fileURL: mediaFile.url), userInfo: EventUserInfo(animated: animated))
case .share(.text(_, let text)):
roomScreenCoordinator?.shareText(text)
case .none:
break
}

return
}
}

Task {
// Flag the room as read on entering, the timeline will take care of the read receipts
await roomProxy.flagAsUnread(false)
}
// Flag the room as read on entering, the timeline will take care of the read receipts
Task { await roomProxy.flagAsUnread(false) }

let userID = userSession.clientProxy.userID
analytics.trackViewRoom(isDM: roomProxy.infoPublisher.value.isDirect, isSpace: roomProxy.infoPublisher.value.isSpace)

let coordinator = makeRoomScreenCoordinator(presentationAction: presentationAction)
roomScreenCoordinator = coordinator

if !isChildFlow {
let animated = UIDevice.current.userInterfaceIdiom == .phone ? animated : false
navigationStackCoordinator.setRootCoordinator(coordinator, animated: animated) { [weak self] in
self?.stateMachine.tryEvent(.dismissFlow)
}
} else {
if joinRoomScreenCoordinator != nil {
navigationStackCoordinator.pop()
}

navigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in
self?.stateMachine.tryEvent(.dismissFlow)
}
}

switch presentationAction {
case .share(.mediaFile(_, let mediaFile)):
stateMachine.tryEvent(.presentMediaUploadPreview(fileURL: mediaFile.url), userInfo: EventUserInfo(animated: animated))
case .share(.text), .eventFocus:
break // These are both handled in the coordinator's init.
case .none:
break
}
}

private func makeRoomScreenCoordinator(presentationAction: PresentationAction?) -> RoomScreenCoordinator {
let userID = userSession.clientProxy.userID
let timelineItemFactory = RoomTimelineItemFactory(userID: userID,
attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()),
stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID))

let timelineController = roomTimelineControllerFactory.buildRoomTimelineController(roomProxy: roomProxy,
initialFocussedEventID: presentationAction?.focusedEvent?.eventID,
timelineItemFactory: timelineItemFactory,
mediaProvider: userSession.mediaProvider)
self.timelineController = timelineController

analytics.trackViewRoom(isDM: roomProxy.infoPublisher.value.isDirect, isSpace: roomProxy.infoPublisher.value.isSpace)

let completionSuggestionService = CompletionSuggestionService(roomProxy: roomProxy)

let composerDraftService = ComposerDraftService(roomProxy: roomProxy, timelineItemfactory: timelineItemFactory)

let parameters = RoomScreenCoordinatorParameters(clientProxy: userSession.clientProxy,
roomProxy: roomProxy,
focussedEvent: presentationAction?.focusedEvent,
sharedText: presentationAction?.sharedText,
timelineController: timelineController,
mediaProvider: userSession.mediaProvider,
mediaPlayerProvider: MediaPlayerProvider(),
Expand Down Expand Up @@ -707,28 +739,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
.store(in: &cancellables)

roomScreenCoordinator = coordinator
if !isChildFlow {
let animated = UIDevice.current.userInterfaceIdiom == .phone ? animated : false
navigationStackCoordinator.setRootCoordinator(coordinator, animated: animated) { [weak self] in
self?.stateMachine.tryEvent(.dismissFlow)
}
} else {
if joinRoomScreenCoordinator != nil {
navigationStackCoordinator.pop()
}

navigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in
self?.stateMachine.tryEvent(.dismissFlow)
}
}

switch presentationAction {
case .share(.mediaFile(_, let mediaFile)):
stateMachine.tryEvent(.presentMediaUploadPreview(fileURL: mediaFile.url), userInfo: EventUserInfo(animated: animated))
default:
break
}
return coordinator
}

private func presentJoinRoomScreen(via: [String], animated: Bool) {
Expand Down
19 changes: 9 additions & 10 deletions ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -207,16 +207,13 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
case .settings, .chatBackupSettings:
settingsFlowCoordinator.handleAppRoute(appRoute, animated: animated)
case .share(let payload):
switch payload {
case .mediaFile(let roomID, _):
if let roomID {
stateMachine.processEvent(.selectRoom(roomID: roomID,
via: [],
entryPoint: .share(payload)),
userInfo: .init(animated: animated))
} else {
stateMachine.processEvent(.showShareExtensionRoomList(sharePayload: payload), userInfo: .init(animated: animated))
}
if let roomID = payload.roomID {
stateMachine.processEvent(.selectRoom(roomID: roomID,
via: [],
entryPoint: .share(payload)),
userInfo: .init(animated: animated))
} else {
stateMachine.processEvent(.showShareExtensionRoomList(sharePayload: payload), userInfo: .init(animated: animated))
}
}
}
Expand Down Expand Up @@ -938,6 +935,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
let sharePayload = switch sharePayload {
case .mediaFile(_, let mediaFile):
ShareExtensionPayload.mediaFile(roomID: roomID, mediaFile: mediaFile)
case .text(_, let text):
ShareExtensionPayload.text(roomID: roomID, text: text)
}

navigationSplitCoordinator.setSheetCoordinator(nil)
Expand Down
8 changes: 4 additions & 4 deletions ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14133,8 +14133,8 @@ class TimelineProxyMock: TimelineProxyProtocol {
var editNewContentCalled: Bool {
return editNewContentCallsCount > 0
}
var editNewContentReceivedArguments: (eventOrTransactionID: EventOrTransactionId, newContent: RoomMessageEventContentWithoutRelation)?
var editNewContentReceivedInvocations: [(eventOrTransactionID: EventOrTransactionId, newContent: RoomMessageEventContentWithoutRelation)] = []
var editNewContentReceivedArguments: (eventOrTransactionID: EventOrTransactionId, newContent: EditedContent)?
var editNewContentReceivedInvocations: [(eventOrTransactionID: EventOrTransactionId, newContent: EditedContent)] = []

var editNewContentUnderlyingReturnValue: Result<Void, TimelineProxyError>!
var editNewContentReturnValue: Result<Void, TimelineProxyError>! {
Expand All @@ -14160,9 +14160,9 @@ class TimelineProxyMock: TimelineProxyProtocol {
}
}
}
var editNewContentClosure: ((EventOrTransactionId, RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>)?
var editNewContentClosure: ((EventOrTransactionId, EditedContent) async -> Result<Void, TimelineProxyError>)?

func edit(_ eventOrTransactionID: EventOrTransactionId, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
func edit(_ eventOrTransactionID: EventOrTransactionId, newContent: EditedContent) async -> Result<Void, TimelineProxyError> {
editNewContentCallsCount += 1
editNewContentReceivedArguments = (eventOrTransactionID: eventOrTransactionID, newContent: newContent)
DispatchQueue.main.async {
Expand Down
1 change: 1 addition & 0 deletions ElementX/Sources/Mocks/JoinedRoomProxyMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ extension JoinedRoomProxyMock {
matrixToEventPermalinkReturnValue = .success(.homeDirectory)
loadDraftReturnValue = .success(nil)
clearDraftReturnValue = .success(())
sendTypingNotificationIsTypingReturnValue = .success(())
}
}

Expand Down
15 changes: 14 additions & 1 deletion ElementX/Sources/Other/Extensions/NSItemProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//

import Foundation
import UIKit
import SwiftUI
import UniformTypeIdentifiers

extension NSItemProvider {
Expand All @@ -15,6 +15,19 @@ extension NSItemProvider {
let fileExtension: String
}

func loadTransferable<T: Transferable>(type transferableType: T.Type) async -> T? {
try? await withCheckedContinuation { continuation in
_ = loadTransferable(type: T.self) { result in
continuation.resume(returning: result)
}
}
.get()
}

func loadString() async -> String? {
try? await loadItem(forTypeIdentifier: UTType.text.identifier) as? String
}

func storeData() async -> URL? {
guard let contentType = preferredContentType else {
MXLog.error("Invalid NSItemProvider: \(self)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,11 @@ extension FormatType {
}

enum ComposerMode: Equatable {
enum EditType { case `default`, addCaption, editCaption }

case `default`
case reply(eventID: String, replyDetails: TimelineItemReplyDetails, isThread: Bool)
case edit(originalEventOrTransactionID: EventOrTransactionId)
case edit(originalEventOrTransactionID: EventOrTransactionId, type: EditType)
case recordVoiceMessage(state: AudioRecorderState)
case previewVoiceMessage(state: AudioPlayerState, waveform: WaveformSource, isUploading: Bool)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import WysiwygComposer
typealias ComposerToolbarViewModelType = StateStoreViewModel<ComposerToolbarViewState, ComposerToolbarViewAction>

final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerToolbarViewModelProtocol {
private var initialText: String?
private let wysiwygViewModel: WysiwygComposerViewModel
private let completionSuggestionService: CompletionSuggestionServiceProtocol
private let analyticsService: AnalyticsService
Expand All @@ -41,12 +42,14 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool

private var replyLoadingTask: Task<Void, Never>?

init(wysiwygViewModel: WysiwygComposerViewModel,
init(initialText: String? = nil,
wysiwygViewModel: WysiwygComposerViewModel,
completionSuggestionService: CompletionSuggestionServiceProtocol,
mediaProvider: MediaProviderProtocol,
mentionDisplayHelper: MentionDisplayHelper,
analyticsService: AnalyticsService,
composerDraftService: ComposerDraftServiceProtocol) {
self.initialText = initialText
self.wysiwygViewModel = wysiwygViewModel
self.completionSuggestionService = completionSuggestionService
self.analyticsService = analyticsService
Expand Down Expand Up @@ -206,6 +209,8 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
} else {
set(text: plainText)
}
case .setFocus:
state.bindings.composerFocused = true
case .removeFocus:
state.bindings.composerFocused = false
case .clear:
Expand All @@ -219,8 +224,12 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
}
}

func loadDraft() {
Task {
func loadDraft() async {
if let initialText {
set(text: initialText)
set(mode: .default)
state.bindings.composerFocused = true
} else {
guard case let .success(draft) = await draftService.loadDraft(),
let draft else {
return
Expand Down Expand Up @@ -258,7 +267,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
case .newMessage:
set(mode: .default)
case .edit(let eventID):
set(mode: .edit(originalEventOrTransactionID: .eventId(eventId: eventID)))
set(mode: .edit(originalEventOrTransactionID: .eventId(eventId: eventID), type: .default))
case .reply(let eventID):
set(mode: .reply(eventID: eventID, replyDetails: .loading(eventID: eventID), isThread: false))
replyLoadingTask = Task {
Expand Down Expand Up @@ -314,7 +323,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
switch state.composerMode {
case .default:
type = .newMessage
case .edit(.eventId(let originalEventID)):
case .edit(.eventId(let originalEventID), .default):
type = .edit(eventID: originalEventID)
case .reply(let eventID, _, _):
type = .reply(eventID: eventID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ protocol ComposerToolbarViewModelProtocol {
var keyCommands: [WysiwygKeyCommand] { get }

func process(timelineAction: TimelineComposerAction)
func loadDraft()
func loadDraft() async
func saveDraft()
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ struct MessageComposer: View {
switch mode {
case .reply(_, let replyDetails, _):
MessageComposerReplyHeader(replyDetails: replyDetails, action: cancellationAction)
case .edit:
MessageComposerEditHeader(action: cancellationAction)
case .edit(_, let editType):
MessageComposerEditHeader(editType: editType, action: cancellationAction)
case .recordVoiceMessage, .previewVoiceMessage, .default:
EmptyView()
}
Expand Down Expand Up @@ -152,14 +152,20 @@ private struct MessageComposerReplyHeader: View {
}

private struct MessageComposerEditHeader: View {
let editType: ComposerMode.EditType
let action: () -> Void

private var title: String {
switch editType {
case .default: L10n.commonEditing
case .addCaption: L10n.commonAddingCaption
case .editCaption: L10n.commonEditingCaption
}
}

var body: some View {
HStack(alignment: .center, spacing: 8) {
Label(L10n.commonEditing,
icon: \.editSolid,
iconSize: .xSmall,
relativeTo: .compound.bodySMSemibold)
Label(title, icon: \.editSolid, iconSize: .xSmall, relativeTo: .compound.bodySMSemibold)
.labelStyle(MessageComposerHeaderLabelStyle())
Spacer()
Button(action: action) {
Expand Down Expand Up @@ -294,13 +300,20 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
messageComposer()

messageComposer(.init(string: "Some message"),
mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString)))
mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), type: .default))

messageComposer(mode: .reply(eventID: UUID().uuidString,
replyDetails: .loaded(sender: .init(id: "Kirk"),
eventID: "123",
eventContent: .message(.text(.init(body: "Text: Where the wild things are")))),
isThread: false))

Color.clear.frame(height: 20)

messageComposer(.init(string: "Some new caption"),
mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), type: .addCaption))
messageComposer(.init(string: "Some updated caption"),
mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), type: .editCaption))
}
.padding(.horizontal)

Expand Down
Loading

0 comments on commit 6b00b9b

Please sign in to comment.