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 */; };
|
||||
B93C1BA421496BFE0014FD6E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B93C1BA321496BFE0014FD6E /* Assets.xcassets */; };
|
||||
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 */; };
|
||||
B94112E0233A4EF800159AE4 /* GamePickupsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94112DF233A4EF800159AE4 /* GamePickupsView.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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -249,7 +247,6 @@
|
||||
B93D60CF22E5006F00DD390F /* ViewModel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B93D60D022E5009700DD390F /* GameViewModel.swift */,
|
||||
B9E2A078233B69D400EAEB14 /* GameSeriesViewModel.swift */,
|
||||
B9D2C6F622E98ED800797F67 /* AccessoryViewModel.swift */,
|
||||
B9F44AE422F418F600FC6B29 /* ConsoleStore.swift */,
|
||||
@@ -446,7 +443,6 @@
|
||||
B94CB50A22D1352F0029BFAD /* Logo+CoreDataProperties.swift in Sources */,
|
||||
B94CB4FF22D1352F0029BFAD /* Accessory+CoreDataClass.swift in Sources */,
|
||||
B98A734D22BAD27D00FB3410 /* Zockerhoehle.xcdatamodeld in Sources */,
|
||||
B93D60D122E5009700DD390F /* GameViewModel.swift in Sources */,
|
||||
B9F44AE722F429D300FC6B29 /* GameStore.swift in Sources */,
|
||||
B90E03EB238557D900E79643 /* LibraryImport.swift in Sources */,
|
||||
B94CB50922D1352F0029BFAD /* Logo+CoreDataClass.swift in Sources */,
|
||||
|
||||
@@ -75,7 +75,7 @@ extension Console : Encodable {
|
||||
var gamesList : [String] = []
|
||||
for game in games! {
|
||||
if let game = game as? Game {
|
||||
gamesList.append(game.uuid!.uuidString)
|
||||
gamesList.append(game.uuid.uuidString)
|
||||
}
|
||||
}
|
||||
try container.encode(gamesList, forKey: .games)
|
||||
|
||||
@@ -13,19 +13,7 @@ import SwiftUI
|
||||
|
||||
@objc(Game)
|
||||
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) {
|
||||
let persistentStoreCoordinator = CDManager.shared.persistentContainer.persistentStoreCoordinator
|
||||
|
||||
@@ -44,16 +32,21 @@ public class Game: NSManagedObject, Identifiable {
|
||||
return gameACreated < gameBCreated
|
||||
}
|
||||
|
||||
init(context: NSManagedObjectContext) {
|
||||
super.init(entity: Game.entity(), insertInto: context)
|
||||
public var id : NSManagedObjectID {
|
||||
get {
|
||||
return self.objectID
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
|
||||
super.init(entity: entity, insertInto: context)
|
||||
|
||||
if self.createdAt == .none {
|
||||
self.createdAt = Date()
|
||||
}
|
||||
}
|
||||
@objc
|
||||
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
|
||||
super.init(entity: entity, insertInto: context)
|
||||
self.uuid = UUID()
|
||||
print("Set UUID to \(self.uuid)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,11 +63,12 @@ extension Game : Encodable {
|
||||
case inWishlist
|
||||
case console
|
||||
case gameSeries
|
||||
case cover
|
||||
case cover_icloud_path
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
print("UUID: \(self.uuid)")
|
||||
try container.encode(uuid, forKey: .uuid)
|
||||
try container.encode(name, forKey: .name)
|
||||
try container.encode(notes ?? "", forKey: .notes)
|
||||
@@ -84,13 +78,11 @@ extension Game : Encodable {
|
||||
try container.encode(publisher ?? "", forKey: .publisher)
|
||||
try container.encode(isFinished, forKey: .isFinished)
|
||||
try container.encode(inWishlist, forKey: .inWishlist)
|
||||
try container.encode(cover_icloud_path ?? "", forKey: .cover_icloud_path)
|
||||
|
||||
let consoleUUID : String = console?.uuid.uuidString ?? ""
|
||||
let gameSeriesUUID : String = series?.uuid.uuidString ?? ""
|
||||
try container.encode(consoleUUID, forKey: .console)
|
||||
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 notes: 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 cover: Cover?
|
||||
@NSManaged public var series: GameSeries?
|
||||
|
||||
}
|
||||
|
||||
@@ -80,13 +80,9 @@ class LibraryImport {
|
||||
cdGame.inWishlist = game.inWishlist
|
||||
cdGame.isFinished = game.isFinished
|
||||
cdGame.lentTo = game.lentTo
|
||||
cdGame.cover_icloud_path = game.cover_icloud_path
|
||||
//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)
|
||||
cdGame.console = cdConsole
|
||||
print("Imported: \(cdGame.name) for \(cdConsole.name)")
|
||||
@@ -152,7 +148,7 @@ class LibraryImport {
|
||||
for console in library.consoles {
|
||||
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 {
|
||||
|
||||
if let game = library.games.first(where: {$0.uuid == uuid}) {
|
||||
@@ -204,7 +200,7 @@ struct BHLGame : Decodable {
|
||||
let publisher : String?
|
||||
let console : UUID?
|
||||
let series : UUID?
|
||||
let cover : UIImage?
|
||||
let cover_icloud_path : String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case uuid
|
||||
@@ -218,7 +214,7 @@ struct BHLGame : Decodable {
|
||||
case publisher
|
||||
case console
|
||||
case series
|
||||
case cover
|
||||
case cover_icloud_path
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
@@ -232,16 +228,10 @@ struct BHLGame : Decodable {
|
||||
notes = try container.decode(String?.self, forKey: .notes)
|
||||
createdAt = try container.decode(String?.self, forKey: .notes)
|
||||
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)
|
||||
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> = {
|
||||
var gamesFetch : NSFetchRequest<Game> = Game.fetchRequest()
|
||||
if let console = consoleFilter {
|
||||
|
||||
/*if let console = consoleFilter {
|
||||
gamesFetch = Game.fetchRequest(console: console)
|
||||
}else if let gameSeries = gameSeriesFilter {
|
||||
gamesFetch = Game.fetchRequest(gameSeries: gameSeries)
|
||||
}else {
|
||||
print("No filter: fetch Limit: \(self.fetchLimit)")
|
||||
}
|
||||
}*/
|
||||
|
||||
gamesFetch.fetchLimit = self.fetchLimit
|
||||
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.presentationMode.wrappedValue.dismiss()},
|
||||
label: { Text("Add") })
|
||||
label: { Text("Fertig") })
|
||||
.disabled(self.modalAddName.trimmingCharacters(in: .whitespacesAndNewlines) == "" )
|
||||
}
|
||||
|
||||
@@ -61,9 +61,9 @@ struct ModalAddToConsoleLibrary : View {
|
||||
})
|
||||
}
|
||||
.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() },
|
||||
label: {Text("Cancel")}),
|
||||
label: {Text("Abbrechen")}),
|
||||
//Add Button is disabled if no name is entered
|
||||
trailing: addButton)
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
@@ -72,14 +72,27 @@ struct ModalAddToConsoleLibrary : View {
|
||||
}
|
||||
|
||||
struct ConsoleLibraryView : View {
|
||||
@State var isVideogamesSelected = true
|
||||
var console : Console?
|
||||
@ObservedObject var gameStore : GameStore
|
||||
@ObservedObject var accessoryStore : AccessoryStore
|
||||
@ObservedObject var console : Console
|
||||
|
||||
@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 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 {
|
||||
VStack {
|
||||
@@ -93,43 +106,32 @@ struct ConsoleLibraryView : View {
|
||||
Spacer()
|
||||
}
|
||||
if self.isVideogamesSelected {
|
||||
List {
|
||||
ForEach(gameStore.games.filter({$0.inWishlist == self.showWishlist})) { game in
|
||||
NavigationLink(destination: GameDetailView(game: game)) {
|
||||
HStack {
|
||||
/*game.cover.map {
|
||||
Image(uiImage: $0.image)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 75)
|
||||
}*/
|
||||
|
||||
Text("\(game.name!)")
|
||||
|
||||
if game.isDigital {
|
||||
Image("digitalGame")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 15)
|
||||
}
|
||||
List(games.filter({$0.inWishlist == self.showWishlist})) { game in
|
||||
NavigationLink(destination: GameDetailView(game: game)) {
|
||||
HStack {
|
||||
Text("\(game.name ?? "n/a")")
|
||||
|
||||
if game.isDigital {
|
||||
Image("digitalGame")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 15)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
List {
|
||||
ForEach(accessoryStore.accessories.filter({$0.inWishlist == self.showWishlist})) { accessory in
|
||||
NavigationLink(destination: AccessoryDetailView(accessoryVM: AccessoryViewModel(accessory: accessory))) {
|
||||
Text("\(accessory.name)")
|
||||
}
|
||||
List(accessories.filter({$0.inWishlist == self.showWishlist})) {accessory in
|
||||
NavigationLink(destination: AccessoryDetailView(accessoryVM: AccessoryViewModel(accessory: accessory))) {
|
||||
Text("\(accessory.name)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitle(Text("\(self.console?.name ?? "N/A")"), displayMode: .automatic)
|
||||
.navigationBarTitle(Text("\(self.console.name ?? "n/a")"), displayMode: .automatic)
|
||||
.navigationBarItems(trailing:
|
||||
HStack {
|
||||
NavigationLink(destination: ConsoleEditView(console: self.console!)) {
|
||||
NavigationLink(destination: ConsoleEditView(console: self.console)) {
|
||||
Image(systemName: "pencil.and.ellipsis.rectangle")
|
||||
}
|
||||
|
||||
@@ -145,18 +147,7 @@ struct ConsoleLibraryView : View {
|
||||
.accentColor(self.showWishlist ? Color.red : Color.blue)
|
||||
})
|
||||
.sheet(isPresented: $showAddToConsoleLibraryModal) {
|
||||
if self.console != nil {
|
||||
ModalAddToConsoleLibrary(modalAddToWishlist: self.showWishlist, isVideogamesSelected: true, console: self.console!)
|
||||
}else{
|
||||
Text("Fehler: Keine Konsole übergeben")
|
||||
}
|
||||
|
||||
ModalAddToConsoleLibrary(modalAddToWishlist: self.showWishlist, isVideogamesSelected: self.isVideogamesSelected, console: self.console)
|
||||
}
|
||||
}
|
||||
|
||||
init(console : Console?) {
|
||||
self.console = console
|
||||
self.gameStore = GameStore(console: console)
|
||||
self.accessoryStore = AccessoryStore(console: console)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct GameDetailView : View {
|
||||
@ObservedObject var gameVM : GameViewModel
|
||||
@ObservedObject var game : Game
|
||||
|
||||
@State private var showDeleteAlert : Bool = false
|
||||
@State var hasFinishedDate : Bool = false
|
||||
@@ -18,83 +18,64 @@ struct GameDetailView : View {
|
||||
@EnvironmentObject var gameSeriesStore : GameSeriesStore
|
||||
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
|
||||
|
||||
|
||||
@State var showingPicker = false
|
||||
|
||||
@State var image : Image? = nil
|
||||
|
||||
@State var isImportingCover : Bool = false
|
||||
@State var isLent : Bool = false
|
||||
|
||||
let defaultImage = UIImage()
|
||||
|
||||
var gameSeriesPicker : some View {
|
||||
Picker(selection: $gameVM.gameSeries, label:
|
||||
Text("TODO GameSeries Picker")
|
||||
/*Picker(selection: $game.gameSeries, label:
|
||||
Text("Spieleserie")
|
||||
, content: {
|
||||
Text("Keine").tag("")
|
||||
ForEach(gameSeriesStore.gameSeries) { gameSeries in
|
||||
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 {
|
||||
Form {
|
||||
Section {
|
||||
TextField("Videogame name", text: $gameVM.name)
|
||||
TextField("Videogame name", text: $game.name ?? "")
|
||||
|
||||
//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")
|
||||
})
|
||||
|
||||
Toggle(isOn: $gameVM.inWishlist, label: {
|
||||
Toggle(isOn: $game.inWishlist, label: {
|
||||
Text("In Wunschliste")
|
||||
})
|
||||
|
||||
Toggle(isOn: $isLent, label: {
|
||||
Text("Verliehen?")
|
||||
}).onReceive(gameVM.objectWillChange) { _ in
|
||||
self.isLent = self.gameVM.lentTo != "";
|
||||
}).onReceive(game.objectWillChange) { _ in
|
||||
self.isLent = self.game.lentTo != "";
|
||||
}.onAppear() {
|
||||
self.isLent = self.gameVM.lentTo != "";
|
||||
self.isLent = self.game.lentTo != "";
|
||||
}
|
||||
|
||||
if isLent {
|
||||
TextField("Verliehen an", text: $gameVM.lentTo)
|
||||
TextField("Verliehen an", text: $game.lentTo ?? "")
|
||||
}
|
||||
|
||||
gameSeriesPicker
|
||||
|
||||
Toggle(isOn: $gameVM.isFinished , label: {
|
||||
Toggle(isOn: $game.isFinished , label: {
|
||||
Text("Durchgezockt")
|
||||
})
|
||||
|
||||
if gameVM.isFinished {
|
||||
if game.isFinished {
|
||||
Toggle(isOn: $hasFinishedDate, label: {
|
||||
Text("Gibts ein Datum")
|
||||
})
|
||||
}
|
||||
|
||||
if hasFinishedDate && gameVM.isFinished {
|
||||
if hasFinishedDate && game.isFinished {
|
||||
DatePicker("Durchgezockt am",
|
||||
selection: $playthroughDate,
|
||||
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{
|
||||
gameDeleteButton
|
||||
}
|
||||
|
||||
}
|
||||
.navigationBarTitle(Text("\(gameVM.name)"), displayMode: .automatic)
|
||||
.sheet(isPresented: $showingPicker,
|
||||
onDismiss: {
|
||||
// do whatever you need here
|
||||
}, content: {
|
||||
ImagePicker.shared.view
|
||||
})
|
||||
.onReceive(ImagePicker.shared.objectWillChange) { image in
|
||||
if let image = image {
|
||||
self.gameVM.cover = image
|
||||
.navigationBarTitle(Text("\(game.name ?? "N/A")"), displayMode: .automatic)
|
||||
.fileImporter(
|
||||
isPresented: $isImportingCover,
|
||||
allowedContentTypes: [.jpeg, .png],
|
||||
allowsMultipleSelection: false
|
||||
) { result in
|
||||
do {
|
||||
let selectedFile : URL = try result.get().first!
|
||||
|
||||
//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)
|
||||
.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: {
|
||||
//self.presentationMode.value.dismiss()
|
||||
self.gameVM.removeGame()
|
||||
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()
|
||||
}), 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 CoreData
|
||||
//extension String: Identifiable {
|
||||
// public var id: String {
|
||||
// return self
|
||||
@@ -20,15 +20,24 @@ struct SettingsView: View {
|
||||
@State var importFiles : [String] = LibraryImport().backupFiles()
|
||||
|
||||
func exportLibrary() {
|
||||
let games = GameStore().games
|
||||
let consoles = ConsoleStore().consoles
|
||||
let gameSeries = GameSeriesStore().gameSeries
|
||||
let accessories = AccessoryStore().accessories
|
||||
|
||||
let libExport = LibraryExporter(games: games, consoles: consoles, gameSeries: gameSeries, accessories: accessories)
|
||||
|
||||
libExport.export(name: Date().formattedInTimeZone())
|
||||
importFiles = LibraryImport().backupFiles()
|
||||
do {
|
||||
let gamesFR = NSFetchRequest<Game>(entityName: "Game")
|
||||
let consolesFR = NSFetchRequest<Console>(entityName: "Console")
|
||||
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)
|
||||
|
||||
libExport.export(name: Date().formattedInTimeZone())
|
||||
importFiles = LibraryImport().backupFiles()
|
||||
}catch {
|
||||
print("ERROR during export")
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
||||
@@ -23,10 +23,9 @@
|
||||
</entity>
|
||||
<entity name="Cover" representedClassName="Cover" syncable="YES">
|
||||
<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 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="inWishlist" 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="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="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"/>
|
||||
<fetchedProperty name="fetchedProperty" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="Game"/>
|
||||
@@ -59,8 +57,8 @@
|
||||
<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="Cover" positionX="-66.69921875" positionY="223.48046875" width="128" height="59"/>
|
||||
<element name="Game" positionX="-288.828125" positionY="276.7421875" width="128" height="245"/>
|
||||
<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="230"/>
|
||||
<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="Logo" positionX="-66.7109375" positionY="110.9765625" width="128" height="44"/>
|
||||
|
||||
Reference in New Issue
Block a user