From 7919351301ef3e521f18f1d87a68172460b71062 Mon Sep 17 00:00:00 2001 From: NiraliSonani Date: Thu, 2 Jan 2025 17:09:52 +0530 Subject: [PATCH] Store video and image in storage --- Data/Data/DI/AppAssembly.swift | 8 ++++ .../Data/Helper/Firebase/StorageManager.swift | 38 ++++++++++++++----- Data/Data/Repository/ExpenseRepository.swift | 2 +- Data/Data/Repository/FeedbackRepository.swift | 6 +++ Data/Data/Repository/GroupRepository.swift | 2 +- .../Repository/TransactionRepository.swift | 2 +- Data/Data/Repository/UserRepository.swift | 2 +- .../Account/Feedback/FeedbackViewModel.swift | 27 ++++++++++--- 8 files changed, 68 insertions(+), 19 deletions(-) diff --git a/Data/Data/DI/AppAssembly.swift b/Data/Data/DI/AppAssembly.swift index 79fba529..4bedaa15 100644 --- a/Data/Data/DI/AppAssembly.swift +++ b/Data/Data/DI/AppAssembly.swift @@ -61,6 +61,10 @@ public class AppAssembly: Assembly { TransactionStore.init() }.inObjectScope(.container) + container.register(FeedbackStore.self) { _ in + FeedbackStore.init() + }.inObjectScope(.container) + // MARK: - Repositories container.register(UserRepository.self) { _ in @@ -87,6 +91,10 @@ public class AppAssembly: Assembly { TransactionRepository.init() }.inObjectScope(.container) + container.register(FeedbackRepository.self) { _ in + FeedbackRepository.init() + }.inObjectScope(.container) + container.register(DeepLinkManager.self) { _ in DeepLinkManager() }.inObjectScope(.container) diff --git a/Data/Data/Helper/Firebase/StorageManager.swift b/Data/Data/Helper/Firebase/StorageManager.swift index 2bb48cf6..6755927f 100644 --- a/Data/Data/Helper/Firebase/StorageManager.swift +++ b/Data/Data/Helper/Firebase/StorageManager.swift @@ -14,6 +14,7 @@ public class StorageManager: ObservableObject { case group case expense case payment + case feedback var pathName: String { switch self { @@ -25,28 +26,47 @@ public class StorageManager: ObservableObject { "expense_images" case .payment: "payment_images" + case .feedback: + "feedback_attachments" + } + } + } + + public enum AttachmentType { + case image + case video + case other + + var contentType: String { + switch self { + case .image: + return "image/jpg" + case .video: + return "video/mp4" + case .other: + return "application/octet-stream" } } } private let storage = Storage.storage() - public func uploadImage(for storeType: ImageStoreType, id: String, imageData: Data) async throws -> String? { + public func uploadAttachment(for storeType: ImageStoreType, id: String, attachmentData: Data, attachmentType: AttachmentType = .image) async throws -> String? { let storageRef = storage.reference(withPath: "/\(storeType.pathName)/\(id)") let metadata = StorageMetadata() - metadata.contentType = "image/jpg" + metadata.contentType = attachmentType.contentType do { - // Upload the image data asynchronously - _ = try await storageRef.putDataAsync(imageData, metadata: metadata) + // Upload the attachment data asynchronously + _ = try await storageRef.putDataAsync(attachmentData, metadata: metadata) // Retrieve the download URL asynchronously - let imageUrl = try await storageRef.downloadURL().absoluteString - LogD("StorageManager: \(#function) Image successfully uploaded to Firebase.") - return imageUrl + let attachmentUrl = try await storageRef.downloadURL().absoluteString + LogD("StorageManager: \(#function) Attachment successfully uploaded to Firebase.") + return attachmentUrl } catch { - LogE("StorageManager: \(#function) Failed to upload image: \(error).") + LogE("StorageManager: \(#function) Failed to upload attachment: \(error).") throw error } } @@ -55,7 +75,7 @@ public class StorageManager: ObservableObject { try await deleteImage(imageUrl: url) // Upload the new image asynchronously - return try await uploadImage(for: type, id: id, imageData: imageData) + return try await uploadAttachment(for: type, id: id, attachmentData: imageData) } public func deleteImage(imageUrl: String) async throws { diff --git a/Data/Data/Repository/ExpenseRepository.swift b/Data/Data/Repository/ExpenseRepository.swift index 6464e0f7..04df05f7 100644 --- a/Data/Data/Repository/ExpenseRepository.swift +++ b/Data/Data/Repository/ExpenseRepository.swift @@ -63,7 +63,7 @@ public class ExpenseRepository: ObservableObject { private func uploadImage(imageData: Data, expense: Expense) async throws -> String { guard let expenseId = expense.id else { return "" } - return try await storageManager.uploadImage(for: .expense, id: expenseId, imageData: imageData) ?? "" + return try await storageManager.uploadAttachment(for: .expense, id: expenseId, attachmentData: imageData) ?? "" } private func hasExpenseChanged(_ expense: Expense, oldExpense: Expense) -> Bool { diff --git a/Data/Data/Repository/FeedbackRepository.swift b/Data/Data/Repository/FeedbackRepository.swift index dc9cec60..ef5de026 100644 --- a/Data/Data/Repository/FeedbackRepository.swift +++ b/Data/Data/Repository/FeedbackRepository.swift @@ -6,12 +6,18 @@ // import Foundation +import UIKit public class FeedbackRepository: ObservableObject { @Inject private var store: FeedbackStore + @Inject private var storageManager: StorageManager public func addFeedback(feedback: Feedback) async throws { try await store.addFeedback(feedback: feedback) } + + public func uploadAttachment(attachmentId: String, attachmentData: Data, attachmentType: StorageManager.AttachmentType) async throws -> String? { + return try await storageManager.uploadAttachment(for: .feedback, id: attachmentId, attachmentData: attachmentData, attachmentType: attachmentType) + } } diff --git a/Data/Data/Repository/GroupRepository.swift b/Data/Data/Repository/GroupRepository.swift index 45dcc12f..1b471ec0 100644 --- a/Data/Data/Repository/GroupRepository.swift +++ b/Data/Data/Repository/GroupRepository.swift @@ -83,7 +83,7 @@ public class GroupRepository: ObservableObject { guard let groupId = group.id else { return "" } // Upload the image and get the image URL - return try await storageManager.uploadImage(for: .group, id: groupId, imageData: imageData) ?? "" + return try await storageManager.uploadAttachment(for: .group, id: groupId, attachmentData: imageData) ?? "" } public func addMemberToGroup(groupId: String, memberId: String) async throws { diff --git a/Data/Data/Repository/TransactionRepository.swift b/Data/Data/Repository/TransactionRepository.swift index 11ee939b..e277ede1 100644 --- a/Data/Data/Repository/TransactionRepository.swift +++ b/Data/Data/Repository/TransactionRepository.swift @@ -71,7 +71,7 @@ public class TransactionRepository: ObservableObject { private func uploadImage(imageData: Data, transaction: Transactions) async throws -> String { guard let transactionId = transaction.id else { return "" } - return try await storageManager.uploadImage(for: .payment, id: transactionId, imageData: imageData) ?? "" + return try await storageManager.uploadAttachment(for: .payment, id: transactionId, attachmentData: imageData) ?? "" } private func hasTransactionChanged(_ transaction: Transactions, oldTransaction: Transactions) -> Bool { diff --git a/Data/Data/Repository/UserRepository.swift b/Data/Data/Repository/UserRepository.swift index 093113ad..af48f57f 100644 --- a/Data/Data/Repository/UserRepository.swift +++ b/Data/Data/Repository/UserRepository.swift @@ -44,7 +44,7 @@ public class UserRepository: ObservableObject { } private func uploadImage(imageData: Data, user: AppUser) async throws -> AppUser { - let imageURL = try await storageManager.uploadImage(for: .user, id: user.id, imageData: imageData) + let imageURL = try await storageManager.uploadAttachment(for: .user, id: user.id, attachmentData: imageData) var newUser = user newUser.imageUrl = imageURL return try await updateUser(user: newUser) diff --git a/Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift b/Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift index c396868c..13a444fb 100644 --- a/Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift +++ b/Splito/UI/Home/Account/Feedback/FeedbackViewModel.swift @@ -76,11 +76,11 @@ extension FeedbackViewModel { self?.showAlert = false self?.router.pop() })) - LogD("ActivityLogViewModel: \(#function) Activity logs fetched successfully.") + LogD("FeedbackViewModel: \(#function) Feedback submitted successfully.") } catch { self?.showLoader = false self?.showToastForError() - LogE("ActivityLogViewModel: \(#function) Failed to fetch activity logs: \(error).") + LogE("FeedbackViewModel: \(#function) Failed to submit feedback: \(error).") } } } @@ -151,11 +151,11 @@ extension FeedbackViewModel { if let imageData = attachment.image?.jpegRepresentationData { let attachmentData = AttachmentData(data: imageData, attachment: attachment) - upload(attachmentData: attachmentData) + upload(attachmentData: attachmentData, attachmentType: .image) } else if let data = attachment.videoData { if data.count <= VIDEO_SIZE_LIMIT_IN_BYTES { let attachmentData = AttachmentData(data: data, attachment: attachment) - upload(attachmentData: attachmentData) + upload(attachmentData: attachmentData, attachmentType: .video) } else { selectedAttachments.removeAll { $0.id == attachment.id } showToastFor(toast: ToastPrompt(type: .error, title: "Error", message: "The video size exceeds the maximum allowed limit. Please select a smaller video.")) @@ -163,10 +163,25 @@ extension FeedbackViewModel { } } - func upload(attachmentData: AttachmentData) { + public func upload(attachmentData: AttachmentData, attachmentType: StorageManager.AttachmentType) { uploadingAttachments.append(attachmentData.attachment) - // Need to upload + Task { + do { + let attachmentId = attachmentData.attachment.id + let attachmentUrl = try await feedbackRepository.uploadAttachment(attachmentId: attachmentId, attachmentData: attachmentData.data, attachmentType: attachmentType) + + // Update attachment URLs with the uploaded URL + if let attachmentUrl { + self.attachmentsUrls.append(AttachmentInfo(id: attachmentId, url: attachmentUrl)) + self.uploadingAttachments.removeAll { $0.id == attachmentId } + } + } catch { + self.failedAttachments.append(attachmentData.attachment) + self.uploadingAttachments.removeAll { $0.id == attachmentData.attachment.id } + LogE("FeedbackViewModel: \(#function) Failed to upload attachment: \(error)") + } + } } }