Skip to content

Commit

Permalink
Edit group detail
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-amisha-i committed Apr 2, 2024
1 parent f5dfbe8 commit 0bbc456
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 81 deletions.
67 changes: 14 additions & 53 deletions Data/Data/Helper/Firebase/StorageManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,73 +41,34 @@ public class StorageManager: ObservableObject {

storageRef.downloadURL { url, error in
if let error {
print("StorageManager: Download url failed", error)
LogE("StorageManager: Download url failed with error: \(error.localizedDescription)")
completion(nil) // Return nil for completion to indicate error
} else if let imageUrl = url?.absoluteString {
print("StorageManager: Image successfully uploaded to Firebase!")
LogD("StorageManager: Image successfully uploaded to Firebase!")
completion(imageUrl)
}
}
}
}

public func deleteImage(imageUrl: String) {
let storageRef = storage.reference(forURL: imageUrl)
public func updateImage(for type: ImageStoreType, id: String, url: String, imageData: Data, completion: @escaping (String?) -> Void) {
deleteImage(imageUrl: url) { error in
guard error == nil else { completion(nil) ; return }

storageRef.delete { error in
guard error != nil else {
LogE("StorageManager: Error while deleting image: \(error as Any)")
return
}
self.uploadImage(for: type, id: id, imageData: imageData, completion: completion)
}
}

public func listAllFiles(storeType: ImageStoreType) {
let storageRef = storage.reference().child(storeType.pathName)

// List all items in the images folder
storageRef.listAll { (result, error) in
if let error {
LogE("StorageManager: Error while listing all files: \(error)")
}

if let result {
for item in result.items {
LogD("StorageManager: Item in images folder: \(item)")
}
}
}
}

public func listItem(storeType: ImageStoreType) {
let storageRef = storage.reference().child(storeType.pathName)

// Create a completion handler - aka what the function should do after it listed all the items
let _: (StorageListResult, Error?) -> Void = { (result, error) in
if let error {
LogE("StorageManager: error: \(error)")
}

let item = result.items
LogD("StorageManager: item: \(item)")
}

// List the items
storageRef.list(maxResults: 1) { result, error in
if let error {
LogE("StorageManager: error: \(error)")
}

let item = result?.items
LogD("StorageManager: item: \(item as Any)")
}
}
public func deleteImage(imageUrl: String, completion: @escaping (Error?) -> Void) {
let storageRef = storage.reference(forURL: imageUrl)

public func deleteItem(item: StorageReference) {
item.delete { error in
if let error {
LogE("StorageManager: Error deleting item, \(error)")
storageRef.delete { error in
guard error == nil else {
LogE("StorageManager: Error while deleting image: \(error as Any)")
completion(error)
return
}
completion(nil)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Data/Data/Model/Groups.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import FirebaseFirestore

public struct Groups: Codable, Identifiable {
public struct Groups: Codable, Identifiable, Hashable {

@DocumentID public var id: String? // Automatically generated ID by Firestore

Expand Down
48 changes: 41 additions & 7 deletions Data/Data/Repository/GroupRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ public class GroupRepository: ObservableObject {
}.eraseToAnyPublisher()
}

public func addMemberToGroup(memberId: String, groupId: String) -> AnyPublisher<Void, ServiceError> {
public func addMemberToGroup(memberId: String, groupId: String) -> AnyPublisher<String, ServiceError> {
return fetchGroupBy(id: groupId)
.flatMap { group -> AnyPublisher<Void, ServiceError> in
.flatMap { group -> AnyPublisher<String, ServiceError> in
guard let group else { return Fail(error: .dataNotFound).eraseToAnyPublisher() }

var newGroup = group
Expand Down Expand Up @@ -107,7 +107,7 @@ public class GroupRepository: ObservableObject {
userRepository.fetchUserBy(userID: userId)
}

public func updateGroup(group: Groups) -> AnyPublisher<Void, ServiceError> {
public func updateGroup(group: Groups) -> AnyPublisher<String, ServiceError> {
store.updateGroup(group: group)
}

Expand All @@ -127,10 +127,44 @@ public class GroupRepository: ObservableObject {

self.updateGroup(group: newGroup)
.sink { completion in
switch completion {
case .finished:
return
case .failure(let error):
if case .failure(let error) = completion {
promise(.failure(error))
}
} receiveValue: { _ in
promise(.success(()))
}.store(in: &self.cancelable)
}
}.eraseToAnyPublisher()
}

public func updateGroupWithImage(imageData: Data?, group: Groups) -> AnyPublisher<Void, ServiceError> {
Future { [weak self] promise in
guard let self, let url = group.imageUrl else {
promise(.failure(.unexpectedError))
return
}

if let imageData {
self.storageManager.deleteImage(imageUrl: url) { error in
guard error == nil else {
promise(.failure(.databaseError))
return
}

self.uploadImage(imageData: imageData, group: group)
.sink { completion in
if case .failure(let error) = completion {
promise(.failure(error))
}
} receiveValue: { _ in
promise(.success(()))
}
.store(in: &self.cancelable)
}
} else {
self.updateGroup(group: group)
.sink { completion in
if case .failure(let error) = completion {
promise(.failure(error))
}
} receiveValue: { _ in
Expand Down
2 changes: 1 addition & 1 deletion Data/Data/Router/AppRoute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public enum AppRoute: Hashable {
// MARK: - Groups Tab
case GroupListView
case GroupHomeView(groupId: String)
case CreateGroupView
case CreateGroupView(group: Groups?)
case InviteMemberView(groupId: String)
case JoinMemberView
case GroupSettingView(groupId: String)
Expand Down
4 changes: 2 additions & 2 deletions Data/Data/Store/GroupStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ class GroupStore: ObservableObject {
completion(nil)
}

func updateGroup(group: Groups) -> AnyPublisher<Void, ServiceError> {
func updateGroup(group: Groups) -> AnyPublisher<String, ServiceError> {
Future { [weak self] promise in
guard let self, let docID = group.id else {
promise(.failure(.unexpectedError))
return
}
do {
try self.database.collection(self.DATABASE_NAME).document(docID).setData(from: group, merge: true)
promise(.success(()))
promise(.success(docID))
} catch {
LogE("GroupStore :: \(#function) error: \(error.localizedDescription)")
promise(.failure(.databaseError))
Expand Down
17 changes: 12 additions & 5 deletions Splito/UI/Home/Groups/Create Group/CreateGroupView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import SwiftUI
import BaseStyle
import Kingfisher

struct CreateGroupView: View {

Expand All @@ -20,18 +21,19 @@ struct CreateGroupView: View {
VStack(spacing: 40) {
VSpacer(30)

AddGroupNameView(image: viewModel.profileImage, groupName: $viewModel.groupName, handleProfileTap: viewModel.handleProfileTap)
AddGroupNameView(image: viewModel.profileImage, imageUrl: viewModel.profileImageUrl,
groupName: $viewModel.groupName, handleProfileTap: viewModel.handleProfileTap)

Spacer()
}
.padding(.horizontal, 20)
.frame(maxWidth: isIpad ? 600 : nil, alignment: .center)
.navigationBarTitle("Create a group", displayMode: .inline)
}
}
.background(surfaceColor)
.toastView(toast: $viewModel.toast)
.backport.alert(isPresented: $viewModel.showAlert, alertStruct: viewModel.alert)
.frame(maxWidth: isIpad ? 600 : nil, alignment: .center)
.navigationBarTitle(viewModel.group == nil ? "Create a group" : "Edit group", displayMode: .inline)
.onTapGesture {
UIApplication.shared.endEditing()
}
Expand Down Expand Up @@ -72,6 +74,7 @@ struct CreateGroupView: View {
private struct AddGroupNameView: View {

var image: UIImage?
var imageUrl: String?
@Binding var groupName: String

let handleProfileTap: (() -> Void)
Expand All @@ -82,7 +85,11 @@ private struct AddGroupNameView: View {
RoundedRectangle(cornerRadius: 8)
.stroke(style: StrokeStyle(lineWidth: 1, dash: [4]))

if let image {
if let imageUrl, let url = URL(string: imageUrl) {
KFImage(url)
.resizable()
.aspectRatio(contentMode: .fill)
} else if let image {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
Expand Down Expand Up @@ -119,5 +126,5 @@ private struct AddGroupNameView: View {
}

#Preview {
CreateGroupView(viewModel: CreateGroupViewModel(router: .init(root: .CreateGroupView)))
CreateGroupView(viewModel: CreateGroupViewModel(router: .init(root: .CreateGroupView(group: nil))))
}
44 changes: 37 additions & 7 deletions Splito/UI/Home/Groups/Create Group/CreateGroupViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ class CreateGroupViewModel: BaseViewModel, ObservableObject {
@Inject var storageManager: StorageManager
@Inject var groupRepository: GroupRepository

@Published var groupName = ""
@Published var sourceTypeIsCamera = false
@Published var showImagePicker = false
@Published var showImagePickerOptions = false

@Published var groupName = ""
@Published var profileImage: UIImage?
@Published var profileImageUrl: String?

@Published var group: Groups?
@Published var currentState: ViewState = .initial
Expand All @@ -39,10 +41,13 @@ class CreateGroupViewModel: BaseViewModel, ObservableObject {

init(router: Router<AppRoute>, group: Groups? = nil) {
self.router = router
self.group = group
self.groupName = group?.name ?? ""
self.profileImageUrl = group?.imageUrl
super.init()
}

func checkCameraPermission(authorized: @escaping (() -> Void)) {
private func checkCameraPermission(authorized: @escaping (() -> Void)) {
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { granted in
Expand Down Expand Up @@ -85,6 +90,14 @@ class CreateGroupViewModel: BaseViewModel, ObservableObject {

/// Create a new group
func handleDoneAction() {
if let group {
updateGroup(group: group)
} else {
createGroup()
}
}

private func createGroup() {
currentState = .loading
let userId = preference.user?.id ?? ""
let group = Groups(name: groupName.capitalized, createdBy: userId, members: [userId], imageUrl: nil, createdAt: Timestamp())
Expand All @@ -94,10 +107,7 @@ class CreateGroupViewModel: BaseViewModel, ObservableObject {

groupRepository.createGroup(group: group, imageData: imageData)
.sink { [weak self] completion in
switch completion {
case .finished:
return
case .failure(let error):
if case .failure(let error) = completion {
self?.currentState = .initial
self?.showAlertFor(error)
}
Expand All @@ -106,7 +116,27 @@ class CreateGroupViewModel: BaseViewModel, ObservableObject {
}.store(in: &cancelable)
}

func goToGroupHome(groupId: String) {
private func updateGroup(group: Groups) {
currentState = .loading

var newGroup = group
newGroup.name = groupName

let resizedImage = profileImage?.aspectFittedToHeight(200)
let imageData = resizedImage?.jpegData(compressionQuality: 0.2)

groupRepository.updateGroupWithImage(imageData: imageData, group: newGroup)
.sink { [weak self] completion in
if case .failure(let error) = completion {
self?.currentState = .initial
self?.showAlertFor(error)
}
} receiveValue: { _ in
self.router.pop()
}.store(in: &cancelable)
}

private func goToGroupHome(groupId: String) {
self.router.pop()
self.router.push(.GroupHomeView(groupId: groupId))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ struct GroupSettingView: View {
VSpacer(20)

GroupTitleView(group: group)
.onTapGesture {
viewModel.handleEditGroupTap()
}

Divider()
.frame(height: 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class GroupSettingViewModel: BaseViewModel, ObservableObject {
}
} receiveValue: { [weak self] group in
guard let self, let group else { return }
self.group = group
self.currentViewState = .success(group: group)
}.store(in: &cancelable)
}
Expand All @@ -62,7 +63,7 @@ class GroupSettingViewModel: BaseViewModel, ObservableObject {
}

func handleEditGroupTap() {
router.push(.CreateGroupView)
router.push(.CreateGroupView(group: group))
}

func handleAddMemberTap() {
Expand Down
2 changes: 1 addition & 1 deletion Splito/UI/Home/Groups/Group/GroupHomeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class GroupHomeViewModel: BaseViewModel, ObservableObject {
}

func handleCreateGroupClick() {
router.push(.CreateGroupView)
router.push(.CreateGroupView(group: nil))
}

func handleAddMemberClick() {
Expand Down
2 changes: 1 addition & 1 deletion Splito/UI/Home/Groups/GroupListViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class GroupListViewModel: BaseViewModel, ObservableObject {
}

func handleCreateGroupBtnTap() {
router.push(.CreateGroupView)
router.push(.CreateGroupView(group: nil))
}

func handleJoinGroupBtnTap() {
Expand Down
4 changes: 2 additions & 2 deletions Splito/UI/Home/Groups/GroupRouteView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ struct GroupRouteView: View {
GroupListView(viewModel: GroupListViewModel(router: appRoute))
case .GroupHomeView(let id):
GroupHomeView(viewModel: GroupHomeViewModel(router: appRoute, groupId: id))
case .CreateGroupView:
CreateGroupView(viewModel: CreateGroupViewModel(router: appRoute))
case .CreateGroupView(let group):
CreateGroupView(viewModel: CreateGroupViewModel(router: appRoute, group: group))
case .InviteMemberView(let id):
InviteMemberView(viewModel: InviteMemberViewModel(router: appRoute, groupId: id))
case .JoinMemberView:
Expand Down

0 comments on commit 0bbc456

Please sign in to comment.