mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Allow the mac app to chose room avatars directly from files instead of the photo library
This commit is contained in:
@@ -63,6 +63,7 @@
|
|||||||
"action_call" = "Call";
|
"action_call" = "Call";
|
||||||
"action_cancel" = "Cancel";
|
"action_cancel" = "Cancel";
|
||||||
"action_cancel_for_now" = "Cancel for now";
|
"action_cancel_for_now" = "Cancel for now";
|
||||||
|
"action_choose_file" = "Choose file";
|
||||||
"action_choose_photo" = "Choose photo";
|
"action_choose_photo" = "Choose photo";
|
||||||
"action_clear" = "Clear";
|
"action_clear" = "Clear";
|
||||||
"action_close" = "Close";
|
"action_close" = "Close";
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
"action_call" = "Call";
|
"action_call" = "Call";
|
||||||
"action_cancel" = "Cancel";
|
"action_cancel" = "Cancel";
|
||||||
"action_cancel_for_now" = "Cancel for now";
|
"action_cancel_for_now" = "Cancel for now";
|
||||||
|
"action_choose_file" = "Choose file";
|
||||||
"action_choose_photo" = "Choose photo";
|
"action_choose_photo" = "Choose photo";
|
||||||
"action_clear" = "Clear";
|
"action_clear" = "Clear";
|
||||||
"action_close" = "Close";
|
"action_close" = "Close";
|
||||||
|
|||||||
@@ -160,6 +160,8 @@ internal enum L10n {
|
|||||||
internal static var actionCancel: String { return L10n.tr("Localizable", "action_cancel") }
|
internal static var actionCancel: String { return L10n.tr("Localizable", "action_cancel") }
|
||||||
/// Cancel for now
|
/// Cancel for now
|
||||||
internal static var actionCancelForNow: String { return L10n.tr("Localizable", "action_cancel_for_now") }
|
internal static var actionCancelForNow: String { return L10n.tr("Localizable", "action_cancel_for_now") }
|
||||||
|
/// Choose file
|
||||||
|
internal static var actionChooseFile: String { return L10n.tr("Localizable", "action_choose_file") }
|
||||||
/// Choose photo
|
/// Choose photo
|
||||||
internal static var actionChoosePhoto: String { return L10n.tr("Localizable", "action_choose_photo") }
|
internal static var actionChoosePhoto: String { return L10n.tr("Localizable", "action_choose_photo") }
|
||||||
/// Clear
|
/// Clear
|
||||||
|
|||||||
@@ -281,6 +281,7 @@ enum A11yIdentifiers {
|
|||||||
let roomName = "create_room-room_name"
|
let roomName = "create_room-room_name"
|
||||||
let roomTopic = "create_room-room_topic"
|
let roomTopic = "create_room-room_topic"
|
||||||
let mediaPicker = "create_room-media_picker"
|
let mediaPicker = "create_room-media_picker"
|
||||||
|
let filePicker = "create_room-file_picker"
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PollFormScreen {
|
struct PollFormScreen {
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ final class CreateRoomScreenCoordinator: CoordinatorProtocol {
|
|||||||
actionsSubject.send(.displayMediaPickerWithMode(.init(source: .camera, selectionType: .single)))
|
actionsSubject.send(.displayMediaPickerWithMode(.init(source: .camera, selectionType: .single)))
|
||||||
case .displayMediaPicker:
|
case .displayMediaPicker:
|
||||||
actionsSubject.send(.displayMediaPickerWithMode(.init(source: .photoLibrary, selectionType: .single)))
|
actionsSubject.send(.displayMediaPickerWithMode(.init(source: .photoLibrary, selectionType: .single)))
|
||||||
|
case .displayFilePicker:
|
||||||
|
actionsSubject.send(.displayMediaPickerWithMode(.init(source: .documents(types: [.image]), selectionType: .single)))
|
||||||
case .dismiss:
|
case .dismiss:
|
||||||
actionsSubject.send(.dismiss)
|
actionsSubject.send(.dismiss)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ enum CreateRoomScreenViewModelAction {
|
|||||||
case createdRoom(JoinedRoomProxyProtocol, SpaceRoomListProxyProtocol?)
|
case createdRoom(JoinedRoomProxyProtocol, SpaceRoomListProxyProtocol?)
|
||||||
case displayMediaPicker
|
case displayMediaPicker
|
||||||
case displayCameraPicker
|
case displayCameraPicker
|
||||||
|
case displayFilePicker
|
||||||
case dismiss
|
case dismiss
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +115,7 @@ enum CreateRoomScreenViewAction {
|
|||||||
case createRoom
|
case createRoom
|
||||||
case displayCameraPicker
|
case displayCameraPicker
|
||||||
case displayMediaPicker
|
case displayMediaPicker
|
||||||
|
case displayFilePicker
|
||||||
case removeImage
|
case removeImage
|
||||||
case updateRoomName(String)
|
case updateRoomName(String)
|
||||||
case updateAliasLocalPart(String)
|
case updateAliasLocalPart(String)
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
|
|||||||
actionsSubject.send(.displayCameraPicker)
|
actionsSubject.send(.displayCameraPicker)
|
||||||
case .displayMediaPicker:
|
case .displayMediaPicker:
|
||||||
actionsSubject.send(.displayMediaPicker)
|
actionsSubject.send(.displayMediaPicker)
|
||||||
|
case .displayFilePicker:
|
||||||
|
actionsSubject.send(.displayFilePicker)
|
||||||
case .removeImage:
|
case .removeImage:
|
||||||
state.avatarMediaInfo = nil
|
state.avatarMediaInfo = nil
|
||||||
case .updateAliasLocalPart(let aliasLocalPart):
|
case .updateAliasLocalPart(let aliasLocalPart):
|
||||||
|
|||||||
@@ -139,11 +139,17 @@ struct CreateRoomScreen: View {
|
|||||||
Button(L10n.actionTakePhoto) {
|
Button(L10n.actionTakePhoto) {
|
||||||
context.send(viewAction: .displayCameraPicker)
|
context.send(viewAction: .displayCameraPicker)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(L10n.actionChoosePhoto) {
|
Button(L10n.actionChoosePhoto) {
|
||||||
context.send(viewAction: .displayMediaPicker)
|
context.send(viewAction: .displayMediaPicker)
|
||||||
}
|
}
|
||||||
.accessibilityIdentifier(A11yIdentifiers.createRoomScreen.mediaPicker)
|
.accessibilityIdentifier(A11yIdentifiers.createRoomScreen.mediaPicker)
|
||||||
|
|
||||||
|
Button(L10n.actionChooseFile) {
|
||||||
|
context.send(viewAction: .displayFilePicker)
|
||||||
|
}
|
||||||
|
.accessibilityIdentifier(A11yIdentifiers.createRoomScreen.filePicker)
|
||||||
|
|
||||||
if context.viewState.avatarImage != nil {
|
if context.viewState.avatarImage != nil {
|
||||||
Button(L10n.actionRemove, role: .destructive) {
|
Button(L10n.actionRemove, role: .destructive) {
|
||||||
context.send(viewAction: .removeImage)
|
context.send(viewAction: .removeImage)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
enum DocumentPickerAction {
|
enum DocumentPickerAction {
|
||||||
case selectedMediaAtURLs([URL])
|
case selectedMediaAtURLs([URL])
|
||||||
@@ -16,19 +17,22 @@ enum DocumentPickerAction {
|
|||||||
|
|
||||||
struct DocumentPicker: UIViewControllerRepresentable {
|
struct DocumentPicker: UIViewControllerRepresentable {
|
||||||
private let selectionType: MediaPickerScreenSelectionType
|
private let selectionType: MediaPickerScreenSelectionType
|
||||||
|
private let contentTypes: [UTType]
|
||||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
private let callback: (DocumentPickerAction) -> Void
|
private let callback: (DocumentPickerAction) -> Void
|
||||||
|
|
||||||
init(selectionType: MediaPickerScreenSelectionType,
|
init(selectionType: MediaPickerScreenSelectionType,
|
||||||
|
contentTypes: [UTType],
|
||||||
userIndicatorController: UserIndicatorControllerProtocol,
|
userIndicatorController: UserIndicatorControllerProtocol,
|
||||||
callback: @escaping (DocumentPickerAction) -> Void) {
|
callback: @escaping (DocumentPickerAction) -> Void) {
|
||||||
self.selectionType = selectionType
|
self.selectionType = selectionType
|
||||||
|
self.contentTypes = contentTypes
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
|
func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
|
||||||
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.data])
|
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes)
|
||||||
documentPicker.delegate = context.coordinator
|
documentPicker.delegate = context.coordinator
|
||||||
|
|
||||||
documentPicker.allowsMultipleSelection = switch selectionType {
|
documentPicker.allowsMultipleSelection = switch selectionType {
|
||||||
|
|||||||
@@ -7,16 +7,17 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
struct MediaPickerScreenMode: Hashable {
|
struct MediaPickerScreenMode: Hashable {
|
||||||
let source: MediaPickerScreenSource
|
let source: MediaPickerScreenSource
|
||||||
let selectionType: MediaPickerScreenSelectionType
|
let selectionType: MediaPickerScreenSelectionType
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MediaPickerScreenSource {
|
enum MediaPickerScreenSource: Hashable {
|
||||||
case camera
|
case camera
|
||||||
case photoLibrary
|
case photoLibrary
|
||||||
case documents
|
case documents(types: [UTType] = [.data])
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MediaPickerScreenSelectionType {
|
enum MediaPickerScreenSelectionType {
|
||||||
@@ -79,10 +80,12 @@ class MediaPickerScreenCoordinator: CoordinatorProtocol {
|
|||||||
self?.callback(.selectedMediaAtURLs(urls))
|
self?.callback(.selectedMediaAtURLs(urls))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .documents:
|
case .documents(let types):
|
||||||
// The document picker automatically dismisses everything on selection
|
// The document picker automatically dismisses everything on selection
|
||||||
// Strongly retain self in the callback to forward actions correctly
|
// Strongly retain self in the callback to forward actions correctly
|
||||||
DocumentPicker(selectionType: mode.selectionType, userIndicatorController: userIndicatorController) { action in
|
DocumentPicker(selectionType: mode.selectionType,
|
||||||
|
contentTypes: types,
|
||||||
|
userIndicatorController: userIndicatorController) { action in
|
||||||
switch action {
|
switch action {
|
||||||
case .cancel:
|
case .cancel:
|
||||||
self.callback(.cancel)
|
self.callback(.cancel)
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ final class RoomDetailsEditScreenCoordinator: CoordinatorProtocol {
|
|||||||
self?.displayMediaPickerWithMode(.init(source: .camera, selectionType: .single))
|
self?.displayMediaPickerWithMode(.init(source: .camera, selectionType: .single))
|
||||||
case .displayMediaPicker:
|
case .displayMediaPicker:
|
||||||
self?.displayMediaPickerWithMode(.init(source: .photoLibrary, selectionType: .single))
|
self?.displayMediaPickerWithMode(.init(source: .photoLibrary, selectionType: .single))
|
||||||
|
case .displayFilePicker:
|
||||||
|
self?.displayMediaPickerWithMode(.init(source: .documents(types: [.image]), selectionType: .single))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ enum RoomDetailsEditScreenViewModelAction {
|
|||||||
case saveFinished
|
case saveFinished
|
||||||
case displayCameraPicker
|
case displayCameraPicker
|
||||||
case displayMediaPicker
|
case displayMediaPicker
|
||||||
|
case displayFilePicker
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RoomDetailsEditScreenViewState: BindableState {
|
struct RoomDetailsEditScreenViewState: BindableState {
|
||||||
@@ -81,5 +82,6 @@ enum RoomDetailsEditScreenViewAction {
|
|||||||
case presentMediaSource
|
case presentMediaSource
|
||||||
case displayCameraPicker
|
case displayCameraPicker
|
||||||
case displayMediaPicker
|
case displayMediaPicker
|
||||||
|
case displayFilePicker
|
||||||
case removeImage
|
case removeImage
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDe
|
|||||||
actionsSubject.send(.displayCameraPicker)
|
actionsSubject.send(.displayCameraPicker)
|
||||||
case .displayMediaPicker:
|
case .displayMediaPicker:
|
||||||
actionsSubject.send(.displayMediaPicker)
|
actionsSubject.send(.displayMediaPicker)
|
||||||
|
case .displayFilePicker:
|
||||||
|
actionsSubject.send(.displayFilePicker)
|
||||||
case .removeImage:
|
case .removeImage:
|
||||||
state.avatarURL = nil
|
state.avatarURL = nil
|
||||||
state.localMedia = nil
|
state.localMedia = nil
|
||||||
|
|||||||
@@ -119,11 +119,19 @@ struct RoomDetailsEditScreen: View {
|
|||||||
} label: {
|
} label: {
|
||||||
Text(L10n.actionTakePhoto)
|
Text(L10n.actionTakePhoto)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
context.send(viewAction: .displayMediaPicker)
|
context.send(viewAction: .displayMediaPicker)
|
||||||
} label: {
|
} label: {
|
||||||
Text(L10n.actionChoosePhoto)
|
Text(L10n.actionChoosePhoto)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
context.send(viewAction: .displayFilePicker)
|
||||||
|
} label: {
|
||||||
|
Text(L10n.actionChooseFile)
|
||||||
|
}
|
||||||
|
|
||||||
if context.viewState.showDeleteImageAction {
|
if context.viewState.showDeleteImageAction {
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
context.send(viewAction: .removeImage)
|
context.send(viewAction: .removeImage)
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
|||||||
case .displayMediaPicker:
|
case .displayMediaPicker:
|
||||||
actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .photoLibrary, selectionType: .multiple)))
|
actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .photoLibrary, selectionType: .multiple)))
|
||||||
case .displayDocumentPicker:
|
case .displayDocumentPicker:
|
||||||
actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .documents, selectionType: .multiple)))
|
actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .documents(), selectionType: .multiple)))
|
||||||
case .displayMediaPreview(let mediaPreviewViewModel):
|
case .displayMediaPreview(let mediaPreviewViewModel):
|
||||||
roomViewModel.displayMediaPreview(mediaPreviewViewModel)
|
roomViewModel.displayMediaPreview(mediaPreviewViewModel)
|
||||||
case .displayLocationPicker:
|
case .displayLocationPicker:
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ final class UserDetailsEditScreenCoordinator: CoordinatorProtocol {
|
|||||||
case .displayMediaPicker:
|
case .displayMediaPicker:
|
||||||
displayMediaPickerWithMode(.init(source: .photoLibrary, selectionType: .single))
|
displayMediaPickerWithMode(.init(source: .photoLibrary, selectionType: .single))
|
||||||
case .displayFilePicker:
|
case .displayFilePicker:
|
||||||
displayMediaPickerWithMode(.init(source: .documents, selectionType: .single))
|
displayMediaPickerWithMode(.init(source: .documents(types: [.image]), selectionType: .single))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|||||||
+1
@@ -67,5 +67,6 @@ enum UserDetailsEditScreenViewAction {
|
|||||||
case presentMediaSource
|
case presentMediaSource
|
||||||
case displayCameraPicker
|
case displayCameraPicker
|
||||||
case displayMediaPicker
|
case displayMediaPicker
|
||||||
|
case displayFilePicker
|
||||||
case removeImage
|
case removeImage
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -77,6 +77,8 @@ class UserDetailsEditScreenViewModel: UserDetailsEditScreenViewModelType, UserDe
|
|||||||
actionsSubject.send(.displayCameraPicker)
|
actionsSubject.send(.displayCameraPicker)
|
||||||
case .displayMediaPicker:
|
case .displayMediaPicker:
|
||||||
actionsSubject.send(.displayMediaPicker)
|
actionsSubject.send(.displayMediaPicker)
|
||||||
|
case .displayFilePicker:
|
||||||
|
actionsSubject.send(.displayFilePicker)
|
||||||
case .removeImage:
|
case .removeImage:
|
||||||
state.localMedia = nil
|
state.localMedia = nil
|
||||||
state.selectedAvatarURL = nil
|
state.selectedAvatarURL = nil
|
||||||
|
|||||||
+7
@@ -96,12 +96,19 @@ struct UserDetailsEditScreen: View {
|
|||||||
} label: {
|
} label: {
|
||||||
Text(L10n.actionTakePhoto)
|
Text(L10n.actionTakePhoto)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
context.send(viewAction: .displayMediaPicker)
|
context.send(viewAction: .displayMediaPicker)
|
||||||
} label: {
|
} label: {
|
||||||
Text(L10n.actionChoosePhoto)
|
Text(L10n.actionChoosePhoto)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
context.send(viewAction: .displayFilePicker)
|
||||||
|
} label: {
|
||||||
|
Text(L10n.actionChooseFile)
|
||||||
|
}
|
||||||
|
|
||||||
if context.viewState.showDeleteImageAction {
|
if context.viewState.showDeleteImageAction {
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
context.send(viewAction: .removeImage)
|
context.send(viewAction: .removeImage)
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ final class ThreadTimelineScreenCoordinator: CoordinatorProtocol {
|
|||||||
case .displayMediaPicker:
|
case .displayMediaPicker:
|
||||||
actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .photoLibrary, selectionType: .multiple)))
|
actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .photoLibrary, selectionType: .multiple)))
|
||||||
case .displayDocumentPicker:
|
case .displayDocumentPicker:
|
||||||
actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .documents, selectionType: .multiple)))
|
actionsSubject.send(.presentMediaUploadPicker(mode: .init(source: .documents(), selectionType: .multiple)))
|
||||||
case .displayMediaPreview(let mediaPreviewViewModel):
|
case .displayMediaPreview(let mediaPreviewViewModel):
|
||||||
viewModel.displayMediaPreview(mediaPreviewViewModel)
|
viewModel.displayMediaPreview(mediaPreviewViewModel)
|
||||||
case .displayLocationPicker:
|
case .displayLocationPicker:
|
||||||
|
|||||||
Reference in New Issue
Block a user