mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
RoomScreenViewModel is now TimelineViewModel (#3157)
Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-13
@@ -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()
|
||||
}
|
||||
|
||||
+6
-1
@@ -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)
|
||||
|
||||
+3
-3
@@ -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?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user