mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Move the media caption composer (and Add Caption action) behind a feature flag for now. (#3560)
This commit is contained in:
@@ -47,6 +47,7 @@ final class AppSettings {
|
|||||||
case fuzzyRoomListSearchEnabled
|
case fuzzyRoomListSearchEnabled
|
||||||
case enableOnlySignedDeviceIsolationMode
|
case enableOnlySignedDeviceIsolationMode
|
||||||
case knockingEnabled
|
case knockingEnabled
|
||||||
|
case createMediaCaptionsEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
||||||
@@ -280,6 +281,9 @@ final class AppSettings {
|
|||||||
@UserPreference(key: UserDefaultsKeys.knockingEnabled, defaultValue: false, storageType: .userDefaults(store))
|
@UserPreference(key: UserDefaultsKeys.knockingEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
var knockingEnabled
|
var knockingEnabled
|
||||||
|
|
||||||
|
@UserPreference(key: UserDefaultsKeys.createMediaCaptionsEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||||
|
var createMediaCaptionsEnabled
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MARK: - Shared
|
// MARK: - Shared
|
||||||
|
|||||||
@@ -996,7 +996,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
roomProxy: roomProxy,
|
roomProxy: roomProxy,
|
||||||
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings),
|
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: appSettings),
|
||||||
title: url.lastPathComponent,
|
title: url.lastPathComponent,
|
||||||
url: url)
|
url: url,
|
||||||
|
createMediaCaptionsEnabled: appSettings.createMediaCaptionsEnabled)
|
||||||
|
|
||||||
let mediaUploadPreviewScreenCoordinator = MediaUploadPreviewScreenCoordinator(parameters: parameters)
|
let mediaUploadPreviewScreenCoordinator = MediaUploadPreviewScreenCoordinator(parameters: parameters)
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -14,6 +14,7 @@ struct MediaUploadPreviewScreenCoordinatorParameters {
|
|||||||
let mediaUploadingPreprocessor: MediaUploadingPreprocessor
|
let mediaUploadingPreprocessor: MediaUploadingPreprocessor
|
||||||
let title: String?
|
let title: String?
|
||||||
let url: URL
|
let url: URL
|
||||||
|
let createMediaCaptionsEnabled: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MediaUploadPreviewScreenCoordinatorAction {
|
enum MediaUploadPreviewScreenCoordinatorAction {
|
||||||
@@ -34,7 +35,8 @@ final class MediaUploadPreviewScreenCoordinator: CoordinatorProtocol {
|
|||||||
roomProxy: parameters.roomProxy,
|
roomProxy: parameters.roomProxy,
|
||||||
mediaUploadingPreprocessor: parameters.mediaUploadingPreprocessor,
|
mediaUploadingPreprocessor: parameters.mediaUploadingPreprocessor,
|
||||||
title: parameters.title,
|
title: parameters.title,
|
||||||
url: parameters.url)
|
url: parameters.url,
|
||||||
|
createMediaCaptionsEnabled: parameters.createMediaCaptionsEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func start() {
|
func start() {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ enum MediaUploadPreviewScreenViewModelAction {
|
|||||||
struct MediaUploadPreviewScreenViewState: BindableState {
|
struct MediaUploadPreviewScreenViewState: BindableState {
|
||||||
let url: URL
|
let url: URL
|
||||||
let title: String?
|
let title: String?
|
||||||
|
let showMediaCaptionComposer: Bool
|
||||||
var shouldDisableInteraction = false
|
var shouldDisableInteraction = false
|
||||||
|
|
||||||
var bindings = MediaUploadPreviewScreenBindings()
|
var bindings = MediaUploadPreviewScreenBindings()
|
||||||
|
|||||||
+3
-2
@@ -32,13 +32,14 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType,
|
|||||||
roomProxy: JoinedRoomProxyProtocol,
|
roomProxy: JoinedRoomProxyProtocol,
|
||||||
mediaUploadingPreprocessor: MediaUploadingPreprocessor,
|
mediaUploadingPreprocessor: MediaUploadingPreprocessor,
|
||||||
title: String?,
|
title: String?,
|
||||||
url: URL) {
|
url: URL,
|
||||||
|
createMediaCaptionsEnabled: Bool) {
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
self.roomProxy = roomProxy
|
self.roomProxy = roomProxy
|
||||||
self.mediaUploadingPreprocessor = mediaUploadingPreprocessor
|
self.mediaUploadingPreprocessor = mediaUploadingPreprocessor
|
||||||
self.url = url
|
self.url = url
|
||||||
|
|
||||||
super.init(initialViewState: MediaUploadPreviewScreenViewState(url: url, title: title))
|
super.init(initialViewState: MediaUploadPreviewScreenViewState(url: url, title: title, showMediaCaptionComposer: createMediaCaptionsEnabled))
|
||||||
}
|
}
|
||||||
|
|
||||||
override func process(viewAction: MediaUploadPreviewScreenViewAction) {
|
override func process(viewAction: MediaUploadPreviewScreenViewAction) {
|
||||||
|
|||||||
+4
-1
@@ -22,11 +22,13 @@ struct MediaUploadPreviewScreen: View {
|
|||||||
.id(context.viewState.url)
|
.id(context.viewState.url)
|
||||||
.ignoresSafeArea(edges: [.horizontal])
|
.ignoresSafeArea(edges: [.horizontal])
|
||||||
.safeAreaInset(edge: .bottom, spacing: 0) {
|
.safeAreaInset(edge: .bottom, spacing: 0) {
|
||||||
|
if context.viewState.showMediaCaptionComposer {
|
||||||
composer
|
composer
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, 12)
|
||||||
.padding(.vertical, 16)
|
.padding(.vertical, 16)
|
||||||
.background() // Don't use compound so we match the QLPreviewController.
|
.background() // Don't use compound so we match the QLPreviewController.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.navigationTitle(title)
|
.navigationTitle(title)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.toolbar { toolbar }
|
.toolbar { toolbar }
|
||||||
@@ -156,7 +158,8 @@ struct MediaUploadPreviewScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
roomProxy: JoinedRoomProxyMock(),
|
roomProxy: JoinedRoomProxyMock(),
|
||||||
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings),
|
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings),
|
||||||
title: "App Icon.png",
|
title: "App Icon.png",
|
||||||
url: snapshotURL)
|
url: snapshotURL,
|
||||||
|
createMediaCaptionsEnabled: true)
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
MediaUploadPreviewScreen(context: viewModel.context)
|
MediaUploadPreviewScreen(context: viewModel.context)
|
||||||
|
|||||||
+1
@@ -37,6 +37,7 @@ struct PinnedEventsTimelineScreen: View {
|
|||||||
pinnedEventIDs: timelineContext.viewState.pinnedEventIDs,
|
pinnedEventIDs: timelineContext.viewState.pinnedEventIDs,
|
||||||
isDM: timelineContext.viewState.isEncryptedOneToOneRoom,
|
isDM: timelineContext.viewState.isEncryptedOneToOneRoom,
|
||||||
isViewSourceEnabled: timelineContext.viewState.isViewSourceEnabled,
|
isViewSourceEnabled: timelineContext.viewState.isViewSourceEnabled,
|
||||||
|
isCreateMediaCaptionsEnabled: timelineContext.viewState.isCreateMediaCaptionsEnabled,
|
||||||
isPinnedEventsTimeline: timelineContext.viewState.isPinnedEventsTimeline,
|
isPinnedEventsTimeline: timelineContext.viewState.isPinnedEventsTimeline,
|
||||||
emojiProvider: timelineContext.viewState.emojiProvider)
|
emojiProvider: timelineContext.viewState.emojiProvider)
|
||||||
.makeActions()
|
.makeActions()
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ struct RoomScreen: View {
|
|||||||
pinnedEventIDs: timelineContext.viewState.pinnedEventIDs,
|
pinnedEventIDs: timelineContext.viewState.pinnedEventIDs,
|
||||||
isDM: timelineContext.viewState.isEncryptedOneToOneRoom,
|
isDM: timelineContext.viewState.isEncryptedOneToOneRoom,
|
||||||
isViewSourceEnabled: timelineContext.viewState.isViewSourceEnabled,
|
isViewSourceEnabled: timelineContext.viewState.isViewSourceEnabled,
|
||||||
|
isCreateMediaCaptionsEnabled: timelineContext.viewState.isCreateMediaCaptionsEnabled,
|
||||||
isPinnedEventsTimeline: timelineContext.viewState.isPinnedEventsTimeline,
|
isPinnedEventsTimeline: timelineContext.viewState.isPinnedEventsTimeline,
|
||||||
emojiProvider: timelineContext.viewState.emojiProvider)
|
emojiProvider: timelineContext.viewState.emojiProvider)
|
||||||
.makeActions()
|
.makeActions()
|
||||||
|
|||||||
+1
@@ -50,6 +50,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
|||||||
var enableOnlySignedDeviceIsolationMode: Bool { get set }
|
var enableOnlySignedDeviceIsolationMode: Bool { get set }
|
||||||
var elementCallBaseURLOverride: URL? { get set }
|
var elementCallBaseURLOverride: URL? { get set }
|
||||||
var knockingEnabled: Bool { get set }
|
var knockingEnabled: Bool { get set }
|
||||||
|
var createMediaCaptionsEnabled: Bool { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppSettings: DeveloperOptionsProtocol { }
|
extension AppSettings: DeveloperOptionsProtocol { }
|
||||||
|
|||||||
+4
@@ -53,6 +53,10 @@ struct DeveloperOptionsScreen: View {
|
|||||||
Toggle(isOn: $context.hideTimelineMedia) {
|
Toggle(isOn: $context.hideTimelineMedia) {
|
||||||
Text("Hide image & video previews")
|
Text("Hide image & video previews")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toggle(isOn: $context.createMediaCaptionsEnabled) {
|
||||||
|
Text("Allow creation of media captions")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Join rules") {
|
Section("Join rules") {
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ struct TimelineViewState: BindableState {
|
|||||||
var canCurrentUserRedactSelf = false
|
var canCurrentUserRedactSelf = false
|
||||||
var canCurrentUserPin = false
|
var canCurrentUserPin = false
|
||||||
var isViewSourceEnabled: Bool
|
var isViewSourceEnabled: Bool
|
||||||
|
var isCreateMediaCaptionsEnabled: Bool
|
||||||
var hideTimelineMedia: Bool
|
var hideTimelineMedia: Bool
|
||||||
|
|
||||||
// The `pinnedEventIDs` are used only to determine if an item is already pinned or not.
|
// The `pinnedEventIDs` are used only to determine if an item is already pinned or not.
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
timelineViewState: TimelineState(focussedEvent: focussedEventID.map { .init(eventID: $0, appearance: .immediate) }),
|
timelineViewState: TimelineState(focussedEvent: focussedEventID.map { .init(eventID: $0, appearance: .immediate) }),
|
||||||
ownUserID: roomProxy.ownUserID,
|
ownUserID: roomProxy.ownUserID,
|
||||||
isViewSourceEnabled: appSettings.viewSourceEnabled,
|
isViewSourceEnabled: appSettings.viewSourceEnabled,
|
||||||
|
isCreateMediaCaptionsEnabled: appSettings.createMediaCaptionsEnabled,
|
||||||
hideTimelineMedia: appSettings.hideTimelineMedia,
|
hideTimelineMedia: appSettings.hideTimelineMedia,
|
||||||
pinnedEventIDs: roomProxy.infoPublisher.value.pinnedEventIDs,
|
pinnedEventIDs: roomProxy.infoPublisher.value.pinnedEventIDs,
|
||||||
bindings: .init(reactionsCollapsed: [:]),
|
bindings: .init(reactionsCollapsed: [:]),
|
||||||
@@ -447,6 +448,10 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
.weakAssign(to: \.state.isViewSourceEnabled, on: self)
|
.weakAssign(to: \.state.isViewSourceEnabled, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
appSettings.$createMediaCaptionsEnabled
|
||||||
|
.weakAssign(to: \.state.isCreateMediaCaptionsEnabled, on: self)
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
appSettings.$hideTimelineMedia
|
appSettings.$hideTimelineMedia
|
||||||
.weakAssign(to: \.state.hideTimelineMedia, on: self)
|
.weakAssign(to: \.state.hideTimelineMedia, on: self)
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
+2
-1
@@ -16,6 +16,7 @@ struct TimelineItemMenuActionProvider {
|
|||||||
let pinnedEventIDs: Set<String>
|
let pinnedEventIDs: Set<String>
|
||||||
let isDM: Bool
|
let isDM: Bool
|
||||||
let isViewSourceEnabled: Bool
|
let isViewSourceEnabled: Bool
|
||||||
|
let isCreateMediaCaptionsEnabled: Bool
|
||||||
let isPinnedEventsTimeline: Bool
|
let isPinnedEventsTimeline: Bool
|
||||||
let emojiProvider: EmojiProviderProtocol
|
let emojiProvider: EmojiProviderProtocol
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ struct TimelineItemMenuActionProvider {
|
|||||||
if let messageItem = item as? EventBasedMessageTimelineItemProtocol, messageItem.supportsMediaCaption {
|
if let messageItem = item as? EventBasedMessageTimelineItemProtocol, messageItem.supportsMediaCaption {
|
||||||
if messageItem.hasMediaCaption {
|
if messageItem.hasMediaCaption {
|
||||||
actions.append(contentsOf: [.editCaption, .removeCaption])
|
actions.append(contentsOf: [.editCaption, .removeCaption])
|
||||||
} else {
|
} else if isCreateMediaCaptionsEnabled {
|
||||||
actions.append(.addCaption)
|
actions.append(.addCaption)
|
||||||
}
|
}
|
||||||
} else if !(item is VoiceMessageRoomTimelineItem) {
|
} else if !(item is VoiceMessageRoomTimelineItem) {
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
|
|||||||
pinnedEventIDs: context.viewState.pinnedEventIDs,
|
pinnedEventIDs: context.viewState.pinnedEventIDs,
|
||||||
isDM: context.viewState.isEncryptedOneToOneRoom,
|
isDM: context.viewState.isEncryptedOneToOneRoom,
|
||||||
isViewSourceEnabled: context.viewState.isViewSourceEnabled,
|
isViewSourceEnabled: context.viewState.isViewSourceEnabled,
|
||||||
|
isCreateMediaCaptionsEnabled: context.viewState.isCreateMediaCaptionsEnabled,
|
||||||
isPinnedEventsTimeline: context.viewState.isPinnedEventsTimeline,
|
isPinnedEventsTimeline: context.viewState.isPinnedEventsTimeline,
|
||||||
emojiProvider: context.viewState.emojiProvider)
|
emojiProvider: context.viewState.emojiProvider)
|
||||||
TimelineItemMacContextMenu(item: timelineItem, actionProvider: provider) { action in
|
TimelineItemMacContextMenu(item: timelineItem, actionProvider: provider) { action in
|
||||||
|
|||||||
@@ -125,7 +125,8 @@ class MediaUploadPreviewScreenViewModelTests: XCTestCase {
|
|||||||
roomProxy: roomProxy,
|
roomProxy: roomProxy,
|
||||||
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings),
|
mediaUploadingPreprocessor: MediaUploadingPreprocessor(appSettings: ServiceLocator.shared.settings),
|
||||||
title: "Some File",
|
title: "Some File",
|
||||||
url: url)
|
url: url,
|
||||||
|
createMediaCaptionsEnabled: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func verifyCaption(_ caption: String?, expectedCaption: String?) -> Result<Void, TimelineProxyError> {
|
private func verifyCaption(_ caption: String?, expectedCaption: String?) -> Result<Void, TimelineProxyError> {
|
||||||
|
|||||||
Reference in New Issue
Block a user