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