This commit is contained in:
fmodf 2024-08-17 10:50:44 +02:00
parent 51cd7f82f6
commit e4c843016e
4 changed files with 437 additions and 12 deletions

View file

@ -50,7 +50,16 @@
"Conversation.startError" = "Error occurs in conversation starting"; "Conversation.startError" = "Error occurs in conversation starting";
"Chat.textfieldPrompt" = "Type a message"; "Chat.textfieldPrompt" = "Type a message";
// MARK: Attachments
"Attachment.Prompt.main" = "Select attachment";
"Attachment.Tab.media" = "Media";
"Attachment.Tab.files" = "Files";
"Attachment.Tab.location" = "Location";
"Attachment.Tab.contacts" = "Contacts";
"Attachment.Send.media" = "Send media";
"Attachment.Send.location" = "Send location";
"Attachment.Send.contact" = "Send contact";
"Attachment.Downloading.retry" = "Retry";
@ -64,13 +73,3 @@
// MARK: Attachments
//"Attachment.Prompt.main" = "Select attachment";
//"Attachment.Tab.media" = "Media";
//"Attachment.Tab.files" = "Files";
//"Attachment.Tab.location" = "Location";
//"Attachment.Tab.contacts" = "Contacts";
//"Attachment.Send.media" = "Send media";
//"Attachment.Send.location" = "Send location";
//"Attachment.Send.contact" = "Send contact";
//"Attachment.Downloading.retry" = "Retry";

View file

@ -0,0 +1,134 @@
import SwiftUI
enum AttachmentTab: Int, CaseIterable {
case media
case files
case location
case contacts
}
struct AttachmentPickerScreen: View {
@Environment(\.router) var router
@State private var selectedTab: AttachmentTab = .media
var body: some View {
ZStack {
// Background color
Color.Material.Background.light
.ignoresSafeArea()
// Content
VStack(spacing: 0) {
// Header
SharedNavigationBar(
leftButton: .init(
image: Image(systemName: "xmark"),
action: {
router.dismissScreen()
}
),
centerText: .init(text: L10n.Attachment.Prompt.main)
)
// Pickers
switch selectedTab {
case .media:
MediaPickerView()
case .files:
Color.blue
// SharingFilesPickerView()
case .location:
Color.green
// SharingLocationPickerView()
case .contacts:
Color.yellow
// SharingContactsPickerView()
}
// Tab bar
AttachmentTabBar(selectedTab: $selectedTab)
}
}
}
}
struct AttachmentTabBar: View {
@Binding var selectedTab: AttachmentTab
var body: some View {
VStack(spacing: 0) {
Rectangle()
.frame(maxWidth: .infinity)
.frame(height: 0.2)
.foregroundColor(.Material.Shape.separator)
HStack(spacing: 0) {
AttachmentTabBarButton(tab: .media, selected: $selectedTab)
AttachmentTabBarButton(tab: .files, selected: $selectedTab)
AttachmentTabBarButton(tab: .location, selected: $selectedTab)
AttachmentTabBarButton(tab: .contacts, selected: $selectedTab)
}
.background(Color.Material.Background.dark)
}
.frame(height: 50)
}
}
private struct AttachmentTabBarButton: View {
let tab: AttachmentTab
@Binding var selected: AttachmentTab
var body: some View {
ZStack {
VStack(spacing: 2) {
buttonImg
.foregroundColor(selected == tab ? .Material.Elements.active : .Material.Elements.inactive)
.font(.system(size: 24, weight: .light))
.symbolRenderingMode(.hierarchical)
Text(buttonTitle)
.font(.sub1)
.foregroundColor(selected == tab ? .Material.Text.main : .Material.Elements.inactive)
}
Rectangle()
.foregroundColor(.white.opacity(0.01))
.onTapGesture {
selected = tab
}
}
}
var buttonImg: Image {
switch tab {
case .media:
return Image(systemName: "photo.on.rectangle.angled")
case .files:
return Image(systemName: "doc.on.doc")
case .location:
return Image(systemName: "location.circle")
case .contacts:
return Image(systemName: "person.crop.circle")
}
}
var buttonTitle: String {
switch tab {
case .media:
return L10n.Attachment.Tab.media
case .files:
return L10n.Attachment.Tab.files
case .location:
return L10n.Attachment.Tab.location
case .contacts:
return L10n.Attachment.Tab.contacts
}
}
}

View file

@ -0,0 +1,289 @@
import AVFoundation
import MobileCoreServices
import Photos
import SwiftUI
struct MediaPickerView: View {
// @State private var showCameraPicker = false
// @State private var cameraReady = false
// @State private var selectedItems: [String] = []
var body: some View {
let columns = Array(repeating: GridItem(.flexible(), spacing: 0), count: 3)
VStack(spacing: 0) {
// List of media
ScrollView(showsIndicators: false) {
LazyVGrid(columns: columns, spacing: 0) {
// For camera
// if store.state.sharingState.isCameraAccessGranted {
// if cameraReady {
// ZStack {
// CameraView()
// .aspectRatio(1, contentMode: .fit)
// .frame(maxWidth: .infinity)
// Image(systemName: "camera")
// .resizable()
// .aspectRatio(contentMode: .fit)
// .frame(width: 40, height: 40)
// .foregroundColor(.white)
// .padding(8)
// .background(Color.black.opacity(0.5))
// .clipShape(Circle())
// .padding(8)
// }
// .onTapGesture {
// showCameraPicker = true
// }
// } else {
// ProgressView()
// .frame(maxWidth: .infinity)
// .frame(height: 100)
// .onAppear {
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
// cameraReady = true
// }
// }
// }
// } else {
// Button {
// openAppSettings()
// } label: {
// ZStack {
// Rectangle()
// .fill(Color.Material.Background.light)
// .overlay {
// VStack {
// Image(systemName: "camera")
// .foregroundColor(.Material.Elements.active)
// .font(.system(size: 30))
// Text("Allow camera access")
// .foregroundColor(.Material.Text.main)
// .font(.body3)
// }
// }
// .frame(height: 100)
// }
// }
// }
// For gallery
// if store.state.sharingState.isGalleryAccessGranted {
// ForEach(store.state.sharingState.galleryItems) { item in
// GridViewItem(item: item, selected: $selectedItems)
// }
// } else {
// Button {
// openAppSettings()
// } label: {
// ZStack {
// Rectangle()
// .fill(Color.Material.Background.light)
// .overlay {
// VStack {
// Image(systemName: "photo")
// .foregroundColor(.Material.Elements.active)
// .font(.system(size: 30))
// Text("Allow gallery access")
// .foregroundColor(.Material.Text.main)
// .font(.body3)
// }
// }
// .frame(height: 100)
// }
// }
// }
}
}
// .fullScreenCover(isPresented: $showCameraPicker) {
// CameraPicker(sourceType: .camera) { data, type in
// store.dispatch(.sharingAction(.cameraCaptured(media: data, type: type)))
// showCameraPicker = false
// store.dispatch(.sharingAction(.showSharing(false)))
// }
// .edgesIgnoringSafeArea(.all)
// }
// Send panel
Rectangle()
.foregroundColor(.Material.Shape.black)
.frame(maxWidth: .infinity)
.frame(height: self.selectedItems.isEmpty ? 0 : 50)
.overlay {
HStack {
Text(L10n.Attachment.Send.media)
.foregroundColor(.Material.Text.white)
.font(.body1)
Image(systemName: "arrow.up.circle")
.foregroundColor(.Material.Text.white)
.font(.body1)
.padding(.leading, 8)
}
.padding()
}
.clipped()
.onTapGesture {
// store.dispatch(.sharingAction(.shareMedia(ids: selectedItems)))
// store.dispatch(.sharingAction(.showSharing(false)))
}
}
// .onAppear {
// store.dispatch(.sharingAction(.checkCameraAccess))
// store.dispatch(.sharingAction(.checkGalleryAccess))
// }
// .onChange(of: store.state.sharingState.isGalleryAccessGranted) { granted in
// if granted {
// store.dispatch(.fileAction(.fetchItemsFromGallery))
// }
// }
}
}
private struct GridViewItem: View {
// let item: SharingGalleryItem
@Binding var selected: [String]
@State var isSelected = false
var body: some View {
Text("Test")
// if let data = item.thumbnail {
// ZStack {
// Image(uiImage: UIImage(data: data) ?? UIImage())
// .resizable()
// .aspectRatio(contentMode: .fill)
// .frame(width: Const.galleryGridSize, height: Const.galleryGridSize)
// .clipped()
// if let duration = item.duration {
// VStack {
// Spacer()
// HStack {
// Spacer()
// Text(duration)
// .foregroundColor(.Material.Text.white)
// .font(.sub1)
// .shadow(color: .black, radius: 2)
// .padding(4)
// }
// }
// }
// if isSelected {
// VStack {
// HStack {
// Spacer()
// Circle()
// .frame(width: 30, height: 30)
// .shadow(color: .black, radius: 2)
// .foregroundColor(.Material.Shape.white)
// .overlay {
// Image(systemName: "checkmark")
// .foregroundColor(.Material.Elements.active)
// .font(.body3)
// }
// .padding(4)
// }
// Spacer()
// }
// }
// }
// .onTapGesture {
// isSelected.toggle()
// if isSelected {
// selected.append(item.id)
// } else {
// selected.removeAll { $0 == item.id }
// }
// }
// } else {
// ZStack {
// Rectangle()
// .fill(Color.Material.Background.light)
// .overlay {
// ProgressView()
// .foregroundColor(.Material.Elements.active)
// }
// .frame(width: Const.galleryGridSize, height: Const.galleryGridSize)
// }
// }
}
}
// class CameraUIView: UIView {
// var previewLayer: AVCaptureVideoPreviewLayer?
//
// override func layoutSubviews() {
// super.layoutSubviews()
// previewLayer?.frame = bounds
// }
// }
//
// struct CameraView: UIViewRepresentable {
// func makeUIView(context _: Context) -> CameraUIView {
// let view = CameraUIView()
//
// let captureSession = AVCaptureSession()
// guard let captureDevice = AVCaptureDevice.default(for: .video) else { return view }
// guard let input = try? AVCaptureDeviceInput(device: captureDevice) else { return view }
// captureSession.addInput(input)
//
// let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
// previewLayer.videoGravity = .resizeAspectFill
// view.layer.addSublayer(previewLayer)
// view.previewLayer = previewLayer
//
// captureSession.startRunning()
//
// return view
// }
//
// func updateUIView(_ uiView: CameraUIView, context _: Context) {
// uiView.previewLayer?.frame = uiView.bounds
// }
// }
//
// struct CameraPicker: UIViewControllerRepresentable {
// var sourceType: UIImagePickerController.SourceType
// var completionHandler: (Data, SharingCameraMediaType) -> Void
//
// func makeUIViewController(context: Context) -> UIImagePickerController {
// let picker = UIImagePickerController()
// picker.sourceType = sourceType
// picker.delegate = context.coordinator
// picker.mediaTypes = [UTType.movie.identifier, UTType.image.identifier]
// picker.videoQuality = .typeHigh
// picker.videoMaximumDuration = Const.videoDurationLimit
// picker.view.backgroundColor = .clear
// return picker
// }
//
// func updateUIViewController(_: UIImagePickerController, context _: Context) {}
//
// func makeCoordinator() -> Coordinator {
// Coordinator(self)
// }
//
// class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
// let parent: CameraPicker
//
// init(_ parent: CameraPicker) {
// self.parent = parent
// }
//
// func imagePickerController(_: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
// // swiftlint:disable:next force_cast
// let mediaType = info[.mediaType] as! String
//
// if mediaType == UTType.image.identifier {
// if let image = info[.originalImage] as? UIImage {
// let data = image.jpegData(compressionQuality: 1.0) ?? Data()
// parent.completionHandler(data, .photo)
// }
// } else if mediaType == UTType.movie.identifier {
// if let url = info[.mediaURL] as? URL {
// let data = try? Data(contentsOf: url)
// parent.completionHandler(data ?? Data(), .video)
// }
// }
// }
// }
// }

View file

@ -2,6 +2,7 @@ import SwiftUI
import UIKit import UIKit
struct ConversationTextInput: View { struct ConversationTextInput: View {
@Environment(\.router) var router
@EnvironmentObject var conversation: ConversationStore @EnvironmentObject var conversation: ConversationStore
@State private var messageStr = "" @State private var messageStr = ""
@ -49,7 +50,9 @@ struct ConversationTextInput: View {
.foregroundColor(.Material.Elements.active) .foregroundColor(.Material.Elements.active)
.padding(.leading, 8) .padding(.leading, 8)
.tappablePadding(.symmetric(8)) { .tappablePadding(.symmetric(8)) {
// store.dispatch(.sharingAction(.showSharing(true))) router.showScreen(.fullScreenCover) { _ in
AttachmentPickerScreen()
}
} }
TextField("", text: $messageStr, prompt: Text(L10n.Chat.textfieldPrompt).foregroundColor(.Material.Shape.separator)) TextField("", text: $messageStr, prompt: Text(L10n.Chat.textfieldPrompt).foregroundColor(.Material.Shape.separator))
.font(.body1) .font(.body1)