Added playtime in Game Detail
This commit is contained in:
@@ -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 = "<group>";
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<PresentationMode>
|
||||
@@ -50,17 +78,6 @@ struct GameDetailView : View {
|
||||
|
||||
let defaultImage = UIImage()
|
||||
|
||||
@State var hasFinishedDate_raw : Bool = false
|
||||
private var hasFinishedDate: Binding<Bool> {
|
||||
Binding<Bool>(
|
||||
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<Bool> {
|
||||
Binding<Bool>(
|
||||
@@ -72,19 +89,58 @@ struct GameDetailView : View {
|
||||
)
|
||||
}
|
||||
|
||||
@State var hasFinishedDate_raw : Bool = false
|
||||
private var hasFinishedDate: Binding<Bool> {
|
||||
Binding<Bool>(
|
||||
get: { self.hasFinishedDate_raw || self.game.finishedDate != .none },
|
||||
set: {
|
||||
hasFinishedDate_raw = $0
|
||||
if !$0 { self.game.finishedDate = .none }
|
||||
}
|
||||
)
|
||||
}
|
||||
var finishedDateBinding: Binding<Date> {
|
||||
Binding<Date>(
|
||||
get: { self.game.finishedDate ?? Date() },
|
||||
set: { self.game.finishedDate = $0 })
|
||||
}
|
||||
|
||||
|
||||
var notesBinding: Binding<String> {
|
||||
Binding<String>(
|
||||
get: { self.game.notes ?? "" },
|
||||
set: { self.game.notes = $0 })
|
||||
}
|
||||
|
||||
var pickupDscriptionBinding: Binding<String> {
|
||||
Binding<String>(
|
||||
get: { self.game.pickupDescription ?? "" },
|
||||
set: { self.game.pickupDescription = $0 })
|
||||
}
|
||||
|
||||
var lentToBinding: Binding<String> {
|
||||
Binding<String>(
|
||||
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
|
||||
|
||||
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: {
|
||||
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)
|
||||
}
|
||||
|
||||
//TZOOOODOOOOOO
|
||||
//self.gameVM.removeGame()
|
||||
}), secondaryButton: Alert.Button.cancel(Text("Lieber doch nicht")))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
<attribute name="name" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="notes" optional="YES" attributeType="String"/>
|
||||
<attribute name="pickupDescription" optional="YES" attributeType="String"/>
|
||||
<attribute name="playtime_h" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="playtime_min" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="publisher" optional="YES" attributeType="String"/>
|
||||
<attribute name="uuid" optional="YES" attributeType="UUID" defaultValueString="00000000-0000-0000-0000-000000000000" usesScalarValueType="NO"/>
|
||||
<relationship name="console" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Console" inverseName="games" inverseEntity="Console"/>
|
||||
@@ -52,7 +54,7 @@
|
||||
<elements>
|
||||
<element name="Accessory" positionX="-265.9140625" positionY="29.15625" width="128" height="149"/>
|
||||
<element name="Console" positionX="-535.7890625" positionY="56.03515625" width="128" height="164"/>
|
||||
<element name="Game" positionX="-288.828125" positionY="276.7421875" width="128" height="260"/>
|
||||
<element name="Game" positionX="-288.828125" positionY="276.7421875" width="128" height="290"/>
|
||||
<element name="GameSeries" positionX="-686.828125" positionY="359.20703125" width="128" height="89"/>
|
||||
<element name="GameSeriesCover" positionX="-477" positionY="180" width="128" height="44"/>
|
||||
</elements>
|
||||
|
||||
Reference in New Issue
Block a user