RoomScreenViewModel is now TimelineViewModel (#3157)

Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
This commit is contained in:
Mauro
2024-08-13 13:36:40 +02:00
committed by GitHub
parent 4519275559
commit 1ad361a6e8
88 changed files with 2266 additions and 1973 deletions
@@ -31,13 +31,13 @@ enum ComposerToolbarVoiceMessageAction {
}
enum ComposerToolbarViewModelAction {
case sendMessage(plain: String, html: String?, mode: RoomScreenComposerMode, intentionalMentions: IntentionalMentions)
case sendMessage(plain: String, html: String?, mode: ComposerMode, intentionalMentions: IntentionalMentions)
case editLastMessage
case attach(ComposerAttachmentType)
case handlePasteOrDrop(provider: NSItemProvider)
case composerModeChanged(mode: RoomScreenComposerMode)
case composerModeChanged(mode: ComposerMode)
case composerFocusedChanged(isFocused: Bool)
case voiceMessage(ComposerToolbarVoiceMessageAction)
@@ -72,7 +72,7 @@ enum ComposerAttachmentType {
}
struct ComposerToolbarViewState: BindableState {
var composerMode: RoomScreenComposerMode = .default
var composerMode: ComposerMode = .default
var composerEmpty = true
var suggestions: [SuggestionItem] = []
var audioPlayerState: AudioPlayerState
@@ -288,3 +288,61 @@ extension FormatType {
}
}
}
enum ComposerMode: Equatable {
case `default`
case reply(itemID: TimelineItemIdentifier, replyDetails: TimelineItemReplyDetails, isThread: Bool)
case edit(originalItemId: TimelineItemIdentifier)
case recordVoiceMessage(state: AudioRecorderState)
case previewVoiceMessage(state: AudioPlayerState, waveform: WaveformSource, isUploading: Bool)
var isEdit: Bool {
switch self {
case .edit:
return true
default:
return false
}
}
var isTextEditingEnabled: Bool {
switch self {
case .default, .reply, .edit:
return true
case .recordVoiceMessage, .previewVoiceMessage:
return false
}
}
var isLoadingReply: Bool {
switch self {
case .reply(_, let replyDetails, _):
switch replyDetails {
case .loading:
return true
default:
return false
}
default:
return false
}
}
var replyEventID: String? {
switch self {
case .reply(let itemID, _, _):
return itemID.eventID
default:
return nil
}
}
var isComposingNewMessage: Bool {
switch self {
case .default, .reply:
return true
default:
return false
}
}
}
@@ -200,8 +200,8 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
}
}
func process(roomAction: RoomScreenComposerAction) {
switch roomAction {
func process(timelineAction: TimelineComposerAction) {
switch timelineAction {
case .setMode(mode: let mode):
if state.composerMode.isComposingNewMessage, mode.isEdit {
handleSaveDraft(isVolatile: true)
@@ -223,19 +223,23 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
set(mode: .default)
set(text: "")
}
case .saveDraft:
handleSaveDraft(isVolatile: false)
case .loadDraft:
Task {
guard case let .success(draft) = await draftService.loadDraft(),
let draft else {
return
}
handleLoadDraft(draft)
}
}
}
func loadDraft() {
Task {
guard case let .success(draft) = await draftService.loadDraft(),
let draft else {
return
}
handleLoadDraft(draft)
}
}
func saveDraft() {
handleSaveDraft(isVolatile: false)
}
var keyCommands: [WysiwygKeyCommand] {
[
.enter { [weak self] in
@@ -480,7 +484,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
}
}
private func set(mode: RoomScreenComposerMode) {
private func set(mode: ComposerMode) {
if state.composerMode.isLoadingReply, state.composerMode.replyEventID != mode.replyEventID {
replyLoadingTask?.cancel()
}
@@ -15,10 +15,15 @@
//
import Combine
import WysiwygComposer
// periphery: ignore - markdown protocol
protocol ComposerToolbarViewModelProtocol {
var actions: AnyPublisher<ComposerToolbarViewModelAction, Never> { get }
var context: ComposerToolbarViewModelType.Context { get }
func process(roomAction: RoomScreenComposerAction)
var keyCommands: [WysiwygKeyCommand] { get }
func process(timelineAction: TimelineComposerAction)
func loadDraft()
func saveDraft()
}
@@ -24,7 +24,7 @@ typealias PasteHandler = (NSItemProvider) -> Void
struct MessageComposer: View {
@Binding var plainComposerText: NSAttributedString
let composerView: WysiwygComposerView
let mode: RoomScreenComposerMode
let mode: ComposerMode
let composerFormattingEnabled: Bool
let showResizeGrabber: Bool
@Binding var isExpanded: Bool
@@ -208,7 +208,7 @@ private struct MessageComposerHeaderLabelStyle: LabelStyle {
}
struct MessageComposer_Previews: PreviewProvider, TestablePreview {
static let viewModel = RoomScreenViewModel.mock
static let viewModel = TimelineViewModel.mock
static let replyTypes: [TimelineItemReplyDetails] = [
.loaded(sender: .init(id: "Dave"),
@@ -241,7 +241,7 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
]
static func messageComposer(_ content: NSAttributedString = .init(string: ""),
mode: RoomScreenComposerMode = .default) -> MessageComposer {
mode: ComposerMode = .default) -> MessageComposer {
let viewModel = WysiwygComposerViewModel(minHeight: 22,
maxExpandedHeight: 250)
viewModel.setMarkdownContent(content.string)
@@ -55,7 +55,7 @@ struct MessageComposerTextField: View {
}
private struct UITextViewWrapper: UIViewRepresentable {
@Environment(\.roomContext) private var roomContext
@Environment(\.timelineContext) private var timelineContext
@Binding var text: NSAttributedString
@@ -69,7 +69,7 @@ private struct UITextViewWrapper: UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<UITextViewWrapper>) -> UITextView {
// Need to use TextKit 1 for mentions
let textView = ElementTextView(usingTextLayoutManager: false)
textView.roomContext = roomContext
textView.timelineContext = timelineContext
textView.delegate = context.coordinator
textView.elementDelegate = context.coordinator
@@ -182,7 +182,7 @@ private protocol ElementTextViewDelegate: AnyObject {
}
private class ElementTextView: UITextView, PillAttachmentViewProviderDelegate {
var roomContext: RoomScreenViewModel.Context?
var timelineContext: TimelineViewModel.Context?
weak var elementDelegate: ElementTextViewDelegate?