mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Implement support for ElementCall through Rust side widgets (#1906)
* Implement support for ElementCall through Rust side widgets * Add Element Call feature flag * Fix the unit tests * Address PR comments
This commit is contained in:
@@ -39,6 +39,7 @@ enum RoomScreenCoordinatorAction {
|
||||
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
|
||||
case presentRoomMemberDetails(member: RoomMemberProxyProtocol)
|
||||
case presentMessageForwarding(itemID: TimelineItemIdentifier)
|
||||
case presentCallScreen
|
||||
}
|
||||
|
||||
final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
@@ -109,6 +110,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
actionsSubject.send(.presentLocationViewer(body: body, geoURI: geoURI, description: description))
|
||||
case .composer(let action):
|
||||
composerViewModel.process(roomAction: action)
|
||||
case .displayCallScreen:
|
||||
actionsSubject.send(.presentCallScreen)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
@@ -34,6 +34,7 @@ enum RoomScreenViewModelAction {
|
||||
case displayMessageForwarding(itemID: TimelineItemIdentifier)
|
||||
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
||||
case composer(action: RoomScreenComposerAction)
|
||||
case displayCallScreen
|
||||
}
|
||||
|
||||
enum RoomScreenComposerMode: Equatable {
|
||||
@@ -63,7 +64,7 @@ enum RoomScreenViewAction {
|
||||
case paginateBackwards
|
||||
case selectedPollOption(pollStartID: String, optionID: String)
|
||||
case endPoll(pollStartID: String)
|
||||
|
||||
|
||||
case timelineItemMenu(itemID: TimelineItemIdentifier)
|
||||
case timelineItemMenuAction(itemID: TimelineItemIdentifier, action: TimelineItemMenuAction)
|
||||
|
||||
@@ -73,7 +74,7 @@ enum RoomScreenViewAction {
|
||||
case tappedOnUser(userID: String)
|
||||
|
||||
case reactionSummary(itemID: TimelineItemIdentifier, key: String)
|
||||
|
||||
|
||||
case retrySend(itemID: TimelineItemIdentifier)
|
||||
case cancelSend(itemID: TimelineItemIdentifier)
|
||||
|
||||
@@ -81,8 +82,11 @@ enum RoomScreenViewAction {
|
||||
|
||||
case enableLongPress(itemID: TimelineItemIdentifier)
|
||||
case disableLongPress(itemID: TimelineItemIdentifier)
|
||||
|
||||
case playPauseAudio(itemID: TimelineItemIdentifier)
|
||||
case seekAudio(itemID: TimelineItemIdentifier, progress: Double)
|
||||
|
||||
case presentCall
|
||||
}
|
||||
|
||||
enum RoomScreenComposerAction {
|
||||
@@ -103,9 +107,13 @@ struct RoomScreenViewState: BindableState {
|
||||
var isEncryptedOneToOneRoom = false
|
||||
var timelineViewState = TimelineViewState() // check the doc before changing this
|
||||
var swiftUITimelineEnabled = false
|
||||
|
||||
var longPressDisabledItemID: TimelineItemIdentifier?
|
||||
var ownUserID: String
|
||||
|
||||
|
||||
var showCallButton = false
|
||||
var isCallOngoing = false
|
||||
|
||||
var bindings: RoomScreenViewStateBindings
|
||||
|
||||
/// A closure providing the actions to show when long pressing on an item in the timeline.
|
||||
@@ -127,14 +135,14 @@ struct RoomScreenViewStateBindings {
|
||||
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<RoomScreenErrorType>?
|
||||
|
||||
|
||||
/// An alert info for confirmation actions (e.g. ending a poll)
|
||||
var confirmationAlertInfo: AlertInfo<UUID>?
|
||||
|
||||
|
||||
var debugInfo: TimelineItemDebugInfo?
|
||||
|
||||
var actionMenuInfo: TimelineItemActionMenuInfo?
|
||||
|
||||
|
||||
var sendFailedConfirmationDialogInfo: SendFailedConfirmationDialogInfo?
|
||||
|
||||
var reactionSummaryInfo: ReactionSummaryInfo?
|
||||
@@ -144,7 +152,7 @@ struct TimelineItemActionMenuInfo: Equatable, Identifiable {
|
||||
static func == (lhs: TimelineItemActionMenuInfo, rhs: TimelineItemActionMenuInfo) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
}
|
||||
|
||||
|
||||
let item: EventBasedTimelineItemProtocol
|
||||
|
||||
var id: TimelineItemIdentifier {
|
||||
@@ -154,7 +162,7 @@ struct TimelineItemActionMenuInfo: Equatable, Identifiable {
|
||||
|
||||
struct SendFailedConfirmationDialogInfo: ConfirmationDialogProtocol {
|
||||
let title = L10n.screenRoomRetrySendMenuTitle
|
||||
|
||||
|
||||
let itemID: TimelineItemIdentifier
|
||||
}
|
||||
|
||||
@@ -184,19 +192,19 @@ struct RoomMemberState {
|
||||
struct TimelineViewState {
|
||||
var canBackPaginate = true
|
||||
var isBackPaginating = false
|
||||
|
||||
|
||||
// These can be removed when we have full swiftUI and moved as @State values in the view
|
||||
var scrollToBottomPublisher = PassthroughSubject<Void, Never>()
|
||||
|
||||
|
||||
var itemsDictionary = OrderedDictionary<String, RoomTimelineItemViewState>()
|
||||
|
||||
var renderedTimelineIDs = [String]()
|
||||
var pendingTimelineIDs = [String]()
|
||||
|
||||
|
||||
var timelineIDs: [String] {
|
||||
itemsDictionary.keys.elements
|
||||
}
|
||||
|
||||
|
||||
var itemViewStates: [RoomTimelineItemViewState] {
|
||||
renderedTimelineIDs.compactMap { itemsDictionary[$0] }
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
readReceiptsEnabled: appSettings.readReceiptsEnabled,
|
||||
isEncryptedOneToOneRoom: roomProxy.isEncryptedOneToOneRoom,
|
||||
ownUserID: roomProxy.ownUserID,
|
||||
isCallOngoing: roomProxy.isCallOngoing,
|
||||
bindings: .init(reactionsCollapsed: [:])),
|
||||
imageProvider: mediaProvider)
|
||||
|
||||
@@ -163,6 +164,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
message: L10n.commonPollEndConfirmation,
|
||||
primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil),
|
||||
secondaryButton: .init(title: L10n.actionOk, action: { self.endPoll(pollStartID: pollStartID) }))
|
||||
case .presentCall:
|
||||
actionsSubject.send(.displayCallScreen)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +246,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
.weakAssign(to: \.state.readReceiptsEnabled, on: self)
|
||||
.store(in: &cancellables)
|
||||
|
||||
appSettings.$elementCallEnabled
|
||||
.weakAssign(to: \.state.showCallButton, on: self)
|
||||
.store(in: &cancellables)
|
||||
|
||||
roomProxy.members
|
||||
.map { members in
|
||||
members.reduce(into: [String: RoomMemberState]()) { dictionary, member in
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Compound
|
||||
import SwiftUI
|
||||
import WysiwygComposer
|
||||
|
||||
@@ -155,8 +156,33 @@ struct RoomScreen: View {
|
||||
ToolbarItem(placement: .principal) {
|
||||
RoomHeaderView(context: context)
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
callButton
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ViewBuilder
|
||||
private var callButton: some View {
|
||||
if context.viewState.showCallButton {
|
||||
if context.viewState.isCallOngoing {
|
||||
Button {
|
||||
context.send(viewAction: .presentCall)
|
||||
} label: {
|
||||
Label(L10n.actionJoin, icon: \.videoCall)
|
||||
.labelStyle(.titleAndIcon)
|
||||
}
|
||||
.buttonStyle(ElementCallButtonStyle())
|
||||
} else {
|
||||
Button {
|
||||
context.send(viewAction: .presentCall)
|
||||
} label: {
|
||||
CompoundIcon(\.videoCall)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var isNavigationBarHidden: Bool {
|
||||
composerToolbarContext.composerActionsEnabled && composerToolbarContext.composerExpanded && UIDevice.current.userInterfaceIdiom == .pad
|
||||
}
|
||||
@@ -167,11 +193,11 @@ struct RoomScreen: View {
|
||||
struct RoomScreen_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
|
||||
mediaProvider: MockMediaProvider(),
|
||||
roomProxy: RoomProxyMock(with: .init(displayName: "Preview room")),
|
||||
roomProxy: RoomProxyMock(with: .init(displayName: "Preview room", isCallOngoing: true)),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
|
||||
static var previews: some View {
|
||||
NavigationStack {
|
||||
RoomScreen(context: viewModel.context, composerToolbar: ComposerToolbar.mock())
|
||||
|
||||
Reference in New Issue
Block a user