From dc4f8b0ebe34748bdb9e07e28e23d4081e0ec03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Julian-Steffen=20M=C3=BCller?= Date: Wed, 26 May 2021 14:58:52 +0200 Subject: [PATCH] Added playtime in Game Detail --- Zockerhoehle.xcodeproj/project.pbxproj | 2 +- Zockerhoehle/CDModel/Game+CoreDataClass.swift | 26 ++-- .../CDModel/Game+CoreDataProperties.swift | 2 + Zockerhoehle/Utils/LibraryImport.swift | 4 + Zockerhoehle/Views/GameDetailView.swift | 145 +++++++++++++----- .../Zockerhoehle.xcdatamodel/contents | 4 +- 6 files changed, 131 insertions(+), 52 deletions(-) diff --git a/Zockerhoehle.xcodeproj/project.pbxproj b/Zockerhoehle.xcodeproj/project.pbxproj index 252620f..3df618d 100644 --- a/Zockerhoehle.xcodeproj/project.pbxproj +++ b/Zockerhoehle.xcodeproj/project.pbxproj @@ -152,6 +152,7 @@ B9A0550022F8C22D0054D9A0 /* GameSeriesAllView.swift */, B93D60CD22D88F5700DD390F /* AccessoryDetailView.swift */, B94CB53622D3B3CC0029BFAD /* GameDetailView.swift */, + B9ED3DDA265D47EB00FD2D46 /* GameView.swift */, B94112E3233B597D00159AE4 /* ConsoleEditView.swift */, B9F44AB922F312E600FC6B29 /* ConsoleLibraryView.swift */, B9E2A07C233B6E4F00EAEB14 /* ConsoleAllView.swift */, @@ -159,7 +160,6 @@ B9A0550222F8C2740054D9A0 /* MainView.swift */, B9EC0986238555BF004BC9AB /* SettingsView.swift */, B9839982233A086A002F9946 /* Overview.swift */, - B9ED3DDA265D47EB00FD2D46 /* GameView.swift */, ); path = Views; sourceTree = ""; diff --git a/Zockerhoehle/CDModel/Game+CoreDataClass.swift b/Zockerhoehle/CDModel/Game+CoreDataClass.swift index 12a52c6..5fb9454 100644 --- a/Zockerhoehle/CDModel/Game+CoreDataClass.swift +++ b/Zockerhoehle/CDModel/Game+CoreDataClass.swift @@ -13,17 +13,17 @@ import SwiftUI @objc(Game) public class Game: NSManagedObject, Identifiable { - public func addGameSeries(by objectIDStringified : String) { - if let url = URL(string: objectIDStringified) { - let persistentStoreCoordinator = CDManager.shared.persistentContainer.persistentStoreCoordinator - - if let objectID = persistentStoreCoordinator.managedObjectID(forURIRepresentation: url) { - if let gameSeries = CDManager.shared.viewContext.object(with: objectID) as? GameSeries { - self.series = gameSeries - } - } - } - } +// public func addGameSeries(by objectIDStringified : String) { +// if let url = URL(string: objectIDStringified) { +// let persistentStoreCoordinator = CDManager.shared.persistentContainer.persistentStoreCoordinator +// +// if let objectID = persistentStoreCoordinator.managedObjectID(forURIRepresentation: url) { +// if let gameSeries = CDManager.shared.viewContext.object(with: objectID) as? GameSeries { +// self.series = gameSeries +// } +// } +// } +// } public static func compareByCreationDate(gameA : Game, gameB : Game) -> Bool { return gameA.createdAt < gameB.createdAt @@ -54,6 +54,8 @@ extension Game : Encodable { case console case cover_icloud_path case pickupDescription + case playtime_h + case playtime_min } public func encode(to encoder: Encoder) throws { @@ -71,6 +73,8 @@ extension Game : Encodable { try container.encode(finishedDate, forKey: .finishedDate) try container.encode(inWishlist, forKey: .inWishlist) try container.encode(cover_icloud_path ?? "", forKey: .cover_icloud_path) + try container.encode(playtime_h, forKey: .playtime_h) + try container.encode(playtime_min, forKey: .playtime_min) let consoleUUID : String = console?.uuid.uuidString ?? "" try container.encode(consoleUUID, forKey: .console) diff --git a/Zockerhoehle/CDModel/Game+CoreDataProperties.swift b/Zockerhoehle/CDModel/Game+CoreDataProperties.swift index b974bb3..a5ff1ad 100644 --- a/Zockerhoehle/CDModel/Game+CoreDataProperties.swift +++ b/Zockerhoehle/CDModel/Game+CoreDataProperties.swift @@ -32,5 +32,7 @@ extension Game { @NSManaged public var cover_icloud_path : String? @NSManaged public var console: Console? @NSManaged public var series: GameSeries? + @NSManaged public var playtime_h : Int + @NSManaged public var playtime_min : Int } diff --git a/Zockerhoehle/Utils/LibraryImport.swift b/Zockerhoehle/Utils/LibraryImport.swift index 8718695..4ea08b3 100644 --- a/Zockerhoehle/Utils/LibraryImport.swift +++ b/Zockerhoehle/Utils/LibraryImport.swift @@ -86,6 +86,8 @@ class LibraryImport { cdGame.cover_icloud_path = game.cover_icloud_path cdGame.pickupDescription = game.pickupDescription cdGame.isDigital = game.isDigital + cdGame.playtime_h = game.playtime_h ?? 0 + cdGame.playtime_min = game.playtime_min ?? 0 if let date = Date.from(string: game.createdAt) { cdGame.createdAt = date @@ -216,6 +218,8 @@ struct BHLGame : Decodable { let publisher : String? let console : UUID let cover_icloud_path : String? + let playtime_h : Int? + let playtime_min : Int? } struct BHLAccessory : Decodable { diff --git a/Zockerhoehle/Views/GameDetailView.swift b/Zockerhoehle/Views/GameDetailView.swift index 82e7c95..bc6950d 100644 --- a/Zockerhoehle/Views/GameDetailView.swift +++ b/Zockerhoehle/Views/GameDetailView.swift @@ -40,6 +40,34 @@ struct GameSeriesPicker: View { } } +struct AttachmentCellImage : View { + @ObservedObject var game : Game + var onClick: ()->() + + let defaultImage = UIImage() + + var body: some View { + HStack{ + Button("Cover") { + self.onClick() + } + + Spacer() + + Group { + Image(uiImage: ICloudManager.imageFrom(path: game.cover_icloud_path) ?? defaultImage) + .resizable() + .scaledToFit() + }.frame(width:100, height: 100) + } + } + + init(game: Game, onClick: @escaping ()->()) { + self.game = game + self.onClick = onClick + } +} + struct GameDetailView : View { @ObservedObject var game : Game @Environment(\.presentationMode) var presentationMode: Binding @@ -49,18 +77,7 @@ struct GameDetailView : View { @State var isImportingCover : Bool = false let defaultImage = UIImage() - - @State var hasFinishedDate_raw : Bool = false - private var hasFinishedDate: Binding { - Binding( - get: { self.hasFinishedDate_raw || self.game.finishedDate != .none }, - set: { - hasFinishedDate_raw = $0 - if !$0 { self.game.finishedDate = .none } - } - ) - } - + @State var isLent_raw : Bool = false private var isLent: Binding { Binding( @@ -72,19 +89,58 @@ struct GameDetailView : View { ) } + @State var hasFinishedDate_raw : Bool = false + private var hasFinishedDate: Binding { + Binding( + get: { self.hasFinishedDate_raw || self.game.finishedDate != .none }, + set: { + hasFinishedDate_raw = $0 + if !$0 { self.game.finishedDate = .none } + } + ) + } var finishedDateBinding: Binding { Binding( get: { self.game.finishedDate ?? Date() }, set: { self.game.finishedDate = $0 }) } + + var notesBinding: Binding { + Binding( + get: { self.game.notes ?? "" }, + set: { self.game.notes = $0 }) + } + + var pickupDscriptionBinding: Binding { + Binding( + get: { self.game.pickupDescription ?? "" }, + set: { self.game.pickupDescription = $0 }) + } + + var lentToBinding: Binding { + Binding( + get: { self.game.lentTo ?? "" }, + set: { self.game.lentTo = $0 }) + } + var GameIsFinished : some View { Group { Toggle(isOn: $game.isFinished , label: { Text("Durchgezockt") - }) + }).onChange(of: game.isFinished) { + if !$0 { + game.playtime_h = 0 + game.playtime_min = 0 + } + } if game.isFinished { + HStack { + Stepper("\(game.playtime_h)h", value: $game.playtime_h, in: 0...200) + Stepper("\(game.playtime_min)min", value: $game.playtime_min, in: 0...60) + } + Toggle(isOn: hasFinishedDate, label: { Text("Gibts ein Datum") }) @@ -105,12 +161,24 @@ struct GameDetailView : View { TextField("Videogame name", text: $game.name) //Gray color should indicate immutable data - Text("\(game.console?.name ?? "No console")").foregroundColor(.gray) + + HStack { + Text("Konsole") + Text("\(game.console?.name ?? "No console")").foregroundColor(.gray) + } Toggle(isOn: $game.isDigital, label: { Text("Nur Digital") }) + + + Toggle(isOn: $game.inWishlist, label: { + Text("In Wunschliste") + }) + } + + Section(header: Text("Details")) { DatePicker("In Sammlung seit", selection: $game.createdAt, in: ...Date(), @@ -118,39 +186,32 @@ struct GameDetailView : View { HStack { Text("Anlass") - TextField("Anlass", text: $game.pickupDescription ?? "") + TextEditor(text: pickupDscriptionBinding).frame(height: 100) } - Toggle(isOn: $game.inWishlist, label: { - Text("In Wunschliste") - }) + GameSeriesPicker(game: game) Toggle(isOn: isLent, label: { Text("Verliehen?") }) if isLent.wrappedValue { - TextField("Verliehen an", text: $game.lentTo ?? "") + TextField("Verliehen an", text: lentToBinding) } - GameSeriesPicker(game: game) - GameIsFinished + } - Section { - VStack{ - Button("Neues Cover auswählen") { + Section(header: Text("Notizen")) { + TextEditor(text: notesBinding).frame(height: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/) + } + + Section(header: Text("Anhänge")){ + List { + AttachmentCellImage(game: game) { self.isImportingCover = true } - - Group { - Image(uiImage: ICloudManager.imageFrom(path: game.cover_icloud_path) ?? defaultImage) - .resizable() - .scaledToFit() - }.frame(width:100, height: 100) - - } } @@ -159,7 +220,7 @@ struct GameDetailView : View { } } - .navigationBarTitle(Text("\(game.name ?? "N/A")"), displayMode: .automatic) + .navigationBarTitle(Text("\(game.name)"), displayMode: .automatic) .fileImporter( isPresented: $isImportingCover, allowedContentTypes: [.jpeg, .png], @@ -174,8 +235,11 @@ struct GameDetailView : View { print("Selected Image in iCloud Path \(game.cover_icloud_path ?? "n/a")") }else{ - Alert(title: Text("Falscher Ordner")) - print("Außerhalb \(selectedFile.relativeString)") + Alert( + title: Text("Falscher Ordner"), + message: Text("Bitte nutze nur Dateien aus dem Zockerhöhle iCloud Ordner"), + dismissButton: .default(Text("Alles klar!")) + ) } }catch{ print("ConsoleAllView::ModalAddConsoleToLibrary Error getting result '\(result)'") @@ -196,10 +260,13 @@ struct GameDetailView : View { }) .accentColor(.red) .alert(isPresented: $showDeleteAlert, content: { - Alert(title: Text("Aus Zockerhöhle entfernen"), message: Text("Willst du '\(self.game.name ?? "n/a")' wirklich aus der Zockerhöhle werfen?"), primaryButton: Alert.Button.destructive(Text("Ja!"), action: { - - //TZOOOODOOOOOO - //self.gameVM.removeGame() + Alert(title: Text("Aus Zockerhöhle entfernen"), message: Text("Willst du '\(self.game.name)' wirklich aus der Zockerhöhle werfen?"), primaryButton: Alert.Button.destructive(Text("Ja!"), action: { + // + self.presentationMode.wrappedValue.dismiss() + DispatchQueue.main.asyncAfter(deadline: .now() + 4) { + CDManager.shared.viewContext.delete(game) + } + }), secondaryButton: Alert.Button.cancel(Text("Lieber doch nicht"))) }) } diff --git a/Zockerhoehle/Zockerhoehle.xcdatamodeld/Zockerhoehle.xcdatamodel/contents b/Zockerhoehle/Zockerhoehle.xcdatamodeld/Zockerhoehle.xcdatamodel/contents index 6c3fd90..2ecca2b 100644 --- a/Zockerhoehle/Zockerhoehle.xcdatamodeld/Zockerhoehle.xcdatamodel/contents +++ b/Zockerhoehle/Zockerhoehle.xcdatamodeld/Zockerhoehle.xcdatamodel/contents @@ -32,6 +32,8 @@ + + @@ -52,7 +54,7 @@ - +