Changed GameLibraryView and GameDetailView to new swiftui core data best practise. Fixed Import/Export of Library
This commit is contained in:
@@ -12,7 +12,6 @@
|
|||||||
B93C1B9D21496BFD0014FD6E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93C1B9C21496BFD0014FD6E /* AppDelegate.swift */; };
|
B93C1B9D21496BFD0014FD6E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93C1B9C21496BFD0014FD6E /* AppDelegate.swift */; };
|
||||||
B93C1BA421496BFE0014FD6E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B93C1BA321496BFE0014FD6E /* Assets.xcassets */; };
|
B93C1BA421496BFE0014FD6E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B93C1BA321496BFE0014FD6E /* Assets.xcassets */; };
|
||||||
B93D60CE22D88F5700DD390F /* AccessoryDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93D60CD22D88F5700DD390F /* AccessoryDetailView.swift */; };
|
B93D60CE22D88F5700DD390F /* AccessoryDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93D60CD22D88F5700DD390F /* AccessoryDetailView.swift */; };
|
||||||
B93D60D122E5009700DD390F /* GameViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93D60D022E5009700DD390F /* GameViewModel.swift */; };
|
|
||||||
B94112DE233A37DD00159AE4 /* DateConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94112DD233A37DD00159AE4 /* DateConversion.swift */; };
|
B94112DE233A37DD00159AE4 /* DateConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94112DD233A37DD00159AE4 /* DateConversion.swift */; };
|
||||||
B94112E0233A4EF800159AE4 /* GamePickupsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94112DF233A4EF800159AE4 /* GamePickupsView.swift */; };
|
B94112E0233A4EF800159AE4 /* GamePickupsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94112DF233A4EF800159AE4 /* GamePickupsView.swift */; };
|
||||||
B94112E4233B597D00159AE4 /* ConsoleEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94112E3233B597D00159AE4 /* ConsoleEditView.swift */; };
|
B94112E4233B597D00159AE4 /* ConsoleEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94112E3233B597D00159AE4 /* ConsoleEditView.swift */; };
|
||||||
@@ -92,7 +91,6 @@
|
|||||||
B93C1BA321496BFE0014FD6E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
B93C1BA321496BFE0014FD6E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
B93C1BA821496BFE0014FD6E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
B93C1BA821496BFE0014FD6E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
B93D60CD22D88F5700DD390F /* AccessoryDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessoryDetailView.swift; sourceTree = "<group>"; };
|
B93D60CD22D88F5700DD390F /* AccessoryDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessoryDetailView.swift; sourceTree = "<group>"; };
|
||||||
B93D60D022E5009700DD390F /* GameViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewModel.swift; sourceTree = "<group>"; };
|
|
||||||
B94112DD233A37DD00159AE4 /* DateConversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateConversion.swift; sourceTree = "<group>"; };
|
B94112DD233A37DD00159AE4 /* DateConversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateConversion.swift; sourceTree = "<group>"; };
|
||||||
B94112DF233A4EF800159AE4 /* GamePickupsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamePickupsView.swift; sourceTree = "<group>"; };
|
B94112DF233A4EF800159AE4 /* GamePickupsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamePickupsView.swift; sourceTree = "<group>"; };
|
||||||
B94112E3233B597D00159AE4 /* ConsoleEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleEditView.swift; sourceTree = "<group>"; };
|
B94112E3233B597D00159AE4 /* ConsoleEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleEditView.swift; sourceTree = "<group>"; };
|
||||||
@@ -249,7 +247,6 @@
|
|||||||
B93D60CF22E5006F00DD390F /* ViewModel */ = {
|
B93D60CF22E5006F00DD390F /* ViewModel */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
B93D60D022E5009700DD390F /* GameViewModel.swift */,
|
|
||||||
B9E2A078233B69D400EAEB14 /* GameSeriesViewModel.swift */,
|
B9E2A078233B69D400EAEB14 /* GameSeriesViewModel.swift */,
|
||||||
B9D2C6F622E98ED800797F67 /* AccessoryViewModel.swift */,
|
B9D2C6F622E98ED800797F67 /* AccessoryViewModel.swift */,
|
||||||
B9F44AE422F418F600FC6B29 /* ConsoleStore.swift */,
|
B9F44AE422F418F600FC6B29 /* ConsoleStore.swift */,
|
||||||
@@ -446,7 +443,6 @@
|
|||||||
B94CB50A22D1352F0029BFAD /* Logo+CoreDataProperties.swift in Sources */,
|
B94CB50A22D1352F0029BFAD /* Logo+CoreDataProperties.swift in Sources */,
|
||||||
B94CB4FF22D1352F0029BFAD /* Accessory+CoreDataClass.swift in Sources */,
|
B94CB4FF22D1352F0029BFAD /* Accessory+CoreDataClass.swift in Sources */,
|
||||||
B98A734D22BAD27D00FB3410 /* Zockerhoehle.xcdatamodeld in Sources */,
|
B98A734D22BAD27D00FB3410 /* Zockerhoehle.xcdatamodeld in Sources */,
|
||||||
B93D60D122E5009700DD390F /* GameViewModel.swift in Sources */,
|
|
||||||
B9F44AE722F429D300FC6B29 /* GameStore.swift in Sources */,
|
B9F44AE722F429D300FC6B29 /* GameStore.swift in Sources */,
|
||||||
B90E03EB238557D900E79643 /* LibraryImport.swift in Sources */,
|
B90E03EB238557D900E79643 /* LibraryImport.swift in Sources */,
|
||||||
B94CB50922D1352F0029BFAD /* Logo+CoreDataClass.swift in Sources */,
|
B94CB50922D1352F0029BFAD /* Logo+CoreDataClass.swift in Sources */,
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ extension Console : Encodable {
|
|||||||
var gamesList : [String] = []
|
var gamesList : [String] = []
|
||||||
for game in games! {
|
for game in games! {
|
||||||
if let game = game as? Game {
|
if let game = game as? Game {
|
||||||
gamesList.append(game.uuid!.uuidString)
|
gamesList.append(game.uuid.uuidString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try container.encode(gamesList, forKey: .games)
|
try container.encode(gamesList, forKey: .games)
|
||||||
|
|||||||
@@ -13,18 +13,6 @@ import SwiftUI
|
|||||||
|
|
||||||
@objc(Game)
|
@objc(Game)
|
||||||
public class Game: NSManagedObject, Identifiable {
|
public class Game: NSManagedObject, Identifiable {
|
||||||
@nonobjc public class func fetchRequest(console : Console) -> NSFetchRequest<Game> {
|
|
||||||
let fetchRequest = NSFetchRequest<Game>(entityName: "Game")
|
|
||||||
fetchRequest.predicate = NSPredicate(format: "console == %@", console)
|
|
||||||
return fetchRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
@nonobjc public class func fetchRequest(gameSeries : GameSeries) -> NSFetchRequest<Game> {
|
|
||||||
let fetchRequest = NSFetchRequest<Game>(entityName: "Game")
|
|
||||||
fetchRequest.predicate = NSPredicate(format: "series == %@", gameSeries)
|
|
||||||
return fetchRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
public func addGameSeries(by objectIDStringified : String) {
|
public func addGameSeries(by objectIDStringified : String) {
|
||||||
if let url = URL(string: objectIDStringified) {
|
if let url = URL(string: objectIDStringified) {
|
||||||
let persistentStoreCoordinator = CDManager.shared.persistentContainer.persistentStoreCoordinator
|
let persistentStoreCoordinator = CDManager.shared.persistentContainer.persistentStoreCoordinator
|
||||||
@@ -44,16 +32,21 @@ public class Game: NSManagedObject, Identifiable {
|
|||||||
return gameACreated < gameBCreated
|
return gameACreated < gameBCreated
|
||||||
}
|
}
|
||||||
|
|
||||||
init(context: NSManagedObjectContext) {
|
public var id : NSManagedObjectID {
|
||||||
super.init(entity: Game.entity(), insertInto: context)
|
get {
|
||||||
|
return self.objectID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
|
||||||
|
super.init(entity: entity, insertInto: context)
|
||||||
|
|
||||||
if self.createdAt == .none {
|
if self.createdAt == .none {
|
||||||
self.createdAt = Date()
|
self.createdAt = Date()
|
||||||
}
|
}
|
||||||
}
|
self.uuid = UUID()
|
||||||
@objc
|
print("Set UUID to \(self.uuid)")
|
||||||
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
|
|
||||||
super.init(entity: entity, insertInto: context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +63,12 @@ extension Game : Encodable {
|
|||||||
case inWishlist
|
case inWishlist
|
||||||
case console
|
case console
|
||||||
case gameSeries
|
case gameSeries
|
||||||
case cover
|
case cover_icloud_path
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
print("UUID: \(self.uuid)")
|
||||||
try container.encode(uuid, forKey: .uuid)
|
try container.encode(uuid, forKey: .uuid)
|
||||||
try container.encode(name, forKey: .name)
|
try container.encode(name, forKey: .name)
|
||||||
try container.encode(notes ?? "", forKey: .notes)
|
try container.encode(notes ?? "", forKey: .notes)
|
||||||
@@ -84,13 +78,11 @@ extension Game : Encodable {
|
|||||||
try container.encode(publisher ?? "", forKey: .publisher)
|
try container.encode(publisher ?? "", forKey: .publisher)
|
||||||
try container.encode(isFinished, forKey: .isFinished)
|
try container.encode(isFinished, forKey: .isFinished)
|
||||||
try container.encode(inWishlist, forKey: .inWishlist)
|
try container.encode(inWishlist, forKey: .inWishlist)
|
||||||
|
try container.encode(cover_icloud_path ?? "", forKey: .cover_icloud_path)
|
||||||
|
|
||||||
let consoleUUID : String = console?.uuid.uuidString ?? ""
|
let consoleUUID : String = console?.uuid.uuidString ?? ""
|
||||||
let gameSeriesUUID : String = series?.uuid.uuidString ?? ""
|
let gameSeriesUUID : String = series?.uuid.uuidString ?? ""
|
||||||
try container.encode(consoleUUID, forKey: .console)
|
try container.encode(consoleUUID, forKey: .console)
|
||||||
try container.encode(gameSeriesUUID, forKey: .gameSeries)
|
try container.encode(gameSeriesUUID, forKey: .gameSeries)
|
||||||
|
|
||||||
let imgBase64 = cover?.image?.pngData()?.base64EncodedString() ?? ""
|
|
||||||
try container.encode(imgBase64, forKey: .cover)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ extension Game {
|
|||||||
@NSManaged public var name: String?
|
@NSManaged public var name: String?
|
||||||
@NSManaged public var notes: String?
|
@NSManaged public var notes: String?
|
||||||
@NSManaged public var publisher: String?
|
@NSManaged public var publisher: String?
|
||||||
@NSManaged public var uuid: UUID?
|
@NSManaged public var uuid: UUID
|
||||||
|
@NSManaged public var cover_icloud_path : String?
|
||||||
@NSManaged public var console: Console?
|
@NSManaged public var console: Console?
|
||||||
@NSManaged public var cover: Cover?
|
|
||||||
@NSManaged public var series: GameSeries?
|
@NSManaged public var series: GameSeries?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,13 +80,9 @@ class LibraryImport {
|
|||||||
cdGame.inWishlist = game.inWishlist
|
cdGame.inWishlist = game.inWishlist
|
||||||
cdGame.isFinished = game.isFinished
|
cdGame.isFinished = game.isFinished
|
||||||
cdGame.lentTo = game.lentTo
|
cdGame.lentTo = game.lentTo
|
||||||
|
cdGame.cover_icloud_path = game.cover_icloud_path
|
||||||
//TODO: cdGame.createdAt = game.createdAt.
|
//TODO: cdGame.createdAt = game.createdAt.
|
||||||
|
|
||||||
let cdCover = Cover(context: CDManager.shared.viewContext)
|
|
||||||
cdCover.image = game.cover
|
|
||||||
cdCover.game = cdGame
|
|
||||||
cdGame.cover = cdCover
|
|
||||||
|
|
||||||
cdConsole.addToGames(cdGame)
|
cdConsole.addToGames(cdGame)
|
||||||
cdGame.console = cdConsole
|
cdGame.console = cdConsole
|
||||||
print("Imported: \(cdGame.name) for \(cdConsole.name)")
|
print("Imported: \(cdGame.name) for \(cdConsole.name)")
|
||||||
@@ -152,7 +148,7 @@ class LibraryImport {
|
|||||||
for console in library.consoles {
|
for console in library.consoles {
|
||||||
let cdConsole = makeCDConsole(from: console)
|
let cdConsole = makeCDConsole(from: console)
|
||||||
|
|
||||||
print("CONSOLE: \(cdConsole.name) with \(console.games.count) games")
|
print("CONSOLE: \(cdConsole.name ?? "n/a") with \(console.games.count) games")
|
||||||
for uuid in console.games {
|
for uuid in console.games {
|
||||||
|
|
||||||
if let game = library.games.first(where: {$0.uuid == uuid}) {
|
if let game = library.games.first(where: {$0.uuid == uuid}) {
|
||||||
@@ -204,7 +200,7 @@ struct BHLGame : Decodable {
|
|||||||
let publisher : String?
|
let publisher : String?
|
||||||
let console : UUID?
|
let console : UUID?
|
||||||
let series : UUID?
|
let series : UUID?
|
||||||
let cover : UIImage?
|
let cover_icloud_path : String?
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case uuid
|
case uuid
|
||||||
@@ -218,7 +214,7 @@ struct BHLGame : Decodable {
|
|||||||
case publisher
|
case publisher
|
||||||
case console
|
case console
|
||||||
case series
|
case series
|
||||||
case cover
|
case cover_icloud_path
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
@@ -232,16 +228,10 @@ struct BHLGame : Decodable {
|
|||||||
notes = try container.decode(String?.self, forKey: .notes)
|
notes = try container.decode(String?.self, forKey: .notes)
|
||||||
createdAt = try container.decode(String?.self, forKey: .notes)
|
createdAt = try container.decode(String?.self, forKey: .notes)
|
||||||
publisher = try container.decode(String?.self, forKey: .publisher)
|
publisher = try container.decode(String?.self, forKey: .publisher)
|
||||||
|
cover_icloud_path = try container.decode(String?.self, forKey: .cover_icloud_path)
|
||||||
console = try container.decode(UUID?.self, forKey: .console)
|
console = try container.decode(UUID?.self, forKey: .console)
|
||||||
series = try container.decode(UUID?.self, forKey: .console)
|
series = try container.decode(UUID?.self, forKey: .console)
|
||||||
|
|
||||||
|
|
||||||
if let coverBase64 = try container.decode(String?.self, forKey: .cover),
|
|
||||||
let coverData = Data(base64Encoded: coverBase64) {
|
|
||||||
cover = UIImage(data: coverData)
|
|
||||||
}else {
|
|
||||||
cover = .none
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,13 +49,14 @@ class GameStore : NSObject, ObservableObject, NSFetchedResultsControllerDelegate
|
|||||||
|
|
||||||
lazy var fetchResultsController : NSFetchedResultsController<Game> = {
|
lazy var fetchResultsController : NSFetchedResultsController<Game> = {
|
||||||
var gamesFetch : NSFetchRequest<Game> = Game.fetchRequest()
|
var gamesFetch : NSFetchRequest<Game> = Game.fetchRequest()
|
||||||
if let console = consoleFilter {
|
|
||||||
|
/*if let console = consoleFilter {
|
||||||
gamesFetch = Game.fetchRequest(console: console)
|
gamesFetch = Game.fetchRequest(console: console)
|
||||||
}else if let gameSeries = gameSeriesFilter {
|
}else if let gameSeries = gameSeriesFilter {
|
||||||
gamesFetch = Game.fetchRequest(gameSeries: gameSeries)
|
gamesFetch = Game.fetchRequest(gameSeries: gameSeries)
|
||||||
}else {
|
}else {
|
||||||
print("No filter: fetch Limit: \(self.fetchLimit)")
|
print("No filter: fetch Limit: \(self.fetchLimit)")
|
||||||
}
|
}*/
|
||||||
|
|
||||||
gamesFetch.fetchLimit = self.fetchLimit
|
gamesFetch.fetchLimit = self.fetchLimit
|
||||||
gamesFetch.sortDescriptors = self.sortDescriptors
|
gamesFetch.sortDescriptors = self.sortDescriptors
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
//
|
|
||||||
// GameViewModel.swift
|
|
||||||
// Zockerhoehle
|
|
||||||
//
|
|
||||||
// Created by Julian-Steffen Müller on 21.07.19.
|
|
||||||
// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
import Combine
|
|
||||||
import CoreData
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
class GameViewModel : ObservableObject {
|
|
||||||
var objectWillChange = ObservableObjectPublisher()
|
|
||||||
|
|
||||||
private var game : Game? {
|
|
||||||
didSet {
|
|
||||||
guard let game = game else { return }
|
|
||||||
|
|
||||||
self.name = game.name!
|
|
||||||
self.inWishlist = game.inWishlist
|
|
||||||
self.isDigital = game.isDigital
|
|
||||||
self.isFinished = game.isFinished
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var lentTo : String {
|
|
||||||
didSet {
|
|
||||||
guard let game = self.game else { return }
|
|
||||||
|
|
||||||
if lentTo != "" {
|
|
||||||
game.lentTo = lentTo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var name : String {
|
|
||||||
didSet {
|
|
||||||
guard let game = self.game else { return }
|
|
||||||
|
|
||||||
game.name = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var inWishlist : Bool {
|
|
||||||
didSet {
|
|
||||||
guard let game = self.game else { return }
|
|
||||||
|
|
||||||
game.inWishlist = inWishlist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDigital : Bool {
|
|
||||||
didSet {
|
|
||||||
guard let game = self.game else { return }
|
|
||||||
|
|
||||||
game.isDigital = isDigital
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isFinished : Bool {
|
|
||||||
didSet {
|
|
||||||
guard let game = self.game else { return }
|
|
||||||
|
|
||||||
game.isFinished = isFinished
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var gameSeries : String {
|
|
||||||
willSet {
|
|
||||||
if newValue != "" , let game = self.game {
|
|
||||||
game.addGameSeries(by: newValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var console : Console? {
|
|
||||||
get {
|
|
||||||
return self.game?.console
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var cover : UIImage? {
|
|
||||||
get {
|
|
||||||
if let coverImage = self.game?.cover?.image {
|
|
||||||
return coverImage
|
|
||||||
}
|
|
||||||
|
|
||||||
return .none
|
|
||||||
}
|
|
||||||
|
|
||||||
set {
|
|
||||||
if let game = self.game {
|
|
||||||
if let coverImage = newValue {
|
|
||||||
let newCover = Cover(context: CDManager.shared.viewContext)
|
|
||||||
newCover.game = game
|
|
||||||
newCover.image = coverImage
|
|
||||||
game.cover = newCover
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeGame() {
|
|
||||||
if let game = self.game {
|
|
||||||
CDManager.shared.viewContext.delete(game)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var NSManagedObjectChangedObserver : AnyCancellable? = .none
|
|
||||||
|
|
||||||
init(game : Game) {
|
|
||||||
self.game = game
|
|
||||||
|
|
||||||
self.name = game.name!
|
|
||||||
self.inWishlist = game.inWishlist
|
|
||||||
self.isDigital = game.isDigital
|
|
||||||
self.isFinished = game.isFinished
|
|
||||||
self.gameSeries = game.series?.id ?? ""
|
|
||||||
self.lentTo = game.lentTo ?? ""
|
|
||||||
|
|
||||||
self.NSManagedObjectChangedObserver = NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange, object: CDManager.shared.viewContext).first().sink { notification in
|
|
||||||
|
|
||||||
guard let game = self.game else { return }
|
|
||||||
guard let userInfo = notification.userInfo else { return }
|
|
||||||
|
|
||||||
var managedObjectIsMatching = false
|
|
||||||
if let inserts = userInfo[NSInsertedObjectsKey] as? Set<NSManagedObject> {
|
|
||||||
if inserts.contains(game) { managedObjectIsMatching = true }
|
|
||||||
}
|
|
||||||
if let updates = userInfo[NSUpdatedObjectsKey] as? Set<NSManagedObject> {
|
|
||||||
if updates.contains(game) { managedObjectIsMatching = true }
|
|
||||||
}
|
|
||||||
if let deletes = userInfo[NSDeletedObjectsKey] as? Set<NSManagedObject> {
|
|
||||||
if deletes.contains(game) { managedObjectIsMatching = true }
|
|
||||||
}
|
|
||||||
|
|
||||||
if managedObjectIsMatching {
|
|
||||||
self.objectWillChange.send()
|
|
||||||
print("GameViewModel::NSMangedObjectChanged Update of \(game.name)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -43,7 +43,7 @@ struct ModalAddToConsoleLibrary : View {
|
|||||||
self.addAccessoryToLibrary()
|
self.addAccessoryToLibrary()
|
||||||
}
|
}
|
||||||
self.presentationMode.wrappedValue.dismiss()},
|
self.presentationMode.wrappedValue.dismiss()},
|
||||||
label: { Text("Add") })
|
label: { Text("Fertig") })
|
||||||
.disabled(self.modalAddName.trimmingCharacters(in: .whitespacesAndNewlines) == "" )
|
.disabled(self.modalAddName.trimmingCharacters(in: .whitespacesAndNewlines) == "" )
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,9 +61,9 @@ struct ModalAddToConsoleLibrary : View {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.navigationBarTitle(self.isVideogamesSelected ? Text("New Game") : Text("New Accessory"))
|
.navigationBarTitle(self.isVideogamesSelected ? Text("Spiel hinzufügen") : Text("Zubehör hinzufügen"))
|
||||||
.navigationBarItems(leading: Button(action: { self.presentationMode.wrappedValue.dismiss() },
|
.navigationBarItems(leading: Button(action: { self.presentationMode.wrappedValue.dismiss() },
|
||||||
label: {Text("Cancel")}),
|
label: {Text("Abbrechen")}),
|
||||||
//Add Button is disabled if no name is entered
|
//Add Button is disabled if no name is entered
|
||||||
trailing: addButton)
|
trailing: addButton)
|
||||||
.navigationViewStyle(StackNavigationViewStyle())
|
.navigationViewStyle(StackNavigationViewStyle())
|
||||||
@@ -72,14 +72,27 @@ struct ModalAddToConsoleLibrary : View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ConsoleLibraryView : View {
|
struct ConsoleLibraryView : View {
|
||||||
@State var isVideogamesSelected = true
|
@ObservedObject var console : Console
|
||||||
var console : Console?
|
|
||||||
@ObservedObject var gameStore : GameStore
|
|
||||||
@ObservedObject var accessoryStore : AccessoryStore
|
|
||||||
|
|
||||||
|
@Environment(\.managedObjectContext) private var viewContext
|
||||||
|
|
||||||
|
var gamesFetchRequest: FetchRequest<Game>
|
||||||
|
var games: FetchedResults<Game> { gamesFetchRequest.wrappedValue }
|
||||||
|
|
||||||
|
var accessoryFetchRequest: FetchRequest<Accessory>
|
||||||
|
var accessories: FetchedResults<Accessory> { accessoryFetchRequest.wrappedValue }
|
||||||
|
|
||||||
|
@State var isVideogamesSelected = true
|
||||||
@State var showWishlist = false
|
@State var showWishlist = false
|
||||||
@State var showAddToConsoleLibraryModal: Bool = false
|
@State var showAddToConsoleLibraryModal: Bool = false
|
||||||
@State var showLogoImagePicker = false
|
|
||||||
|
init (console: Console) {
|
||||||
|
self.console = console
|
||||||
|
|
||||||
|
self.gamesFetchRequest = FetchRequest<Game>(entity: Game.entity(), sortDescriptors: [NSSortDescriptor(key: "name", ascending: true)], predicate: NSPredicate(format: "console == %@", console))
|
||||||
|
|
||||||
|
self.accessoryFetchRequest = FetchRequest<Accessory>(entity: Accessory.entity(), sortDescriptors: [NSSortDescriptor(key: "name", ascending: true)], predicate: NSPredicate(format: "console == %@", console))
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
@@ -93,18 +106,10 @@ struct ConsoleLibraryView : View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
if self.isVideogamesSelected {
|
if self.isVideogamesSelected {
|
||||||
List {
|
List(games.filter({$0.inWishlist == self.showWishlist})) { game in
|
||||||
ForEach(gameStore.games.filter({$0.inWishlist == self.showWishlist})) { game in
|
|
||||||
NavigationLink(destination: GameDetailView(game: game)) {
|
NavigationLink(destination: GameDetailView(game: game)) {
|
||||||
HStack {
|
HStack {
|
||||||
/*game.cover.map {
|
Text("\(game.name ?? "n/a")")
|
||||||
Image(uiImage: $0.image)
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(height: 75)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
Text("\(game.name!)")
|
|
||||||
|
|
||||||
if game.isDigital {
|
if game.isDigital {
|
||||||
Image("digitalGame")
|
Image("digitalGame")
|
||||||
@@ -115,21 +120,18 @@ struct ConsoleLibraryView : View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}else {
|
}else {
|
||||||
List {
|
List(accessories.filter({$0.inWishlist == self.showWishlist})) {accessory in
|
||||||
ForEach(accessoryStore.accessories.filter({$0.inWishlist == self.showWishlist})) { accessory in
|
|
||||||
NavigationLink(destination: AccessoryDetailView(accessoryVM: AccessoryViewModel(accessory: accessory))) {
|
NavigationLink(destination: AccessoryDetailView(accessoryVM: AccessoryViewModel(accessory: accessory))) {
|
||||||
Text("\(accessory.name)")
|
Text("\(accessory.name)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
.navigationBarTitle(Text("\(self.console.name ?? "n/a")"), displayMode: .automatic)
|
||||||
.navigationBarTitle(Text("\(self.console?.name ?? "N/A")"), displayMode: .automatic)
|
|
||||||
.navigationBarItems(trailing:
|
.navigationBarItems(trailing:
|
||||||
HStack {
|
HStack {
|
||||||
NavigationLink(destination: ConsoleEditView(console: self.console!)) {
|
NavigationLink(destination: ConsoleEditView(console: self.console)) {
|
||||||
Image(systemName: "pencil.and.ellipsis.rectangle")
|
Image(systemName: "pencil.and.ellipsis.rectangle")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,18 +147,7 @@ struct ConsoleLibraryView : View {
|
|||||||
.accentColor(self.showWishlist ? Color.red : Color.blue)
|
.accentColor(self.showWishlist ? Color.red : Color.blue)
|
||||||
})
|
})
|
||||||
.sheet(isPresented: $showAddToConsoleLibraryModal) {
|
.sheet(isPresented: $showAddToConsoleLibraryModal) {
|
||||||
if self.console != nil {
|
ModalAddToConsoleLibrary(modalAddToWishlist: self.showWishlist, isVideogamesSelected: self.isVideogamesSelected, console: self.console)
|
||||||
ModalAddToConsoleLibrary(modalAddToWishlist: self.showWishlist, isVideogamesSelected: true, console: self.console!)
|
|
||||||
}else{
|
|
||||||
Text("Fehler: Keine Konsole übergeben")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(console : Console?) {
|
|
||||||
self.console = console
|
|
||||||
self.gameStore = GameStore(console: console)
|
|
||||||
self.accessoryStore = AccessoryStore(console: console)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct GameDetailView : View {
|
struct GameDetailView : View {
|
||||||
@ObservedObject var gameVM : GameViewModel
|
@ObservedObject var game : Game
|
||||||
|
|
||||||
@State private var showDeleteAlert : Bool = false
|
@State private var showDeleteAlert : Bool = false
|
||||||
@State var hasFinishedDate : Bool = false
|
@State var hasFinishedDate : Bool = false
|
||||||
@@ -18,83 +18,64 @@ struct GameDetailView : View {
|
|||||||
@EnvironmentObject var gameSeriesStore : GameSeriesStore
|
@EnvironmentObject var gameSeriesStore : GameSeriesStore
|
||||||
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
|
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
|
||||||
|
|
||||||
|
@State var isImportingCover : Bool = false
|
||||||
@State var showingPicker = false
|
|
||||||
|
|
||||||
@State var image : Image? = nil
|
|
||||||
|
|
||||||
@State var isLent : Bool = false
|
@State var isLent : Bool = false
|
||||||
|
|
||||||
|
let defaultImage = UIImage()
|
||||||
|
|
||||||
var gameSeriesPicker : some View {
|
var gameSeriesPicker : some View {
|
||||||
Picker(selection: $gameVM.gameSeries, label:
|
Text("TODO GameSeries Picker")
|
||||||
|
/*Picker(selection: $game.gameSeries, label:
|
||||||
Text("Spieleserie")
|
Text("Spieleserie")
|
||||||
, content: {
|
, content: {
|
||||||
Text("Keine").tag("")
|
Text("Keine").tag("")
|
||||||
ForEach(gameSeriesStore.gameSeries) { gameSeries in
|
ForEach(gameSeriesStore.gameSeries) { gameSeries in
|
||||||
Text("\(gameSeries.name)").tag(gameSeries.id)
|
Text("\(gameSeries.name)").tag(gameSeries.id)
|
||||||
}
|
}
|
||||||
})
|
})*/
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageCoverSection : some View {
|
|
||||||
Section {
|
|
||||||
VStack{
|
|
||||||
Button("Show image picker") {
|
|
||||||
self.showingPicker = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.gameVM.cover != nil {
|
|
||||||
Image(uiImage: self.gameVM.cover!)
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(height: 100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Form {
|
Form {
|
||||||
Section {
|
Section {
|
||||||
TextField("Videogame name", text: $gameVM.name)
|
TextField("Videogame name", text: $game.name ?? "")
|
||||||
|
|
||||||
//Gray color should indicate immutable data
|
//Gray color should indicate immutable data
|
||||||
Text("\(gameVM.console?.name ?? "No console")").foregroundColor(.gray)
|
Text("\(game.console?.name ?? "No console")").foregroundColor(.gray)
|
||||||
|
|
||||||
Toggle(isOn: $gameVM.isDigital, label: {
|
Toggle(isOn: $game.isDigital, label: {
|
||||||
Text("Nur Digital")
|
Text("Nur Digital")
|
||||||
})
|
})
|
||||||
|
|
||||||
Toggle(isOn: $gameVM.inWishlist, label: {
|
Toggle(isOn: $game.inWishlist, label: {
|
||||||
Text("In Wunschliste")
|
Text("In Wunschliste")
|
||||||
})
|
})
|
||||||
|
|
||||||
Toggle(isOn: $isLent, label: {
|
Toggle(isOn: $isLent, label: {
|
||||||
Text("Verliehen?")
|
Text("Verliehen?")
|
||||||
}).onReceive(gameVM.objectWillChange) { _ in
|
}).onReceive(game.objectWillChange) { _ in
|
||||||
self.isLent = self.gameVM.lentTo != "";
|
self.isLent = self.game.lentTo != "";
|
||||||
}.onAppear() {
|
}.onAppear() {
|
||||||
self.isLent = self.gameVM.lentTo != "";
|
self.isLent = self.game.lentTo != "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if isLent {
|
if isLent {
|
||||||
TextField("Verliehen an", text: $gameVM.lentTo)
|
TextField("Verliehen an", text: $game.lentTo ?? "")
|
||||||
}
|
}
|
||||||
|
|
||||||
gameSeriesPicker
|
gameSeriesPicker
|
||||||
|
|
||||||
Toggle(isOn: $gameVM.isFinished , label: {
|
Toggle(isOn: $game.isFinished , label: {
|
||||||
Text("Durchgezockt")
|
Text("Durchgezockt")
|
||||||
})
|
})
|
||||||
|
|
||||||
if gameVM.isFinished {
|
if game.isFinished {
|
||||||
Toggle(isOn: $hasFinishedDate, label: {
|
Toggle(isOn: $hasFinishedDate, label: {
|
||||||
Text("Gibts ein Datum")
|
Text("Gibts ein Datum")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasFinishedDate && gameVM.isFinished {
|
if hasFinishedDate && game.isFinished {
|
||||||
DatePicker("Durchgezockt am",
|
DatePicker("Durchgezockt am",
|
||||||
selection: $playthroughDate,
|
selection: $playthroughDate,
|
||||||
in: ...Date(),
|
in: ...Date(),
|
||||||
@@ -102,23 +83,43 @@ struct GameDetailView : View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imageCoverSection
|
Section {
|
||||||
|
VStack{
|
||||||
|
Button("Neues Cover auswählen") {
|
||||||
|
self.isImportingCover = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Image(uiImage: ICloudManager.imageFrom(path: game.cover_icloud_path) ?? defaultImage)
|
||||||
|
.resizable()
|
||||||
|
.frame(width:100, height: 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Section{
|
Section{
|
||||||
gameDeleteButton
|
gameDeleteButton
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.navigationBarTitle(Text("\(gameVM.name)"), displayMode: .automatic)
|
.navigationBarTitle(Text("\(game.name ?? "N/A")"), displayMode: .automatic)
|
||||||
.sheet(isPresented: $showingPicker,
|
.fileImporter(
|
||||||
onDismiss: {
|
isPresented: $isImportingCover,
|
||||||
// do whatever you need here
|
allowedContentTypes: [.jpeg, .png],
|
||||||
}, content: {
|
allowsMultipleSelection: false
|
||||||
ImagePicker.shared.view
|
) { result in
|
||||||
})
|
do {
|
||||||
.onReceive(ImagePicker.shared.objectWillChange) { image in
|
let selectedFile : URL = try result.get().first!
|
||||||
if let image = image {
|
|
||||||
self.gameVM.cover = image
|
//It seems that isUbiquitousItem checks if the file is contained in the Apps iCloud folder
|
||||||
|
if (FileManager.default.isUbiquitousItem(at: selectedFile)) {
|
||||||
|
game.cover_icloud_path = ICloudManager.relativePathFrom(url: selectedFile)
|
||||||
|
|
||||||
|
print("Selected Image in iCloud Path \(game.cover_icloud_path ?? "n/a")")
|
||||||
|
}else{
|
||||||
|
Alert(title: Text("Falscher Ordner"))
|
||||||
|
print("Außerhalb \(selectedFile.relativeString)")
|
||||||
|
}
|
||||||
|
}catch{
|
||||||
|
print("ConsoleAllView::ModalAddConsoleToLibrary Error getting result '\(result)'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,19 +137,12 @@ struct GameDetailView : View {
|
|||||||
})
|
})
|
||||||
.accentColor(.red)
|
.accentColor(.red)
|
||||||
.alert(isPresented: $showDeleteAlert, content: {
|
.alert(isPresented: $showDeleteAlert, content: {
|
||||||
Alert(title: Text("Aus Zockerhöhle entfernen"), message: Text("Willst du '\(self.gameVM.name)' 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 ?? "n/a")' wirklich aus der Zockerhöhle werfen?"), primaryButton: Alert.Button.destructive(Text("Ja!"), action: {
|
||||||
//self.presentationMode.value.dismiss()
|
|
||||||
self.gameVM.removeGame()
|
//TZOOOODOOOOOO
|
||||||
|
//self.gameVM.removeGame()
|
||||||
}), secondaryButton: Alert.Button.cancel(Text("Lieber doch nicht")))
|
}), secondaryButton: Alert.Button.cancel(Text("Lieber doch nicht")))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
init(gameVM : GameViewModel?) {
|
|
||||||
self.gameVM = gameVM!
|
|
||||||
}
|
|
||||||
|
|
||||||
init(game : Game) {
|
|
||||||
self.gameVM = GameViewModel(game: game)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import CoreData
|
||||||
//extension String: Identifiable {
|
//extension String: Identifiable {
|
||||||
// public var id: String {
|
// public var id: String {
|
||||||
// return self
|
// return self
|
||||||
@@ -20,15 +20,24 @@ struct SettingsView: View {
|
|||||||
@State var importFiles : [String] = LibraryImport().backupFiles()
|
@State var importFiles : [String] = LibraryImport().backupFiles()
|
||||||
|
|
||||||
func exportLibrary() {
|
func exportLibrary() {
|
||||||
let games = GameStore().games
|
do {
|
||||||
let consoles = ConsoleStore().consoles
|
let gamesFR = NSFetchRequest<Game>(entityName: "Game")
|
||||||
let gameSeries = GameSeriesStore().gameSeries
|
let consolesFR = NSFetchRequest<Console>(entityName: "Console")
|
||||||
let accessories = AccessoryStore().accessories
|
let gameSeriesFR = NSFetchRequest<GameSeries>(entityName: "GameSeries")
|
||||||
|
let accessoriesFR = NSFetchRequest<Accessory>(entityName: "Accessory")
|
||||||
|
|
||||||
|
let games = try CDManager.shared.viewContext.fetch(gamesFR)
|
||||||
|
let consoles = try CDManager.shared.viewContext.fetch(consolesFR)
|
||||||
|
let gameSeries = try CDManager.shared.viewContext.fetch(gameSeriesFR)
|
||||||
|
let accessories = try CDManager.shared.viewContext.fetch(accessoriesFR)
|
||||||
|
|
||||||
let libExport = LibraryExporter(games: games, consoles: consoles, gameSeries: gameSeries, accessories: accessories)
|
let libExport = LibraryExporter(games: games, consoles: consoles, gameSeries: gameSeries, accessories: accessories)
|
||||||
|
|
||||||
libExport.export(name: Date().formattedInTimeZone())
|
libExport.export(name: Date().formattedInTimeZone())
|
||||||
importFiles = LibraryImport().backupFiles()
|
importFiles = LibraryImport().backupFiles()
|
||||||
|
}catch {
|
||||||
|
print("ERROR during export")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|||||||
@@ -23,10 +23,9 @@
|
|||||||
</entity>
|
</entity>
|
||||||
<entity name="Cover" representedClassName="Cover" syncable="YES">
|
<entity name="Cover" representedClassName="Cover" syncable="YES">
|
||||||
<attribute name="image" optional="YES" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromData"/>
|
<attribute name="image" optional="YES" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromData"/>
|
||||||
<relationship name="game" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Game" inverseName="cover" inverseEntity="Game"/>
|
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="Game" representedClassName="Game" syncable="YES">
|
<entity name="Game" representedClassName="Game" syncable="YES">
|
||||||
<attribute name="circumstances" optional="YES" attributeType="String"/>
|
<attribute name="cover_icloud_path" optional="YES" attributeType="String"/>
|
||||||
<attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="inWishlist" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
<attribute name="inWishlist" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
<attribute name="isDigital" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
<attribute name="isDigital" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||||
@@ -37,7 +36,6 @@
|
|||||||
<attribute name="publisher" optional="YES" attributeType="String"/>
|
<attribute name="publisher" optional="YES" attributeType="String"/>
|
||||||
<attribute name="uuid" optional="YES" attributeType="UUID" defaultValueString="00000000-0000-0000-0000-000000000000" usesScalarValueType="NO"/>
|
<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"/>
|
<relationship name="console" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Console" inverseName="games" inverseEntity="Console"/>
|
||||||
<relationship name="cover" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Cover" inverseName="game" inverseEntity="Cover"/>
|
|
||||||
<relationship name="series" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="GameSeries" inverseName="games" inverseEntity="GameSeries"/>
|
<relationship name="series" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="GameSeries" inverseName="games" inverseEntity="GameSeries"/>
|
||||||
<fetchedProperty name="fetchedProperty" optional="YES">
|
<fetchedProperty name="fetchedProperty" optional="YES">
|
||||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="Game"/>
|
<fetchRequest name="fetchedPropertyFetchRequest" entity="Game"/>
|
||||||
@@ -59,8 +57,8 @@
|
|||||||
<elements>
|
<elements>
|
||||||
<element name="Accessory" positionX="-265.9140625" positionY="29.15625" width="128" height="149"/>
|
<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="Console" positionX="-535.7890625" positionY="56.03515625" width="128" height="164"/>
|
||||||
<element name="Cover" positionX="-66.69921875" positionY="223.48046875" width="128" height="59"/>
|
<element name="Cover" positionX="-66.69921875" positionY="223.48046875" width="128" height="44"/>
|
||||||
<element name="Game" positionX="-288.828125" positionY="276.7421875" width="128" height="245"/>
|
<element name="Game" positionX="-288.828125" positionY="276.7421875" width="128" height="230"/>
|
||||||
<element name="GameSeries" positionX="-686.828125" positionY="359.20703125" width="128" height="89"/>
|
<element name="GameSeries" positionX="-686.828125" positionY="359.20703125" width="128" height="89"/>
|
||||||
<element name="GameSeriesCover" positionX="-477" positionY="180" width="128" height="59"/>
|
<element name="GameSeriesCover" positionX="-477" positionY="180" width="128" height="59"/>
|
||||||
<element name="Logo" positionX="-66.7109375" positionY="110.9765625" width="128" height="44"/>
|
<element name="Logo" positionX="-66.7109375" positionY="110.9765625" width="128" height="44"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user