add illustration image for worlds

This commit is contained in:
Giovanni committed 2026-09-05 13:34:07 +02:00
1 parent 85259446b1
commit 21614116fc
7 files changed
+164 -59

No files matched your search

@@ -10,5 +10,13 @@
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>2C96045430463C2E0003A2A8</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
+11 -4
View File
@@ -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))
+4 -2
View File
@@ -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
@@ -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"
)
}
}
}
}
@@ -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
)
}
}
}
@@ -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
}
}
}
}
}
@@ -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
)
)
)
}
}