diff --git a/WorldBuilder.xcodeproj/xcuserdata/giovannijosserand.xcuserdatad/xcschemes/xcschememanagement.plist b/WorldBuilder.xcodeproj/xcuserdata/giovannijosserand.xcuserdatad/xcschemes/xcschememanagement.plist
index b4799e3..29b7ec6 100644
--- a/WorldBuilder.xcodeproj/xcuserdata/giovannijosserand.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/WorldBuilder.xcodeproj/xcuserdata/giovannijosserand.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -10,5 +10,13 @@
0
+ SuppressBuildableAutocreation
+
+ 2C96045430463C2E0003A2A8
+
+ primary
+
+
+
diff --git a/WorldBuilder/Components/WorldCardView.swift b/WorldBuilder/Components/WorldCardView.swift
index 387aae6..ff9cd81 100644
--- a/WorldBuilder/Components/WorldCardView.swift
+++ b/WorldBuilder/Components/WorldCardView.swift
@@ -36,11 +36,18 @@ struct WorldCardView : View {
.padding(.horizontal, 4)
}
- .frame(height: 220)
+ .frame(height: 250)
.background {
- Image(systemName: "globe.europe.africa")
- .resizable()
- .scaledToFill()
+ if let dataImage = world.illustrationData,
+ let uiImage = UIImage(data: dataImage) {
+ Image(uiImage: uiImage)
+ .resizable()
+ .scaledToFill()
+ }else {
+ Image(systemName: "globe.europe.africa")
+ .resizable()
+ .scaledToFill()
+ }
}
.clipShape(RoundedRectangle(cornerRadius: 20))
.contentShape(RoundedRectangle(cornerRadius: 20))
diff --git a/WorldBuilder/Models/World.swift b/WorldBuilder/Models/World.swift
index 4f28ae8..3cff42f 100644
--- a/WorldBuilder/Models/World.swift
+++ b/WorldBuilder/Models/World.swift
@@ -15,18 +15,20 @@ class World {
var updatedAt : Date
var name : String
var overview : String
+ @Attribute(.externalStorage) var illustrationData : Data?
- init(name: String, overview: String) {
+ init(name: String, overview: String, illustrationData: Data?) {
self.id = UUID()
self.name = name
self.overview = overview
self.createdAt = Date()
self.updatedAt = Date()
+ self.illustrationData = illustrationData
}
func duplicate() -> World {
let newWorld = World(
- name: self.name, overview: self.overview
+ name: self.name, overview: self.overview, illustrationData: self.illustrationData
)
return newWorld
diff --git a/WorldBuilder/Views/CreateWorld/Components/IllustrationSection.swift b/WorldBuilder/Views/CreateWorld/Components/IllustrationSection.swift
new file mode 100644
index 0000000..5adf1a6
--- /dev/null
+++ b/WorldBuilder/Views/CreateWorld/Components/IllustrationSection.swift
@@ -0,0 +1,37 @@
+//
+// IllustrationSection.swift
+// WorldBuilder
+//
+// Created by Giovanni Josserand on 05/09/2026.
+//
+
+import SwiftUI
+import PhotosUI
+
+struct IllustrationSection : View {
+ @Binding var selectedItem: PhotosPickerItem?
+ @Binding var selectedImageData: Data?
+
+ var body: some View {
+ Section("Illustration") {
+ if let selectedImageData, let uiImage = UIImage(data: selectedImageData) {
+ Image(uiImage: uiImage)
+ .resizable()
+ .scaledToFill()
+ .frame(height: 150)
+ .clipShape(RoundedRectangle(cornerRadius: 10))
+ .listRowInsets(EdgeInsets())
+ }
+
+ PhotosPicker(
+ selection: $selectedItem,
+ matching: .any(of: [.images, .not(.screenshots)])
+ ) {
+ Label(
+ selectedImageData == nil ? "Sélectionner une photo" : "Modifier la photo",
+ systemImage: "photo"
+ )
+ }
+ }
+ }
+}
diff --git a/WorldBuilder/Views/CreateWorld/Components/InformationsSection.swift b/WorldBuilder/Views/CreateWorld/Components/InformationsSection.swift
new file mode 100644
index 0000000..bedbcd9
--- /dev/null
+++ b/WorldBuilder/Views/CreateWorld/Components/InformationsSection.swift
@@ -0,0 +1,25 @@
+//
+// InformationsSection.swift
+// WorldBuilder
+//
+// Created by Giovanni Josserand on 05/09/2026.
+//
+
+import SwiftUI
+
+struct InformationsSection : View {
+ @Binding var worldName : String
+ @Binding var worldOverview : String
+
+ var body: some View {
+ Section("Informations") {
+ TextField("Nom du monde", text: $worldName)
+
+ TextField(
+ "Description",
+ text: $worldOverview,
+ axis: .vertical
+ )
+ }
+ }
+}
diff --git a/WorldBuilder/Views/CreateWorld/CreateWorldView.swift b/WorldBuilder/Views/CreateWorld/CreateWorldView.swift
index 3e2726c..eeb1d87 100644
--- a/WorldBuilder/Views/CreateWorld/CreateWorldView.swift
+++ b/WorldBuilder/Views/CreateWorld/CreateWorldView.swift
@@ -5,42 +5,58 @@
// Created by Giovanni Josserand on 01/09/2026.
//
+//
+// CreateWorldView.swift
+// WorldBuilder
+//
+
import SwiftUI
import SwiftData
+import PhotosUI
struct CreateWorldView: View {
@State private var worldName = ""
@State private var worldOverview = ""
-
+
@Environment(\.modelContext) private var context
@Environment(\.dismiss) private var dismiss
@Environment(AppRouter.self) private var router
-
+
@State private var showSaveError = false
@State private var saveErrorMessage = ""
-
+
+ @State private var selectedItem: PhotosPickerItem?
+ @State private var selectedImageData: Data?
+
var body: some View {
Form {
- Section("Informations") {
- TextField("Nom du monde", text: $worldName)
+ InformationsSection(
+ worldName: $worldName,
+ worldOverview: $worldOverview
+ )
- TextField(
- "Description",
- text: $worldOverview,
- axis: .vertical
- )
- }
+ IllustrationSection(
+ selectedItem: $selectedItem,
+ selectedImageData: $selectedImageData
+ )
Section {
Button("Créer le monde") {
- let world = World(name: worldName, overview: worldOverview)
+ let world = World(
+ name: worldName,
+ overview: worldOverview,
+ illustrationData: selectedImageData
+ )
+
context.insert(world)
+
do {
try context.save()
router.selectedTab = .worldsList
dismiss()
- }catch {
- saveErrorMessage = "Impossible de sauvegarder le monde : \(error.localizedDescription)"
+ } catch {
+ saveErrorMessage =
+ "Impossible de sauvegarder le monde : \(error.localizedDescription)"
showSaveError = true
}
}
@@ -61,5 +77,12 @@ struct CreateWorldView: View {
} message: {
Text(saveErrorMessage)
}
+ .onChange(of: selectedItem) { _, newItem in
+ Task {
+ if let data = try? await newItem?.loadTransferable(type: Data.self) {
+ selectedImageData = data
+ }
+ }
+ }
}
}
diff --git a/WorldBuilder/Views/WorldList/WorldListView.swift b/WorldBuilder/Views/WorldList/WorldListView.swift
index 249ddf4..10d45b6 100644
--- a/WorldBuilder/Views/WorldList/WorldListView.swift
+++ b/WorldBuilder/Views/WorldList/WorldListView.swift
@@ -19,52 +19,55 @@ struct WorldListView: View {
var body: some View {
- ScrollView {
VStack(alignment: .leading, spacing: 24){
- WorldListHeaderView(worlds: worlds)
if worlds.isEmpty {
EmptyWorldView()
}else{
- LazyVGrid(columns: columns){
- ForEach(worlds) {world in
- if isSelecting {
- WorldCardView(
- world: world,
- isSelected: selectedWorlds.contains(world.id)
- )
- .onTapGesture {
- if selectedWorlds.contains(world.id) {
- selectedWorlds.remove(world.id)
- } else {
- selectedWorlds.insert(world.id)
- }
- }
-
- }else {
- NavigationLink{
- WorldOverviewView()
- } label: {
- WorldCardView(world: world)
- }
- .contextMenu{
- Button {
- context.insert(world.duplicate())
- } label: {
- Label("Dupliquer", systemImage: "plus.square.on.square")
+ ScrollView {
+ LazyVGrid(columns: columns){
+ ForEach(worlds) {world in
+ if isSelecting {
+ WorldCardView(
+ world: world,
+ isSelected: selectedWorlds.contains(world.id)
+ )
+ .onTapGesture {
+ if selectedWorlds.contains(world.id) {
+ selectedWorlds.remove(world.id)
+ } else {
+ selectedWorlds.insert(world.id)
+ }
}
- Button(role: .destructive){
- context.delete(world)
- }label : {
- Label("Supprimer", systemImage: "trash")
+ }else {
+ NavigationLink{
+ WorldOverviewView()
+ } label: {
+ WorldCardView(world: world)
+ }
+ .contextMenu{
+ Button {
+ context.insert(world.duplicate())
+ } label: {
+ Label("Dupliquer", systemImage: "plus.square.on.square")
+ }
+
+ Button(role: .destructive){
+ context.delete(world)
+ }label : {
+ Label("Supprimer", systemImage: "trash")
+ }
}
}
}
}
}
+ .scrollIndicators(.hidden)
}
}
+ .navigationTitle("Bibliothèque")
+ .navigationBarTitleDisplayMode(.inline)
.padding(.horizontal, 8)
.frame(maxHeight: .infinity, alignment: .topLeading)
.modifier(
@@ -74,13 +77,13 @@ struct WorldListView: View {
worlds: worlds
)
)
- }
- .modifier(
- WorldListToolbarModifier(
- isSelecting: $isSelecting,
- selectedWorlds: $selectedWorlds,
- worldsIsEmpty: worlds.isEmpty
+ .modifier(
+ WorldListToolbarModifier(
+ isSelecting: $isSelecting,
+ selectedWorlds: $selectedWorlds,
+ worldsIsEmpty: worlds.isEmpty
+ )
)
- )
+
}
}