diff --git a/src/App/App.xcodeproj/project.pbxproj b/src/App/App.xcodeproj/project.pbxproj index 22cfc71..27c34a6 100644 --- a/src/App/App.xcodeproj/project.pbxproj +++ b/src/App/App.xcodeproj/project.pbxproj @@ -14,14 +14,17 @@ 1E0D88F42A1E759F00786FE3 /* AppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0D88F32A1E759F00786FE3 /* AppTests.swift */; }; 1E0D88FE2A1E75A000786FE3 /* AppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0D88FD2A1E75A000786FE3 /* AppUITests.swift */; }; 1E0D89002A1E75A000786FE3 /* AppUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0D88FF2A1E75A000786FE3 /* AppUITestsLaunchTests.swift */; }; - 1E0D890F2A1E7B9C00786FE3 /* Model in Frameworks */ = {isa = PBXBuildFile; productRef = 1E0D890E2A1E7B9C00786FE3 /* Model */; }; - 1E0D89132A1E7C4500786FE3 /* CalculatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0D89122A1E7C4500786FE3 /* CalculatorView.swift */; }; 1E0D89152A1E7F5800786FE3 /* BlocListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0D89142A1E7F5800786FE3 /* BlocListItem.swift */; }; 1E0D89172A1E838700786FE3 /* UEListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0D89162A1E838700786FE3 /* UEListItem.swift */; }; 1E0D891B2A1E9BEF00786FE3 /* UEView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0D891A2A1E9BEF00786FE3 /* UEView.swift */; }; - 1E160AB22A1FA51600ECDB3F /* NoteSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E160AB12A1FA51600ECDB3F /* NoteSlider.swift */; }; - 1E4D71792A29E50A008342F0 /* UEEditSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4D71782A29E50A008342F0 /* UEEditSheet.swift */; }; - 1EDC99232A20DDAB00C3561D /* NoteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EDC99222A20DDAB00C3561D /* NoteInfo.swift */; }; + 1E160AB22A1FA51600ECDB3F /* UENoteSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E160AB12A1FA51600ECDB3F /* UENoteSlider.swift */; }; + 1E1FF22F2A3221BB0046EBE0 /* Stub in Frameworks */ = {isa = PBXBuildFile; productRef = 1E1FF22E2A3221BB0046EBE0 /* Stub */; }; + 1E47C4572A3605E3000B9AAA /* MatiereInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E47C4562A3605E3000B9AAA /* MatiereInfo.swift */; }; + 1E4D71792A29E50A008342F0 /* UEEdit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4D71782A29E50A008342F0 /* UEEdit.swift */; }; + 1E96424E2A3DFD0100199C75 /* Exemple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E96424D2A3DFD0000199C75 /* Exemple.swift */; }; + 1EC2337A2A35BCB9006AE897 /* ViewModel in Frameworks */ = {isa = PBXBuildFile; productRef = 1EC233792A35BCB9006AE897 /* ViewModel */; }; + 1ECAD3A12A38FB0B00B61BF8 /* MatiereNoteSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ECAD3A02A38FB0B00B61BF8 /* MatiereNoteSlider.swift */; }; + 1EDC99232A20DDAB00C3561D /* UEInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EDC99222A20DDAB00C3561D /* UEInfo.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -52,13 +55,15 @@ 1E0D88F92A1E759F00786FE3 /* AppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1E0D88FD2A1E75A000786FE3 /* AppUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUITests.swift; sourceTree = ""; }; 1E0D88FF2A1E75A000786FE3 /* AppUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUITestsLaunchTests.swift; sourceTree = ""; }; - 1E0D89122A1E7C4500786FE3 /* CalculatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorView.swift; sourceTree = ""; }; 1E0D89142A1E7F5800786FE3 /* BlocListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlocListItem.swift; sourceTree = ""; }; 1E0D89162A1E838700786FE3 /* UEListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UEListItem.swift; sourceTree = ""; }; 1E0D891A2A1E9BEF00786FE3 /* UEView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UEView.swift; sourceTree = ""; }; - 1E160AB12A1FA51600ECDB3F /* NoteSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteSlider.swift; sourceTree = ""; }; - 1E4D71782A29E50A008342F0 /* UEEditSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UEEditSheet.swift; sourceTree = ""; }; - 1EDC99222A20DDAB00C3561D /* NoteInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteInfo.swift; sourceTree = ""; }; + 1E160AB12A1FA51600ECDB3F /* UENoteSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UENoteSlider.swift; sourceTree = ""; }; + 1E47C4562A3605E3000B9AAA /* MatiereInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatiereInfo.swift; sourceTree = ""; }; + 1E4D71782A29E50A008342F0 /* UEEdit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UEEdit.swift; sourceTree = ""; }; + 1E96424D2A3DFD0000199C75 /* Exemple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exemple.swift; sourceTree = ""; }; + 1ECAD3A02A38FB0B00B61BF8 /* MatiereNoteSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatiereNoteSlider.swift; sourceTree = ""; }; + 1EDC99222A20DDAB00C3561D /* UEInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UEInfo.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -66,7 +71,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1E0D890F2A1E7B9C00786FE3 /* Model in Frameworks */, + 1E1FF22F2A3221BB0046EBE0 /* Stub in Frameworks */, + 1EC2337A2A35BCB9006AE897 /* ViewModel in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -155,13 +161,15 @@ 1E0D89112A1E7C0800786FE3 /* Views */ = { isa = PBXGroup; children = ( - 1E0D89122A1E7C4500786FE3 /* CalculatorView.swift */, 1E0D89142A1E7F5800786FE3 /* BlocListItem.swift */, 1E0D89162A1E838700786FE3 /* UEListItem.swift */, 1E0D891A2A1E9BEF00786FE3 /* UEView.swift */, - 1E160AB12A1FA51600ECDB3F /* NoteSlider.swift */, - 1EDC99222A20DDAB00C3561D /* NoteInfo.swift */, - 1E4D71782A29E50A008342F0 /* UEEditSheet.swift */, + 1E160AB12A1FA51600ECDB3F /* UENoteSlider.swift */, + 1EDC99222A20DDAB00C3561D /* UEInfo.swift */, + 1E4D71782A29E50A008342F0 /* UEEdit.swift */, + 1E47C4562A3605E3000B9AAA /* MatiereInfo.swift */, + 1ECAD3A02A38FB0B00B61BF8 /* MatiereNoteSlider.swift */, + 1E96424D2A3DFD0000199C75 /* Exemple.swift */, ); path = Views; sourceTree = ""; @@ -183,7 +191,8 @@ ); name = App; packageProductDependencies = ( - 1E0D890E2A1E7B9C00786FE3 /* Model */, + 1E1FF22E2A3221BB0046EBE0 /* Stub */, + 1EC233792A35BCB9006AE897 /* ViewModel */, ); productName = App; productReference = 1E0D88DF2A1E759A00786FE3 /* AverageCalculator.app */; @@ -299,14 +308,16 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1E160AB22A1FA51600ECDB3F /* NoteSlider.swift in Sources */, + 1ECAD3A12A38FB0B00B61BF8 /* MatiereNoteSlider.swift in Sources */, + 1E160AB22A1FA51600ECDB3F /* UENoteSlider.swift in Sources */, + 1E47C4572A3605E3000B9AAA /* MatiereInfo.swift in Sources */, 1E0D89152A1E7F5800786FE3 /* BlocListItem.swift in Sources */, 1E0D88E52A1E759A00786FE3 /* ContentView.swift in Sources */, - 1E0D89132A1E7C4500786FE3 /* CalculatorView.swift in Sources */, 1E0D88E32A1E759A00786FE3 /* AppApp.swift in Sources */, - 1EDC99232A20DDAB00C3561D /* NoteInfo.swift in Sources */, + 1EDC99232A20DDAB00C3561D /* UEInfo.swift in Sources */, 1E0D891B2A1E9BEF00786FE3 /* UEView.swift in Sources */, - 1E4D71792A29E50A008342F0 /* UEEditSheet.swift in Sources */, + 1E96424E2A3DFD0100199C75 /* Exemple.swift in Sources */, + 1E4D71792A29E50A008342F0 /* UEEdit.swift in Sources */, 1E0D89172A1E838700786FE3 /* UEListItem.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -630,9 +641,13 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - 1E0D890E2A1E7B9C00786FE3 /* Model */ = { + 1E1FF22E2A3221BB0046EBE0 /* Stub */ = { isa = XCSwiftPackageProductDependency; - productName = Model; + productName = Stub; + }; + 1EC233792A35BCB9006AE897 /* ViewModel */ = { + isa = XCSwiftPackageProductDependency; + productName = ViewModel; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/src/App/App.xcodeproj/xcuserdata/djyohann.xcuserdatad/xcschemes/xcschememanagement.plist b/src/App/App.xcodeproj/xcuserdata/djyohann.xcuserdatad/xcschemes/xcschememanagement.plist index 74c9b79..b04f406 100644 --- a/src/App/App.xcodeproj/xcuserdata/djyohann.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/src/App/App.xcodeproj/xcuserdata/djyohann.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ App.xcscheme_^#shared#^_ orderHint - 3 + 0 diff --git a/src/App/App/AppApp.swift b/src/App/App/AppApp.swift index 448d169..efe67fd 100644 --- a/src/App/App/AppApp.swift +++ b/src/App/App/AppApp.swift @@ -1,17 +1,12 @@ -// -// AppApp.swift -// App -// -// Created by BREUIL Yohann on 24/05/2023. -// - import SwiftUI +import ViewModel +import Stub @main struct AppApp: App { var body: some Scene { WindowGroup { - ContentView() + ContentView(odin: OdinVM(blocs: Stub().loadBlocs())) } } } diff --git a/src/App/App/ContentView.swift b/src/App/App/ContentView.swift index 749c06f..058a4d5 100644 --- a/src/App/App/ContentView.swift +++ b/src/App/App/ContentView.swift @@ -1,20 +1,26 @@ -// -// ContentView.swift -// App -// -// Created by BREUIL Yohann on 24/05/2023. -// - import SwiftUI +import ViewModel +import Stub struct ContentView: View { + @StateObject var odin: OdinVM + var body: some View { - CalculatorView() + NavigationStack { + ScrollView { + BlocListItem(odin: odin) + Divider() + UEListItem(odin: odin) + } + .navigationTitle("Calculette") + } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView() + let odinVM = OdinVM(blocs: Stub().loadBlocs()) + + ContentView(odin: odinVM) } } diff --git a/src/App/Views/BlocListItem.swift b/src/App/Views/BlocListItem.swift index c57f9f5..56d23ab 100644 --- a/src/App/Views/BlocListItem.swift +++ b/src/App/Views/BlocListItem.swift @@ -1,22 +1,22 @@ import SwiftUI +import Stub +import ViewModel struct BlocListItem: View { + @StateObject var odin: OdinVM + var body: some View { VStack(alignment: .leading) { Label("Blocs", systemImage: "doc.on.doc.fill") .font(.title) Text("Vous devez avoir la moyenne à chacun de ces blocs pour avoir votre diplôme.") - HStack { - Label("Total", systemImage: "doc.on.doc.fill") - Spacer() - Text("11.67") - Image(systemName: "graduationcap.circle.fill") - } - HStack { - Label("Total", systemImage: "doc.on.doc.fill") - Spacer() - Text("11.67") - Image(systemName: "graduationcap.circle.fill") + ForEach(odin.blocsVM) { blocVM in + HStack { + Label("\(blocVM.name)", systemImage: "doc.on.doc.fill") + Spacer() + Text("\(String(format: "%.2f", blocVM.average))") + Image(systemName: "graduationcap.circle.fill") + } } } .padding() @@ -27,6 +27,8 @@ struct BlocListItem: View { struct BlocListItem_Previews: PreviewProvider { static var previews: some View { - BlocListItem() + let odinVM = OdinVM(blocs: Stub().loadBlocs()) + + BlocListItem(odin: odinVM) } } diff --git a/src/App/Views/CalculatorView.swift b/src/App/Views/CalculatorView.swift deleted file mode 100644 index 39c9efb..0000000 --- a/src/App/Views/CalculatorView.swift +++ /dev/null @@ -1,21 +0,0 @@ -import SwiftUI - -struct CalculatorView: View { - var body: some View { - NavigationStack { - ScrollView { - BlocListItem() - Divider() - UEListItem() - } - .navigationTitle("Calculette") - } - - } -} - -struct CalculatorView_Previews: PreviewProvider { - static var previews: some View { - CalculatorView() - } -} diff --git a/src/App/Views/Exemple.swift b/src/App/Views/Exemple.swift new file mode 100644 index 0000000..5b85c17 --- /dev/null +++ b/src/App/Views/Exemple.swift @@ -0,0 +1,23 @@ +// +// Exemple.swift +// App +// +// Created by BREUIL Yohann on 17/06/2023. +// + +import SwiftUI + +struct Exemple: View { + var body: some View { + @State var number = 100 + Form{ + TextField("inputNumber",value:$number,format: .number) + } + } +} + +struct Exemple_Previews: PreviewProvider { + static var previews: some View { + Exemple() + } +} diff --git a/src/App/Views/MatiereInfo.swift b/src/App/Views/MatiereInfo.swift new file mode 100644 index 0000000..b651312 --- /dev/null +++ b/src/App/Views/MatiereInfo.swift @@ -0,0 +1,33 @@ +import Foundation + +import SwiftUI +import Stub +import ViewModel + +struct MatiereInfo: View { + @StateObject var matiereVM: MatiereVM + + var canEdit: Bool + + var body: some View { + VStack { + HStack() { + Text("\(matiereVM.name)") + Spacer() + Text("\(matiereVM.factor)") + } + MatiereNoteSlider(matiereVM: matiereVM, canEdit: canEdit) + Divider() + } + } +} + +struct MatiereInfo_Previews: PreviewProvider { + static var previews: some View { + let odin = OdinVM(blocs: Stub().loadBlocs()) + let matiereVM = odin.blocsVM[0].uesVM[0].matieresVM[0] + + MatiereInfo(matiereVM: matiereVM, canEdit: true) + //NoteInfo(canEdit: false) + } +} diff --git a/src/App/Views/NoteSlider.swift b/src/App/Views/MatiereNoteSlider.swift similarity index 59% rename from src/App/Views/NoteSlider.swift rename to src/App/Views/MatiereNoteSlider.swift index e6399d8..cadd88f 100644 --- a/src/App/Views/NoteSlider.swift +++ b/src/App/Views/MatiereNoteSlider.swift @@ -1,13 +1,10 @@ -// -// NoteSliderComponent.swift -// App -// -// Created by BREUIL Yohann on 25/05/2023. -// - import SwiftUI +import Stub +import ViewModel -struct NoteSlider: View { +struct MatiereNoteSlider: View { + @ObservedObject var matiereVM: MatiereVM + @State private var sliderProgress: CGFloat = 0 @State private var sliderWidth: CGFloat = 20 @State private var sliderMaxWidth: CGFloat = 200 @@ -22,8 +19,10 @@ struct NoteSlider: View { sliderWidth = sliderWidth > sliderMaxWidth ? sliderMaxWidth : sliderWidth sliderWidth = sliderWidth >= 0 ? sliderWidth : 20 - let progress = sliderWidth / sliderMaxWidth - sliderProgress = progress <= 1.0 ? progress : 1 + let progress = sliderWidth / sliderMaxWidth * 20 + sliderProgress = progress <= 20 ? progress : 1 + + matiereVM.note = Float(sliderProgress) } .onEnded { value in sliderWidth = sliderWidth > sliderMaxWidth ? sliderMaxWidth : sliderWidth @@ -33,22 +32,26 @@ struct NoteSlider: View { } } + var canEdit: Bool + var body: some View { HStack { Rectangle() - .fill(sliderProgress < 0.5 ? Color("BadColor") : Color("GoodColor")) + .fill(sliderProgress < 10 ? Color("BadColor") : Color("GoodColor")) .frame(width: sliderWidth, height: 25) .clipShape(Capsule()) - .gesture(drag) + .gesture(drag, including: canEdit ? .gesture : .none) Spacer() - Text("\(sliderProgress)") + Text("\(String(format: "%.2f", matiereVM.note))") } - .padding() } } -struct NoteSliderComponent_Previews: PreviewProvider { +struct MatiereNoteSlider_Previews: PreviewProvider { static var previews: some View { - NoteSlider() + let odin = OdinVM(blocs: Stub().loadBlocs()) + let matierevM = odin.blocsVM[0].uesVM[0].matieresVM[0] + + MatiereNoteSlider(matiereVM: matierevM, canEdit: true) } } diff --git a/src/App/Views/NoteInfo.swift b/src/App/Views/NoteInfo.swift deleted file mode 100644 index a7acdf4..0000000 --- a/src/App/Views/NoteInfo.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// NoteInfo.swift -// App -// -// Created by BREUIL Yohann on 26/05/2023. -// - -import SwiftUI - -struct NoteInfo: View { - var body: some View { - VStack { - HStack() { - Text("Qualité de Développement") - Spacer() - Text("6") - } - NoteSlider() - Divider() - } - } -} - -struct NoteInfo_Previews: PreviewProvider { - static var previews: some View { - NoteInfo() - } -} diff --git a/src/App/Views/UEEdit.swift b/src/App/Views/UEEdit.swift new file mode 100644 index 0000000..5521e45 --- /dev/null +++ b/src/App/Views/UEEdit.swift @@ -0,0 +1,81 @@ +import SwiftUI +import ViewModel +import Stub + +struct UEEdit: View { + @ObservedObject var ueEditVM : UEVM + + @State var newMatiereName = "" + + @State var number: Int32 = 2 + + var body: some View { + NavigationStack { + Form { + Section(header: Text("UE\(String(ueEditVM.number))")) { + VStack(alignment: .leading) { + Text("Nom").font(.headline) + TextField("Nom", text: $ueEditVM.name) + } + + VStack(alignment: .leading) { + Text("Coefficient").font(.headline) + TextField("Coefficient",value: $ueEditVM.factor, format: .number) + .keyboardType(.numberPad) + } + } + + Section(header: Text("Matières")) { + ForEach($ueEditVM.matieresVM) { $matiereVM in + VStack { + TextField("Nom", text: $matiereVM.name) + TextField("Coeeficient", value: $matiereVM.factor, format: .number) + .keyboardType(.numberPad) + } + + .swipeActions(edge:.trailing){ + Button(role: .destructive) { + + } label: { + Label("Delete", systemImage: "trash") + } + } + } + HStack { + TextField("Nouvelle matière", text: $newMatiereName) + Button(action: {}) { + Image(systemName: "plus.circle.fill") + } + } + } + } + .navigationBarTitleDisplayMode(.inline) + .navigationTitle("UE\(String(ueEditVM.number))") + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button(action: { + ueEditVM.onEdited(isCancelled: true) + }) { + Text("Cancel") + } + } + ToolbarItem(placement: .confirmationAction) { + Button(action: { + ueEditVM.onEdited() + }) { + Text("Done") + } + } + } + } + } +} + +struct UEEdit_Previews: PreviewProvider { + static var previews: some View { + let odin = OdinVM(blocs: Stub().loadBlocs()) + let ueVM = odin.blocsVM[0].uesVM[0] + + UEEdit(ueEditVM: ueVM) + } +} diff --git a/src/App/Views/UEEditSheet.swift b/src/App/Views/UEEditSheet.swift deleted file mode 100644 index 1b0ca10..0000000 --- a/src/App/Views/UEEditSheet.swift +++ /dev/null @@ -1,29 +0,0 @@ -import SwiftUI - -struct UEEditSheet: View { - var body: some View { - NavigationStack { - VStack { - Text("SALUT") - } - .toolbar { - ToolbarItem(placement: .cancellationAction) { - Button(action: {}) { - Text("Cancel") - } - } - ToolbarItem(placement: .confirmationAction) { - Button(action: {}) { - Text("Save") - } - } - } - } - } -} - -struct UEEditSheet_Previews: PreviewProvider { - static var previews: some View { - UEEditSheet() - } -} diff --git a/src/App/Views/UEInfo.swift b/src/App/Views/UEInfo.swift new file mode 100644 index 0000000..3cea761 --- /dev/null +++ b/src/App/Views/UEInfo.swift @@ -0,0 +1,28 @@ +import SwiftUI +import Stub +import ViewModel + +struct UEInfo: View { + @StateObject var ueVM: UEVM + + var body: some View { + VStack { + HStack() { + Text("UE\(ueVM.number) \(ueVM.name)") + Spacer() + Text("\(ueVM.factor)") + } + UENoteSlider(ueVM: ueVM) + Divider() + } + } +} + +struct UEInfo_Previews: PreviewProvider { + static var previews: some View { + let odin = OdinVM(blocs: Stub().loadBlocs()) + let ueVM = odin.blocsVM[0].uesVM[0] + + UEInfo(ueVM: ueVM) + } +} diff --git a/src/App/Views/UEListItem.swift b/src/App/Views/UEListItem.swift index 684574e..231101f 100644 --- a/src/App/Views/UEListItem.swift +++ b/src/App/Views/UEListItem.swift @@ -1,13 +1,10 @@ -// -// UEListItem.swift -// App -// -// Created by BREUIL Yohann on 24/05/2023. -// - import SwiftUI +import Stub +import ViewModel struct UEListItem: View { + @StateObject var odin: OdinVM + var body: some View { NavigationStack { VStack(alignment: .leading) { @@ -15,46 +12,17 @@ struct UEListItem: View { .font(.title) Text("Détails des UEs") LazyVStack { - HStack { - NoteInfo() - NavigationLink(destination: UEView()) { - Image(systemName: "square.and.pencil") - } - Divider() - } - .padding() - HStack { - NoteInfo() - NavigationLink(destination: UEView()) { - Image(systemName: "square.and.pencil") - } - Divider() - } - .padding() - HStack { - NoteInfo() - NavigationLink(destination: UEView()) { - Image(systemName: "square.and.pencil") - } - Divider() - } - .padding() - HStack { - NoteInfo() - NavigationLink(destination: UEView()) { - Image(systemName: "square.and.pencil") - } - Divider() - } - .padding() - HStack { - NoteInfo() - NavigationLink(destination: UEView()) { - Image(systemName: "square.and.pencil") + ForEach(odin.blocsVM) { blocVM in + ForEach(blocVM.uesVM) { ueVM in + HStack { + UEInfo(ueVM: ueVM) + NavigationLink(destination: UEView(ueVM: ueVM)) { + Image(systemName: "square.and.pencil") + } + Divider() + } } - Divider() } - .padding() } } .padding() @@ -66,6 +34,8 @@ struct UEListItem: View { struct UEListItem_Previews: PreviewProvider { static var previews: some View { - UEListItem() + let odinVM = OdinVM(blocs: Stub().loadBlocs()) + + UEListItem(odin: odinVM) } } diff --git a/src/App/Views/UENoteSlider.swift b/src/App/Views/UENoteSlider.swift new file mode 100644 index 0000000..260a31e --- /dev/null +++ b/src/App/Views/UENoteSlider.swift @@ -0,0 +1,43 @@ +import SwiftUI +import Stub +import ViewModel + +struct UENoteSlider: View { + @StateObject var ueVM: UEVM + + @State private var sliderProgress: CGFloat = 0 + @State private var sliderWidth: CGFloat = 20 + @State private var sliderMaxWidth: CGFloat = 220 + @State private var sliderCurrentWidth: CGFloat = 0 + + var drag: some Gesture { + DragGesture() + .onEnded { _ in + sliderWidth = sliderWidth > sliderMaxWidth ? sliderMaxWidth : sliderWidth + sliderWidth = sliderWidth >= 0 ? sliderWidth : 20 + + sliderCurrentWidth = sliderWidth + } + } + + var body: some View { + HStack { + Rectangle() + .fill(ueVM.average < 10 ? Color("BadColor") : Color("GoodColor")) + .frame(width: CGFloat(ueVM.average) * 10, height: 25) + .clipShape(Capsule()) + .gesture(drag, including: .none) + Spacer() + Text("\(String(format: "%.2f", ueVM.average))") + } + } +} + +struct UENoteSlider_Previews: PreviewProvider { + static var previews: some View { + let odin = OdinVM(blocs: Stub().loadBlocs()) + let ueVM = odin.blocsVM[0].uesVM[0] + + UENoteSlider(ueVM: ueVM) + } +} diff --git a/src/App/Views/UEView.swift b/src/App/Views/UEView.swift index 1cc57f7..02b855e 100644 --- a/src/App/Views/UEView.swift +++ b/src/App/Views/UEView.swift @@ -1,64 +1,59 @@ import SwiftUI +import Stub +import ViewModel struct UEView: View { - @State private var showingSheet = false + @StateObject var ueVM: UEVM + + @State private var canEditNote = false var body: some View { NavigationStack { ScrollView { - NoteInfo() + UEInfo(ueVM: ueVM) VStack(alignment: .leading) { - Label("Coefficcient : 6", systemImage: "xmark.circle.fill") + Label("Coefficcient : \(ueVM.factor)", systemImage: "xmark.circle.fill") Label("Détails des notes ", systemImage: "note.text") } + .padding() + LazyVStack { - HStack { - Button(action: {}) { - Image(systemName: "lock") - } - NoteInfo() - } - HStack { - Button(action: {}) { - Image(systemName: "lock") - } - NoteInfo() - } - HStack { - Button(action: {}) { - Image(systemName: "lock") - } - NoteInfo() - } - HStack { - Button(action: {}) { - Image(systemName: "lock") + ForEach(ueVM.matieresVM) { matiereVM in + HStack { + Button(action: { + canEditNote.toggle() + }) { + Image(systemName: canEditNote ? "lock.open" : "lock") + } + MatiereInfo(matiereVM: matiereVM, canEdit: canEditNote) } - NoteInfo() } } } .padding() - .navigationTitle("UE1 Génie logiciel") + .navigationTitle("UE\(ueVM.number) \(ueVM.name)") .toolbar { ToolbarItem { Button(action: { - showingSheet = true + ueVM.isEditing.toggle() }) { Text("Edit") } - .sheet(isPresented: $showingSheet) { - UEEditSheet() - } } } + .sheet(isPresented: $ueVM.isEditing) { + UEEdit(ueEditVM: ueVM) + } } } } struct UEView_Previews: PreviewProvider { static var previews: some View { - UEView() + let odin = OdinVM(blocs: Stub().loadBlocs()) + let ueVM = odin.blocsVM[0].uesVM[0] + + UEView(ueVM: ueVM) } } diff --git a/src/AverageCalculator.xcworkspace/xcuserdata/djyohann.xcuserdatad/UserInterfaceState.xcuserstate b/src/AverageCalculator.xcworkspace/xcuserdata/djyohann.xcuserdatad/UserInterfaceState.xcuserstate index 4890433..1f5414d 100644 Binary files a/src/AverageCalculator.xcworkspace/xcuserdata/djyohann.xcuserdatad/UserInterfaceState.xcuserstate and b/src/AverageCalculator.xcworkspace/xcuserdata/djyohann.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/src/Model/Sources/Model/Bloc.swift b/src/Model/Sources/Model/Bloc.swift index 040a244..ce3653e 100644 --- a/src/Model/Sources/Model/Bloc.swift +++ b/src/Model/Sources/Model/Bloc.swift @@ -6,6 +6,18 @@ public struct Bloc: Identifiable, Equatable { public var name: String public var ues: [UE] + public var average: Float { + var averages : Float = 0 + var factors: Float = 0 + + for ue in ues { + averages = averages + (ue.average * Float(ue.factor)) + factors = factors + Float(ue.factor) + } + + return averages / factors + } + public init(id: UUID, name: String, ues: [UE]) { self.id = id self.name = name diff --git a/src/Model/Sources/Model/DataManager.swift b/src/Model/Sources/Model/DataManager.swift new file mode 100644 index 0000000..0691a51 --- /dev/null +++ b/src/Model/Sources/Model/DataManager.swift @@ -0,0 +1,7 @@ +import Foundation + +public protocol DataManager { + func loadBlocs() -> [Bloc] + + func saveBlocs(blocs: [Bloc]) -> Void +} diff --git a/src/Model/Sources/Model/Manager.swift b/src/Model/Sources/Model/Manager.swift deleted file mode 100644 index 249f60f..0000000 --- a/src/Model/Sources/Model/Manager.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -struct Manager { - -} diff --git a/src/Model/Sources/Model/Odin.swift b/src/Model/Sources/Model/Odin.swift new file mode 100644 index 0000000..6d72258 --- /dev/null +++ b/src/Model/Sources/Model/Odin.swift @@ -0,0 +1,21 @@ +import Foundation + +public struct Odin { + let dataManager: DataManager + public var blocs: [Bloc] = [] + + public init(dataManager: DataManager) { + self.dataManager = dataManager + } + + public mutating func loadBlocs(){ + self.blocs.removeAll() + for bloc in self.dataManager.loadBlocs() { + self.blocs.append(bloc) + } + } + + public func saveBlocs() { + self.dataManager.saveBlocs(blocs: self.blocs) + } +} diff --git a/src/Model/Sources/Model/UE.swift b/src/Model/Sources/Model/UE.swift index 03585e2..93bce18 100644 --- a/src/Model/Sources/Model/UE.swift +++ b/src/Model/Sources/Model/UE.swift @@ -8,6 +8,18 @@ public struct UE: Identifiable, Equatable { public var factor: Int32 public var matieres: [Matiere] + public var average: Float { + var averages : Float = 0 + var factors: Float = 0 + + for matiere in matieres { + averages = averages + (matiere.note * Float(matiere.factor)) + factors = factors + Float(matiere.factor) + } + + return averages / factors + } + public init(id: UUID, number: Int32, name: String, factor: Int32, matieres: [Matiere]) { self.id = id self.number = number diff --git a/src/Stub/Sources/Stub/Stub.swift b/src/Stub/Sources/Stub/Stub.swift index 156688c..70b9e0a 100644 --- a/src/Stub/Sources/Stub/Stub.swift +++ b/src/Stub/Sources/Stub/Stub.swift @@ -1,11 +1,13 @@ import Model import Foundation -public struct Stub { +public struct Stub : DataManager { + public init() {} + public func loadBlocs() -> [Bloc] { var blocs: [Bloc] = [] - var bloc1 = Bloc(name: "Total", ues: [ + let bloc1 = Bloc(name: "Total", ues: [ UE(number: 1, name: "Génie logiciel", factor: 6, matieres: [ Matiere(name: "Processus de développement", factor: 4, note: 19.04), Matiere(name: "Programmation objets", factor: 9, note: 9.08), @@ -13,39 +15,39 @@ public struct Stub { Matiere(name: "Remise à niveau Objets", factor: 4, note: 12), ]), UE(number: 2, name: "Systèmes et réseaux", factor: 6, matieres: [ - Matiere(name: "Internet des Objets", factor: 4, note: 10), - Matiere(name: "Réseaux", factor: 4, note: 10), - Matiere(name: "Services Mobiles", factor: 4, note: 10), - Matiere(name: "Système", factor: 5, note: 10) + Matiere(name: "Internet des Objets", factor: 4, note: 9), + Matiere(name: "Réseaux", factor: 4, note: 8), + Matiere(name: "Services Mobiles", factor: 4, note: 7), + Matiere(name: "Système", factor: 5, note: 12) ]), UE(number: 3, name: "Insertion Professionnellle", factor: 6, matieres: [ - Matiere(name: "Anglais", factor: 5, note: 10), - Matiere(name: "Économie", factor: 4, note: 10), - Matiere(name: "Gestion", factor: 3, note: 10), - Matiere(name: "Communication", factor: 4, note: 10) + Matiere(name: "Anglais", factor: 5, note: 4), + Matiere(name: "Économie", factor: 4, note: 1), + Matiere(name: "Gestion", factor: 3, note: 1), + Matiere(name: "Communication", factor: 4, note: 14) ]), UE(number: 4, name: "Technologies Mobiles 1", factor: 9, matieres: [ - Matiere(name: "Android", factor: 6, note: 10), - Matiere(name: "Architecture de projets .NET (1)", factor: 5, note: 10), - Matiere(name: "C++", factor: 4, note: 10), - Matiere(name: "Swift", factor: 5, note: 10) + Matiere(name: "Android", factor: 6, note: 2), + Matiere(name: "Architecture de projets .NET (1)", factor: 5, note: 13), + Matiere(name: "C++", factor: 4, note: 8), + Matiere(name: "Swift", factor: 5, note: 8.5) ]), UE(number: 5, name: "Technologies Mobiles 2", factor: 9, matieres: [ - Matiere(name: "Architecture de projets .NET (2)", factor: 4, note: 10), - Matiere(name: "Client / Serveur", factor: 4, note: 10), - Matiere(name: "iOS", factor: 5, note: 10), - Matiere(name: "Multiplateformes", factor: 3, note: 10), - Matiere(name: "QT Quick", factor: 5, note: 10), + Matiere(name: "Architecture de projets .NET (2)", factor: 4, note: 12), + Matiere(name: "Client / Serveur", factor: 4, note: 17), + Matiere(name: "iOS", factor: 5, note: 20), + Matiere(name: "Multiplateformes", factor: 3, note: 15), + Matiere(name: "QT Quick", factor: 5, note: 1), Matiere(name: "Xamarin", factor: 5, note: 10) ]), ]) - var bloc2 = Bloc(name: "Projet / Stage", ues: [ + let bloc2 = Bloc(name: "Projet / Stage", ues: [ UE(number: 6, name: "Projet", factor: 9, matieres: [ - Matiere(name: "Projet", factor: 1, note: 10) + Matiere(name: "Projet", factor: 1, note: 12) ]), UE(number: 7, name: "Stage", factor: 15, matieres: [ - Matiere(name: "Stage", factor: 1, note: 10) + Matiere(name: "Stage", factor: 1, note: 15) ]) ]) @@ -54,5 +56,7 @@ public struct Stub { return blocs } - + public func saveBlocs(blocs: [Model.Bloc]) { + + } } diff --git a/src/ViewModel/Sources/ViewModel/ArrayExtension.swift b/src/ViewModel/Sources/ViewModel/ArrayExtension.swift new file mode 100644 index 0000000..d63d2fc --- /dev/null +++ b/src/ViewModel/Sources/ViewModel/ArrayExtension.swift @@ -0,0 +1,11 @@ +import Foundation + +extension Array where Element: Equatable { + func compare(to other: [Element]) -> Bool { + self.count == other.count && self.allSatisfy({ elt in + other.contains { otherElt in + otherElt == elt + } + }) + } +} diff --git a/src/ViewModel/Sources/ViewModel/BlocVM.swift b/src/ViewModel/Sources/ViewModel/BlocVM.swift index eeae83d..5c47f39 100644 --- a/src/ViewModel/Sources/ViewModel/BlocVM.swift +++ b/src/ViewModel/Sources/ViewModel/BlocVM.swift @@ -2,28 +2,30 @@ import Foundation import Model @available(iOS 13.0, *) -public class BlocVM : ObservableObject, Identifiable { +public class BlocVM : ObservableObject, Identifiable, Equatable { public init(model: Bloc) { self.model = model } public var id: UUID { model.id } - @Published - var model: Bloc = Bloc(id: UUID(), name: "", ues: []) { + @Published var model: Bloc = Bloc(id: UUID(), name: "", ues: []) { didSet { if self.name != model.name { self.name = self.model.name } - if self.ues != model.ues { - self.ues = self.model.ues + if !self.model.ues.compare(to: self.uesVM.map({$0.model})) { + self.uesVM = self.model.ues.map({UEVM(model: $0)}) + } + + if self.average != self.model.average { + self.average = self.model.average } } } - @Published - var name: String = "" { + @Published public var name: String = "" { didSet { if self.name != self.model.name { self.name = self.model.name @@ -31,12 +33,24 @@ public class BlocVM : ObservableObject, Identifiable { } } - @Published - var ues: [UE] = [] { + @Published public var uesVM: [UEVM] = [] { didSet { - if self.ues != self.model.ues { - self.ues = self.model.ues + let ues = self.uesVM.map({$0.model}) + if !self.model.ues.compare(to: ues) { + self.model.ues = uesVM.map({$0.model}) } } } + + @Published public var average: Float = 0 { + didSet { + if self.average != self.model.average { + self.average = self.model.average + } + } + } + + public static func == (lhs: BlocVM, rhs: BlocVM) -> Bool { + lhs.id == rhs.id + } } diff --git a/src/ViewModel/Sources/ViewModel/MatiereVM.swift b/src/ViewModel/Sources/ViewModel/MatiereVM.swift index b6d09d4..a1a1c84 100644 --- a/src/ViewModel/Sources/ViewModel/MatiereVM.swift +++ b/src/ViewModel/Sources/ViewModel/MatiereVM.swift @@ -2,11 +2,17 @@ import Foundation import Model @available(iOS 13.0, *) -class MatiereVM : ObservableObject, Identifiable { +public class MatiereVM : ObservableObject, Identifiable, Equatable { public init(model: Matiere) { self.model = model } + private var copy: MatiereVM { + MatiereVM(model: self.model) + } + + public var editedCopy: MatiereVM? + public var id: UUID { model.id } @Published @@ -26,8 +32,7 @@ class MatiereVM : ObservableObject, Identifiable { } } - @Published - var name: String = "" { + @Published public var name: String = "" { didSet { if model.name != self.model.name { self.name = self.model.name @@ -35,8 +40,7 @@ class MatiereVM : ObservableObject, Identifiable { } } - @Published - var factor: Int = 0 { + @Published public var factor: Int = 0 { didSet { if model.factor != self.model.factor { self.factor = self.model.factor @@ -44,12 +48,32 @@ class MatiereVM : ObservableObject, Identifiable { } } - @Published - var note: Float = 0 { + @Published public var note: Float = 0 { didSet { if model.note != self.model.note { self.note = self.model.note } } } + + @Published + public var isEditing: Bool = false + + func onEditing(){ + editedCopy = self.copy + isEditing = true + } + + func onEdited(isCancelled: Bool = false){ + if(!isCancelled){ + if let edit = editedCopy { + self.model = edit.model + } + } + isEditing = false + } + + public static func == (lhs: MatiereVM, rhs: MatiereVM) -> Bool { + lhs.id == rhs.id + } } diff --git a/src/ViewModel/Sources/ViewModel/OdinVM.swift b/src/ViewModel/Sources/ViewModel/OdinVM.swift new file mode 100644 index 0000000..76ef306 --- /dev/null +++ b/src/ViewModel/Sources/ViewModel/OdinVM.swift @@ -0,0 +1,15 @@ +import Foundation +import Model + +@available(iOS 13.0, *) +public class OdinVM: ObservableObject { + @Published public var blocsVM: [BlocVM] = [] + + public init(blocs: [Bloc]) { + self.blocsVM = blocs.map({BlocVM(model: $0)}) + } + + public init(blocsVM: [BlocVM]) { + self.blocsVM = blocsVM + } +} diff --git a/src/ViewModel/Sources/ViewModel/UEVM.swift b/src/ViewModel/Sources/ViewModel/UEVM.swift index 2ad4b6b..90988b8 100644 --- a/src/ViewModel/Sources/ViewModel/UEVM.swift +++ b/src/ViewModel/Sources/ViewModel/UEVM.swift @@ -2,11 +2,17 @@ import Foundation import Model @available(iOS 13.0, *) -public class UEVM : ObservableObject, Identifiable { +public class UEVM : ObservableObject, Identifiable, Equatable { public init(model: UE) { self.model = model } + private var copy: UEVM { + UEVM(model: self.model) + } + + public var editedCopy: UEVM? + public var id: UUID { model.id } @Published @@ -24,14 +30,17 @@ public class UEVM : ObservableObject, Identifiable { self.factor = self.model.factor } - if self.matieres != self.model.matieres { - self.matieres = self.model.matieres + if !self.model.matieres.compare(to: self.matieresVM.map({$0.model})) { + self.matieresVM = self.model.matieres.map({MatiereVM(model: $0)}) + } + + if self.average != self.model.average { + self.average = self.model.average } } } - @Published - var number: Int32 = 0 { + @Published public var number: Int32 = 0 { didSet { if model.number != self.model.number { self.number = self.model.number @@ -39,8 +48,7 @@ public class UEVM : ObservableObject, Identifiable { } } - @Published - var name: String = "" { + @Published public var name: String = "" { didSet { if model.name != self.model.name { self.name = self.model.name @@ -48,8 +56,7 @@ public class UEVM : ObservableObject, Identifiable { } } - @Published - var factor: Int32 = 0 { + @Published public var factor: Int32 = 0 { didSet { if model.factor != self.model.factor { self.factor = self.model.factor @@ -57,12 +64,41 @@ public class UEVM : ObservableObject, Identifiable { } } - @Published - var matieres: [Matiere] = [] { + @Published public var matieresVM: [MatiereVM] = [] { + didSet { + let matieres = self.matieresVM.map({$0.model}) + if !self.model.matieres.compare(to: matieres) { + self.model.matieres = matieresVM.map({$0.model}) + } + } + } + + @Published public var average: Float = 0 { didSet { - if model.matieres != self.model.matieres { - self.matieres = self.model.matieres + if self.average != self.model.average { + self.average = self.model.average + } + } + } + + @Published + public var isEditing: Bool = false + + public func onEditing(){ + editedCopy = self.copy + isEditing = true + } + + public func onEdited(isCancelled: Bool = false){ + if(!isCancelled) { + if let edit = editedCopy { + self.model = edit.model } } + isEditing = false + } + + public static func == (lhs: UEVM, rhs: UEVM) -> Bool { + lhs.id == rhs.id } }