mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Share extension (#3506)
* Setup simple share extension * Switch the app url scheme to be the full bundle identifier * Setup a share extension that show a SwiftUI view, uses rust tracing and redirects to the hosting aplication * Move media as json through the custom scheme into the main app and deep link into the media upload preview screen * Fix message forwarding and global search screen room summary provider filtering. * Tweak the message forwarding and global search screen designs. * Add a room selection screen to use after receiving a share request from the share extension * Fix share extension entitlements * Share the temporary directory between the main app and the extensions; rename the caches one. * Remove the no longer needed notification avatar flipping fix. * Extract the placeholder avatar image generator from the NSE * Nest `AvatarSize` within the new `Avatars` enum * Donate an `INSendMessageIntent` to the system every time we send a message so they appear as share suggestions * Support suggestions in the share extension itself * Improve sharing animations and fix presentation when room already on the stack * Clear all routes when sharing without a preselected room. * Fix broken unit tests * Various initial tweaks following code review. * Correctly clean up and dismiss the share extension for all paths. * Move the share extension path to a constants enum * Rename UserSessionFlowCoordinator specific share extension states and events * Add UserSession and Room flow coordinator share route tests * Tweak the share extension logic.
This commit is contained in:
@@ -83,7 +83,7 @@ class EncryptionSettingsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case .roomList, .room, .roomAlias, .childRoom, .childRoomAlias,
|
||||
.roomDetails, .roomMemberDetails, .userProfile,
|
||||
.event, .eventOnRoomAlias, .childEvent, .childEventOnRoomAlias,
|
||||
.call, .genericCallLink, .settings:
|
||||
.call, .genericCallLink, .settings, .share:
|
||||
// These routes aren't in this flow so clear the entire stack.
|
||||
clearRoute(animated: animated)
|
||||
case .chatBackupSettings:
|
||||
|
||||
@@ -293,9 +293,7 @@ class OnboardingFlowCoordinator: FlowCoordinatorProtocol {
|
||||
let coordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: parameters)
|
||||
|
||||
coordinator.actions
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
.sink { action in
|
||||
switch action {
|
||||
case .complete:
|
||||
break // Moving to next state is Handled by the global session verification listener
|
||||
|
||||
@@ -65,7 +65,9 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
|
||||
attributedStringBuilder: AttributedStringBuilder(mentionBuilder: MentionBuilder()),
|
||||
stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID))
|
||||
|
||||
guard let timelineController = await roomTimelineControllerFactory.buildRoomPinnedTimelineController(roomProxy: roomProxy, timelineItemFactory: timelineItemFactory) else {
|
||||
guard let timelineController = await roomTimelineControllerFactory.buildRoomPinnedTimelineController(roomProxy: roomProxy,
|
||||
timelineItemFactory: timelineItemFactory,
|
||||
mediaProvider: userSession.mediaProvider) else {
|
||||
fatalError("This can never fail because we allow this view to be presented only when the timeline is fully loaded and not nil")
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ enum RoomFlowCoordinatorEntryPoint: Hashable {
|
||||
case eventID(String)
|
||||
/// The flow will start by showing the room's details.
|
||||
case roomDetails
|
||||
/// An external media share request
|
||||
case share(ShareExtensionPayload)
|
||||
|
||||
var isEventID: Bool {
|
||||
guard case .eventID = self else { return false }
|
||||
@@ -41,6 +43,32 @@ enum RoomFlowCoordinatorEntryPoint: Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
struct FocusEvent: Hashable {
|
||||
/// The event ID that the timeline should be focussed around
|
||||
let eventID: String
|
||||
/// if the focus is coming from the pinned timeline, this should also update the pin banner
|
||||
let shouldSetPin: Bool
|
||||
}
|
||||
|
||||
private enum PinnedEventsTimelineSource: Hashable {
|
||||
case room
|
||||
case details(isRoot: Bool)
|
||||
}
|
||||
|
||||
private enum PresentationAction: Hashable {
|
||||
case eventFocus(FocusEvent)
|
||||
case share(ShareExtensionPayload)
|
||||
|
||||
var focusedEvent: FocusEvent? {
|
||||
switch self {
|
||||
case .eventFocus(let focusEvent):
|
||||
return focusEvent
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next type_body_length
|
||||
class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let roomID: String
|
||||
@@ -112,6 +140,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
fatalError("This flow coordinator expect a route")
|
||||
}
|
||||
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||
guard stateMachine.state != .complete else {
|
||||
fatalError("This flow coordinator is `finished` ☠️")
|
||||
@@ -152,7 +181,12 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
stateMachine.tryEvent(.presentRoomMemberDetails(userID: userID), userInfo: EventUserInfo(animated: animated))
|
||||
}
|
||||
case .event(let eventID, let roomID, let via):
|
||||
Task { await handleRoomRoute(roomID: roomID, via: via, focussedEventID: eventID, animated: animated) }
|
||||
Task {
|
||||
await handleRoomRoute(roomID: roomID,
|
||||
via: via,
|
||||
presentationAction: .eventFocus(.init(eventID: eventID, shouldSetPin: false)),
|
||||
animated: animated)
|
||||
}
|
||||
case .childEvent(let eventID, let roomID, let via):
|
||||
if case .presentingChild = stateMachine.state, let childRoomFlowCoordinator {
|
||||
childRoomFlowCoordinator.handleAppRoute(appRoute, animated: animated)
|
||||
@@ -161,6 +195,21 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
} else {
|
||||
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 {
|
||||
fatalError("Navigation route doesn't belong to this room flow.")
|
||||
}
|
||||
|
||||
Task {
|
||||
await handleRoomRoute(roomID: roomID,
|
||||
via: [],
|
||||
presentationAction: .share(payload),
|
||||
animated: animated)
|
||||
}
|
||||
case .roomAlias, .childRoomAlias, .eventOnRoomAlias, .childEventOnRoomAlias:
|
||||
break // These are converted to a room ID route one level above.
|
||||
case .roomList, .userProfile, .call, .genericCallLink, .settings, .chatBackupSettings:
|
||||
@@ -176,7 +225,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
actionsSubject.send(.presentCallScreen(roomProxy: roomProxy))
|
||||
}
|
||||
|
||||
private func handleRoomRoute(roomID: String, via: [String], focussedEventID: String? = nil, animated: Bool) async {
|
||||
private func handleRoomRoute(roomID: String, via: [String], presentationAction: PresentationAction? = nil, animated: Bool) async {
|
||||
guard roomID == self.roomID else { fatalError("Navigation route doesn't belong to this room flow.") }
|
||||
|
||||
guard let room = await userSession.clientProxy.roomForIdentifier(roomID) else {
|
||||
@@ -187,8 +236,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
switch room {
|
||||
case .joined(let roomProxy):
|
||||
await storeAndSubscribeToRoomProxy(roomProxy)
|
||||
let focussedEvent = focussedEventID.map { FocusEvent(eventID: $0, shouldSetPin: false) }
|
||||
stateMachine.tryEvent(.presentRoom(focussedEvent: focussedEvent), userInfo: EventUserInfo(animated: animated))
|
||||
stateMachine.tryEvent(.presentRoom(presentationAction: presentationAction), userInfo: EventUserInfo(animated: animated))
|
||||
default:
|
||||
stateMachine.tryEvent(.presentJoinRoomScreen(via: via), userInfo: EventUserInfo(animated: animated))
|
||||
}
|
||||
@@ -376,9 +424,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
presentJoinRoomScreen(via: via, animated: true)
|
||||
case (_, .dismissJoinRoomScreen, .complete):
|
||||
dismissFlow(animated: animated)
|
||||
|
||||
case (_, .presentRoom(let focussedEvent), .room):
|
||||
Task { await self.presentRoom(fromState: context.fromState, focussedEvent: focussedEvent, animated: animated) }
|
||||
|
||||
case (_, .presentRoom(let presentationAction), .room):
|
||||
Task {
|
||||
await self.presentRoom(fromState: context.fromState,
|
||||
presentationAction: presentationAction,
|
||||
animated: animated)
|
||||
}
|
||||
case (_, .dismissFlow, .complete):
|
||||
dismissFlow(animated: animated)
|
||||
|
||||
@@ -445,9 +497,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
break
|
||||
|
||||
case (.mediaUploadPicker, .presentMediaUploadPreview, .mediaUploadPreview(let fileURL)):
|
||||
presentMediaUploadPreviewScreen(for: fileURL)
|
||||
presentMediaUploadPreviewScreen(for: fileURL, animated: animated)
|
||||
case (.room, .presentMediaUploadPreview, .mediaUploadPreview(let fileURL)):
|
||||
presentMediaUploadPreviewScreen(for: fileURL)
|
||||
presentMediaUploadPreviewScreen(for: fileURL, animated: animated)
|
||||
case (.mediaUploadPreview, .dismissMediaUploadPreview, .room):
|
||||
break
|
||||
|
||||
@@ -542,7 +594,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
/// - fromState: The state that asked for the room presentation.
|
||||
/// - focussedEvent: An (optional) struct that contains the event ID that the timeline should be focussed around, and a boolean telling if such event should update the pinned events banner
|
||||
/// - animated: whether it should animate the transition
|
||||
private func presentRoom(fromState: State, focussedEvent: FocusEvent?, animated: Bool) async {
|
||||
private func presentRoom(fromState: State, presentationAction: PresentationAction?, animated: Bool) async {
|
||||
// If any sheets are presented dismiss them, rely on their dismissal callbacks to transition the state machine
|
||||
// through the correct states before presenting the room
|
||||
navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
@@ -559,9 +611,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
default:
|
||||
// The room is already on the stack, no need to present it again
|
||||
|
||||
// Check if we need to focus on an event
|
||||
if let focussedEvent {
|
||||
roomScreenCoordinator?.focusOnEvent(focussedEvent)
|
||||
switch presentationAction {
|
||||
case .eventFocus(let focusedEvent):
|
||||
roomScreenCoordinator?.focusOnEvent(focusedEvent)
|
||||
case .share(.mediaFile(_, let mediaFile)):
|
||||
stateMachine.tryEvent(.presentMediaUploadPreview(fileURL: mediaFile.url))
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return
|
||||
@@ -580,8 +636,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID))
|
||||
|
||||
let timelineController = roomTimelineControllerFactory.buildRoomTimelineController(roomProxy: roomProxy,
|
||||
initialFocussedEventID: focussedEvent?.eventID,
|
||||
timelineItemFactory: timelineItemFactory)
|
||||
initialFocussedEventID: presentationAction?.focusedEvent?.eventID,
|
||||
timelineItemFactory: timelineItemFactory,
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
self.timelineController = timelineController
|
||||
|
||||
analytics.trackViewRoom(isDM: roomProxy.infoPublisher.value.isDirect, isSpace: roomProxy.infoPublisher.value.isSpace)
|
||||
@@ -592,7 +649,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
let parameters = RoomScreenCoordinatorParameters(clientProxy: userSession.clientProxy,
|
||||
roomProxy: roomProxy,
|
||||
focussedEvent: focussedEvent,
|
||||
focussedEvent: presentationAction?.focusedEvent,
|
||||
timelineController: timelineController,
|
||||
mediaProvider: userSession.mediaProvider,
|
||||
mediaPlayerProvider: MediaPlayerProvider(),
|
||||
@@ -655,6 +712,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
self?.stateMachine.tryEvent(.dismissFlow)
|
||||
}
|
||||
}
|
||||
|
||||
switch presentationAction {
|
||||
case .share(.mediaFile(_, let mediaFile)):
|
||||
stateMachine.tryEvent(.presentMediaUploadPreview(fileURL: mediaFile.url), userInfo: EventUserInfo(animated: animated))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private func presentJoinRoomScreen(via: [String], animated: Bool) {
|
||||
@@ -679,7 +743,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
if case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) {
|
||||
await storeAndSubscribeToRoomProxy(roomProxy)
|
||||
stateMachine.tryEvent(.presentRoom(focussedEvent: nil), userInfo: EventUserInfo(animated: animated))
|
||||
stateMachine.tryEvent(.presentRoom(presentationAction: nil), userInfo: EventUserInfo(animated: animated))
|
||||
|
||||
analytics.trackJoinedRoom(isDM: roomProxy.infoPublisher.value.isDirect,
|
||||
isSpace: roomProxy.infoPublisher.value.isSpace,
|
||||
@@ -894,7 +958,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private func presentMediaUploadPreviewScreen(for url: URL) {
|
||||
private func presentMediaUploadPreviewScreen(for url: URL, animated: Bool) {
|
||||
let stackCoordinator = NavigationStackCoordinator()
|
||||
|
||||
let parameters = MediaUploadPreviewScreenCoordinatorParameters(userIndicatorController: userIndicatorController,
|
||||
@@ -918,7 +982,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
stackCoordinator.setRootCoordinator(mediaUploadPreviewScreenCoordinator)
|
||||
|
||||
navigationStackCoordinator.setSheetCoordinator(stackCoordinator) { [weak self] in
|
||||
navigationStackCoordinator.setSheetCoordinator(stackCoordinator, animated: animated) { [weak self] in
|
||||
self?.stateMachine.tryEvent(.dismissMediaUploadPreview)
|
||||
}
|
||||
}
|
||||
@@ -1091,7 +1155,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
let roomTimelineController = roomTimelineControllerFactory.buildRoomTimelineController(roomProxy: roomProxy,
|
||||
initialFocussedEventID: nil,
|
||||
timelineItemFactory: timelineItemFactory)
|
||||
timelineItemFactory: timelineItemFactory,
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
let parameters = RoomPollsHistoryScreenCoordinatorParameters(pollInteractionHandler: PollInteractionHandler(analyticsService: analytics, roomProxy: roomProxy),
|
||||
roomTimelineController: roomTimelineController)
|
||||
@@ -1361,7 +1426,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
stateMachine.tryEvent(.startChildFlow(roomID: roomID, via: [], entryPoint: .room))
|
||||
case .displayRoomScreenWithFocussedPin(let eventID):
|
||||
navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
stateMachine.tryEvent(.presentRoom(focussedEvent: .init(eventID: eventID, shouldSetPin: true)))
|
||||
stateMachine.tryEvent(.presentRoom(presentationAction: .eventFocus(.init(eventID: eventID, shouldSetPin: true))))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
@@ -1427,6 +1492,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
coordinator.handleAppRoute(.event(eventID: eventID, roomID: roomID, via: via), animated: true)
|
||||
case .roomDetails:
|
||||
coordinator.handleAppRoute(.roomDetails(roomID: roomID), animated: true)
|
||||
case .share(let payload):
|
||||
coordinator.handleAppRoute(.share(payload), animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1483,7 +1550,7 @@ private extension RoomFlowCoordinator {
|
||||
case presentJoinRoomScreen(via: [String])
|
||||
case dismissJoinRoomScreen
|
||||
|
||||
case presentRoom(focussedEvent: FocusEvent?)
|
||||
case presentRoom(presentationAction: PresentationAction?)
|
||||
case dismissFlow
|
||||
|
||||
case presentReportContent(itemID: TimelineItemIdentifier, senderID: String)
|
||||
@@ -1559,15 +1626,3 @@ private extension Result {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum PinnedEventsTimelineSource: Hashable {
|
||||
case room
|
||||
case details(isRoot: Bool)
|
||||
}
|
||||
|
||||
struct FocusEvent: Hashable {
|
||||
/// The event ID that the timeline should be focussed around
|
||||
let eventID: String
|
||||
/// if the focus is coming from the pinned timeline, this should also update the pin banner
|
||||
let shouldSetPin: Bool
|
||||
}
|
||||
|
||||
@@ -206,6 +206,18 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
presentCallScreen(genericCallLink: url)
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +255,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case .room: .room(roomID: roomID, via: via)
|
||||
case .roomDetails: .roomDetails(roomID: roomID)
|
||||
case .eventID(let eventID): .event(eventID: eventID, roomID: roomID, via: via) // ignored.
|
||||
case .share(let payload): .share(payload)
|
||||
}
|
||||
roomFlowCoordinator.handleAppRoute(route, animated: animated)
|
||||
} else {
|
||||
@@ -296,6 +309,12 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
case (.userProfileScreen, .dismissedUserProfileScreen, .roomList):
|
||||
break
|
||||
|
||||
case (.roomList, .showShareExtensionRoomList, .shareExtensionRoomList(let sharePayload)):
|
||||
clearRoute(animated: animated)
|
||||
presentRoomSelectionScreen(sharePayload: sharePayload, animated: animated)
|
||||
case (.shareExtensionRoomList, .dismissedShareExtensionRoomList, .roomList):
|
||||
dismissRoomSelectionScreen()
|
||||
|
||||
default:
|
||||
fatalError("Unknown transition: \(context)")
|
||||
}
|
||||
@@ -583,6 +602,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
coordinator.handleAppRoute(.event(eventID: eventID, roomID: roomID, via: via), animated: animated)
|
||||
case .roomDetails:
|
||||
coordinator.handleAppRoute(.roomDetails(roomID: roomID), animated: animated)
|
||||
case .share(let payload):
|
||||
coordinator.handleAppRoute(.share(payload), animated: animated)
|
||||
}
|
||||
|
||||
Task {
|
||||
@@ -894,6 +915,52 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Sharing
|
||||
|
||||
private func presentRoomSelectionScreen(sharePayload: ShareExtensionPayload, animated: Bool) {
|
||||
guard let roomSummaryProvider = userSession.clientProxy.alternateRoomSummaryProvider else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
let stackCoordinator = NavigationStackCoordinator()
|
||||
|
||||
let coordinator = RoomSelectionScreenCoordinator(parameters: .init(clientProxy: userSession.clientProxy,
|
||||
roomSummaryProvider: roomSummaryProvider,
|
||||
mediaProvider: userSession.mediaProvider))
|
||||
|
||||
coordinator.actionsPublisher.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
switch action {
|
||||
case .dismiss:
|
||||
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
case .confirm(let roomID):
|
||||
let sharePayload = switch sharePayload {
|
||||
case .mediaFile(_, let mediaFile):
|
||||
ShareExtensionPayload.mediaFile(roomID: roomID, mediaFile: mediaFile)
|
||||
}
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
|
||||
stateMachine.processEvent(.selectRoom(roomID: roomID,
|
||||
via: [],
|
||||
entryPoint: .share(sharePayload)),
|
||||
userInfo: .init(animated: animated))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
stackCoordinator.setRootCoordinator(coordinator)
|
||||
|
||||
navigationSplitCoordinator.setSheetCoordinator(stackCoordinator, animated: animated) { [weak self] in
|
||||
self?.stateMachine.processEvent(.dismissedShareExtensionRoomList)
|
||||
}
|
||||
}
|
||||
|
||||
private func dismissRoomSelectionScreen() {
|
||||
navigationSplitCoordinator.setSheetCoordinator(nil)
|
||||
}
|
||||
|
||||
// MARK: Toasts and loading indicators
|
||||
|
||||
private static let loadingIndicatorIdentifier = "\(UserSessionFlowCoordinator.self)-Loading"
|
||||
|
||||
@@ -42,10 +42,12 @@ class UserSessionFlowCoordinatorStateMachine {
|
||||
/// Showing the user profile screen. This screen clears the navigation.
|
||||
case userProfileScreen
|
||||
|
||||
case shareExtensionRoomList(sharePayload: ShareExtensionPayload)
|
||||
|
||||
/// The selected room ID from the state if available.
|
||||
var selectedRoomID: String? {
|
||||
switch self {
|
||||
case .initial, .userProfileScreen:
|
||||
case .initial, .userProfileScreen, .shareExtensionRoomList:
|
||||
nil
|
||||
case .roomList(let selectedRoomID),
|
||||
.feedbackScreen(let selectedRoomID),
|
||||
@@ -116,6 +118,9 @@ class UserSessionFlowCoordinatorStateMachine {
|
||||
case showUserProfileScreen(userID: String)
|
||||
/// The user profile screen has been dismissed.
|
||||
case dismissedUserProfileScreen
|
||||
|
||||
case showShareExtensionRoomList(sharePayload: ShareExtensionPayload)
|
||||
case dismissedShareExtensionRoomList
|
||||
}
|
||||
|
||||
private let stateMachine: StateMachine<State, Event>
|
||||
@@ -184,6 +189,11 @@ class UserSessionFlowCoordinatorStateMachine {
|
||||
case (.userProfileScreen, .dismissedUserProfileScreen):
|
||||
return .roomList(selectedRoomID: nil)
|
||||
|
||||
case (.roomList, .showShareExtensionRoomList(let sharePayload)):
|
||||
return .shareExtensionRoomList(sharePayload: sharePayload)
|
||||
case (.shareExtensionRoomList, .dismissedShareExtensionRoomList):
|
||||
return .roomList(selectedRoomID: nil)
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user