diff --git a/ArkitDoushiQi/ArkitDoushiQi.xcodeproj/project.pbxproj b/ArkitDoushiQi/ArkitDoushiQi.xcodeproj/project.pbxproj index 107c71d..baed39e 100644 --- a/ArkitDoushiQi/ArkitDoushiQi.xcodeproj/project.pbxproj +++ b/ArkitDoushiQi/ArkitDoushiQi.xcodeproj/project.pbxproj @@ -29,7 +29,9 @@ C24DAB5E2C061E3A00681CD0 /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24DAB5D2C061E3A00681CD0 /* Language.swift */; }; C24DAB622C062DBC00681CD0 /* ProfileEdit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24DAB612C062DBC00681CD0 /* ProfileEdit.swift */; }; C25220EE2C00AC7E0026B71F /* GameParametersMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25220ED2C00AC7E0026B71F /* GameParametersMenuView.swift */; }; - C25220F32C00AF490026B71F /* EditComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25220F22C00AF490026B71F /* EditComponent.swift */; }; + C25220F32C00AF490026B71F /* EditTextComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25220F22C00AF490026B71F /* EditTextComponent.swift */; }; + C2F015042C09BC6B000F7221 /* KeyboardReadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F015032C09BC6B000F7221 /* KeyboardReadable.swift */; }; + C2F015062C09C384000F7221 /* EditImageComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F015052C09C384000F7221 /* EditImageComponent.swift */; }; C2F394082C0462400070B4F6 /* PhotoButtonComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F394072C0462400070B4F6 /* PhotoButtonComponent.swift */; }; C2F3940B2C0463940070B4F6 /* ProfileComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F3940A2C0463940070B4F6 /* ProfileComponent.swift */; }; /* End PBXBuildFile section */ @@ -77,7 +79,9 @@ C24DAB5D2C061E3A00681CD0 /* Language.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = ""; }; C24DAB612C062DBC00681CD0 /* ProfileEdit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileEdit.swift; sourceTree = ""; }; C25220ED2C00AC7E0026B71F /* GameParametersMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameParametersMenuView.swift; sourceTree = ""; }; - C25220F22C00AF490026B71F /* EditComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditComponent.swift; sourceTree = ""; }; + C25220F22C00AF490026B71F /* EditTextComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditTextComponent.swift; sourceTree = ""; }; + C2F015032C09BC6B000F7221 /* KeyboardReadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardReadable.swift; sourceTree = ""; }; + C2F015052C09C384000F7221 /* EditImageComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditImageComponent.swift; sourceTree = ""; }; C2F394072C0462400070B4F6 /* PhotoButtonComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoButtonComponent.swift; sourceTree = ""; }; C2F3940A2C0463940070B4F6 /* ProfileComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileComponent.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -178,6 +182,7 @@ C205A2BC2BF373380097BD93 /* Views */ = { isa = PBXGroup; children = ( + C2F015022C09BC56000F7221 /* EventTriggers */, C24DAB5A2C061DAA00681CD0 /* Enum */, C25220F02C00AD7F0026B71F /* Components */, C25220EC2C00AC530026B71F /* GameParametersMenu */, @@ -254,12 +259,21 @@ C20310D52BFCB5FB0031657D /* PickerComponent.swift */, C20310D92BFCC8600031657D /* ToggleComponent.swift */, C24659E82BF60FAA004E80D5 /* ButtonComponent.swift */, - C25220F22C00AF490026B71F /* EditComponent.swift */, + C25220F22C00AF490026B71F /* EditTextComponent.swift */, C2F394072C0462400070B4F6 /* PhotoButtonComponent.swift */, + C2F015052C09C384000F7221 /* EditImageComponent.swift */, ); path = Controls; sourceTree = ""; }; + C2F015022C09BC56000F7221 /* EventTriggers */ = { + isa = PBXGroup; + children = ( + C2F015032C09BC6B000F7221 /* KeyboardReadable.swift */, + ); + path = EventTriggers; + sourceTree = ""; + }; C2F394092C04636C0070B4F6 /* Visuals */ = { isa = PBXGroup; children = ( @@ -402,6 +416,7 @@ C205A2B92BF373360097BD93 /* ContentView.swift in Sources */, 82CE59EF2C0460E500ADEE24 /* SpriteMoople.swift in Sources */, 82CE59E92C045D1100ADEE24 /* GameScene.swift in Sources */, + C2F015062C09C384000F7221 /* EditImageComponent.swift in Sources */, 82F9D3312BFE3A9F009EDFAF /* HistoryGameDetail.swift in Sources */, C24659E92BF60FAA004E80D5 /* ButtonComponent.swift in Sources */, C24DAB5E2C061E3A00681CD0 /* Language.swift in Sources */, @@ -410,9 +425,10 @@ 82F9D3362BFE3B3C009EDFAF /* HistoryView.swift in Sources */, C20310D82BFCC2410031657D /* GeneralParametersMenuView.swift in Sources */, C2F3940B2C0463940070B4F6 /* ProfileComponent.swift in Sources */, + C2F015042C09BC6B000F7221 /* KeyboardReadable.swift in Sources */, C205A2B72BF373360097BD93 /* ArkitDoushiQiApp.swift in Sources */, C24DAB5C2C061DC700681CD0 /* AI.swift in Sources */, - C25220F32C00AF490026B71F /* EditComponent.swift in Sources */, + C25220F32C00AF490026B71F /* EditTextComponent.swift in Sources */, C20310D62BFCB5FB0031657D /* PickerComponent.swift in Sources */, 82F9D3332BFE3B12009EDFAF /* HistoryHeader.swift in Sources */, 82CE59EB2C045E3800ADEE24 /* GameView.swift in Sources */, diff --git a/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditImageComponent.swift b/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditImageComponent.swift new file mode 100644 index 0000000..113e6dd --- /dev/null +++ b/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditImageComponent.swift @@ -0,0 +1,74 @@ +// +// EditImageComponent.swift +// ArkitDoushiQi +// +// Created by Johan LACHENAL on 31/05/2024. +// + +import SwiftUI +import PhotosUI + +struct EditImageComponent: View { + @State private var avatarItem: PhotosPickerItem? + @State private var avatarImage: Image? + let color: Color + let profileWidth: CGFloat + let profileHeight: CGFloat + let defaultImage: Image + let imageTextChange: String + var body: some View { + HStack { + + VStack { + HStack { + GeometryReader { geometry in + ZStack { + // Background color + color + + // Profile Image + ProfileComponent(color: color, profileWidth: profileWidth, profileHeight: profileHeight, image: avatarImage ?? defaultImage + ) + } + // Ensure the ZStack takes the size of the GeometryReader + .frame(width: geometry.size.width, height: geometry.size.height) + .clipShape(Circle()) + } + .aspectRatio(1, contentMode: .fit) + .frame(width: profileWidth, height: profileHeight) // Optional fixed size + + PhotosPicker(selection: $avatarItem, matching: .images) { + Text(imageTextChange) + } + .onChange(of: avatarItem) { newValue in + if let newItem = newValue { + Task { + if let data = try? await newItem.loadTransferable(type: Data.self), + let uiImage = UIImage(data: data) { + avatarImage = Image(uiImage: uiImage) + } else { + print("Failed to load image") + } + } + } + } + } + } + } + } +} + +struct EditImageComponent_Previews: PreviewProvider { + static var previews: some View { + EditImageComponent( + color: Color(.red), + profileWidth: 100, + profileHeight: 100, + defaultImage: Image("profil"), + imageTextChange: "Changer d'avatar" + ) + .previewLayout(.sizeThatFits) + .padding() + } +} + diff --git a/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditComponent.swift b/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditTextComponent.swift similarity index 75% rename from ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditComponent.swift rename to ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditTextComponent.swift index 60d522d..a16a7fb 100644 --- a/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditComponent.swift +++ b/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Controls/EditTextComponent.swift @@ -7,7 +7,7 @@ import SwiftUI -struct EditComponent: View { +struct EditTextComponent: View { let explanation : String @State private var name : String init(explanation: String, value: String) { @@ -23,8 +23,8 @@ struct EditComponent: View { } } -struct EditComponent_Previews: PreviewProvider { +struct EditTextComponent_Previews: PreviewProvider { static var previews: some View { - EditComponent(explanation: "Nom du Joueur 1", value: "Joueur 1") + EditTextComponent(explanation: "Nom du Joueur 1", value: "Joueur 1") } } diff --git a/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Visuals/ProfileComponent.swift b/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Visuals/ProfileComponent.swift index 242d2f8..96e5811 100644 --- a/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Visuals/ProfileComponent.swift +++ b/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Visuals/ProfileComponent.swift @@ -8,10 +8,10 @@ import SwiftUI struct ProfileComponent: View { - let imageName: String let color : Color let profileWidth : CGFloat let profileHeight : CGFloat + let image : Image var body: some View { GeometryReader { geometry in ZStack { @@ -19,7 +19,7 @@ struct ProfileComponent: View { color // Profile Image - Image(imageName) + image .resizable() .scaledToFill() .clipShape(Circle()) @@ -37,10 +37,10 @@ struct ProfileComponent: View { struct ProfileComponent_Previews: PreviewProvider { static var previews: some View { ProfileComponent( - imageName: "profil", color: Color(.red), profileWidth: 200, - profileHeight : 200 + profileHeight : 200, + image: Image("profil") ) .previewLayout(.sizeThatFits) .padding() diff --git a/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Visuals/ProfileEdit.swift b/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Visuals/ProfileEdit.swift index 35987fe..4da9202 100644 --- a/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Visuals/ProfileEdit.swift +++ b/ArkitDoushiQi/ArkitDoushiQi/Views/Components/Visuals/ProfileEdit.swift @@ -8,20 +8,36 @@ import SwiftUI struct ProfileEdit: View { + let color : Color + let profileWidth : CGFloat + let profileHeight : CGFloat + let defaultImage: Image + let imageTextChange : String var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) - } -} - -struct ProfileEdit_Previews: PreviewProvider { - static var previews: some View { - VStack { - ProfileComponent(imageName: "profil", color: Color(.red), profileWidth: 100, profileHeight: 100) + VStack(alignment: .leading) { + EditImageComponent( + color: color, + profileWidth: profileWidth, + profileHeight: profileHeight, + defaultImage: defaultImage, + imageTextChange: imageTextChange + ).padding(EdgeInsets(top: 0, leading: 32, bottom: 0, trailing: 32)) VStack(alignment: .trailing) { HStack { - EditComponent(explanation: "Nom du Joueur 1", value: "Joueur 1") + EditTextComponent(explanation: "Nom du Joueur 1", value: "Joueur 1") } } } } } + +struct ProfileEdit_Previews: PreviewProvider { + static var previews: some View { + ProfileEdit(color: Color(.red), + profileWidth: 100, + profileHeight: 100, + defaultImage: Image("profil"), + imageTextChange: "Changer d'avatar" + ) + } +} diff --git a/ArkitDoushiQi/ArkitDoushiQi/Views/EventTriggers/KeyboardReadable.swift b/ArkitDoushiQi/ArkitDoushiQi/Views/EventTriggers/KeyboardReadable.swift new file mode 100644 index 0000000..dec17a6 --- /dev/null +++ b/ArkitDoushiQi/ArkitDoushiQi/Views/EventTriggers/KeyboardReadable.swift @@ -0,0 +1,31 @@ +// +// KeyboardReadable.swift +// ArkitDoushiQi +// +// Created by Johan LACHENAL on 31/05/2024. +// + +import Foundation +import Combine +import UIKit + + +// Publisher to read keyboard changes. +protocol KeyboardReadable { + var keyboardPublisher: AnyPublisher { get } +} + +extension KeyboardReadable { + var keyboardPublisher: AnyPublisher { + Publishers.Merge( + NotificationCenter.default + .publisher(for: UIResponder.keyboardWillShowNotification) + .map { _ in true }, + + NotificationCenter.default + .publisher(for: UIResponder.keyboardWillHideNotification) + .map { _ in false } + ) + .eraseToAnyPublisher() + } +} diff --git a/ArkitDoushiQi/ArkitDoushiQi/Views/GameParametersMenu/GameParametersMenuView.swift b/ArkitDoushiQi/ArkitDoushiQi/Views/GameParametersMenu/GameParametersMenuView.swift index 0c04497..13d6346 100644 --- a/ArkitDoushiQi/ArkitDoushiQi/Views/GameParametersMenu/GameParametersMenuView.swift +++ b/ArkitDoushiQi/ArkitDoushiQi/Views/GameParametersMenu/GameParametersMenuView.swift @@ -22,9 +22,10 @@ enum Rules: String, CaseIterable, Identifiable, Hashable { var id: String { self.rawValue } } -struct GameParametersMenuView: View { +struct GameParametersMenuView: View, KeyboardReadable { @State private var selectedAIOption: AIT = .RandomAction @State private var selectedRulesOption: Rules = .Regular + @State private var isKeyboardVisible = false var body: some View { NavigationView { VStack(alignment: .leading) { @@ -37,24 +38,16 @@ struct GameParametersMenuView: View { PickerComponent(title: "Sélectionne une IA :", selectedOption: $selectedAIOption, options: AIT.allCases) - ProfileComponent( - imageName: "profil", - color: Color(.red), - profileWidth: 100, - profileHeight : 100 - ) - EditComponent(explanation: "Nom du joueur 1", value: "Joueur 1").frame(width: .infinity,height: 100) - ProfileComponent( - imageName: "profil", - color: Color(.red), - profileWidth: 100, - profileHeight : 100 - ) - EditComponent(explanation: "Nom du joueur 2",value: "Joueur 2").frame(width: .infinity,height: 100) - ButtonComponent(title: "Lancer la partie") { - GameView() - }.padding(EdgeInsets(top: 10, leading: 32, bottom: 10, trailing: 32)) + ProfileEdit(color: Color(.red), profileWidth: 100, profileHeight: 100, defaultImage: Image("profil"), imageTextChange: "changer l'avatar du joueur 1") + ProfileEdit(color: Color(.blue), profileWidth: 100, profileHeight: 100, defaultImage: Image("profil"), imageTextChange: "changer l'avatar du joueur 2") + if !isKeyboardVisible + { + ButtonComponent(title: "Lancer la partie") { + GameView() + }.padding(EdgeInsets(top: 10, leading: 32, bottom: 10, trailing: 32)) + } } + .onReceive(keyboardPublisher) { value in isKeyboardVisible = value } .frame(maxHeight: .infinity, alignment: .top) } }