diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..841a85c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+Cartfile.resolved
+Carthage/
+Zockerhoehle.xcodeproj/project.xcworkspace/xcuserdata/
+Zockerhoehle.xcodeproj/xcuserdata/julian.xcuserdatad/xcdebugger/
+Zockerhoehle.xcodeproj/xcuserdata/julian.xcuserdatad/xcschemes/Zockerhoehle.xcscheme
diff --git a/Cartfile b/Cartfile
new file mode 100644
index 0000000..feb86a6
--- /dev/null
+++ b/Cartfile
@@ -0,0 +1 @@
+github "dstranz/Disk" "feature/SPM_xcode11"
diff --git a/Zockerhoehle copy-Info.plist b/Zockerhoehle copy-Info.plist
new file mode 100644
index 0000000..e49a713
--- /dev/null
+++ b/Zockerhoehle copy-Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Zockerhöhle
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/Zockerhoehle.xcodeproj/project.pbxproj b/Zockerhoehle.xcodeproj/project.pbxproj
index 3eea45e..2b5bddd 100644
--- a/Zockerhoehle.xcodeproj/project.pbxproj
+++ b/Zockerhoehle.xcodeproj/project.pbxproj
@@ -7,21 +7,89 @@
objects = {
/* Begin PBXBuildFile section */
+ B926F12B2149B173004D36B7 /* ConsoleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F12A2149B173004D36B7 /* ConsoleCell.swift */; };
+ B926F12D2149B264004D36B7 /* FlockeEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F12C2149B264004D36B7 /* FlockeEntry.swift */; };
+ B926F131214AD9E4004D36B7 /* GameCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F130214AD9E4004D36B7 /* GameCollection.swift */; };
+ B926F139214AE884004D36B7 /* FlockeWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F138214AE884004D36B7 /* FlockeWS.swift */; };
+ B926F13C214C44FE004D36B7 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F13B214C44FE004D36B7 /* Attachment.swift */; };
+ B926F13F214E4678004D36B7 /* GameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F13E214E4678004D36B7 /* GameCell.swift */; };
+ B926F14721502D53004D36B7 /* CodableExtensionAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F14621502D53004D36B7 /* CodableExtensionAny.swift */; };
+ B926F14A21502DE1004D36B7 /* ConsoleEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F14921502DE1004D36B7 /* ConsoleEntry.swift */; };
B93C1B9D21496BFD0014FD6E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93C1B9C21496BFD0014FD6E /* AppDelegate.swift */; };
- B93C1B9F21496BFD0014FD6E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93C1B9E21496BFD0014FD6E /* ViewController.swift */; };
B93C1BA221496BFD0014FD6E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B93C1BA021496BFD0014FD6E /* Main.storyboard */; };
B93C1BA421496BFE0014FD6E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B93C1BA321496BFE0014FD6E /* Assets.xcassets */; };
- B93C1BA721496BFE0014FD6E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B93C1BA521496BFE0014FD6E /* LaunchScreen.storyboard */; };
+ B93C1BB02149750E0014FD6E /* AllConsolesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93C1BAF2149750E0014FD6E /* AllConsolesViewController.swift */; };
+ B93D60CC22D88F2B00DD390F /* AccessoryDetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93D60CB22D88F2B00DD390F /* AccessoryDetailController.swift */; };
+ B93D60CE22D88F5700DD390F /* AccessoryDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93D60CD22D88F5700DD390F /* AccessoryDetailView.swift */; };
+ B9418449215422ED0050D099 /* AddEntryPopUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9418448215422ED0050D099 /* AddEntryPopUpViewController.swift */; };
+ B941844B2156891E0050D099 /* UIButtonX.swift in Sources */ = {isa = PBXBuildFile; fileRef = B941844A2156891E0050D099 /* UIButtonX.swift */; };
+ B94CB4FF22D1352F0029BFAD /* Accessory+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4F322D1352F0029BFAD /* Accessory+CoreDataClass.swift */; };
+ B94CB50022D1352F0029BFAD /* Accessory+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4F422D1352F0029BFAD /* Accessory+CoreDataProperties.swift */; };
+ B94CB50122D1352F0029BFAD /* Cover+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4F522D1352F0029BFAD /* Cover+CoreDataClass.swift */; };
+ B94CB50222D1352F0029BFAD /* Cover+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4F622D1352F0029BFAD /* Cover+CoreDataProperties.swift */; };
+ B94CB50322D1352F0029BFAD /* Game+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4F722D1352F0029BFAD /* Game+CoreDataClass.swift */; };
+ B94CB50422D1352F0029BFAD /* Game+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4F822D1352F0029BFAD /* Game+CoreDataProperties.swift */; };
+ B94CB50522D1352F0029BFAD /* Console+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4F922D1352F0029BFAD /* Console+CoreDataClass.swift */; };
+ B94CB50622D1352F0029BFAD /* Console+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4FA22D1352F0029BFAD /* Console+CoreDataProperties.swift */; };
+ B94CB50722D1352F0029BFAD /* GameSeries+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4FB22D1352F0029BFAD /* GameSeries+CoreDataClass.swift */; };
+ B94CB50822D1352F0029BFAD /* GameSeries+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4FC22D1352F0029BFAD /* GameSeries+CoreDataProperties.swift */; };
+ B94CB50922D1352F0029BFAD /* Logo+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4FD22D1352F0029BFAD /* Logo+CoreDataClass.swift */; };
+ B94CB50A22D1352F0029BFAD /* Logo+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB4FE22D1352F0029BFAD /* Logo+CoreDataProperties.swift */; };
+ B94CB53722D3B3CC0029BFAD /* GameDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB53622D3B3CC0029BFAD /* GameDetailView.swift */; };
+ B94CB53922D3B6490029BFAD /* GameDetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B94CB53822D3B6490029BFAD /* GameDetailController.swift */; };
+ B98A734D22BAD27D00FB3410 /* Zockerhoehle.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B98A731722BA9E4600FB3410 /* Zockerhoehle.xcdatamodeld */; };
+ B98A735E22BFAA4B00FB3410 /* ConsoleLibraryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B926F12E2149B6F5004D36B7 /* ConsoleLibraryViewController.swift */; };
+ B98A736022C1738800FB3410 /* CDManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98A735F22C1738800FB3410 /* CDManager.swift */; };
+ B9BCF4CA2168ACB600ECBAAC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9BCF4C92168ACB600ECBAAC /* LaunchScreen.storyboard */; };
+ B9BCF523217900D700ECBAAC /* WaitingPopOver.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9BCF521217900D700ECBAAC /* WaitingPopOver.storyboard */; };
+ B9D6A39A22D885DD00A280DC /* AccessoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D6A39922D885DD00A280DC /* AccessoryCell.swift */; };
+ B9E256FE2156D026009FD133 /* UIViewX.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9E256FD2156D026009FD133 /* UIViewX.swift */; };
+ B9F002E52187AA3200E12B0A /* FlockeConnector.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9F002E42187AA3200E12B0A /* FlockeConnector.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
+ B926F12A2149B173004D36B7 /* ConsoleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleCell.swift; sourceTree = ""; };
+ B926F12C2149B264004D36B7 /* FlockeEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlockeEntry.swift; sourceTree = ""; };
+ B926F12E2149B6F5004D36B7 /* ConsoleLibraryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleLibraryViewController.swift; sourceTree = ""; };
+ B926F130214AD9E4004D36B7 /* GameCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameCollection.swift; sourceTree = ""; };
+ B926F138214AE884004D36B7 /* FlockeWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlockeWS.swift; sourceTree = ""; };
+ B926F13B214C44FE004D36B7 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; };
+ B926F13E214E4678004D36B7 /* GameCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameCell.swift; sourceTree = ""; };
+ B926F14621502D53004D36B7 /* CodableExtensionAny.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableExtensionAny.swift; sourceTree = ""; };
+ B926F14921502DE1004D36B7 /* ConsoleEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsoleEntry.swift; sourceTree = ""; };
B93C1B9921496BFD0014FD6E /* Zockerhoehle.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Zockerhoehle.app; sourceTree = BUILT_PRODUCTS_DIR; };
B93C1B9C21496BFD0014FD6E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
- B93C1B9E21496BFD0014FD6E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
B93C1BA121496BFD0014FD6E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
B93C1BA321496BFE0014FD6E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
- B93C1BA621496BFE0014FD6E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
B93C1BA821496BFE0014FD6E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ B93C1BAE21496CC50014FD6E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; sourceTree = ""; };
+ B93C1BAF2149750E0014FD6E /* AllConsolesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllConsolesViewController.swift; sourceTree = ""; };
+ B93D60CB22D88F2B00DD390F /* AccessoryDetailController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessoryDetailController.swift; sourceTree = ""; };
+ B93D60CD22D88F5700DD390F /* AccessoryDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessoryDetailView.swift; sourceTree = ""; };
+ B9418448215422ED0050D099 /* AddEntryPopUpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEntryPopUpViewController.swift; sourceTree = ""; };
+ B941844A2156891E0050D099 /* UIButtonX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIButtonX.swift; sourceTree = ""; };
+ B94CB4F322D1352F0029BFAD /* Accessory+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Accessory+CoreDataClass.swift"; sourceTree = ""; };
+ B94CB4F422D1352F0029BFAD /* Accessory+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Accessory+CoreDataProperties.swift"; sourceTree = ""; };
+ B94CB4F522D1352F0029BFAD /* Cover+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Cover+CoreDataClass.swift"; sourceTree = ""; };
+ B94CB4F622D1352F0029BFAD /* Cover+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Cover+CoreDataProperties.swift"; sourceTree = ""; };
+ B94CB4F722D1352F0029BFAD /* Game+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Game+CoreDataClass.swift"; sourceTree = ""; };
+ B94CB4F822D1352F0029BFAD /* Game+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Game+CoreDataProperties.swift"; sourceTree = ""; };
+ B94CB4F922D1352F0029BFAD /* Console+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Console+CoreDataClass.swift"; sourceTree = ""; };
+ B94CB4FA22D1352F0029BFAD /* Console+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Console+CoreDataProperties.swift"; sourceTree = ""; };
+ B94CB4FB22D1352F0029BFAD /* GameSeries+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GameSeries+CoreDataClass.swift"; sourceTree = ""; };
+ B94CB4FC22D1352F0029BFAD /* GameSeries+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GameSeries+CoreDataProperties.swift"; sourceTree = ""; };
+ B94CB4FD22D1352F0029BFAD /* Logo+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logo+CoreDataClass.swift"; sourceTree = ""; };
+ B94CB4FE22D1352F0029BFAD /* Logo+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logo+CoreDataProperties.swift"; sourceTree = ""; };
+ B94CB53522D3708F0029BFAD /* Zockerhoehle copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Zockerhoehle copy-Info.plist"; path = "/Users/julian/Entwicklung/Zockerhoehle/Zockerhoehle copy-Info.plist"; sourceTree = ""; };
+ B94CB53622D3B3CC0029BFAD /* GameDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameDetailView.swift; sourceTree = ""; };
+ B94CB53822D3B6490029BFAD /* GameDetailController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameDetailController.swift; sourceTree = ""; };
+ B98A731822BA9E4600FB3410 /* Zockerhoehle.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Zockerhoehle.xcdatamodel; sourceTree = ""; };
+ B98A735F22C1738800FB3410 /* CDManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CDManager.swift; sourceTree = ""; };
+ B9BCF4C92168ACB600ECBAAC /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; };
+ B9BCF522217900D700ECBAAC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Zockerhoehle/Base.lproj/WaitingPopOver.storyboard; sourceTree = ""; };
+ B9D6A39922D885DD00A280DC /* AccessoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessoryCell.swift; sourceTree = ""; };
+ B9E256FD2156D026009FD133 /* UIViewX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewX.swift; sourceTree = ""; };
+ B9F002E42187AA3200E12B0A /* FlockeConnector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlockeConnector.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -35,11 +103,74 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ B90B64A12235909900E54BA3 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ B926F134214AE2C0004D36B7 /* Model */ = {
+ isa = PBXGroup;
+ children = (
+ B926F130214AD9E4004D36B7 /* GameCollection.swift */,
+ B926F13B214C44FE004D36B7 /* Attachment.swift */,
+ B926F12C2149B264004D36B7 /* FlockeEntry.swift */,
+ B926F14921502DE1004D36B7 /* ConsoleEntry.swift */,
+ );
+ path = Model;
+ sourceTree = "";
+ };
+ B926F135214AE2D4004D36B7 /* ViewController */ = {
+ isa = PBXGroup;
+ children = (
+ B926F12E2149B6F5004D36B7 /* ConsoleLibraryViewController.swift */,
+ B93C1BAF2149750E0014FD6E /* AllConsolesViewController.swift */,
+ B9418448215422ED0050D099 /* AddEntryPopUpViewController.swift */,
+ B94CB53822D3B6490029BFAD /* GameDetailController.swift */,
+ B93D60CB22D88F2B00DD390F /* AccessoryDetailController.swift */,
+ );
+ path = ViewController;
+ sourceTree = "";
+ };
+ B926F136214AE2E3004D36B7 /* Views */ = {
+ isa = PBXGroup;
+ children = (
+ B926F12A2149B173004D36B7 /* ConsoleCell.swift */,
+ B926F13E214E4678004D36B7 /* GameCell.swift */,
+ B94CB53622D3B3CC0029BFAD /* GameDetailView.swift */,
+ B9D6A39922D885DD00A280DC /* AccessoryCell.swift */,
+ B93D60CD22D88F5700DD390F /* AccessoryDetailView.swift */,
+ );
+ path = Views;
+ sourceTree = "";
+ };
+ B926F13A214AF21B004D36B7 /* Utils */ = {
+ isa = PBXGroup;
+ children = (
+ B926F138214AE884004D36B7 /* FlockeWS.swift */,
+ B9F002E42187AA3200E12B0A /* FlockeConnector.swift */,
+ );
+ path = Utils;
+ sourceTree = "";
+ };
+ B926F14821502D7F004D36B7 /* Lib */ = {
+ isa = PBXGroup;
+ children = (
+ B926F14621502D53004D36B7 /* CodableExtensionAny.swift */,
+ B941844A2156891E0050D099 /* UIButtonX.swift */,
+ B9E256FD2156D026009FD133 /* UIViewX.swift */,
+ );
+ path = Lib;
+ sourceTree = "";
+ };
B93C1B9021496BFD0014FD6E = {
isa = PBXGroup;
children = (
B93C1B9B21496BFD0014FD6E /* Zockerhoehle */,
B93C1B9A21496BFD0014FD6E /* Products */,
+ B90B64A12235909900E54BA3 /* Frameworks */,
+ B94CB53522D3708F0029BFAD /* Zockerhoehle copy-Info.plist */,
);
sourceTree = "";
};
@@ -54,16 +185,43 @@
B93C1B9B21496BFD0014FD6E /* Zockerhoehle */ = {
isa = PBXGroup;
children = (
+ B98A734622BACA9C00FB3410 /* CDModel */,
+ B926F14821502D7F004D36B7 /* Lib */,
+ B926F13A214AF21B004D36B7 /* Utils */,
+ B926F136214AE2E3004D36B7 /* Views */,
+ B926F135214AE2D4004D36B7 /* ViewController */,
+ B926F134214AE2C0004D36B7 /* Model */,
B93C1B9C21496BFD0014FD6E /* AppDelegate.swift */,
- B93C1B9E21496BFD0014FD6E /* ViewController.swift */,
+ B9BCF521217900D700ECBAAC /* WaitingPopOver.storyboard */,
B93C1BA021496BFD0014FD6E /* Main.storyboard */,
+ B9BCF4C92168ACB600ECBAAC /* LaunchScreen.storyboard */,
+ B98A735F22C1738800FB3410 /* CDManager.swift */,
B93C1BA321496BFE0014FD6E /* Assets.xcassets */,
- B93C1BA521496BFE0014FD6E /* LaunchScreen.storyboard */,
B93C1BA821496BFE0014FD6E /* Info.plist */,
+ B98A731722BA9E4600FB3410 /* Zockerhoehle.xcdatamodeld */,
);
path = Zockerhoehle;
sourceTree = "";
};
+ B98A734622BACA9C00FB3410 /* CDModel */ = {
+ isa = PBXGroup;
+ children = (
+ B94CB4F322D1352F0029BFAD /* Accessory+CoreDataClass.swift */,
+ B94CB4F422D1352F0029BFAD /* Accessory+CoreDataProperties.swift */,
+ B94CB4F522D1352F0029BFAD /* Cover+CoreDataClass.swift */,
+ B94CB4F622D1352F0029BFAD /* Cover+CoreDataProperties.swift */,
+ B94CB4F722D1352F0029BFAD /* Game+CoreDataClass.swift */,
+ B94CB4F822D1352F0029BFAD /* Game+CoreDataProperties.swift */,
+ B94CB4F922D1352F0029BFAD /* Console+CoreDataClass.swift */,
+ B94CB4FA22D1352F0029BFAD /* Console+CoreDataProperties.swift */,
+ B94CB4FB22D1352F0029BFAD /* GameSeries+CoreDataClass.swift */,
+ B94CB4FC22D1352F0029BFAD /* GameSeries+CoreDataProperties.swift */,
+ B94CB4FD22D1352F0029BFAD /* Logo+CoreDataClass.swift */,
+ B94CB4FE22D1352F0029BFAD /* Logo+CoreDataProperties.swift */,
+ );
+ path = CDModel;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -74,6 +232,7 @@
B93C1B9521496BFD0014FD6E /* Sources */,
B93C1B9621496BFD0014FD6E /* Frameworks */,
B93C1B9721496BFD0014FD6E /* Resources */,
+ B90B64A4223590DA00E54BA3 /* ShellScript */,
);
buildRules = (
);
@@ -96,6 +255,7 @@
TargetAttributes = {
B93C1B9821496BFD0014FD6E = {
CreatedOnToolsVersion = 9.4.1;
+ LastSwiftMigration = 1020;
};
};
};
@@ -106,6 +266,7 @@
knownRegions = (
en,
Base,
+ de,
);
mainGroup = B93C1B9021496BFD0014FD6E;
productRefGroup = B93C1B9A21496BFD0014FD6E /* Products */;
@@ -122,21 +283,75 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- B93C1BA721496BFE0014FD6E /* LaunchScreen.storyboard in Resources */,
+ B9BCF4CA2168ACB600ECBAAC /* LaunchScreen.storyboard in Resources */,
B93C1BA421496BFE0014FD6E /* Assets.xcassets in Resources */,
+ B9BCF523217900D700ECBAAC /* WaitingPopOver.storyboard in Resources */,
B93C1BA221496BFD0014FD6E /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
+/* Begin PBXShellScriptBuildPhase section */
+ B90B64A4223590DA00E54BA3 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/Carthage/Build/iOS/Disk.framework",
+ );
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/usr/local/bin/carthage copy-frameworks\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
/* Begin PBXSourcesBuildPhase section */
B93C1B9521496BFD0014FD6E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- B93C1B9F21496BFD0014FD6E /* ViewController.swift in Sources */,
+ B94CB53922D3B6490029BFAD /* GameDetailController.swift in Sources */,
+ B926F139214AE884004D36B7 /* FlockeWS.swift in Sources */,
+ B926F13C214C44FE004D36B7 /* Attachment.swift in Sources */,
B93C1B9D21496BFD0014FD6E /* AppDelegate.swift in Sources */,
+ B94CB53722D3B3CC0029BFAD /* GameDetailView.swift in Sources */,
+ B94CB50322D1352F0029BFAD /* Game+CoreDataClass.swift in Sources */,
+ B94CB50822D1352F0029BFAD /* GameSeries+CoreDataProperties.swift in Sources */,
+ B93C1BB02149750E0014FD6E /* AllConsolesViewController.swift in Sources */,
+ B926F13F214E4678004D36B7 /* GameCell.swift in Sources */,
+ B9F002E52187AA3200E12B0A /* FlockeConnector.swift in Sources */,
+ B94CB50A22D1352F0029BFAD /* Logo+CoreDataProperties.swift in Sources */,
+ B94CB4FF22D1352F0029BFAD /* Accessory+CoreDataClass.swift in Sources */,
+ B98A734D22BAD27D00FB3410 /* Zockerhoehle.xcdatamodeld in Sources */,
+ B9E256FE2156D026009FD133 /* UIViewX.swift in Sources */,
+ B926F12B2149B173004D36B7 /* ConsoleCell.swift in Sources */,
+ B926F12D2149B264004D36B7 /* FlockeEntry.swift in Sources */,
+ B98A735E22BFAA4B00FB3410 /* ConsoleLibraryViewController.swift in Sources */,
+ B94CB50522D1352F0029BFAD /* Console+CoreDataClass.swift in Sources */,
+ B941844B2156891E0050D099 /* UIButtonX.swift in Sources */,
+ B94CB50922D1352F0029BFAD /* Logo+CoreDataClass.swift in Sources */,
+ B94CB50622D1352F0029BFAD /* Console+CoreDataProperties.swift in Sources */,
+ B926F131214AD9E4004D36B7 /* GameCollection.swift in Sources */,
+ B93D60CE22D88F5700DD390F /* AccessoryDetailView.swift in Sources */,
+ B926F14A21502DE1004D36B7 /* ConsoleEntry.swift in Sources */,
+ B93D60CC22D88F2B00DD390F /* AccessoryDetailController.swift in Sources */,
+ B94CB50722D1352F0029BFAD /* GameSeries+CoreDataClass.swift in Sources */,
+ B9418449215422ED0050D099 /* AddEntryPopUpViewController.swift in Sources */,
+ B94CB50022D1352F0029BFAD /* Accessory+CoreDataProperties.swift in Sources */,
+ B9D6A39A22D885DD00A280DC /* AccessoryCell.swift in Sources */,
+ B926F14721502D53004D36B7 /* CodableExtensionAny.swift in Sources */,
+ B94CB50422D1352F0029BFAD /* Game+CoreDataProperties.swift in Sources */,
+ B98A736022C1738800FB3410 /* CDManager.swift in Sources */,
+ B94CB50222D1352F0029BFAD /* Cover+CoreDataProperties.swift in Sources */,
+ B94CB50122D1352F0029BFAD /* Cover+CoreDataClass.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -147,16 +362,17 @@
isa = PBXVariantGroup;
children = (
B93C1BA121496BFD0014FD6E /* Base */,
+ B93C1BAE21496CC50014FD6E /* de */,
);
name = Main.storyboard;
sourceTree = "";
};
- B93C1BA521496BFE0014FD6E /* LaunchScreen.storyboard */ = {
+ B9BCF521217900D700ECBAAC /* WaitingPopOver.storyboard */ = {
isa = PBXVariantGroup;
children = (
- B93C1BA621496BFE0014FD6E /* Base */,
+ B9BCF522217900D700ECBAAC /* Base */,
);
- name = LaunchScreen.storyboard;
+ name = WaitingPopOver.storyboard;
sourceTree = "";
};
/* End PBXVariantGroup section */
@@ -166,6 +382,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@@ -213,7 +430,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.4;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -226,6 +443,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@@ -267,7 +485,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.4;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
@@ -282,6 +500,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = M9N7K3KZX9;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Carthage/Build/iOS",
+ );
INFOPLIST_FILE = Zockerhoehle/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -289,7 +511,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "de.mm-neuemedien.Zockerhoehle";
PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
@@ -300,6 +522,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = M9N7K3KZX9;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Carthage/Build/iOS",
+ );
INFOPLIST_FILE = Zockerhoehle/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -307,7 +533,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "de.mm-neuemedien.Zockerhoehle";
PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
@@ -334,6 +560,19 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
+
+/* Begin XCVersionGroup section */
+ B98A731722BA9E4600FB3410 /* Zockerhoehle.xcdatamodeld */ = {
+ isa = XCVersionGroup;
+ children = (
+ B98A731822BA9E4600FB3410 /* Zockerhoehle.xcdatamodel */,
+ );
+ currentVersion = B98A731822BA9E4600FB3410 /* Zockerhoehle.xcdatamodel */;
+ path = Zockerhoehle.xcdatamodeld;
+ sourceTree = "";
+ versionGroupType = wrapper.xcdatamodel;
+ };
+/* End XCVersionGroup section */
};
rootObject = B93C1B9121496BFD0014FD6E /* Project object */;
}
diff --git a/Zockerhoehle.xcodeproj/xcuserdata/julian.xcuserdatad/xcschemes/xcschememanagement.plist b/Zockerhoehle.xcodeproj/xcuserdata/julian.xcuserdatad/xcschemes/xcschememanagement.plist
index 764b9de..381e402 100644
--- a/Zockerhoehle.xcodeproj/xcuserdata/julian.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Zockerhoehle.xcodeproj/xcuserdata/julian.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -4,11 +4,24 @@
SchemeUserState
+ Zockerhoehle copy.xcscheme_^#shared#^_
+
+ orderHint
+ 1
+
Zockerhoehle.xcscheme
orderHint
0
+ SuppressBuildableAutocreation
+
+ B93C1B9821496BFD0014FD6E
+
+ primary
+
+
+
diff --git a/Zockerhoehle/AppDelegate.swift b/Zockerhoehle/AppDelegate.swift
index 443320d..a429f28 100644
--- a/Zockerhoehle/AppDelegate.swift
+++ b/Zockerhoehle/AppDelegate.swift
@@ -7,15 +7,23 @@
//
import UIKit
+import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
-
- func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
+ #if targetEnvironment(simulator)
+ if let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.path {
+ print("Documents Directory: \(documentsPath)")
+ }
+ #endif
+
+ print("disFinishLaunchung")
+
return true
}
@@ -40,7 +48,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
-
-
}
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Contents.json b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Contents.json
index d8db8d6..6cbb23b 100644
--- a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1,93 +1,111 @@
{
"images" : [
{
- "idiom" : "iphone",
"size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-40.png",
"scale" : "2x"
},
{
- "idiom" : "iphone",
"size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-60.png",
"scale" : "3x"
},
{
- "idiom" : "iphone",
"size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-58.png",
"scale" : "2x"
},
{
- "idiom" : "iphone",
"size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-87.png",
"scale" : "3x"
},
{
- "idiom" : "iphone",
"size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-80.png",
"scale" : "2x"
},
{
- "idiom" : "iphone",
"size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-121.png",
"scale" : "3x"
},
{
- "idiom" : "iphone",
"size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-120.png",
"scale" : "2x"
},
{
- "idiom" : "iphone",
"size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-180.png",
"scale" : "3x"
},
{
- "idiom" : "ipad",
"size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-20.png",
"scale" : "1x"
},
{
- "idiom" : "ipad",
"size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-41.png",
"scale" : "2x"
},
{
- "idiom" : "ipad",
"size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-29.png",
"scale" : "1x"
},
{
- "idiom" : "ipad",
"size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-59.png",
"scale" : "2x"
},
{
- "idiom" : "ipad",
"size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-42.png",
"scale" : "1x"
},
{
- "idiom" : "ipad",
"size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-81.png",
"scale" : "2x"
},
{
- "idiom" : "ipad",
"size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-76.png",
"scale" : "1x"
},
{
- "idiom" : "ipad",
"size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-152.png",
"scale" : "2x"
},
{
- "idiom" : "ipad",
"size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "Icon-167.png",
"scale" : "2x"
},
{
- "idiom" : "ios-marketing",
"size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "Icon-1024.png",
"scale" : "1x"
}
],
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-1024.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-1024.png
new file mode 100644
index 0000000..02827a7
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-1024.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-120.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-120.png
new file mode 100644
index 0000000..9057a9d
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-120.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-121.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-121.png
new file mode 100644
index 0000000..9057a9d
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-121.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-152.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-152.png
new file mode 100644
index 0000000..e5acd22
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-152.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-167.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-167.png
new file mode 100644
index 0000000..6467f47
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-167.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-180.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-180.png
new file mode 100644
index 0000000..0c20764
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-180.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-20.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-20.png
new file mode 100644
index 0000000..f1c3d0f
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-20.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-29.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-29.png
new file mode 100644
index 0000000..c23207e
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-29.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-40.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-40.png
new file mode 100644
index 0000000..664d4b6
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-40.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-41.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-41.png
new file mode 100644
index 0000000..664d4b6
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-41.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-42.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-42.png
new file mode 100644
index 0000000..664d4b6
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-42.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-58.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-58.png
new file mode 100644
index 0000000..36a836b
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-58.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-59.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-59.png
new file mode 100644
index 0000000..36a836b
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-59.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-60.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-60.png
new file mode 100644
index 0000000..e3dd297
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-60.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-76.png
new file mode 100644
index 0000000..493400e
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-76.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-80.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-80.png
new file mode 100644
index 0000000..c352eb7
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-80.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-81.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-81.png
new file mode 100644
index 0000000..c352eb7
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-81.png differ
diff --git a/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-87.png b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-87.png
new file mode 100644
index 0000000..b401f0d
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/AppIcon.appiconset/Icon-87.png differ
diff --git a/Zockerhoehle/Assets.xcassets/LaunchScreen.imageset/Contents.json b/Zockerhoehle/Assets.xcassets/LaunchScreen.imageset/Contents.json
new file mode 100644
index 0000000..e9221c4
--- /dev/null
+++ b/Zockerhoehle/Assets.xcassets/LaunchScreen.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "filename" : "Default-2436h.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Zockerhoehle/Assets.xcassets/LaunchScreen.imageset/Default-2436h.png b/Zockerhoehle/Assets.xcassets/LaunchScreen.imageset/Default-2436h.png
new file mode 100644
index 0000000..a4bb9b3
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/LaunchScreen.imageset/Default-2436h.png differ
diff --git a/Zockerhoehle/Assets.xcassets/basket.imageset/Contents.json b/Zockerhoehle/Assets.xcassets/basket.imageset/Contents.json
new file mode 100644
index 0000000..63f8852
--- /dev/null
+++ b/Zockerhoehle/Assets.xcassets/basket.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "basket-supermarket.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Zockerhoehle/Assets.xcassets/basket.imageset/basket-supermarket.png b/Zockerhoehle/Assets.xcassets/basket.imageset/basket-supermarket.png
new file mode 100644
index 0000000..13f478d
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/basket.imageset/basket-supermarket.png differ
diff --git a/Zockerhoehle/Assets.xcassets/cave.imageset/Contents.json b/Zockerhoehle/Assets.xcassets/cave.imageset/Contents.json
new file mode 100644
index 0000000..76d4481
--- /dev/null
+++ b/Zockerhoehle/Assets.xcassets/cave.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "cave-2.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Zockerhoehle/Assets.xcassets/cave.imageset/cave-2.png b/Zockerhoehle/Assets.xcassets/cave.imageset/cave-2.png
new file mode 100644
index 0000000..ceb6916
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/cave.imageset/cave-2.png differ
diff --git a/Zockerhoehle/Assets.xcassets/delete.imageset/Contents.json b/Zockerhoehle/Assets.xcassets/delete.imageset/Contents.json
new file mode 100644
index 0000000..41b3654
--- /dev/null
+++ b/Zockerhoehle/Assets.xcassets/delete.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "delete.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Zockerhoehle/Assets.xcassets/delete.imageset/delete.png b/Zockerhoehle/Assets.xcassets/delete.imageset/delete.png
new file mode 100644
index 0000000..8b88b2c
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/delete.imageset/delete.png differ
diff --git a/Zockerhoehle/Assets.xcassets/star.imageset/Contents.json b/Zockerhoehle/Assets.xcassets/star.imageset/Contents.json
new file mode 100644
index 0000000..a6b6629
--- /dev/null
+++ b/Zockerhoehle/Assets.xcassets/star.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "star.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Zockerhoehle/Assets.xcassets/star.imageset/star.png b/Zockerhoehle/Assets.xcassets/star.imageset/star.png
new file mode 100644
index 0000000..3f1caa5
Binary files /dev/null and b/Zockerhoehle/Assets.xcassets/star.imageset/star.png differ
diff --git a/Zockerhoehle/Base.lproj/LaunchScreen.storyboard b/Zockerhoehle/Base.lproj/LaunchScreen.storyboard
deleted file mode 100644
index f83f6fd..0000000
--- a/Zockerhoehle/Base.lproj/LaunchScreen.storyboard
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Zockerhoehle/Base.lproj/Main.storyboard b/Zockerhoehle/Base.lproj/Main.storyboard
index 03c13c2..bb8a284 100644
--- a/Zockerhoehle/Base.lproj/Main.storyboard
+++ b/Zockerhoehle/Base.lproj/Main.storyboard
@@ -1,24 +1,504 @@
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Zockerhoehle/CDManager.swift b/Zockerhoehle/CDManager.swift
new file mode 100644
index 0000000..d53a697
--- /dev/null
+++ b/Zockerhoehle/CDManager.swift
@@ -0,0 +1,69 @@
+//
+// CDManager.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 24.06.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+import CoreData
+
+class CDManager {
+
+ static let shared : CDManager = CDManager();
+
+ private init() {
+
+ }
+
+ // MARK: - Core Data stack
+
+ lazy var persistentContainer: NSPersistentContainer = {
+ /*
+ The persistent container for the application. This implementation
+ creates and returns a container, having loaded the store for the
+ application to it. This property is optional since there are legitimate
+ error conditions that could cause the creation of the store to fail.
+ */
+ let container = NSPersistentContainer(name: "Zockerhoehle")
+ container.loadPersistentStores(completionHandler: { (storeDescription, error) in
+ if let error = error as NSError? {
+ // Replace this implementation with code to handle the error appropriately.
+ // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
+
+ /*
+ Typical reasons for an error here include:
+ * The parent directory does not exist, cannot be created, or disallows writing.
+ * The persistent store is not accessible, due to permissions or data protection when the device is locked.
+ * The device is out of space.
+ * The store could not be migrated to the current model version.
+ Check the error message to determine what the actual problem was.
+ */
+ fatalError("Unresolved error \(error), \(error.userInfo)")
+ }
+ })
+ return container
+ }()
+
+ lazy var viewContext : NSManagedObjectContext = {
+ self.persistentContainer.viewContext
+ }()
+
+ // MARK: - Core Data Saving support
+
+ func saveContext () {
+ persistentContainer.performBackgroundTask({(context) in
+ if context.hasChanges {
+ do {
+ try context.save()
+ } catch {
+ // Replace this implementation with code to handle the error appropriately.
+ // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
+ let nserror = error as NSError
+ fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
+ }
+ }
+ })
+ }
+}
diff --git a/Zockerhoehle/CDModel/Accessory+CoreDataClass.swift b/Zockerhoehle/CDModel/Accessory+CoreDataClass.swift
new file mode 100644
index 0000000..bb01f19
--- /dev/null
+++ b/Zockerhoehle/CDModel/Accessory+CoreDataClass.swift
@@ -0,0 +1,16 @@
+//
+// Accessory+CoreDataClass.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+@objc(Accessory)
+public class Accessory: NSManagedObject {
+
+}
diff --git a/Zockerhoehle/CDModel/Accessory+CoreDataProperties.swift b/Zockerhoehle/CDModel/Accessory+CoreDataProperties.swift
new file mode 100644
index 0000000..0b47bb3
--- /dev/null
+++ b/Zockerhoehle/CDModel/Accessory+CoreDataProperties.swift
@@ -0,0 +1,26 @@
+//
+// Accessory+CoreDataProperties.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+
+extension Accessory {
+
+ @nonobjc public class func fetchRequest() -> NSFetchRequest {
+ return NSFetchRequest(entityName: "Accessory")
+ }
+
+ @NSManaged public var color: String?
+ @NSManaged public var manufacturer: String?
+ @NSManaged public var name: String
+ @NSManaged public var inWishlist: Bool
+ @NSManaged public var console: Console?
+
+}
diff --git a/Zockerhoehle/CDModel/Console+CoreDataClass.swift b/Zockerhoehle/CDModel/Console+CoreDataClass.swift
new file mode 100644
index 0000000..febe48f
--- /dev/null
+++ b/Zockerhoehle/CDModel/Console+CoreDataClass.swift
@@ -0,0 +1,16 @@
+//
+// Console+CoreDataClass.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+@objc(Console)
+public class Console: NSManagedObject {
+
+}
diff --git a/Zockerhoehle/CDModel/Console+CoreDataProperties.swift b/Zockerhoehle/CDModel/Console+CoreDataProperties.swift
new file mode 100644
index 0000000..b5e34b6
--- /dev/null
+++ b/Zockerhoehle/CDModel/Console+CoreDataProperties.swift
@@ -0,0 +1,61 @@
+//
+// Console+CoreDataProperties.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+
+extension Console {
+
+ @nonobjc public class func fetchRequest() -> NSFetchRequest {
+ return NSFetchRequest(entityName: "Console")
+ }
+
+ @NSManaged public var generation: Int64
+ @NSManaged public var manufacturer: String?
+ @NSManaged public var name: String?
+ @NSManaged public var accessories: NSSet
+ @NSManaged public var games: NSSet
+ @NSManaged public var logo: Logo?
+
+}
+
+// MARK: Generated accessors for accessories
+extension Console {
+
+ @objc(addAccessoriesObject:)
+ @NSManaged public func addToAccessories(_ value: Accessory)
+
+ @objc(removeAccessoriesObject:)
+ @NSManaged public func removeFromAccessories(_ value: Accessory)
+
+ @objc(addAccessories:)
+ @NSManaged public func addToAccessories(_ values: NSSet)
+
+ @objc(removeAccessories:)
+ @NSManaged public func removeFromAccessories(_ values: NSSet)
+
+}
+
+// MARK: Generated accessors for games
+extension Console {
+
+ @objc(addGamesObject:)
+ @NSManaged public func addToGames(_ value: Game)
+
+ @objc(removeGamesObject:)
+ @NSManaged public func removeFromGames(_ value: Game)
+
+ @objc(addGames:)
+ @NSManaged public func addToGames(_ values: NSSet)
+
+ @objc(removeGames:)
+ @NSManaged public func removeFromGames(_ values: NSSet)
+
+}
diff --git a/Zockerhoehle/CDModel/Cover+CoreDataClass.swift b/Zockerhoehle/CDModel/Cover+CoreDataClass.swift
new file mode 100644
index 0000000..3eeba26
--- /dev/null
+++ b/Zockerhoehle/CDModel/Cover+CoreDataClass.swift
@@ -0,0 +1,16 @@
+//
+// Cover+CoreDataClass.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+@objc(Cover)
+public class Cover: NSManagedObject {
+
+}
diff --git a/Zockerhoehle/CDModel/Cover+CoreDataProperties.swift b/Zockerhoehle/CDModel/Cover+CoreDataProperties.swift
new file mode 100644
index 0000000..25e0dba
--- /dev/null
+++ b/Zockerhoehle/CDModel/Cover+CoreDataProperties.swift
@@ -0,0 +1,23 @@
+//
+// Cover+CoreDataProperties.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+import UIKit.UIImage
+
+extension Cover {
+
+ @nonobjc public class func fetchRequest() -> NSFetchRequest {
+ return NSFetchRequest(entityName: "Cover")
+ }
+
+ @NSManaged public var image: UIImage?
+ @NSManaged public var game: Game?
+
+}
diff --git a/Zockerhoehle/CDModel/Game+CoreDataClass.swift b/Zockerhoehle/CDModel/Game+CoreDataClass.swift
new file mode 100644
index 0000000..0f6cf8b
--- /dev/null
+++ b/Zockerhoehle/CDModel/Game+CoreDataClass.swift
@@ -0,0 +1,16 @@
+//
+// Game+CoreDataClass.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+@objc(Game)
+public class Game: NSManagedObject {
+
+}
diff --git a/Zockerhoehle/CDModel/Game+CoreDataProperties.swift b/Zockerhoehle/CDModel/Game+CoreDataProperties.swift
new file mode 100644
index 0000000..132928e
--- /dev/null
+++ b/Zockerhoehle/CDModel/Game+CoreDataProperties.swift
@@ -0,0 +1,30 @@
+//
+// Game+CoreDataProperties.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+
+extension Game {
+
+ @nonobjc public class func fetchRequest() -> NSFetchRequest {
+ return NSFetchRequest(entityName: "Game")
+ }
+
+ @NSManaged public var finished: Date?
+ @NSManaged public var inWishlist: Bool
+ @NSManaged public var isDigital: Bool
+ @NSManaged public var name: String
+ @NSManaged public var notes: String?
+ @NSManaged public var publisher: String?
+ @NSManaged public var console: Console?
+ @NSManaged public var series: GameSeries?
+ @NSManaged public var cover: Cover?
+
+}
diff --git a/Zockerhoehle/CDModel/GameSeries+CoreDataClass.swift b/Zockerhoehle/CDModel/GameSeries+CoreDataClass.swift
new file mode 100644
index 0000000..887afef
--- /dev/null
+++ b/Zockerhoehle/CDModel/GameSeries+CoreDataClass.swift
@@ -0,0 +1,16 @@
+//
+// GameSeries+CoreDataClass.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+@objc(GameSeries)
+public class GameSeries: NSManagedObject {
+
+}
diff --git a/Zockerhoehle/CDModel/GameSeries+CoreDataProperties.swift b/Zockerhoehle/CDModel/GameSeries+CoreDataProperties.swift
new file mode 100644
index 0000000..52fc4e6
--- /dev/null
+++ b/Zockerhoehle/CDModel/GameSeries+CoreDataProperties.swift
@@ -0,0 +1,41 @@
+//
+// GameSeries+CoreDataProperties.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+
+extension GameSeries {
+
+ @nonobjc public class func fetchRequest() -> NSFetchRequest {
+ return NSFetchRequest(entityName: "GameSeries")
+ }
+
+ @NSManaged public var cover: Data?
+ @NSManaged public var name: String?
+ @NSManaged public var games: NSSet
+
+}
+
+// MARK: Generated accessors for games
+extension GameSeries {
+
+ @objc(addGamesObject:)
+ @NSManaged public func addToGames(_ value: Game)
+
+ @objc(removeGamesObject:)
+ @NSManaged public func removeFromGames(_ value: Game)
+
+ @objc(addGames:)
+ @NSManaged public func addToGames(_ values: NSSet)
+
+ @objc(removeGames:)
+ @NSManaged public func removeFromGames(_ values: NSSet)
+
+}
diff --git a/Zockerhoehle/CDModel/Logo+CoreDataClass.swift b/Zockerhoehle/CDModel/Logo+CoreDataClass.swift
new file mode 100644
index 0000000..e1f4c51
--- /dev/null
+++ b/Zockerhoehle/CDModel/Logo+CoreDataClass.swift
@@ -0,0 +1,16 @@
+//
+// Logo+CoreDataClass.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+
+@objc(Logo)
+public class Logo: NSManagedObject {
+
+}
diff --git a/Zockerhoehle/CDModel/Logo+CoreDataProperties.swift b/Zockerhoehle/CDModel/Logo+CoreDataProperties.swift
new file mode 100644
index 0000000..a4025cf
--- /dev/null
+++ b/Zockerhoehle/CDModel/Logo+CoreDataProperties.swift
@@ -0,0 +1,23 @@
+//
+// Logo+CoreDataProperties.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 06.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+//
+
+import Foundation
+import CoreData
+import UIKit.UIImage
+
+extension Logo {
+
+ @nonobjc public class func fetchRequest() -> NSFetchRequest {
+ return NSFetchRequest(entityName: "Logo")
+ }
+
+ @NSManaged public var image: UIImage?
+ @NSManaged public var console: Console?
+
+}
diff --git a/Zockerhoehle/Info.plist b/Zockerhoehle/Info.plist
index 16be3b6..e49a713 100644
--- a/Zockerhoehle/Info.plist
+++ b/Zockerhoehle/Info.plist
@@ -4,6 +4,8 @@
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Zockerhöhle
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
@@ -20,6 +22,11 @@
1
LSRequiresIPhoneOS
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
diff --git a/Zockerhoehle/LaunchScreen.storyboard b/Zockerhoehle/LaunchScreen.storyboard
new file mode 100644
index 0000000..1d70994
--- /dev/null
+++ b/Zockerhoehle/LaunchScreen.storyboard
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Zockerhoehle/Lib/CodableExtensionAny.swift b/Zockerhoehle/Lib/CodableExtensionAny.swift
new file mode 100644
index 0000000..0270f59
--- /dev/null
+++ b/Zockerhoehle/Lib/CodableExtensionAny.swift
@@ -0,0 +1,111 @@
+//
+// Ext.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 17.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+
+// Inspired by https://gist.github.com/mbuchetics/c9bc6c22033014aa0c550d3b4324411a
+
+struct JSONCodingKeys: CodingKey {
+ var stringValue: String
+
+ init?(stringValue: String) {
+ self.stringValue = stringValue
+ }
+
+ var intValue: Int?
+
+ init?(intValue: Int) {
+ self.init(stringValue: "\(intValue)")
+ self.intValue = intValue
+ }
+}
+
+
+extension KeyedDecodingContainer {
+
+ func decode(_ type: Dictionary.Type, forKey key: K) throws -> Dictionary {
+ let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
+ return try container.decode(type)
+ }
+
+ func decodeIfPresent(_ type: Dictionary.Type, forKey key: K) throws -> Dictionary? {
+ guard contains(key) else {
+ return nil
+ }
+ guard try decodeNil(forKey: key) == false else {
+ return nil
+ }
+ return try decode(type, forKey: key)
+ }
+
+ func decode(_ type: Array.Type, forKey key: K) throws -> Array {
+ var container = try self.nestedUnkeyedContainer(forKey: key)
+ return try container.decode(type)
+ }
+
+ func decodeIfPresent(_ type: Array.Type, forKey key: K) throws -> Array? {
+ guard contains(key) else {
+ return nil
+ }
+ guard try decodeNil(forKey: key) == false else {
+ return nil
+ }
+ return try decode(type, forKey: key)
+ }
+
+ func decode(_ type: Dictionary.Type) throws -> Dictionary {
+ var dictionary = Dictionary()
+
+ for key in allKeys {
+ if let boolValue = try? decode(Bool.self, forKey: key) {
+ dictionary[key.stringValue] = boolValue
+ } else if let stringValue = try? decode(String.self, forKey: key) {
+ dictionary[key.stringValue] = stringValue
+ } else if let intValue = try? decode(Int.self, forKey: key) {
+ dictionary[key.stringValue] = intValue
+ } else if let doubleValue = try? decode(Double.self, forKey: key) {
+ dictionary[key.stringValue] = doubleValue
+ } else if let nestedDictionary = try? decode(Dictionary.self, forKey: key) {
+ dictionary[key.stringValue] = nestedDictionary
+ } else if let nestedArray = try? decode(Array.self, forKey: key) {
+ dictionary[key.stringValue] = nestedArray
+ }
+ }
+ return dictionary
+ }
+}
+
+extension UnkeyedDecodingContainer {
+
+ mutating func decode(_ type: Array.Type) throws -> Array {
+ var array: [Any] = []
+ while isAtEnd == false {
+ // See if the current value in the JSON array is `null` first and prevent infite recursion with nested arrays.
+ if try decodeNil() {
+ continue
+ } else if let value = try? decode(Bool.self) {
+ array.append(value)
+ } else if let value = try? decode(Double.self) {
+ array.append(value)
+ } else if let value = try? decode(String.self) {
+ array.append(value)
+ } else if let nestedDictionary = try? decode(Dictionary.self) {
+ array.append(nestedDictionary)
+ } else if let nestedArray = try? decode(Array.self) {
+ array.append(nestedArray)
+ }
+ }
+ return array
+ }
+
+ mutating func decode(_ type: Dictionary.Type) throws -> Dictionary {
+
+ let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self)
+ return try nestedContainer.decode(type)
+ }
+}
diff --git a/Zockerhoehle/Lib/UIButtonX.swift b/Zockerhoehle/Lib/UIButtonX.swift
new file mode 100644
index 0000000..2914c46
--- /dev/null
+++ b/Zockerhoehle/Lib/UIButtonX.swift
@@ -0,0 +1,43 @@
+//
+// UIButtonStoryBoardExtenstion.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 22.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import UIKit
+import Foundation
+
+@IBDesignable class UIButtonX : UIButton {
+
+ @IBInspectable var borderWidth: CGFloat {
+ set {
+ layer.borderWidth = newValue
+ }
+ get {
+ return layer.borderWidth
+ }
+ }
+
+ @IBInspectable var cornerRadius: CGFloat {
+ set {
+ layer.cornerRadius = newValue
+ }
+ get {
+ return layer.cornerRadius
+ }
+ }
+
+ @IBInspectable var borderColor: UIColor? {
+ set {
+ guard let uiColor = newValue else { return }
+ layer.borderColor = uiColor.cgColor
+ }
+ get {
+ guard let color = layer.borderColor else { return nil }
+ return UIColor(cgColor: color)
+ }
+ }
+}
+
diff --git a/Zockerhoehle/Lib/UIViewX.swift b/Zockerhoehle/Lib/UIViewX.swift
new file mode 100644
index 0000000..cb399fe
--- /dev/null
+++ b/Zockerhoehle/Lib/UIViewX.swift
@@ -0,0 +1,53 @@
+//
+// UIViewX.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 22.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+
+//
+// UIButtonStoryBoardExtenstion.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 22.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import UIKit
+import Foundation
+
+@IBDesignable class UIViewX : UIView {
+
+ @IBInspectable var borderWidth: CGFloat {
+ set {
+ layer.borderWidth = newValue
+ }
+ get {
+ return layer.borderWidth
+ }
+ }
+
+ @IBInspectable var cornerRadius: CGFloat {
+ set {
+ layer.cornerRadius = newValue
+ }
+ get {
+ return layer.cornerRadius
+ }
+ }
+
+ @IBInspectable var borderColor: UIColor? {
+ set {
+ guard let uiColor = newValue else { return }
+ layer.borderColor = uiColor.cgColor
+ }
+ get {
+ guard let color = layer.borderColor else { return nil }
+ return UIColor(cgColor: color)
+ }
+ }
+}
+
diff --git a/Zockerhoehle/Model/Attachment.swift b/Zockerhoehle/Model/Attachment.swift
new file mode 100644
index 0000000..23b36c4
--- /dev/null
+++ b/Zockerhoehle/Model/Attachment.swift
@@ -0,0 +1,31 @@
+//
+// Attachment.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 14.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+
+typealias AttachmentID = String
+
+struct Attachment : Codable {
+ var id : AttachmentID
+ var type : String
+ var file : Data?
+ var isDeleted : Bool
+ var description : String
+ var createdOn : String
+ var changedOn : String
+
+ enum CodingKeys : String, CodingKey {
+ case id = "_id"
+ case type
+ case file
+ case isDeleted
+ case description
+ case createdOn = "created"
+ case changedOn = "changed"
+ }
+}
diff --git a/Zockerhoehle/Model/ConsoleEntry.swift b/Zockerhoehle/Model/ConsoleEntry.swift
new file mode 100644
index 0000000..ea97868
--- /dev/null
+++ b/Zockerhoehle/Model/ConsoleEntry.swift
@@ -0,0 +1,44 @@
+//
+// ConsoleEntry.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 17.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+
+class ConsoleEntry : FlockeEntry {
+ var generation : Int? {
+ get {
+ return self.content["Generation"] as? Int
+ }
+ }
+
+ var manufacturer : String? {
+ get {
+ return self.content["Manufacturer"] as? String
+ }
+ }
+
+ override init(entry: FlockeEntry) {
+ super.init(entry: entry)
+ }
+
+ required init(from decoder: Decoder) throws {
+ try super.init(from: decoder)
+ }
+
+ override func encodeContent(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+
+ var contentContainer = container.nestedContainer(keyedBy: CodingKeysContentConsoleEntry.self, forKey: CodingKeys.content)
+ try contentContainer.encode(self.generation, forKey: CodingKeysContentConsoleEntry.Generation)
+ try contentContainer.encode(self.manufacturer, forKey: CodingKeysContentConsoleEntry.Manufacturer)
+ }
+
+ enum CodingKeysContentConsoleEntry : String, CodingKey {
+ case Generation = "Generation"
+ case Manufacturer
+ }
+}
diff --git a/Zockerhoehle/Model/FlockeEntry.swift b/Zockerhoehle/Model/FlockeEntry.swift
new file mode 100644
index 0000000..4b1595c
--- /dev/null
+++ b/Zockerhoehle/Model/FlockeEntry.swift
@@ -0,0 +1,103 @@
+//
+// Console.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 12.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+
+typealias FlockeEntryID = String
+
+class FlockeEntry : Codable {
+ let id : FlockeEntryID
+ let isDeleted : Bool
+ let name : String
+ let createdOn : String
+ let changedOn : String
+ let content : [String : Any]
+ var iconAttachment : Attachment?
+ var parents : [FlockeEntryID]
+
+ init (entry : FlockeEntry) {
+ self.id = entry.id
+ self.isDeleted = entry.isDeleted
+ self.name = entry.name
+ self.createdOn = entry.createdOn
+ self.changedOn = entry.changedOn
+ self.content = entry.content
+ self.iconAttachment = entry.iconAttachment
+ self.parents = entry.parents
+ }
+
+ required init(from decoder: Decoder) throws {
+ let container = try decoder.container(keyedBy: CodingKeys.self)
+
+ id = try container.decode(String.self, forKey: .id)
+ isDeleted = try container.decode(Bool.self, forKey: .isDeleted)
+ name = try container.decode(String.self, forKey: .name)
+ createdOn = try container.decode(String.self, forKey: .createdOn)
+ changedOn = try container.decode(String.self, forKey: .changedOn)
+
+ parents = try container.decode([FlockeEntryID].self, forKey: .parents)
+
+ do {
+ content = try container.decode([String : Any].self, forKey: .content)
+ }catch{
+ content = [:]
+ }
+
+ do {
+ let attachmentContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .attachments)
+
+ iconAttachment = try? attachmentContainer.decode(Attachment.self, forKey: .icon)
+ }catch {
+ iconAttachment = nil
+ }
+ }
+
+ func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+
+ try container.encode(self.id, forKey: .id)
+ try container.encode(self.isDeleted, forKey: .isDeleted)
+ try container.encode(self.name, forKey: .name)
+ try container.encode(self.createdOn, forKey: .createdOn)
+ try container.encode(self.changedOn, forKey: .changedOn)
+
+ try container.encode(self.parents, forKey: .parents)
+
+ var attachmentContainer = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .attachments)
+
+ try attachmentContainer.encode(self.iconAttachment, forKey: .icon)
+
+ if (!self.content.isEmpty) {
+ try encodeContent(to: encoder);
+ }
+ }
+
+ func encodeContent(to encoder: Encoder) throws {}
+
+ enum CodingKeys : String, CodingKey {
+ case id = "_id"
+ case isDeleted
+ case name = "name"
+ case createdOn = "created"
+ case changedOn = "changed"
+ case content
+ case manufacturer = "Manufacturer"
+ case generation = "Generation"
+ case attachments
+ case icon
+ case parents
+ }
+}
+
+extension FlockeEntry: Equatable {
+ static func == (lhs: FlockeEntry, rhs: FlockeEntry) -> Bool {
+ return lhs.id == rhs.id
+ }
+
+
+}
diff --git a/Zockerhoehle/Model/GameCollection.swift b/Zockerhoehle/Model/GameCollection.swift
new file mode 100644
index 0000000..660562d
--- /dev/null
+++ b/Zockerhoehle/Model/GameCollection.swift
@@ -0,0 +1,185 @@
+//
+// Consoles.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 13.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+import Disk
+import CoreData
+
+protocol ConsoleItemObserver {
+ func consoleItemDataUpdate(for parent : FlockeEntryID)
+}
+
+protocol AttachmentObserver {
+ func attachmentUpdate(attachmentID : AttachmentID)
+}
+
+class GameCollection {
+ static let shared : GameCollection = GameCollection()
+
+ //TODO: Zusammenfuehren von consoles und consoleItemsByParent
+ var consoles : [ConsoleEntry] = []
+ var consoleItemsByParent : [FlockeEntryID : [FlockeEntry]] = [:]
+ var attachments : [AttachmentID : Attachment] = [:]
+
+ private var consoleItemObservers : [ConsoleItemObserver] = []
+ private var attachmentObservers : [AttachmentObserver] = []
+
+ init() {
+ do {
+ self.consoles = try Disk.retrieve("consoles.json", from: .caches, as: [ConsoleEntry].self)
+ self.consoleItemsByParent = try Disk.retrieve("consoleItems.json", from: .caches, as: [FlockeEntryID : [FlockeEntry]].self)
+ self.attachments = try Disk.retrieve("attachments.json", from: .caches, as: [AttachmentID : Attachment].self)
+
+ //Fill core data on Startup
+
+ print("Game Collection import begin");
+
+ let cdm = CDManager.shared
+
+ for console in self.consoles {
+ let cdConsole = Console(entity: Console.entity(), insertInto: cdm.viewContext)
+ cdConsole.name = console.name
+
+ cdConsole.generation = Int64(console.generation ?? 0)
+ cdConsole.manufacturer = console.manufacturer
+
+ guard let consoleItems = self.consoleItemsByParent[console.id] else {
+ print("No games: \(console.name)")
+ continue
+ }
+
+ if let imgID = console.iconAttachment?.id , let img = self.attachments[imgID]?.file {
+ let cdLogo = Logo(entity: Logo.entity(), insertInto: cdm.viewContext)
+ cdLogo.image = UIImage(data: img)
+ cdConsole.logo = cdLogo
+ }
+
+ for item in consoleItems {
+ if (item.parents.contains(GameCollection.accessoryID)) {
+ let cdAccessory = Accessory(entity: Accessory.entity(), insertInto: cdm.viewContext)
+
+ cdAccessory.name = item.name
+ cdAccessory.inWishlist = item.parents.contains(GameCollection.wishlistID)
+ cdConsole.addToAccessories(cdAccessory)
+
+ }else if (item.parents.contains(GameCollection.videogameID)) {
+ let cdGame = Game(entity: Game.entity(), insertInto: cdm.viewContext)
+
+ cdGame.name = item.name
+ cdGame.inWishlist = item.parents.contains(GameCollection.wishlistID)
+
+ cdConsole.addToGames(cdGame)
+ }
+ }
+ }
+
+ }catch let error as NSError {
+ print("Load of Chached not possible \(error.localizedDescription)");
+ }
+ }
+
+ func addFlockeEntryObserver(observer: ConsoleItemObserver) {
+ self.consoleItemObservers.append(observer)
+ }
+
+ func addAttachmentObserver(observer: AttachmentObserver) {
+ self.attachmentObservers.append(observer)
+ }
+
+ fileprivate func notifyConSoleItemObservers(_ parent: FlockeEntryID) {
+ for observer in self.consoleItemObservers {
+ observer.consoleItemDataUpdate(for: parent)
+ }
+ }
+
+ func updateGameItems(items : [FlockeEntry], with parent : FlockeEntryID) {
+ if parent == GameCollection.consoleID {
+ updateConsoles(entrys: items)
+ }else {
+ self.consoleItemsByParent[parent] = items
+
+ do {
+ try Disk.save(self.consoleItemsByParent, to: .caches, as: "consoleItems.json")
+ }catch let error as NSError {
+ print("Write of GameItems not possible \(error.localizedDescription)");
+ }
+ }
+
+ notifyConSoleItemObservers(parent)
+ }
+
+ func remove(from: FlockeEntry, parentID: FlockeEntryID) {
+ from.parents.removeAll(where: {$0 == parentID})
+
+ for parent in from.parents {
+ notifyConSoleItemObservers(parent)
+ }
+ }
+
+ func removeGameItem(from console : FlockeEntry, item: FlockeEntry) {
+ guard let consoleItems : [FlockeEntry] = self.consoleItemsByParent[console.id] else {
+ return
+ }
+
+ if let index = consoleItems.firstIndex(of: item) {
+ consoleItemsByParent[console.id]!.remove(at: index);
+
+ notifyConSoleItemObservers(console.id)
+ }
+ }
+
+ func updateAttachment(attachment : Attachment) {
+ self.attachments[attachment.id] = attachment
+
+ do {
+ try Disk.save(self.attachments, to: .caches, as: "attachments.json")
+ }catch let error as NSError {
+ print("Write of Attachments not possible \(error.localizedDescription)");
+ }
+
+ for observer in self.attachmentObservers {
+ observer.attachmentUpdate(attachmentID: attachment.id)
+ }
+ }
+
+ func updateConsoles(entrys: [FlockeEntry]) {
+ self.consoles = []
+ for entry in entrys {
+ self.consoles.append(ConsoleEntry(entry: entry))
+ }
+
+ //IN-Place Sort
+ self.consoles.sort {
+ //1. Sort by manufacturer
+ if ($0.manufacturer == $1.manufacturer) {
+// //2. Sort by console generation
+ if ($0.generation == $1.generation) {
+// //3. Sort by console name
+ return $0.name < $1.name
+ }
+
+ return $0.generation! < $1.generation!
+ }
+
+ return $0.manufacturer! < $1.manufacturer!
+ }
+
+ do {
+ try Disk.save(self.consoles, to: .caches, as: "consoles.json")
+ }catch let error as NSError {
+ print("Write of ConsoleItem not possible \(error.localizedDescription)");
+ }
+ }
+}
+
+extension GameCollection {
+ static let consoleID : FlockeEntryID = "5b0c2ff8ba0c0b4ae7559911"
+ static let videogameID : FlockeEntryID = "5b116282ba0c0b4ae75599be"
+ static let wishlistID : FlockeEntryID = "5b11628dba0c0b4ae75599bf"
+ static let accessoryID : FlockeEntryID = "5b1162ccba0c0b4ae75599c1"
+}
diff --git a/Zockerhoehle/Utils/FlockeConnector.swift b/Zockerhoehle/Utils/FlockeConnector.swift
new file mode 100644
index 0000000..2e5eedf
--- /dev/null
+++ b/Zockerhoehle/Utils/FlockeConnector.swift
@@ -0,0 +1,45 @@
+//
+// FlockeConnector.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 29.10.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+
+class FlockeConnector {
+ let flockeURL : URL?
+ let bodyDict : NSDictionary?
+ let requestType : String
+ let completionHandler : (Data?, URLResponse?, Error?) -> Void
+
+ init(url : String, requestType : String = "GET", bodyDict : NSDictionary?, _ completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) {
+ self.flockeURL = URL.init(string: url)
+ self.bodyDict = bodyDict
+ self.requestType = requestType
+ self.completionHandler = completionHandler
+ }
+
+ func doRequest() {
+ guard let url = self.flockeURL else {
+ print("DO Request: Creating URL fails")
+ return
+ }
+
+
+ do {
+ let requestBodyJSON = try JSONSerialization.data(withJSONObject: self.bodyDict!)
+
+ var req = URLRequest.init(url: url)
+ req.httpMethod = self.requestType
+ req.httpBody = requestBodyJSON
+ req.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
+
+ URLSession.shared.dataTask(with: req, completionHandler: self.completionHandler).resume()
+ }catch {
+ print("Cannot convert to JSON")
+ return
+ }
+ }
+}
diff --git a/Zockerhoehle/Utils/FlockeWS.swift b/Zockerhoehle/Utils/FlockeWS.swift
new file mode 100644
index 0000000..e5f7200
--- /dev/null
+++ b/Zockerhoehle/Utils/FlockeWS.swift
@@ -0,0 +1,143 @@
+//
+// FlockeLoader.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 13.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+import Disk
+
+extension Notification.Name {
+ static let FlockeWSDeleteFinished = Notification.Name("flockeWSDeleteFinished")
+ static let FlockeWSAddFinished = Notification.Name("flockeWSAddFinished")
+}
+
+class FlockeWS {
+ @objc enum ERROR_STATE : Int {
+ case NO_ERROR
+ case REQUEST_FAILED
+ }
+
+ static func fetchEntries(for parent: FlockeEntryID) {
+ guard let fetchEntriesURL = URL.init(string: "http://flocke.mueller.haus:8081/entry/parent/\(parent)") else {
+ print("FETCH ENTRIES: Creating URL fails")
+ return
+ }
+
+ let task = URLSession.shared.dataTask(with: fetchEntriesURL) { (data, resp, err) in
+ if (err == nil) {
+ let consoles : [FlockeEntry] = try! JSONDecoder().decode([FlockeEntry].self, from: data!)
+
+ DispatchQueue.main.async {
+ GameCollection.shared.updateGameItems(items: consoles, with: parent)
+ }
+ }
+ }
+ task.resume()
+ }
+
+ static func fetchAttachment(attachment attachmentId : AttachmentID) {
+ guard let fetchAttachmentURL = URL.init(string: "http://flocke.mueller.haus:8081/attachment/\(attachmentId)") else {
+ print("FETCH ATTACHMENT: Creating URL fails")
+ return
+ }
+
+ URLSession.shared.dataTask(with: fetchAttachmentURL) { (data, resp, err) in
+ if (err == nil) {
+ let attachment : Attachment = try! JSONDecoder().decode(Attachment.self, from: data!)
+
+
+ DispatchQueue.main.async {
+ GameCollection.shared.updateAttachment(attachment: attachment)
+ }
+ }
+
+ }.resume()
+ }
+
+ static func deleteEntry(by entry: FlockeEntryID) {
+ guard let flockeDeleteEntryURL = URL.init(string: "http://flocke.mueller.haus:8081/entry/\(entry)") else {
+ print("DELETE ENTRY: Creating URL fails")
+ return
+ }
+
+ var req = URLRequest.init(url: flockeDeleteEntryURL)
+ req.httpMethod = "DELETE"
+
+ URLSession.shared.dataTask(with: req) { (data, resp, err) in
+ if (err == nil) {
+ DispatchQueue.main.async {
+ //TODO GameCollection Update
+ NotificationCenter.default.post(name: .FlockeWSDeleteFinished, object: nil)
+ }
+ }
+ }.resume()
+ }
+
+ static func deleteParents(entry entryID : FlockeEntryID, parents : [FlockeEntryID]) {
+ print("DELETE PARENTS WS \(entryID) - \(parents)")
+
+ let addJSON : NSMutableDictionary = NSMutableDictionary()
+ addJSON.setValue(entryID, forKey: "id")
+ addJSON.setValue(parents, forKey: "parents")
+
+ do {
+ let jsonBodyData = try JSONSerialization.data(withJSONObject: addJSON, options: [])
+ let jsonBodyString = String(data: jsonBodyData, encoding: .utf8) ?? "{}"
+ print(jsonBodyString)
+
+ let connector : FlockeConnector = FlockeConnector(url: "http://flocke.mueller.haus:8081/entry/deleteParents",
+ requestType: "PUT",
+ bodyDict: addJSON) { (data, resp, err) in
+// DispatchQueue.main.async {
+// //NOP
+// }
+ }
+
+ connector.doRequest()
+ }catch {
+ return;
+ }
+
+ return;
+ }
+
+
+ static func addEntry(name : String, consoleID : FlockeEntryID, isVideogame : Bool, isOnWishlist : Bool) {
+ print("ADD WS \(name) \(isVideogame) \(isOnWishlist)")
+
+ var parents : [String] = [consoleID]
+
+ if (isVideogame) {
+ parents.append(GameCollection.videogameID)
+ }else{
+ parents.append(GameCollection.accessoryID)
+ }
+
+ if isOnWishlist {
+ parents.append(GameCollection.wishlistID)
+ }
+
+ let addJSON : NSMutableDictionary = NSMutableDictionary()
+ addJSON.setValue(name, forKey: "name")
+ addJSON.setValue(parents, forKey: "parents")
+
+ let connector : FlockeConnector = FlockeConnector(url: "http://flocke.mueller.haus:8081/entry/",
+ requestType: "POST",
+ bodyDict: addJSON) { (data, resp, err) in
+ var requestError = FlockeWS.ERROR_STATE.NO_ERROR
+
+ if (err != nil) { requestError = FlockeWS.ERROR_STATE.REQUEST_FAILED }
+
+
+ DispatchQueue.main.async {
+ let userInfo:[String: FlockeWS.ERROR_STATE] = ["error_state": requestError]
+ NotificationCenter.default.post(name: .FlockeWSAddFinished, object: nil, userInfo: userInfo)
+ }
+ }
+
+ connector.doRequest()
+ }
+}
diff --git a/Zockerhoehle/ViewController.swift b/Zockerhoehle/ViewController.swift
deleted file mode 100644
index 51493a3..0000000
--- a/Zockerhoehle/ViewController.swift
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// ViewController.swift
-// Zockerhoehle
-//
-// Created by Julian-Steffen Müller on 12.09.18.
-// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
-//
-
-import UIKit
-
-class ViewController: UIViewController {
-
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do any additional setup after loading the view, typically from a nib.
- }
-
- override func didReceiveMemoryWarning() {
- super.didReceiveMemoryWarning()
- // Dispose of any resources that can be recreated.
- }
-
-
-}
-
diff --git a/Zockerhoehle/ViewController/AccessoryDetailController.swift b/Zockerhoehle/ViewController/AccessoryDetailController.swift
new file mode 100644
index 0000000..2724821
--- /dev/null
+++ b/Zockerhoehle/ViewController/AccessoryDetailController.swift
@@ -0,0 +1,20 @@
+//
+// AccessoryDetailController.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 12.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+import UIKit
+import SwiftUI
+
+class AccessoryDetailController : UIViewController {
+ var accessory : Accessory?
+
+
+ @IBSegueAction func emebdedAccessoryDetaio(_ coder: NSCoder) -> UIViewController? {
+ return UIHostingController(coder: coder, rootView: AccessoryDetailView(accessory: accessory))
+ }
+}
diff --git a/Zockerhoehle/ViewController/AddEntryPopUpViewController.swift b/Zockerhoehle/ViewController/AddEntryPopUpViewController.swift
new file mode 100644
index 0000000..d009b3a
--- /dev/null
+++ b/Zockerhoehle/ViewController/AddEntryPopUpViewController.swift
@@ -0,0 +1,71 @@
+//
+// AddEntryPopUpViewController.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 20.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import UIKit
+
+class AddEntryPopUpViewController: UIViewController {
+ var isWishlist : Bool = false
+ var isVideogame : Bool = true
+ var console : Console?
+
+ @IBOutlet weak var icon: UIImageView!
+ @IBOutlet weak var category: UISegmentedControl!
+ @IBOutlet weak var wishlistIcon: UIImageView!
+ @IBOutlet weak var name: UITextField!
+ @IBOutlet weak var addButton: UIButtonX!
+
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+
+ self.category.selectedSegmentIndex = 0
+
+ if (!self.isVideogame && !self.isWishlist) {
+ self.category.selectedSegmentIndex = 1
+ }
+
+ self.wishlistIcon.isHidden = !self.isWishlist
+
+ self.icon.image = self.console?.logo?.image
+
+ //If the name is not filled the add Button should be disabled
+ addButton.isEnabled = name.text != ""
+ }
+
+ @IBAction func nameChanged(_ sender: Any) {
+ addButton.isEnabled = name.text != ""
+ }
+
+ @IBAction func add(_ sender: Any) {
+ self.isVideogame = self.category.selectedSegmentIndex == 0
+
+ guard let name = self.name.text else {
+ print("ERROR AddEntryPopoUpViewController::Add; Game name is empty")
+ return
+ }
+
+ if self.isVideogame {
+ let game = Game(entity: Game.entity(), insertInto: CDManager.shared.viewContext)
+ game.name = name
+ game.console = console
+
+ print("Added Game '\(game.name)'")
+ }else{
+ let accessory = Accessory(entity: Accessory.entity(), insertInto: CDManager.shared.viewContext)
+ accessory.name = name
+ accessory.console = console
+
+ print("Added Accessory '\(accessory.name)'")
+ }
+
+ self.dismiss(animated: true)
+ }
+
+ @IBAction func cancel(_ sender: Any) {
+ self.dismiss(animated: true)
+ }
+}
diff --git a/Zockerhoehle/ViewController/AllConsolesViewController.swift b/Zockerhoehle/ViewController/AllConsolesViewController.swift
new file mode 100644
index 0000000..4912a25
--- /dev/null
+++ b/Zockerhoehle/ViewController/AllConsolesViewController.swift
@@ -0,0 +1,78 @@
+//
+// UIConsoleTableViewController.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 12.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import UIKit
+import CoreData
+
+class AllConsolesViewController: UIViewController, NSFetchedResultsControllerDelegate {
+ @IBOutlet weak var consolesTable: UITableView!
+ @IBOutlet weak var manufacturer: UILabel!
+ @IBOutlet weak var consoleLogo: UIImageView!
+
+ lazy var fetchResultsController : NSFetchedResultsController = {
+ let consolesFetch : NSFetchRequest = Console.fetchRequest()
+
+ consolesFetch.sortDescriptors = [NSSortDescriptor(key: "manufacturer", ascending: true), NSSortDescriptor(key: "generation", ascending: true), NSSortDescriptor(key: "name", ascending: true)]
+
+ var consolesfetchRC = NSFetchedResultsController(fetchRequest: consolesFetch, managedObjectContext: CDManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil)
+
+ consolesfetchRC.delegate = self
+
+ return consolesfetchRC
+
+ }()
+
+ func controllerDidChangeContent(_ controller: NSFetchedResultsController) {
+ print("AllConsolesViewController::controllerDidChangeContent")
+ self.consolesTable.reloadData()
+ }
+
+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+ if (segue.identifier == "consoleDetail" && sender! is ConsoleCell) {
+ guard let consoleVC = segue.destination as? ConsoleLibraryViewController else {
+ return
+ }
+ guard let consoleCell = sender as? ConsoleCell else {
+ return
+ }
+
+ consoleVC.console = consoleCell.console
+ }
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ FlockeWS.fetchEntries(for: GameCollection.consoleID)
+ do {
+ try fetchResultsController.performFetch()
+ }catch{
+ print("AllConsolesViewController::viewDidLoad: Fetch not possible");
+ }
+ }
+}
+extension AllConsolesViewController: UITableViewDataSource {
+ func numberOfSections(in tableView: UITableView) -> Int {
+ guard let sections = fetchResultsController.sections else { return 0 }
+
+ return sections.count
+ }
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ guard let sections = fetchResultsController.sections else { return 0 }
+
+ return sections[section].numberOfObjects
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = (tableView.dequeueReusableCell(withIdentifier: "ConsoleCell", for: indexPath)) as! ConsoleCell
+
+ cell.console = fetchResultsController.object(at: indexPath)
+
+ return cell
+ }
+}
diff --git a/Zockerhoehle/ViewController/ConsoleLibraryViewController.swift b/Zockerhoehle/ViewController/ConsoleLibraryViewController.swift
new file mode 100644
index 0000000..f42df2a
--- /dev/null
+++ b/Zockerhoehle/ViewController/ConsoleLibraryViewController.swift
@@ -0,0 +1,189 @@
+//
+// ConsoleViewController.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 12.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import UIKit
+import CoreData
+import Combine
+
+class ConsoleLibraryViewController: UIViewController {
+ @IBOutlet weak var consoleItemTable: UITableView!
+ @IBOutlet weak var category: UISegmentedControl!
+ @IBOutlet weak var toggleWishList: UIBarButtonItem!
+
+ var subsriber : Subscribers.Sink?
+ var videoGamesInLibrary : [Bool : [Game]] = [:]
+ var accessoriesinLibrary : [Bool : [Accessory]] = [:]
+ var showWishlist : Bool = false
+
+ var console : Console? {
+ didSet {
+ self.title = console?.name ?? "N/A"
+
+ //Remove subscription to old console object
+ subsriber?.cancel()
+
+ subsriber = console?.publisher(for: \.games, options: .new).sink(receiveValue: {_ in
+ self.refreshConsoleLibrary()
+ })
+
+ refreshConsoleLibrary()
+ }
+ }
+
+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+ if segue.identifier == "detail" {
+ guard let indexpath = self.consoleItemTable.indexPathForSelectedRow else {
+ print("ConsoleLibraryViewController::prepare::detail IndexPath for selectedRow could not be retreived")
+ return
+ }
+
+ if let dest = segue.destination as? GameDetailController {
+ dest.game = self.videoGamesInLibrary[self.showWishlist]?[indexpath.row]
+ }else if let dest = segue.destination as? AccessoryDetailController {
+ dest.accessory = self.accessoriesinLibrary[self.showWishlist]?[indexpath.row]
+ }
+ }else if (segue.identifier == "consoleEntryAdd") {
+ guard let addPopup = segue.destination as? AddEntryPopUpViewController else {
+ print("ConsoleLibraryViewController::prepare::consoleEntryAdd Destination is no AddEntryPopUpViewController")
+ return
+ }
+
+ addPopup.console = self.console
+ addPopup.isVideogame = self.category.selectedSegmentIndex == 0
+ }
+
+ }
+
+ @IBAction func categoryChanged(_ sender: Any) {
+ self.consoleItemTable.reloadData()
+ }
+
+ override func viewWillAppear(_ animated: Bool) {
+ if self.showWishlist {
+ self.toggleWishList.tintColor = UIColor.red
+ }else{
+ self.toggleWishList.tintColor = UIColor.black
+ }
+
+ self.toggleWishList.tintColor = UIColor.black
+ }
+
+ func refreshConsoleLibrary() {
+ let videogames = self.console?.games.map({$0 as! Game}) ?? []
+ self.videoGamesInLibrary[true] = videogames.filter({$0.inWishlist})
+ self.videoGamesInLibrary[false] = videogames.filter({!$0.inWishlist})
+
+ let accessories = self.console?.accessories.map({$0 as! Accessory}) ?? []
+ self.accessoriesinLibrary[true] = accessories.filter({$0.inWishlist})
+ self.accessoriesinLibrary[false] = accessories.filter({!$0.inWishlist})
+
+ consoleItemTable?.reloadData()
+ }
+
+ @IBAction func toggleWishlist(_ sender: Any) {
+ self.showWishlist = !self.showWishlist
+
+ if self.showWishlist {
+ self.toggleWishList.tintColor = UIColor.red
+ }else{
+ self.toggleWishList.tintColor = UIColor.black
+ }
+
+ consoleItemTable.reloadData()
+ }
+}
+
+extension ConsoleLibraryViewController: UITableViewDataSource {
+ func numberOfSections(in tableView: UITableView) -> Int {
+ return 1
+ }
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ if self.category.selectedSegmentIndex == 0 {
+ return self.videoGamesInLibrary[self.showWishlist]?.count ?? 0
+ }else{
+ return self.accessoriesinLibrary[self.showWishlist]?.count ?? 0
+ }
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ if self.category.selectedSegmentIndex == 0 {
+ let gameCell = tableView.dequeueReusableCell(withIdentifier: "gameCell") as! GameCell
+
+ gameCell.game = self.videoGamesInLibrary[self.showWishlist]?[indexPath.row]
+
+ return gameCell
+ }else{
+ let accessoryCell = tableView.dequeueReusableCell(withIdentifier: "accessoryCell") as! AccessoryCell
+
+
+ accessoryCell.accessory = self.accessoriesinLibrary[self.showWishlist]?[indexPath.row]
+
+ return accessoryCell
+ }
+
+ }
+}
+
+
+// Swipe Action - Delete / move console items from / into the library
+extension ConsoleLibraryViewController: UITableViewDelegate {
+
+ // Move console item to library
+ func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
+ let bought = UIContextualAction(style: .destructive, title: "") { (action, view, actionDone) in
+ actionDone(true)
+ if self.category.selectedSegmentIndex == 0 {
+ let game = self.videoGamesInLibrary[self.showWishlist]?[indexPath.row]
+ game?.inWishlist = false
+ }else{
+ let accessory = self.accessoriesinLibrary[self.showWishlist]?[indexPath.row]
+ accessory?.inWishlist = false
+ }
+
+ self.refreshConsoleLibrary()
+ }
+
+ bought.image = #imageLiteral(resourceName: "cave")
+ bought.backgroundColor = #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)
+
+ if (self.showWishlist) {
+ return UISwipeActionsConfiguration(actions: [bought])
+ }
+
+ return UISwipeActionsConfiguration(actions: [])
+ }
+
+ // Delete console item from library
+ func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
+ /*let selectedItem = self.consoleItemsToDisplay()[indexPath.row]
+ let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, view, actionDone) in
+ let deleteWarning = UIAlertController( title: "Aus Zockerhöhle entfernen",
+ message: "Willst du '\("N/A")' wirklich aus der Zockerhöhle tragen?",
+ preferredStyle: .alert)
+
+ deleteWarning.addAction(UIAlertAction(title: "Ja", style: .destructive, handler: { (action) in
+ actionDone(true)
+
+ //FlockeWS.deleteEntry(by: selectedItem.id);
+ //GameCollection.shared.removeGameItem(from: self.currentConsole!, item: selectedItem)
+ }))
+
+ deleteWarning.addAction(UIAlertAction(title: "Nein", style: .cancel, handler: { (action) in
+ actionDone(false)
+ }))
+
+ self.present(deleteWarning, animated: true, completion: nil)
+ }*/
+
+ //delete.image = #imageLiteral(resourceName: "delete")
+ //delete.backgroundColor = #colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1)
+
+ return UISwipeActionsConfiguration(actions: [])//delete])
+ }
+}
diff --git a/Zockerhoehle/ViewController/GameDetailController.swift b/Zockerhoehle/ViewController/GameDetailController.swift
new file mode 100644
index 0000000..0a6914a
--- /dev/null
+++ b/Zockerhoehle/ViewController/GameDetailController.swift
@@ -0,0 +1,20 @@
+//
+// ConsoleDetailEmbewdViewController.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 08.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+
+import Foundation
+import UIKit
+import SwiftUI
+
+class GameDetailController : UIViewController {
+ var game : Game?
+
+
+ @IBSegueAction func embedConsoleDetail(_ coder: NSCoder) -> UIViewController? {
+ return UIHostingController(coder: coder, rootView: GameDetailView(game: game))
+ }
+}
diff --git a/Zockerhoehle/Views/AccessoryCell.swift b/Zockerhoehle/Views/AccessoryCell.swift
new file mode 100644
index 0000000..9961014
--- /dev/null
+++ b/Zockerhoehle/Views/AccessoryCell.swift
@@ -0,0 +1,24 @@
+//
+// AccessoryCell.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 12.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+
+import UIKit
+
+class AccessoryCell: UITableViewCell {
+ @IBOutlet weak var name: UILabel!
+
+ var accessory : Accessory? {
+ didSet {
+ self.name.text = accessory?.name ?? "N/A"
+ }
+ }
+
+ /*func setAccessory(accessory : Accessory?) {
+ self.accessory = accessory
+ self.name.text = accessory?.name ?? "N/A"
+ }*/
+}
diff --git a/Zockerhoehle/Views/AccessoryDetailView.swift b/Zockerhoehle/Views/AccessoryDetailView.swift
new file mode 100644
index 0000000..b061641
--- /dev/null
+++ b/Zockerhoehle/Views/AccessoryDetailView.swift
@@ -0,0 +1,29 @@
+//
+// AccessoryDetailView.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 12.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+
+import SwiftUI
+
+struct AccessoryDetailView : View {
+ var accessory : Accessory?
+
+ var body: some View {
+ Text(accessory?.name ?? "N/A").color(Color.red)
+ }
+
+ init(accessory : Accessory?) {
+ self.accessory = accessory
+ }
+}
+
+#if DEBUG
+struct AccessoryDetailView_Previews : PreviewProvider {
+ static var previews: some View {
+ AccessoryDetailView(accessory: nil)
+ }
+}
+#endif
diff --git a/Zockerhoehle/Views/ConsoleCell.swift b/Zockerhoehle/Views/ConsoleCell.swift
new file mode 100644
index 0000000..165770c
--- /dev/null
+++ b/Zockerhoehle/Views/ConsoleCell.swift
@@ -0,0 +1,30 @@
+//
+// ConsoleCell.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 12.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import UIKit
+
+class ConsoleCell: UITableViewCell {
+ @IBOutlet weak var consoleName: UILabel!
+ @IBOutlet weak var logo: UIImageView!
+ @IBOutlet weak var gamesCounter: UILabel!
+ @IBOutlet weak var accessoryCounter: UILabel!
+
+ public var console: Console? {
+ didSet {
+ consoleName.text = console?.name
+ self.logo.image = console?.logo?.image
+
+ let ownedGames = console?.games.filtered(using: NSPredicate(format: "inWishlist = false")).count ?? 0
+ let ownedAccessories = console?.accessories.filtered(using: NSPredicate(format: "inWishlist = false")).count ?? 0
+ self.gamesCounter.text = "\(ownedGames)"
+ self.accessoryCounter.text = "\(ownedAccessories)"
+
+ self.setNeedsDisplay()
+ }
+ }
+}
diff --git a/Zockerhoehle/Views/GameCell.swift b/Zockerhoehle/Views/GameCell.swift
new file mode 100644
index 0000000..3f35e36
--- /dev/null
+++ b/Zockerhoehle/Views/GameCell.swift
@@ -0,0 +1,20 @@
+//
+// GameCell.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 16.09.18.
+// Copyright © 2018 Julian-Steffen Müller. All rights reserved.
+//
+
+import UIKit
+
+class GameCell: UITableViewCell {
+ @IBOutlet weak var name: UILabel!
+
+ var game : Game? {
+ didSet {
+ self.name.text = game?.name ?? "N/A"
+ }
+ }
+}
+
diff --git a/Zockerhoehle/Views/GameDetailView.swift b/Zockerhoehle/Views/GameDetailView.swift
new file mode 100644
index 0000000..c9dbffe
--- /dev/null
+++ b/Zockerhoehle/Views/GameDetailView.swift
@@ -0,0 +1,28 @@
+//
+// GameDetailView.swift
+// Zockerhoehle
+//
+// Created by Julian-Steffen Müller on 08.07.19.
+// Copyright © 2019 Julian-Steffen Müller. All rights reserved.
+//
+
+import SwiftUI
+
+struct GameDetailView : View {
+ var game : Game?
+ var body: some View {
+ Text(game?.name ?? "N/A")
+ }
+
+ init(game : Game?) {
+ self.game = game
+ }
+}
+
+#if DEBUG
+struct GameDetailView_Previews : PreviewProvider {
+ static var previews: some View {
+ GameDetailView(game: nil)
+ }
+}
+#endif
diff --git a/Zockerhoehle/Zockerhoehle.xcdatamodeld/Zockerhoehle.xcdatamodel/contents b/Zockerhoehle/Zockerhoehle.xcdatamodeld/Zockerhoehle.xcdatamodel/contents
new file mode 100644
index 0000000..0a345bc
--- /dev/null
+++ b/Zockerhoehle/Zockerhoehle.xcdatamodeld/Zockerhoehle.xcdatamodel/contents
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Zockerhoehle/Zockerhoehle/Base.lproj/WaitingPopOver.storyboard b/Zockerhoehle/Zockerhoehle/Base.lproj/WaitingPopOver.storyboard
new file mode 100644
index 0000000..99d74f9
--- /dev/null
+++ b/Zockerhoehle/Zockerhoehle/Base.lproj/WaitingPopOver.storyboard
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Zockerhoehle/de.lproj/Main.strings b/Zockerhoehle/de.lproj/Main.strings
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Zockerhoehle/de.lproj/Main.strings
@@ -0,0 +1 @@
+