diff --git a/DouShouQi_App/DouShouQi_App.xcodeproj/project.pbxproj b/DouShouQi_App/DouShouQi_App.xcodeproj/project.pbxproj index 7a59dbd..dc0afa3 100644 --- a/DouShouQi_App/DouShouQi_App.xcodeproj/project.pbxproj +++ b/DouShouQi_App/DouShouQi_App.xcodeproj/project.pbxproj @@ -64,6 +64,7 @@ ECB636512C046379007CD5E2 /* MusicPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB636502C046379007CD5E2 /* MusicPlayer.swift */; }; ECB636532C0463A9007CD5E2 /* SoundPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB636522C0463A9007CD5E2 /* SoundPlayer.swift */; }; ECB636552C047992007CD5E2 /* Image.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ECB636542C047992007CD5E2 /* Image.xcassets */; }; + ECE777142C2068F400D354B0 /* EditPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECE777132C2068F400D354B0 /* EditPlayerView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -145,6 +146,7 @@ ECB636502C046379007CD5E2 /* MusicPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicPlayer.swift; sourceTree = ""; }; ECB636522C0463A9007CD5E2 /* SoundPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundPlayer.swift; sourceTree = ""; }; ECB636542C047992007CD5E2 /* Image.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Image.xcassets; sourceTree = ""; }; + ECE777132C2068F400D354B0 /* EditPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditPlayerView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -260,6 +262,7 @@ 64FC4D682C09C78000D08B8B /* SelectPlayerView.swift */, 645B4C242BFCD3C600FD658A /* ScoreBoardView.swift */, EC62C4FA2C038BD20048CD0B /* PlayersView.swift */, + ECE777132C2068F400D354B0 /* EditPlayerView.swift */, ); path = Player; sourceTree = ""; @@ -630,6 +633,7 @@ 64D992722C06281B002ACBC6 /* SystemIcons.swift in Sources */, 645B4C252BFCD3C600FD658A /* ScoreBoardView.swift in Sources */, 649ABF602BF60F2D002E8894 /* MainMenuButton.swift in Sources */, + ECE777142C2068F400D354B0 /* EditPlayerView.swift in Sources */, EC62C5382C1C64EE0048CD0B /* CoreManager.swift in Sources */, EC62C5252C0F68830048CD0B /* PlayerVM.swift in Sources */, EC62C51B2C09D1790048CD0B /* PlayerStatView.swift in Sources */, diff --git a/DouShouQi_App/DouShouQi_App/AppModelAndExtension/Class/CoreData/CoreManager.swift b/DouShouQi_App/DouShouQi_App/AppModelAndExtension/Class/CoreData/CoreManager.swift index 4e56d90..5aa44cc 100644 --- a/DouShouQi_App/DouShouQi_App/AppModelAndExtension/Class/CoreData/CoreManager.swift +++ b/DouShouQi_App/DouShouQi_App/AppModelAndExtension/Class/CoreData/CoreManager.swift @@ -55,4 +55,39 @@ class CoreDataManager { return [] } } + + func deletePlayer(playerVM: PlayerVM) { + let fetchRequest: NSFetchRequest = CDPlayer.fetchRequest() + fetchRequest.predicate = NSPredicate(format: "name == %@", playerVM.player.name) + + do { + let players = try context.fetch(fetchRequest) + if let playerToDelete = players.first { + context.delete(playerToDelete) + saveContext() + } else { + print("Player not found") + } + } catch { + print("Failed to fetch player for deletion: \(error)") + } + } + + func updatePlayer(playerVM: PlayerVM) { + let fetchRequest: NSFetchRequest = CDPlayer.fetchRequest() + fetchRequest.predicate = NSPredicate(format: "name == %@", playerVM.player.name) + + do { + let players = try context.fetch(fetchRequest) + if let playerToUpdate = players.first { + playerToUpdate.name = playerVM.player.name + playerToUpdate.photo = playerVM.player.photo + saveContext() + } else { + print("Player not found") + } + } catch { + print("Failed to fetch player for update: \(error)") + } + } } diff --git a/DouShouQi_App/DouShouQi_App/Components/Player/PlayerRow.swift b/DouShouQi_App/DouShouQi_App/Components/Player/PlayerRow.swift index 5d01fc4..eebebba 100644 --- a/DouShouQi_App/DouShouQi_App/Components/Player/PlayerRow.swift +++ b/DouShouQi_App/DouShouQi_App/Components/Player/PlayerRow.swift @@ -1,18 +1,11 @@ -// -// PlayerRow.swift -// DouShouQi_App -// -// Created by étudiant on 26/05/2024. -// - import Foundation import SwiftUI struct PlayerRow: View { - var player: PlayerVM - @ObservedObject var players: PlayersVM - + @ObservedObject var player: PlayerVM @State private var showDetailView = false + @ObservedObject var players: PlayersVM + var body: some View { HStack { @@ -36,14 +29,17 @@ struct PlayerRow: View { .font(.subheadline) } Spacer() - Button(action: { - showDetailView.toggle() - }) { - Image(systemName: "info.circle") - .foregroundColor(.blue) - } - .sheet(isPresented: $showDetailView) { - PlayerStatView(player: player) + HStack(spacing: 10) { + Button(action: { + showDetailView.toggle() + }) { + Image(systemName: "info.circle") + .foregroundColor(.blue) + } + .sheet(isPresented: $showDetailView) { + PlayerStatView(player: player, players: players, showDetailView: $showDetailView) + .presentationDetents([.medium, .large]) + } } } .padding() diff --git a/DouShouQi_App/DouShouQi_App/Components/Player/PlayerStatView.swift b/DouShouQi_App/DouShouQi_App/Components/Player/PlayerStatView.swift index ed26d7f..0c7963f 100644 --- a/DouShouQi_App/DouShouQi_App/Components/Player/PlayerStatView.swift +++ b/DouShouQi_App/DouShouQi_App/Components/Player/PlayerStatView.swift @@ -9,7 +9,10 @@ import SwiftUI struct PlayerStatView: View { var player: PlayerVM - + @State private var showEditView = false + @State private var showDeleteAlert = false + @ObservedObject var players: PlayersVM + @Binding var showDetailView: Bool var body: some View { VStack { if let image = UIImage(contentsOfFile: player.player.photo) { @@ -26,12 +29,12 @@ struct PlayerStatView: View { .foregroundColor(.gray) .padding(.top, 10) } - + Text(player.player.name) .font(.largeTitle) .foregroundColor(.black) .padding(.top, 10) - + VStack(alignment: .leading, spacing: 10) { HStack { Image(systemName: "trophy.fill") @@ -53,6 +56,40 @@ struct PlayerStatView: View { Text("Rank : 3") .font(.title2) } + + + HStack{ + Button(action: { + showEditView.toggle() + }) { + Image(systemName: "pencil") + .foregroundColor(.green) + } + .sheet(isPresented: $showEditView) { + EditPlayerView(isPresented: $showEditView, player: player, playersVM: players) + } + + Button(action: { + showDeleteAlert.toggle() + }) { + Image(systemName: "trash") + .foregroundColor(.red) + } + .alert(isPresented: $showDeleteAlert) { + Alert( + title: Text("Delete Player"), + message: Text("Are you sure you want to delete this player?"), + primaryButton: .destructive(Text("Delete")) { + CoreDataManager.shared.deletePlayer(playerVM: player) + players.refreshPlayers() + showDetailView = false + }, + secondaryButton: .cancel() + ) + } + + } + } .padding() Spacer() diff --git a/DouShouQi_App/DouShouQi_App/ViewModel/Players/PlayersVM.swift b/DouShouQi_App/DouShouQi_App/ViewModel/Players/PlayersVM.swift index ec46dfc..e2b7476 100644 --- a/DouShouQi_App/DouShouQi_App/ViewModel/Players/PlayersVM.swift +++ b/DouShouQi_App/DouShouQi_App/ViewModel/Players/PlayersVM.swift @@ -31,17 +31,23 @@ public class PlayersVM: ObservableObject{ return players } + func refreshPlayers() { + let cdPlayers = CoreDataManager.shared.fetchPlayers() + players = cdPlayers.map { PlayerVM(player: Player(name: $0.name ?? "", photo: $0.photo ?? "")) } + } + + func updatePlayer(playerVM: PlayerVM) { + if let index = players.firstIndex(where: { $0.player.name == playerVM.player.name }) { + players[index] = playerVM + CoreDataManager.shared.saveContext() + refreshPlayers() + } + } + init() { players = [] players = getAllPlayer() - - /* let player = PlayerVM(player: Player(name: "Rayhan", photo: "")) - players.append(player) - let player2 = PlayerVM(player: Player(name: "Nathan", photo: "")) - players.append(player2) - let player3 = PlayerVM(player: Player(name: "ayoub", photo: "")) - players.append(player3) */ } } diff --git a/DouShouQi_App/DouShouQi_App/Views/Player/EditPlayerView.swift b/DouShouQi_App/DouShouQi_App/Views/Player/EditPlayerView.swift new file mode 100644 index 0000000..c36319d --- /dev/null +++ b/DouShouQi_App/DouShouQi_App/Views/Player/EditPlayerView.swift @@ -0,0 +1,88 @@ +// +// EditPlayerView.swift +// DouShouQi_App +// +// Created by étudiant on 17/06/2024. +// + +import Foundation +import SwiftUI + +struct EditPlayerView: View { + @Binding var isPresented: Bool + @ObservedObject var player: PlayerVM + @ObservedObject var playersVM: PlayersVM + + @State private var profileImage: UIImage? = nil + @State private var showImagePicker = false + @State private var imagePickerSourceType: UIImagePickerController.SourceType = .photoLibrary + + var body: some View { + VStack(spacing: 20) { + Text("Edit Player") + .font(.headline) + + TextField("Player Name", text: $player.player.name) + .padding() + .background(Color(.systemGray6)) + .cornerRadius(10) + + if let profileImage = profileImage { + Image(uiImage: profileImage) + .resizable() + .frame(width: 100, height: 100) + .clipShape(Circle()) + } else { + Button(action: { + showImagePicker = true + }) { + Text("Select Profile Photo") + .foregroundColor(.white) + .padding() + .background(Color.blue) + .cornerRadius(10) + } + } + + HStack { + Button(action: { + if let image = profileImage, let imageData = image.jpegData(compressionQuality: 0.8) { + let filename = UUID().uuidString + ".jpg" + let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) + let documentsDirectory = paths[0] + let fileURL = documentsDirectory.appendingPathComponent(filename) + try? imageData.write(to: fileURL) + player.player.photo = fileURL.path + } + playersVM.updatePlayer(playerVM: player) + playersVM.refreshPlayers() + isPresented = false + }) { + Text("Save") + .foregroundColor(.white) + .padding() + .background(Color.blue) + .cornerRadius(10) + } + + Button(action: { + isPresented = false + }) { + Text("Cancel") + .foregroundColor(.white) + .padding() + .background(Color.red) + .cornerRadius(10) + } + } + } + .padding() + .frame(maxWidth: 300) + .background(Color.white) + .cornerRadius(20) + .shadow(radius: 10) + .sheet(isPresented: $showImagePicker) { + ImagePicker(image: $profileImage, sourceType: imagePickerSourceType) + } + } +}