changeset 10:a793f33f05fb

refactor code and fix layout
author Dennis C. M. <dennis@denniscm.com>
date Sat, 08 Oct 2022 21:36:40 +0200
parents 3540c7efc216
children 039b26a99a48
files GeoQuiz.xcodeproj/project.pbxproj GeoQuiz/Assets.xcassets/Custom colors/AtomicTangerine.colorset/Contents.json GeoQuiz/Assets.xcassets/Custom colors/BlueBell.colorset/Contents.json GeoQuiz/Assets.xcassets/Custom colors/ChinaPink.colorset/Contents.json GeoQuiz/Assets.xcassets/Custom colors/MaizeCrayola.colorset/Contents.json GeoQuiz/Assets.xcassets/Custom colors/MayaBlue.colorset/Contents.json GeoQuiz/Assets.xcassets/Custom colors/MiddleRed.colorset/Contents.json GeoQuiz/Assets.xcassets/Custom colors/PinkLavender.colorset/Contents.json GeoQuiz/Assets.xcassets/Custom colors/RoyalLightBlue.colorset/Contents.json GeoQuiz/Components/AnswerButtonHelper.swift GeoQuiz/Components/CityMapHelper.swift GeoQuiz/Components/ColorExtension.swift GeoQuiz/Components/FlagImageHelper.swift GeoQuiz/Components/FormatterExtension.swift GeoQuiz/Components/GameAlertsModifier.swift GeoQuiz/Components/GameButtonHelper.swift GeoQuiz/Components/GameToolbarHelper.swift GeoQuiz/Components/GradientExtension.swift GeoQuiz/Components/LinkHelper.swift GeoQuiz/ContentView.swift GeoQuiz/GuessTheCapitalView.swift GeoQuiz/GuessTheCountryView.swift GeoQuiz/GuessTheCurrencyView.swift GeoQuiz/GuessTheFlagView.swift GeoQuiz/GuessThePopulationView.swift GeoQuiz/Helpers/AnswerButton.swift GeoQuiz/Helpers/CityMap.swift GeoQuiz/Helpers/CustomColors.swift GeoQuiz/Helpers/CustomGradients.swift GeoQuiz/Helpers/FlagImage.swift GeoQuiz/Helpers/GameAlertsModifier.swift GeoQuiz/Helpers/GameButton.swift GeoQuiz/Helpers/GameToolbar.swift GeoQuiz/Helpers/LinkComponent.swift GeoQuiz/Logic/CityGame.swift GeoQuiz/Logic/CityGameClass.swift GeoQuiz/Logic/CityModel.swift GeoQuiz/Logic/CountryGame.swift GeoQuiz/Logic/CountryGameClass.swift GeoQuiz/Logic/CountryModel.swift GeoQuiz/Logic/Game.swift GeoQuiz/Logic/GameProtocol+Extension.swift GeoQuiz/Logic/Haptics.swift GeoQuiz/Logic/HapticsClass.swift GeoQuiz/Logic/Load.swift GeoQuiz/Logic/LoadFunc.swift GeoQuiz/Logic/User.swift GeoQuiz/Logic/UserClass.swift GeoQuiz/Logic/UserSettingsModel.swift GeoQuiz/Models/CityModel.swift GeoQuiz/Models/CountryModel.swift GeoQuiz/Models/UserSettingsModel.swift GeoQuiz/SettingsModalView.swift
diffstat 53 files changed, 1231 insertions(+), 1128 deletions(-) [+]
line wrap: on
line diff
--- a/GeoQuiz.xcodeproj/project.pbxproj	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz.xcodeproj/project.pbxproj	Sat Oct 08 21:36:40 2022 +0200
@@ -7,16 +7,15 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		95030CEA28D1BA4D001AA3A1 /* AnswerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95030CE928D1BA4D001AA3A1 /* AnswerButton.swift */; };
+		95030CEA28D1BA4D001AA3A1 /* AnswerButtonHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95030CE928D1BA4D001AA3A1 /* AnswerButtonHelper.swift */; };
 		9509A8DE28E5A19A00CFCDBA /* countries.json in Resources */ = {isa = PBXBuildFile; fileRef = 9509A8DD28E5A19A00CFCDBA /* countries.json */; };
-		9509A8E028E5A3C500CFCDBA /* GuessTheCurrencyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9509A8DF28E5A3C500CFCDBA /* GuessTheCurrencyView.swift */; };
 		9509A8E228E5A3D700CFCDBA /* GuessThePopulationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9509A8E128E5A3D700CFCDBA /* GuessThePopulationView.swift */; };
 		951AFAEA28E5655C00A4A4BD /* cities.json in Resources */ = {isa = PBXBuildFile; fileRef = 951AFAE828E5655C00A4A4BD /* cities.json */; };
 		951AFAED28E5657500A4A4BD /* CityModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951AFAEC28E5657500A4A4BD /* CityModel.swift */; };
 		951AFAEF28E565FE00A4A4BD /* CountryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951AFAEE28E565FE00A4A4BD /* CountryModel.swift */; };
-		951AFAF128E5735400A4A4BD /* CityGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951AFAF028E5735400A4A4BD /* CityGame.swift */; };
+		951AFAF128E5735400A4A4BD /* CityGameClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951AFAF028E5735400A4A4BD /* CityGameClass.swift */; };
 		951B630228D1A87C004F9877 /* GuessTheCapitalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951B630128D1A87C004F9877 /* GuessTheCapitalView.swift */; };
-		951D197328D485E000671FAD /* CustomColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951D197228D485E000671FAD /* CustomColors.swift */; };
+		951D197328D485E000671FAD /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951D197228D485E000671FAD /* ColorExtension.swift */; };
 		952E41E928DC521200198643 /* GameAlertsModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952E41E828DC521200198643 /* GameAlertsModifier.swift */; };
 		952E41ED28DC658900198643 /* SettingsModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952E41EC28DC658900198643 /* SettingsModalView.swift */; };
 		952E41F228DC6F6E00198643 /* correctAnswer.wav in Resources */ = {isa = PBXBuildFile; fileRef = 952E41F028DC6F6D00198643 /* correctAnswer.wav */; };
@@ -24,35 +23,35 @@
 		9539829328C51EDE00B70973 /* GeoQuizApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9539829228C51EDE00B70973 /* GeoQuizApp.swift */; };
 		9539829728C51EDF00B70973 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9539829628C51EDF00B70973 /* Assets.xcassets */; };
 		9539829A28C51EDF00B70973 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9539829928C51EDF00B70973 /* Preview Assets.xcassets */; };
-		955A658128D703EB00CEEC6D /* GameToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A658028D703EB00CEEC6D /* GameToolbar.swift */; };
-		955A658328D733E400CEEC6D /* Game.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A658228D733E400CEEC6D /* Game.swift */; };
-		955A65A928D7815E00CEEC6D /* Haptics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A65A828D7815E00CEEC6D /* Haptics.swift */; };
-		956273EA28CB2E98008DC094 /* FlagImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956273E928CB2E98008DC094 /* FlagImage.swift */; };
+		955950BB28F15FF2001BDEE8 /* FormatterExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955950BA28F15FF2001BDEE8 /* FormatterExtension.swift */; };
+		955A658128D703EB00CEEC6D /* GameToolbarHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A658028D703EB00CEEC6D /* GameToolbarHelper.swift */; };
+		955A658328D733E400CEEC6D /* GameProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A658228D733E400CEEC6D /* GameProtocol+Extension.swift */; };
+		955A65A928D7815E00CEEC6D /* HapticsClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955A65A828D7815E00CEEC6D /* HapticsClass.swift */; };
+		956273EA28CB2E98008DC094 /* FlagImageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956273E928CB2E98008DC094 /* FlagImageHelper.swift */; };
 		9590359528E098FF00B24560 /* ProfileModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9590359428E098FF00B24560 /* ProfileModalView.swift */; };
-		95919DB628F076BF00F21F8F /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95919DB528F076BF00F21F8F /* User.swift */; };
+		95919DB628F076BF00F21F8F /* UserClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95919DB528F076BF00F21F8F /* UserClass.swift */; };
 		95919DB828F079D100F21F8F /* UserSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95919DB728F079D100F21F8F /* UserSettingsModel.swift */; };
-		95919DBC28F08D0600F21F8F /* LinkComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95919DBB28F08D0600F21F8F /* LinkComponent.swift */; };
-		95AE8D5728C8750E0067F219 /* Load.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AE8D5628C8750E0067F219 /* Load.swift */; };
+		95919DBC28F08D0600F21F8F /* LinkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95919DBB28F08D0600F21F8F /* LinkHelper.swift */; };
+		95AE8D5728C8750E0067F219 /* LoadFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AE8D5628C8750E0067F219 /* LoadFunc.swift */; };
 		95AF322A28DF293900023ACC /* GuessTheCountryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AF322928DF293900023ACC /* GuessTheCountryView.swift */; };
-		95BC392D28EC42570049AB49 /* CityMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BC392C28EC42570049AB49 /* CityMap.swift */; };
-		95C430F928D0A8E500480D23 /* CustomGradients.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C430F828D0A8E500480D23 /* CustomGradients.swift */; };
+		95BC392D28EC42570049AB49 /* CityMapHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BC392C28EC42570049AB49 /* CityMapHelper.swift */; };
+		95C430F928D0A8E500480D23 /* GradientExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C430F828D0A8E500480D23 /* GradientExtension.swift */; };
 		95C4315628C64A8C00212131 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C4315528C64A8C00212131 /* ContentView.swift */; };
-		95C4315928C6500000212131 /* GameButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C4315828C6500000212131 /* GameButton.swift */; };
+		95C4315928C6500000212131 /* GameButtonHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C4315828C6500000212131 /* GameButtonHelper.swift */; };
 		95FA409A28D9876B00129B60 /* GuessTheFlagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FA409928D9876B00129B60 /* GuessTheFlagView.swift */; };
-		95FA409C28D9881100129B60 /* CountryGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FA409B28D9881100129B60 /* CountryGame.swift */; };
+		95FA409C28D9881100129B60 /* CountryGameClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FA409B28D9881100129B60 /* CountryGameClass.swift */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		95030CE928D1BA4D001AA3A1 /* AnswerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnswerButton.swift; sourceTree = "<group>"; };
+		95030CE928D1BA4D001AA3A1 /* AnswerButtonHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnswerButtonHelper.swift; sourceTree = "<group>"; };
 		9509A8DD28E5A19A00CFCDBA /* countries.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = countries.json; sourceTree = "<group>"; };
-		9509A8DF28E5A3C500CFCDBA /* GuessTheCurrencyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuessTheCurrencyView.swift; sourceTree = "<group>"; };
 		9509A8E128E5A3D700CFCDBA /* GuessThePopulationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuessThePopulationView.swift; sourceTree = "<group>"; };
 		951AFAE828E5655C00A4A4BD /* cities.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = cities.json; sourceTree = "<group>"; };
 		951AFAEC28E5657500A4A4BD /* CityModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityModel.swift; sourceTree = "<group>"; };
 		951AFAEE28E565FE00A4A4BD /* CountryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountryModel.swift; sourceTree = "<group>"; };
-		951AFAF028E5735400A4A4BD /* CityGame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityGame.swift; sourceTree = "<group>"; };
+		951AFAF028E5735400A4A4BD /* CityGameClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityGameClass.swift; sourceTree = "<group>"; };
 		951B630128D1A87C004F9877 /* GuessTheCapitalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuessTheCapitalView.swift; sourceTree = "<group>"; };
-		951D197228D485E000671FAD /* CustomColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomColors.swift; sourceTree = "<group>"; };
+		951D197228D485E000671FAD /* ColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtension.swift; sourceTree = "<group>"; };
 		952E41E828DC521200198643 /* GameAlertsModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameAlertsModifier.swift; sourceTree = "<group>"; };
 		952E41EC28DC658900198643 /* SettingsModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModalView.swift; sourceTree = "<group>"; };
 		952E41F028DC6F6D00198643 /* correctAnswer.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = correctAnswer.wav; sourceTree = "<group>"; };
@@ -61,23 +60,24 @@
 		9539829228C51EDE00B70973 /* GeoQuizApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoQuizApp.swift; sourceTree = "<group>"; };
 		9539829628C51EDF00B70973 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		9539829928C51EDF00B70973 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
-		955A658028D703EB00CEEC6D /* GameToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameToolbar.swift; sourceTree = "<group>"; };
-		955A658228D733E400CEEC6D /* Game.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Game.swift; sourceTree = "<group>"; };
-		955A65A828D7815E00CEEC6D /* Haptics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Haptics.swift; sourceTree = "<group>"; };
-		956273E928CB2E98008DC094 /* FlagImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlagImage.swift; sourceTree = "<group>"; };
+		955950BA28F15FF2001BDEE8 /* FormatterExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormatterExtension.swift; sourceTree = "<group>"; };
+		955A658028D703EB00CEEC6D /* GameToolbarHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameToolbarHelper.swift; sourceTree = "<group>"; };
+		955A658228D733E400CEEC6D /* GameProtocol+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GameProtocol+Extension.swift"; sourceTree = "<group>"; };
+		955A65A828D7815E00CEEC6D /* HapticsClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticsClass.swift; sourceTree = "<group>"; };
+		956273E928CB2E98008DC094 /* FlagImageHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlagImageHelper.swift; sourceTree = "<group>"; };
 		9590359428E098FF00B24560 /* ProfileModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileModalView.swift; sourceTree = "<group>"; };
-		95919DB528F076BF00F21F8F /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
+		95919DB528F076BF00F21F8F /* UserClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserClass.swift; sourceTree = "<group>"; };
 		95919DB728F079D100F21F8F /* UserSettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsModel.swift; sourceTree = "<group>"; };
-		95919DBB28F08D0600F21F8F /* LinkComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkComponent.swift; sourceTree = "<group>"; };
-		95AE8D5628C8750E0067F219 /* Load.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Load.swift; sourceTree = "<group>"; };
+		95919DBB28F08D0600F21F8F /* LinkHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkHelper.swift; sourceTree = "<group>"; };
+		95AE8D5628C8750E0067F219 /* LoadFunc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadFunc.swift; sourceTree = "<group>"; };
 		95AF322928DF293900023ACC /* GuessTheCountryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuessTheCountryView.swift; sourceTree = "<group>"; };
-		95BC392C28EC42570049AB49 /* CityMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityMap.swift; sourceTree = "<group>"; };
-		95C430F828D0A8E500480D23 /* CustomGradients.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomGradients.swift; sourceTree = "<group>"; };
+		95BC392C28EC42570049AB49 /* CityMapHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityMapHelper.swift; sourceTree = "<group>"; };
+		95C430F828D0A8E500480D23 /* GradientExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientExtension.swift; sourceTree = "<group>"; };
 		95C4315528C64A8C00212131 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
-		95C4315828C6500000212131 /* GameButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameButton.swift; sourceTree = "<group>"; };
+		95C4315828C6500000212131 /* GameButtonHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameButtonHelper.swift; sourceTree = "<group>"; };
 		95E6188428DDDB5C003359ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
 		95FA409928D9876B00129B60 /* GuessTheFlagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuessTheFlagView.swift; sourceTree = "<group>"; };
-		95FA409B28D9881100129B60 /* CountryGame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountryGame.swift; sourceTree = "<group>"; };
+		95FA409B28D9881100129B60 /* CountryGameClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountryGameClass.swift; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -94,12 +94,15 @@
 		95030CE728D1B60F001AA3A1 /* Logic */ = {
 			isa = PBXGroup;
 			children = (
-				95AE8D5628C8750E0067F219 /* Load.swift */,
-				955A65A828D7815E00CEEC6D /* Haptics.swift */,
-				955A658228D733E400CEEC6D /* Game.swift */,
-				95FA409B28D9881100129B60 /* CountryGame.swift */,
-				951AFAF028E5735400A4A4BD /* CityGame.swift */,
-				95919DB528F076BF00F21F8F /* User.swift */,
+				951AFAEC28E5657500A4A4BD /* CityModel.swift */,
+				951AFAEE28E565FE00A4A4BD /* CountryModel.swift */,
+				95919DB728F079D100F21F8F /* UserSettingsModel.swift */,
+				955A658228D733E400CEEC6D /* GameProtocol+Extension.swift */,
+				955A65A828D7815E00CEEC6D /* HapticsClass.swift */,
+				95FA409B28D9881100129B60 /* CountryGameClass.swift */,
+				951AFAF028E5735400A4A4BD /* CityGameClass.swift */,
+				95919DB528F076BF00F21F8F /* UserClass.swift */,
+				95AE8D5628C8750E0067F219 /* LoadFunc.swift */,
 			);
 			path = Logic;
 			sourceTree = "<group>";
@@ -140,13 +143,11 @@
 				95C4315528C64A8C00212131 /* ContentView.swift */,
 				95FA409928D9876B00129B60 /* GuessTheFlagView.swift */,
 				951B630128D1A87C004F9877 /* GuessTheCapitalView.swift */,
-				9509A8DF28E5A3C500CFCDBA /* GuessTheCurrencyView.swift */,
+				95AF322928DF293900023ACC /* GuessTheCountryView.swift */,
 				9509A8E128E5A3D700CFCDBA /* GuessThePopulationView.swift */,
-				95AF322928DF293900023ACC /* GuessTheCountryView.swift */,
 				9590359428E098FF00B24560 /* ProfileModalView.swift */,
 				952E41EC28DC658900198643 /* SettingsModalView.swift */,
-				959D414728C87EA600BAAC14 /* Helpers */,
-				959D414528C87E8D00BAAC14 /* Models */,
+				959D414728C87EA600BAAC14 /* Components */,
 				95030CE728D1B60F001AA3A1 /* Logic */,
 				9520ABBA28C86D0300A3D4D7 /* Resources */,
 				9539829828C51EDF00B70973 /* Preview Content */,
@@ -162,30 +163,21 @@
 			path = "Preview Content";
 			sourceTree = "<group>";
 		};
-		959D414528C87E8D00BAAC14 /* Models */ = {
+		959D414728C87EA600BAAC14 /* Components */ = {
 			isa = PBXGroup;
 			children = (
-				951AFAEC28E5657500A4A4BD /* CityModel.swift */,
-				951AFAEE28E565FE00A4A4BD /* CountryModel.swift */,
-				95919DB728F079D100F21F8F /* UserSettingsModel.swift */,
+				95C4315828C6500000212131 /* GameButtonHelper.swift */,
+				956273E928CB2E98008DC094 /* FlagImageHelper.swift */,
+				95030CE928D1BA4D001AA3A1 /* AnswerButtonHelper.swift */,
+				955A658028D703EB00CEEC6D /* GameToolbarHelper.swift */,
+				95BC392C28EC42570049AB49 /* CityMapHelper.swift */,
+				95919DBB28F08D0600F21F8F /* LinkHelper.swift */,
+				952E41E828DC521200198643 /* GameAlertsModifier.swift */,
+				95C430F828D0A8E500480D23 /* GradientExtension.swift */,
+				951D197228D485E000671FAD /* ColorExtension.swift */,
+				955950BA28F15FF2001BDEE8 /* FormatterExtension.swift */,
 			);
-			path = Models;
-			sourceTree = "<group>";
-		};
-		959D414728C87EA600BAAC14 /* Helpers */ = {
-			isa = PBXGroup;
-			children = (
-				95C4315828C6500000212131 /* GameButton.swift */,
-				956273E928CB2E98008DC094 /* FlagImage.swift */,
-				95030CE928D1BA4D001AA3A1 /* AnswerButton.swift */,
-				955A658028D703EB00CEEC6D /* GameToolbar.swift */,
-				952E41E828DC521200198643 /* GameAlertsModifier.swift */,
-				95C430F828D0A8E500480D23 /* CustomGradients.swift */,
-				951D197228D485E000671FAD /* CustomColors.swift */,
-				95BC392C28EC42570049AB49 /* CityMap.swift */,
-				95919DBB28F08D0600F21F8F /* LinkComponent.swift */,
-			);
-			path = Helpers;
+			path = Components;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
@@ -262,33 +254,33 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				955A65A928D7815E00CEEC6D /* Haptics.swift in Sources */,
-				95BC392D28EC42570049AB49 /* CityMap.swift in Sources */,
+				955A65A928D7815E00CEEC6D /* HapticsClass.swift in Sources */,
+				95BC392D28EC42570049AB49 /* CityMapHelper.swift in Sources */,
 				952E41E928DC521200198643 /* GameAlertsModifier.swift in Sources */,
 				95919DB828F079D100F21F8F /* UserSettingsModel.swift in Sources */,
 				9509A8E228E5A3D700CFCDBA /* GuessThePopulationView.swift in Sources */,
-				955A658328D733E400CEEC6D /* Game.swift in Sources */,
-				95919DB628F076BF00F21F8F /* User.swift in Sources */,
+				955A658328D733E400CEEC6D /* GameProtocol+Extension.swift in Sources */,
+				95919DB628F076BF00F21F8F /* UserClass.swift in Sources */,
 				95C4315628C64A8C00212131 /* ContentView.swift in Sources */,
-				95C4315928C6500000212131 /* GameButton.swift in Sources */,
-				956273EA28CB2E98008DC094 /* FlagImage.swift in Sources */,
+				95C4315928C6500000212131 /* GameButtonHelper.swift in Sources */,
+				956273EA28CB2E98008DC094 /* FlagImageHelper.swift in Sources */,
 				951AFAED28E5657500A4A4BD /* CityModel.swift in Sources */,
 				951B630228D1A87C004F9877 /* GuessTheCapitalView.swift in Sources */,
-				9509A8E028E5A3C500CFCDBA /* GuessTheCurrencyView.swift in Sources */,
 				9539829328C51EDE00B70973 /* GeoQuizApp.swift in Sources */,
 				95AF322A28DF293900023ACC /* GuessTheCountryView.swift in Sources */,
-				95919DBC28F08D0600F21F8F /* LinkComponent.swift in Sources */,
+				95919DBC28F08D0600F21F8F /* LinkHelper.swift in Sources */,
 				951AFAEF28E565FE00A4A4BD /* CountryModel.swift in Sources */,
-				95030CEA28D1BA4D001AA3A1 /* AnswerButton.swift in Sources */,
-				95FA409C28D9881100129B60 /* CountryGame.swift in Sources */,
-				955A658128D703EB00CEEC6D /* GameToolbar.swift in Sources */,
-				95AE8D5728C8750E0067F219 /* Load.swift in Sources */,
+				95030CEA28D1BA4D001AA3A1 /* AnswerButtonHelper.swift in Sources */,
+				95FA409C28D9881100129B60 /* CountryGameClass.swift in Sources */,
+				955A658128D703EB00CEEC6D /* GameToolbarHelper.swift in Sources */,
+				95AE8D5728C8750E0067F219 /* LoadFunc.swift in Sources */,
 				9590359528E098FF00B24560 /* ProfileModalView.swift in Sources */,
-				951D197328D485E000671FAD /* CustomColors.swift in Sources */,
-				95C430F928D0A8E500480D23 /* CustomGradients.swift in Sources */,
+				955950BB28F15FF2001BDEE8 /* FormatterExtension.swift in Sources */,
+				951D197328D485E000671FAD /* ColorExtension.swift in Sources */,
+				95C430F928D0A8E500480D23 /* GradientExtension.swift in Sources */,
 				952E41ED28DC658900198643 /* SettingsModalView.swift in Sources */,
 				95FA409A28D9876B00129B60 /* GuessTheFlagView.swift in Sources */,
-				951AFAF128E5735400A4A4BD /* CityGame.swift in Sources */,
+				951AFAF128E5735400A4A4BD /* CityGameClass.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
--- a/GeoQuiz/Assets.xcassets/Custom colors/AtomicTangerine.colorset/Contents.json	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/Assets.xcassets/Custom colors/AtomicTangerine.colorset/Contents.json	Sat Oct 08 21:36:40 2022 +0200
@@ -5,9 +5,9 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "0x54",
-          "green" : "0x8E",
-          "red" : "0xF7"
+          "blue" : "84",
+          "green" : "142",
+          "red" : "247"
         }
       },
       "idiom" : "universal"
@@ -23,8 +23,8 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "74",
-          "green" : "132",
+          "blue" : "54",
+          "green" : "112",
           "red" : "247"
         }
       },
--- a/GeoQuiz/Assets.xcassets/Custom colors/BlueBell.colorset/Contents.json	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/Assets.xcassets/Custom colors/BlueBell.colorset/Contents.json	Sat Oct 08 21:36:40 2022 +0200
@@ -23,8 +23,8 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "193",
-          "green" : "133",
+          "blue" : "173",
+          "green" : "113",
           "red" : "157"
         }
       },
--- a/GeoQuiz/Assets.xcassets/Custom colors/ChinaPink.colorset/Contents.json	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/Assets.xcassets/Custom colors/ChinaPink.colorset/Contents.json	Sat Oct 08 21:36:40 2022 +0200
@@ -23,8 +23,8 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "147",
-          "green" : "109",
+          "blue" : "127",
+          "green" : "89",
           "red" : "221"
         }
       },
--- a/GeoQuiz/Assets.xcassets/Custom colors/MaizeCrayola.colorset/Contents.json	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/Assets.xcassets/Custom colors/MaizeCrayola.colorset/Contents.json	Sat Oct 08 21:36:40 2022 +0200
@@ -23,8 +23,8 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "74",
-          "green" : "189",
+          "blue" : "54",
+          "green" : "169",
           "red" : "248"
         }
       },
--- a/GeoQuiz/Assets.xcassets/Custom colors/MayaBlue.colorset/Contents.json	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/Assets.xcassets/Custom colors/MayaBlue.colorset/Contents.json	Sat Oct 08 21:36:40 2022 +0200
@@ -23,8 +23,8 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "238",
-          "green" : "177",
+          "blue" : "218",
+          "green" : "157",
           "red" : "82"
         }
       },
--- a/GeoQuiz/Assets.xcassets/Custom colors/MiddleRed.colorset/Contents.json	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/Assets.xcassets/Custom colors/MiddleRed.colorset/Contents.json	Sat Oct 08 21:36:40 2022 +0200
@@ -23,8 +23,8 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "103",
-          "green" : "133",
+          "blue" : "83",
+          "green" : "113",
           "red" : "223"
         }
       },
--- a/GeoQuiz/Assets.xcassets/Custom colors/PinkLavender.colorset/Contents.json	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/Assets.xcassets/Custom colors/PinkLavender.colorset/Contents.json	Sat Oct 08 21:36:40 2022 +0200
@@ -23,8 +23,8 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "221",
-          "green" : "185",
+          "blue" : "201",
+          "green" : "165",
           "red" : "238"
         }
       },
--- a/GeoQuiz/Assets.xcassets/Custom colors/RoyalLightBlue.colorset/Contents.json	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/Assets.xcassets/Custom colors/RoyalLightBlue.colorset/Contents.json	Sat Oct 08 21:36:40 2022 +0200
@@ -23,8 +23,8 @@
         "color-space" : "srgb",
         "components" : {
           "alpha" : "1.000",
-          "blue" : "218",
-          "green" : "105",
+          "blue" : "198",
+          "green" : "85",
           "red" : "90"
         }
       },
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/AnswerButtonHelper.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,39 @@
+//
+//  AnswerButtonHelper.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 14/9/22.
+//
+
+import SwiftUI
+
+struct AnswerButton: View {
+    let optionName: String
+    let color: Color
+    
+    var body: some View {
+        RoundedRectangle(cornerRadius: 15)
+            .foregroundColor(.white)
+            .overlay(
+                Text(optionName)
+                    .font(.title2.bold())
+                    .foregroundColor(color)
+            )
+    }
+}
+
+struct AnswerButton_Previews: PreviewProvider {
+    static var previews: some View {
+        ZStack {
+            LinearGradient(gradient: .main, startPoint: .top, endPoint: .bottom)
+                .ignoresSafeArea()
+            
+            VStack {
+                Spacer()
+                AnswerButton(optionName: "Madrid", color: .royalLightBlue)
+                    .frame(height: 70)
+            }
+            .padding()
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/CityMapHelper.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,69 @@
+//
+//  CityMapHelper.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 4/10/22.
+//
+
+import SwiftUI
+import MapKit
+
+struct CityMap: View {
+    @ObservedObject var game: CityGame
+    @State private var mapImage: UIImage? = nil
+    
+    var body: some View {
+        VStack {
+            if let mapImage = mapImage {
+                Image(uiImage: mapImage)
+                    .resizable()
+                    .scaledToFit()
+                    .clipShape(Circle())
+                    .overlay {
+                        Circle()
+                            .strokeBorder(.white, lineWidth: 4)
+                    }
+                    .shadow(radius: 10)
+            } else {
+                ProgressView()
+            }
+        }
+        .onChange(of: game.correctAnswer.value) { _ in getMapImage() }
+        .onAppear(perform: getMapImage)
+    }
+    
+    private func getMapImage() {
+        let region = MKCoordinateRegion(
+            center: CLLocationCoordinate2D(
+                latitude: game.correctAnswer.value.lat,
+                longitude: game.correctAnswer.value.lon
+            ),
+            span: MKCoordinateSpan(
+                latitudeDelta: 0.1,
+                longitudeDelta: 0.1
+            )
+        )
+
+        // Map options
+        let mapOptions = MKMapSnapshotter.Options()
+        mapOptions.region = region
+        mapOptions.size = CGSize(width: 500, height: 500)
+        mapOptions.pointOfInterestFilter = .excludingAll
+
+        // Create the snapshotter and run it
+        let snapshotter = MKMapSnapshotter(options: mapOptions)
+        snapshotter.start { (snapshot, error) in
+            if let snapshot = snapshot {
+                self.mapImage = snapshot.image
+            } else if let error = error {
+                print(error.localizedDescription)
+            }
+        }
+    }
+}
+
+struct CityMap_Previews: PreviewProvider {
+    static var previews: some View {
+        CityMap(game: CityGame())
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/ColorExtension.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,43 @@
+//
+//  ColorExtension.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 16/9/22.
+//
+
+import Foundation
+import SwiftUI
+
+extension ShapeStyle where Self == Color {
+    static var atomicTangerine: Color {
+        Color("AtomicTangerine")
+    }
+    
+    static var blueBell: Color {
+        Color("BlueBell")
+    }
+    
+    static var chinaPink: Color {
+        Color("ChinaPink")
+    }
+    
+    static var maizeCrayola: Color {
+        Color("MaizeCrayola")
+    }
+    
+    static var mayaBlue: Color {
+        Color("MayaBlue")
+    }
+    
+    static var middleRed: Color {
+        Color("MiddleRed")
+    }
+    
+    static var pinkLavender: Color {
+        Color("PinkLavender")
+    }
+    
+    static var royalLightBlue: Color {
+        Color("RoyalLightBlue")
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/FlagImageHelper.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,29 @@
+//
+//  FlagImageHelper.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 9/9/22.
+//
+
+import SwiftUI
+
+struct FlagImage: View {
+    @Environment(\.colorScheme) var colorScheme
+    
+    var flagSymbol: String
+    var cornerRadius: Double
+    
+    var body: some View {
+        Image(flagSymbol)
+            .renderingMode(.original)
+            .resizable()
+            .scaledToFit()
+    }
+}
+
+struct FlagImage_Previews: PreviewProvider {
+    static var previews: some View {
+        FlagImage(flagSymbol: "es", cornerRadius: 20)
+            .frame(height: 130)
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/FormatterExtension.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,22 @@
+//
+//  Formatters.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 8/10/22.
+//
+
+import Foundation
+
+extension Formatter {
+    static let withSeparator: NumberFormatter = {
+        let formatter = NumberFormatter()
+        formatter.numberStyle = .decimal
+        return formatter
+    }()
+}
+
+extension Int {
+    var formattedWithSeparator: String {
+        return Formatter.withSeparator.string(for: self) ?? ""
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/GameAlertsModifier.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,55 @@
+//
+//  GameAlertsModifier.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 22/9/22.
+//
+
+import SwiftUI
+
+struct GameAlertsModifier<T: Game>: ViewModifier {
+    @ObservedObject var game: T
+    @Environment(\.dismiss) var dismiss
+    
+    func body(content: Content) -> some View {
+        content
+            .alert(game.alertTitle, isPresented: $game.showingWrongAnswerAlert) {
+                Button("Continue", role: .cancel) {
+                    game.askQuestion {
+                        game.selector()
+                    }
+                }
+            } message: {
+                Text(game.alertMessage)
+            }
+        
+            .alert(game.alertTitle, isPresented: $game.showingGameOverAlert) {
+                Button("Try again") {
+                    game.reset {
+                        game.selector()
+                    }
+                }
+                Button("Exit", role: .cancel) { dismiss()}
+            } message: {
+                Text(game.alertMessage)
+            }
+            
+            .alert(game.alertTitle, isPresented: $game.showingEndGameAlert) {
+                Button("Play again") {
+                    game.reset() {
+                        game.selector()
+                    }
+                }
+                Button("Exit", role: .cancel) { dismiss() }
+            } message: {
+                Text(game.alertMessage)
+            }
+        
+            .alert("Are you sure?", isPresented: $game.showingExitGameAlert) {
+                Button("Exit", role: .destructive) { dismiss() }
+                Button("Cancel", role: .cancel) { }
+            } message: {
+                Text("Progress won't be saved.")
+            }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/GameButtonHelper.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,65 @@
+//
+//  GameButtonHelper.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 5/9/22.
+//
+
+import SwiftUI
+
+struct GameButton: View {
+    let gradient: Gradient
+    let level: String
+    let symbol: String
+    let name: String
+    
+    var body: some View {
+        ZStack {
+            RoundedRectangle(cornerRadius: 20)
+                .fill(
+                    LinearGradient(
+                        gradient: gradient,
+                        startPoint: .trailing, endPoint: .leading
+                    )
+                )
+                .frame(height: 180)
+            
+            VStack(alignment: .leading) {
+                HStack {
+                    Image(systemName: symbol)
+                        .font(.headline)
+                        .padding(5)
+                        .background(
+                            RoundedRectangle(cornerRadius: 5)
+                                .stroke(lineWidth: 1.5)
+                        )
+                    
+                    Spacer()
+                }
+                .padding(.bottom)
+                
+                VStack(alignment: .leading, spacing: 5) {
+                    Text(level)
+                        .font(.callout)
+                    
+                    Text(name)
+                        .font(.title.bold())
+                }
+            }
+            .foregroundColor(.white)
+            .padding()
+        }
+        .frame(maxWidth: 700)
+    }
+}
+
+struct GameButton_Previews: PreviewProvider {
+    static var previews: some View {
+        GameButton(
+            gradient: .main,
+            level: "Level 1",
+            symbol: "checkmark",
+            name: "Guess the flag"
+        )
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/GameToolbarHelper.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,90 @@
+//
+//  GameToolbarHelper.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 18/9/22.
+//
+
+import SwiftUI
+
+struct GameToolbar<T: Game>: View {
+    @ObservedObject var game: T
+    
+    var color: Color
+    
+    var body: some View {
+        HStack(spacing: 0) {
+            Group {
+                Button {
+                    game.showingExitGameAlert = true
+                } label: {
+                    Image(systemName: "multiply")
+                        .font(.headline)
+                        .foregroundColor(color)
+                        .padding(10)
+                        .background(
+                            Circle()
+                                .foregroundColor(.white)
+                        )
+                }
+            }
+            .font(.headline)
+            .frame(maxWidth: .infinity, alignment: .leading)
+            
+            Group {
+                Text("\(game.userScore)")
+                    .font(.title.bold())
+                    .foregroundColor(color)
+                    .padding()
+                    .background(
+                        Group {
+                            if game.userScore < 1000 {
+                                Circle()
+                            } else {
+                                Capsule()
+                            }
+                        }
+                            .foregroundColor(.white)
+                    )
+            }
+            .font(.title2)
+            .scaleEffect(game.scoreScaleAmount)
+            .frame(maxWidth: .infinity, alignment: .center)
+            
+            Group {
+                HStack {
+                    Image(systemName: "heart.fill")
+                    Text("\(game.userLives)")
+                }
+                .font(.headline)
+                .foregroundColor(color)
+                .padding(10)
+                .background(
+                    Capsule()
+                        .foregroundColor(.white)
+                )
+                .scaleEffect(game.livesScaleAmount)
+            }
+            .font(.headline)
+            .frame(maxWidth: .infinity, alignment: .trailing)
+        }
+    }
+}
+
+struct GameToolbar_Previews: PreviewProvider {
+    static var previews: some View {
+        ZStack {
+            LinearGradient(gradient: .main, startPoint: .top, endPoint: .bottom)
+                .ignoresSafeArea()
+            
+            GeometryReader { geo in
+                VStack {
+                    GameToolbar(game: CountryGame(), color: .mayaBlue)
+                    
+                    Spacer()
+                }
+                .padding()
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/GradientExtension.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,27 @@
+//
+//  GradientExtension.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 13/9/22.
+//
+
+import Foundation
+import SwiftUI
+
+extension ShapeStyle where Self == Gradient {
+    static var main: Gradient {
+        Gradient(colors: [Color("MayaBlue"), Color("RoyalLightBlue")])
+    }
+    
+    static var secondary: Gradient {
+        Gradient(colors: [Color("AtomicTangerine"), Color("ChinaPink")])
+    }
+    
+    static var tertiary: Gradient {
+        Gradient(colors: [Color("PinkLavender"), Color("BlueBell")])
+    }
+    
+    static var quaternary: Gradient {
+        Gradient(colors: [Color("MaizeCrayola"), Color("MiddleRed")])
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Components/LinkHelper.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,41 @@
+//
+//  LinkHelper.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 7/10/22.
+//
+
+import SwiftUI
+
+struct LinkComponent: View {
+    var color: Color
+    var iconName: String
+    var text: String
+    var url: URL
+    
+    @Environment(\.openURL) var openURL
+    
+    var body: some View {
+        Link(destination: url) {
+            HStack(alignment: .center, spacing: 20) {
+                Image(systemName: iconName)
+                    .imageScale(.large)
+                    .foregroundColor(color)
+                
+                Text(text)
+                    .foregroundColor(.primary)
+            }
+        }
+    }
+}
+
+struct LinkComponent_Previews: PreviewProvider {
+    static var previews: some View {
+        LinkComponent(
+            color: .mayaBlue,
+            iconName: "info.circle.fill",
+            text: "About",
+            url: URL(string: "https://dennistech.io")!
+        )
+    }
+}
--- a/GeoQuiz/ContentView.swift	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/ContentView.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -14,7 +14,11 @@
     var body: some View {
         NavigationView {
             ScrollView(showsIndicators: false) {
-                VStack(spacing: 20) {
+                VStack(alignment: .leading, spacing: 20) {
+                    
+                    Text("Select a game 🎮")
+                        .font(.largeTitle.bold())
+                        .padding(.bottom)
                     
                     NavigationLink(destination: GuessTheFlagView()) {
                         GameButton(
@@ -36,21 +40,18 @@
                             level: "Level 3", symbol: "globe.americas.fill", name: "Guess the country"
                         )
                     }
-
-//                    NavigationLink(
-//                        destination: Text("Guess the population"),
-//                        tag: GameName.guessThePopulation,
-//                        selection: $gameName
-//                    ) {
-//                        GameButton(
-//                            gradient: .quaternary,
-//                            level: "Level 4", symbol: "person.3.fill", name: "Guess the population"
-//                        )
-//                    }
+                    
+                    NavigationLink(destination: GuessThePopulationView()) {
+                        GameButton(
+                            gradient: .quaternary,
+                            level: "Level 4", symbol: "person.fill", name: "Guess the population"
+                        )
+                    }
                 }
                 .padding()
             }
-            .navigationTitle("Select a game 🎮")
+            .navigationTitle("GeoQuiz")
+            .navigationBarTitleDisplayMode(.inline)
             .toolbar {
                 ToolbarItem(placement: .navigationBarLeading) {
                     Button {
--- a/GeoQuiz/GuessTheCapitalView.swift	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/GuessTheCapitalView.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -16,18 +16,19 @@
                 .ignoresSafeArea()
             
             GeometryReader { geo in
-                VStack(spacing: 20) {
+                VStack {
                     GameToolbar(game: game, color: .atomicTangerine)
                     
                     Spacer()
                     
                     FlagImage(flagSymbol: game.correctAnswer.value.flag, cornerRadius: 20)
+                        .clipShape(RoundedRectangle(cornerRadius: 20))
                         .shadow(radius: 10)
                         .frame(height: geo.size.height * 0.15)
                     
                     Spacer()
                     
-                    HStack {
+                    VStack(alignment: .leading) {
                         VStack(alignment: .leading, spacing: 10) {
                             Text("Question \(game.questionCounter) of \(game.data.count)")
                                 .font(.title3)
@@ -39,24 +40,23 @@
                                 .foregroundColor(.white)
                         }
                         
-                        Spacer()
-                    }
-                    
-                    VStack {
-                        ForEach(Array(game.userChoices.keys), id: \.self) { countryName in
-                            Button {
-                                game.answer((key: countryName, value: game.data[countryName]!)) {
-                                    game.selector()
+                        VStack(spacing: 15) {
+                            ForEach(Array(game.userChoices.keys), id: \.self) { countryName in
+                                Button {
+                                    game.answer((key: countryName, value: game.data[countryName]!)) {
+                                        game.selector()
+                                    }
+                                } label: {
+                                    AnswerButton(
+                                        optionName: game.data[countryName]!.capital,
+                                        color: .chinaPink
+                                    )
+                                    .frame(height: geo.size.height * 0.08)
                                 }
-                            } label: {
-                                AnswerButton(
-                                    optionName: game.data[countryName]!.capital,
-                                    color: .chinaPink
-                                )
-                                .frame(height: geo.size.height * 0.08)
                             }
                         }
                     }
+                    .frame(maxWidth: 500)
                 }
                 .padding()
             }
@@ -66,10 +66,14 @@
     }
 }
 
-struct GuessCapitalView_Previews: PreviewProvider {
+struct GuessTheCapitalView_Previews: PreviewProvider {
     static var previews: some View {
-        NavigationView {
-            GuessTheCapitalView()
-        }
+        GuessTheCapitalView()
+            .previewDevice(PreviewDevice(rawValue: "iPhone 14 Pro Max"))
+            .previewDisplayName("iPhone 14 Pro Max")
+        
+        GuessTheCapitalView()
+            .previewDevice(PreviewDevice(rawValue: "iPad Pro (12.9-inch) (5th generation)"))
+            .previewDisplayName("iPad Pro (12.9-inch) (5th generation)")
     }
 }
--- a/GeoQuiz/GuessTheCountryView.swift	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/GuessTheCountryView.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -16,16 +16,17 @@
                 .ignoresSafeArea()
             
             GeometryReader { geo in
-                VStack(spacing: 20) {
+                VStack {
                     GameToolbar(game: game, color: .pinkLavender)
                     
                     Spacer()
-    
-                    CityMap(game: game, geo: geo)
+                    
+                    CityMap(game: game)
+                        .frame(height: geo.size.height * 0.35)
                     
                     Spacer()
                     
-                    HStack {
+                    VStack(alignment: .leading) {
                         VStack(alignment: .leading, spacing: 10) {
                             Text("Question \(game.questionCounter) of \(game.data.count)")
                                 .font(.title3)
@@ -37,25 +38,23 @@
                                 .foregroundColor(.white)
                         }
                         
-                        Spacer()
-                    }
-                    
-                    VStack {
-                        ForEach(Array(game.userChoices.keys), id: \.self) { cityName in
-                            Button {
-                                game.answer((key: cityName, value: game.data[cityName]!)) {
-                                    game.selector()
+                        VStack(spacing: 15) {
+                            ForEach(Array(game.userChoices.keys), id: \.self) { cityName in
+                                Button {
+                                    game.answer((key: cityName, value: game.data[cityName]!)) {
+                                        game.selector()
+                                    }
+                                } label: {
+                                    AnswerButton(
+                                        optionName: game.data[cityName]!.country,
+                                        color: .blueBell
+                                    )
+                                    .frame(height: geo.size.height * 0.08)
                                 }
-                            } label: {
-                                AnswerButton(
-                                    optionName: game.data[cityName]!.country,
-                                    color: .blueBell
-                                )
-                                .frame(height: geo.size.height * 0.08)
                             }
                         }
                     }
-                    
+                    .frame(maxWidth: 500)
                 }
                 .padding()
             }
@@ -68,5 +67,11 @@
 struct GuessTheCountryView_Previews: PreviewProvider {
     static var previews: some View {
         GuessTheCountryView()
+            .previewDevice(PreviewDevice(rawValue: "iPhone 14 Pro Max"))
+            .previewDisplayName("iPhone 14 Pro Max")
+        
+        GuessTheCountryView()
+            .previewDevice(PreviewDevice(rawValue: "iPad Pro (12.9-inch) (5th generation)"))
+            .previewDisplayName("iPad Pro (12.9-inch) (5th generation)")
     }
 }
--- a/GeoQuiz/GuessTheCurrencyView.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-//
-//  GuessTheCurrencyView.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 29/9/22.
-//
-
-import SwiftUI
-
-struct GuessTheCurrencyView: View {
-    var body: some View {
-        Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
-    }
-}
-
-struct GuessTheCurrency_Previews: PreviewProvider {
-    static var previews: some View {
-        GuessTheCurrencyView()
-    }
-}
--- a/GeoQuiz/GuessTheFlagView.swift	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/GuessTheFlagView.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -16,37 +16,44 @@
                 .ignoresSafeArea()
             
             GeometryReader { geo in
-                VStack(spacing: 20) {
+                VStack {
                     GameToolbar(game: game, color: .mayaBlue)
+                        .padding(.bottom)
                     
-                    HStack {
-                        VStack(alignment: .leading, spacing: 10) {
-                            Text("Question \(game.questionCounter) of \(game.data.count)")
-                                .font(.title3)
-                                .foregroundColor(.white.opacity(0.7))
-                            
-                            Text("What is the flag of \(game.correctAnswer.key)?")
-                                .font(.title)
-                                .fontWeight(.semibold)
-                                .foregroundColor(.white)
-                        }
+                    VStack(spacing: 10) {
+                        Text("Question \(game.questionCounter) of \(game.data.count)")
+                            .font(.title3)
+                            .foregroundColor(.white.opacity(0.7))
                         
-                        Spacer()
+                        Text("What is the flag of")
+                            .font(.title)
+                            .fontWeight(.semibold)
+                            .foregroundColor(.white)
+                        
+                        Text("\(game.correctAnswer.key)?")
+                            .font(.largeTitle.bold())
+                            .foregroundColor(.white)
+                        
                     }
                     
                     Spacer()
-                    
-                    ForEach(Array(game.userChoices.keys), id: \.self) { countryName in
-                        Button {
-                            game.answer((key: countryName, value: game.data[countryName]!)) {
-                                game.selector()
+                    VStack(spacing: 30) {
+                        ForEach(Array(game.userChoices.keys), id: \.self) { countryName in
+                            Button {
+                                game.answer((key: countryName, value: game.data[countryName]!)) {
+                                    game.selector()
+                                }
+                            } label: {
+                                FlagImage(flagSymbol: game.data[countryName]!.flag, cornerRadius: 20)
+                                    .clipShape(Circle())
+                                    .overlay {
+                                        Circle()
+                                            .strokeBorder(.white, lineWidth: 4)
+                                    }
+                                    .shadow(radius: 10)
+                                    .frame(height: geo.size.height * 0.15)
                             }
-                        } label: {
-                            FlagImage(flagSymbol: game.data[countryName]!.flag, cornerRadius: 20)
-                                .shadow(radius: 10)
-                                .frame(height: geo.size.height * 0.15)
                         }
-                        .padding(.top)
                     }
                     
                     Spacer()
@@ -62,5 +69,11 @@
 struct GuessTheFlagView_Previews: PreviewProvider {
     static var previews: some View {
         GuessTheFlagView()
+            .previewDevice(PreviewDevice(rawValue: "iPhone 14 Pro Max"))
+            .previewDisplayName("iPhone 14 Pro Max")
+        
+        GuessTheFlagView()
+            .previewDevice(PreviewDevice(rawValue: "iPad Pro (12.9-inch) (5th generation)"))
+            .previewDisplayName("iPad Pro (12.9-inch) (5th generation)")
     }
 }
--- a/GeoQuiz/GuessThePopulationView.swift	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/GuessThePopulationView.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -8,13 +8,73 @@
 import SwiftUI
 
 struct GuessThePopulationView: View {
+    @StateObject var game = CountryGame()
+    
     var body: some View {
-        Text("Hello, World!")
+        ZStack {
+            LinearGradient(gradient: .quaternary, startPoint: .top, endPoint: .bottom)
+                .ignoresSafeArea()
+            
+            GeometryReader { geo in
+                VStack {
+                    GameToolbar(game: game, color: .maizeCrayola)
+                    
+                    Spacer()
+                    
+                    FlagImage(flagSymbol: game.correctAnswer.value.flag, cornerRadius: 20)
+                        .clipShape(RoundedRectangle(cornerRadius: 20))
+                        .shadow(radius: 10)
+                        .frame(height: geo.size.height * 0.15)
+                    
+                    Spacer()
+                    
+                    VStack(alignment: .leading) {
+                        VStack(alignment: .leading, spacing: 10) {
+                            Text("Question \(game.questionCounter) of \(game.data.count)")
+                                .font(.title3)
+                                .foregroundColor(.white.opacity(0.7))
+                            
+                            Text("What is the population of \(game.correctAnswer.key)?")
+                                .font(.title)
+                                .fontWeight(.semibold)
+                                .foregroundColor(.white)
+                        }
+                        
+                        VStack(spacing: 15) {
+                            ForEach(Array(game.userChoices.keys), id: \.self) { countryName in
+                                Button {
+                                    game.answer((key: countryName, value: game.data[countryName]!)) {
+                                        game.selector()
+                                    }
+                                } label: {
+                                    let population = game.data[countryName]!.population
+                                    AnswerButton(
+                                        optionName: population.formattedWithSeparator,
+                                        color: .middleRed
+                                    )
+                                    .frame(height: geo.size.height * 0.08)
+                                }
+                            }
+                        }
+                    }
+                    .frame(maxWidth: 500)
+                }
+                .padding()
+            }
+        }
+        .navigationBarHidden(true)
+        .modifier(GameAlertsModifier(game: game))
     }
 }
 
-struct GuessThePopulation_Previews: PreviewProvider {
+struct GuessThePopulationView_Previews: PreviewProvider {
     static var previews: some View {
         GuessThePopulationView()
+            .previewDevice(PreviewDevice(rawValue: "iPhone 14 Pro Max"))
+            .previewDisplayName("iPhone 14 Pro Max")
+        
+        GuessThePopulationView()
+            .previewDevice(PreviewDevice(rawValue: "iPad Pro (12.9-inch) (5th generation)"))
+            .previewDisplayName("iPad Pro (12.9-inch) (5th generation)")
     }
 }
--- a/GeoQuiz/Helpers/AnswerButton.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-//
-//  AnswerButton.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 14/9/22.
-//
-
-import SwiftUI
-
-struct AnswerButton: View {
-    let optionName: String
-    let color: Color
-    
-    var body: some View {
-        RoundedRectangle(cornerRadius: 15)
-            .foregroundStyle(.ultraThickMaterial)
-            .overlay(
-                Text(optionName)
-                    .font(.title2.bold())
-                    .foregroundColor(color)
-            )
-    }
-}
-
-struct AnswerButton_Previews: PreviewProvider {
-    static var previews: some View {
-        ZStack {
-            LinearGradient(gradient: .main, startPoint: .top, endPoint: .bottom)
-                .ignoresSafeArea()
-            
-            VStack {
-                Spacer()
-                AnswerButton(optionName: "Madrid", color: .royalLightBlue)
-                    .frame(height: 70)
-            }
-            .padding()
-        }
-    }
-}
--- a/GeoQuiz/Helpers/CityMap.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-//
-//  CityMap.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 4/10/22.
-//
-
-import SwiftUI
-import MapKit
-
-struct CityMap: View {
-    @ObservedObject var game: CityGame
-    @State private var mapImage: UIImage? = nil
-    
-    let geo: GeometryProxy
-    
-    var body: some View {
-        VStack {
-            if let mapImage = mapImage {
-                Image(uiImage: mapImage)
-                    .resizable()
-                    .scaledToFit()
-                    .clipShape(RoundedRectangle(cornerRadius: 20))
-                    .shadow(radius: 10)
-            } else {
-                ProgressView()
-            }
-        }
-        .onChange(of: game.correctAnswer.value) { _ in getMapImage() }
-        .onAppear(perform: getMapImage)
-    }
-    
-    private func getMapImage() {
-        let region = MKCoordinateRegion(
-            center: CLLocationCoordinate2D(
-                latitude: game.correctAnswer.value.lat,
-                longitude: game.correctAnswer.value.lon
-            ),
-            span: MKCoordinateSpan(
-                latitudeDelta: 0.1,
-                longitudeDelta: 0.1
-            )
-        )
-
-        // Map options
-        let mapOptions = MKMapSnapshotter.Options()
-        mapOptions.region = region
-        mapOptions.size = CGSize(width: geo.size.width * 0.8, height: geo.size.width * 0.8)
-        mapOptions.pointOfInterestFilter = .excludingAll
-
-        // Create the snapshotter and run it
-        let snapshotter = MKMapSnapshotter(options: mapOptions)
-        snapshotter.start { (snapshot, error) in
-            if let snapshot = snapshot {
-                self.mapImage = snapshot.image
-            } else if let error = error {
-                print(error.localizedDescription)
-            }
-        }
-    }
-}
-
-//struct CityMap_Previews: PreviewProvider {
-//    static var previews: some View {
-//        CityMap(game: CityGame())
-//    }
-//}
--- a/GeoQuiz/Helpers/CustomColors.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-//
-//  CustomColors.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 16/9/22.
-//
-
-import Foundation
-import SwiftUI
-
-extension ShapeStyle where Self == Color {
-    static var atomicTangerine: Color {
-        Color("AtomicTangerine")
-    }
-    
-    static var blueBell: Color {
-        Color("BlueBell")
-    }
-    
-    static var chinaPink: Color {
-        Color("ChinaPink")
-    }
-    
-    static var maizeCrayola: Color {
-        Color("MaizeCrayola")
-    }
-    
-    static var mayaBlue: Color {
-        Color("MayaBlue")
-    }
-    
-    static var middleRed: Color {
-        Color("MiddleRed")
-    }
-    
-    static var pinkLavender: Color {
-        Color("PinkLavender")
-    }
-    
-    static var royalLightBlue: Color {
-        Color("RoyalLightBlue")
-    }
-}
--- a/GeoQuiz/Helpers/CustomGradients.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-//
-//  CustomGradients.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 13/9/22.
-//
-
-import Foundation
-import SwiftUI
-
-extension ShapeStyle where Self == Gradient {
-    static var main: Gradient {
-        Gradient(colors: [Color("MayaBlue"), Color("RoyalLightBlue")])
-    }
-    
-    static var secondary: Gradient {
-        Gradient(colors: [Color("AtomicTangerine"), Color("ChinaPink")])
-    }
-    
-    static var tertiary: Gradient {
-        Gradient(colors: [Color("PinkLavender"), Color("BlueBell")])
-    }
-    
-    static var quaternary: Gradient {
-        Gradient(colors: [Color("MaizeCrayola"), Color("MiddleRed")])
-    }
-}
--- a/GeoQuiz/Helpers/FlagImage.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-//
-//  FlagImage.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 9/9/22.
-//
-
-import SwiftUI
-
-struct FlagImage: View {
-    @Environment(\.colorScheme) var colorScheme
-    
-    var flagSymbol: String
-    var cornerRadius: Double
-    
-    var body: some View {
-        Image(flagSymbol)
-            .renderingMode(.original)
-            .resizable()
-            .scaledToFit()
-            .clipShape(RoundedRectangle(cornerRadius: cornerRadius))
-    }
-}
-
-struct FlagImage_Previews: PreviewProvider {
-    static var previews: some View {
-        FlagImage(flagSymbol: "np", cornerRadius: 20)
-            .frame(height: 130)
-    }
-}
--- a/GeoQuiz/Helpers/GameAlertsModifier.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-//
-//  GameAlertsModifier.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 22/9/22.
-//
-
-import SwiftUI
-
-struct GameAlertsModifier<T: Game>: ViewModifier {
-    @ObservedObject var game: T
-    @Environment(\.dismiss) var dismiss
-    
-    func body(content: Content) -> some View {
-        content
-            .alert(game.alertTitle, isPresented: $game.showingWrongAnswerAlert) {
-                Button("Continue", role: .cancel) {
-                    game.askQuestion {
-                        game.selector()
-                    }
-                }
-            } message: {
-                Text(game.alertMessage)
-            }
-        
-            .alert(game.alertTitle, isPresented: $game.showingGameOverAlert) {
-                Button("Try again") {
-                    game.reset {
-                        game.selector()
-                    }
-                }
-                Button("Exit", role: .cancel) { dismiss()}
-            } message: {
-                Text(game.alertMessage)
-            }
-            
-            .alert(game.alertTitle, isPresented: $game.showingEndGameAlert) {
-                Button("Play again") {
-                    game.reset() {
-                        game.selector()
-                    }
-                }
-                Button("Exit", role: .cancel) { dismiss() }
-            } message: {
-                Text(game.alertMessage)
-            }
-        
-            .alert("Are you sure?", isPresented: $game.showingExitGameAlert) {
-                Button("Exit", role: .destructive) { dismiss() }
-                Button("Cancel", role: .cancel) { }
-            } message: {
-                Text("Progress won't be saved.")
-            }
-    }
-}
--- a/GeoQuiz/Helpers/GameButton.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-//
-//  GameButton.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 5/9/22.
-//
-
-import SwiftUI
-
-struct GameButton: View {
-    let gradient: Gradient
-    let level: String
-    let symbol: String
-    let name: String
-    
-    var body: some View {
-        ZStack {
-            RoundedRectangle(cornerRadius: 20)
-                .fill(
-                    LinearGradient(
-                        gradient: gradient,
-                        startPoint: .trailing, endPoint: .leading
-                    )
-                )
-                .frame(height: 180)
-            
-            VStack(alignment: .leading) {
-                HStack {
-                    Image(systemName: symbol)
-                        .font(.headline)
-                        .padding(5)
-                        .background(
-                            RoundedRectangle(cornerRadius: 5)
-                                .stroke(lineWidth: 1.5)
-                        )
-                    
-                    Spacer()
-                }
-                .padding(.bottom)
-                
-                VStack(alignment: .leading, spacing: 5) {
-                    Text(level)
-                        .font(.callout)
-                    
-                    Text(name)
-                        .font(.title.bold())
-                }
-            }
-            .foregroundColor(.white)
-            .padding()
-        }
-    }
-}
-
-struct PlayButton_Previews: PreviewProvider {
-    static var previews: some View {
-        GameButton(
-            gradient: Gradient(colors: [Color("MainDark"), Color("Main")]),
-            level: "Level 1",
-            symbol: "checkmark",
-            name: "Guess the flag"
-        )
-    }
-}
--- a/GeoQuiz/Helpers/GameToolbar.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-//
-//  GameToolbar.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 18/9/22.
-//
-
-import SwiftUI
-
-struct GameToolbar<T: Game>: View {
-    @ObservedObject var game: T
-    
-    var color: Color
-    
-    var body: some View {
-        HStack(spacing: 0) {
-            Group {
-                Button {
-                    game.showingExitGameAlert = true
-                } label: {
-                    Image(systemName: "multiply")
-                        .font(.headline)
-                        .foregroundColor(color)
-                        .padding(10)
-                        .background(
-                            Circle()
-                                .foregroundStyle(.ultraThickMaterial)
-                        )
-                }
-            }
-            .font(.headline)
-            .frame(maxWidth: .infinity, alignment: .leading)
-            
-            Group {
-                Text("\(game.userScore)")
-                    .font(.title.bold())
-                    .foregroundColor(color)
-                    .padding()
-                    .background(
-                        Group {
-                            if game.userScore < 1000 {
-                                Circle()
-                            } else {
-                                Capsule()
-                            }
-                        }
-                        .foregroundStyle(.ultraThickMaterial)
-                    )
-            }
-            .font(.title2)
-            .scaleEffect(game.scoreScaleAmount)
-            .frame(maxWidth: .infinity, alignment: .center)
-            
-            Group {
-                HStack {
-                    Image(systemName: "heart.fill")
-                    Text("\(game.userLives)")
-                }
-                .font(.headline)
-                .foregroundColor(color)
-                .padding(10)
-                .background(
-                    Capsule()
-                        .foregroundStyle(.ultraThickMaterial)
-                )
-                .scaleEffect(game.livesScaleAmount)
-            }
-            .font(.headline)
-            .frame(maxWidth: .infinity, alignment: .trailing)
-        }
-    }
-}
-
-struct GameToolbar_Previews: PreviewProvider {
-    static var previews: some View {
-        ZStack {
-            LinearGradient(gradient: .main, startPoint: .top, endPoint: .bottom)
-                .ignoresSafeArea()
-            
-            GeometryReader { geo in
-                VStack {
-                    GameToolbar(game: CountryGame(), color: .mayaBlue)
-                    
-                    Spacer()
-                }
-                .padding()
-            }
-        }
-    }
-}
--- a/GeoQuiz/Helpers/LinkComponent.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-//
-//  LinkComponent.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 7/10/22.
-//
-
-import SwiftUI
-
-struct LinkComponent: View {
-    var color: Color
-    var iconName: String
-    var text: String
-    var url: URL
-    
-    @Environment(\.openURL) var openURL
-    
-    var body: some View {
-        Link(destination: url) {
-            HStack(alignment: .center, spacing: 20) {
-                Image(systemName: iconName)
-                    .imageScale(.large)
-                    .foregroundColor(color)
-                
-                Text(text)
-                    .foregroundColor(.primary)
-            }
-        }
-    }
-}
-
-struct LinkComponent_Previews: PreviewProvider {
-    static var previews: some View {
-        LinkComponent(
-            color: .mayaBlue,
-            iconName: "info.circle.fill",
-            text: "About",
-            url: URL(string: "https://dennistech.io")!
-        )
-    }
-}
--- a/GeoQuiz/Logic/CityGame.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-//
-//  CityGame.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 29/9/22.
-//
-
-import Foundation
-import AVFAudio
-
-class CityGame: Game, ObservableObject {
-    
-    // Define type of generics
-    typealias T = CityModel.CityData
-    
-    var data: [String: T]
-    var dataAsked = [String: T]()
-    
-    // Data
-    @Published var correctAnswer = (
-        key: String(),
-        value: T(country: String(), lat: Double(), lon: Double())
-    )
-    
-    // User
-    @Published var userChoices = [String: T]()
-    @Published var userScore = 0
-    @Published var userLives = 3
-    @Published var correctAnswers = [String: T]()
-    @Published var wrongAnswers = [String: T]()
-    
-    // Alerts
-    @Published var alertTitle = String()
-    @Published var alertMessage = String()
-    @Published var showingGameOverAlert = false
-    @Published var showingEndGameAlert = false
-    @Published var showingWrongAnswerAlert = false
-    @Published var showingExitGameAlert = false
-    
-    // Animations
-    @Published var scoreScaleAmount = 1.0
-    @Published var livesScaleAmount = 1.0
-    
-    // Sound effects
-    @Published var player: AVAudioPlayer?
-    
-    init() {
-        let data: CityModel = load("cities.json")
-        self.data = data.cities
-        askQuestion {
-            selector()
-        }
-    }
-}
-
-extension CityGame {
-    func selector() {
-        
-        // Get random choices
-        var userChoices = [String: T]()
-        
-        while userChoices.count < 2 {
-            if let choice = data.randomElement() {
-                let userChoicesCountry = userChoices.map { $0.value.country }
-                
-                if !userChoicesCountry.contains(choice.value.country) {
-                    userChoices[choice.key] = choice.value
-                }
-            } else {
-                fatalError("Couldn't get a random value from data")
-            }
-        }
-        
-        // Get question asked (correct answer)
-        let userChoicesCountry = userChoices.map { $0.value.country }
-        let correctAnswer = data.first(where: {
-            !userChoices.keys.contains($0.key) &&           // Avoid duplicated cities
-            !dataAsked.keys.contains($0.key) &&             // Avoid cities already asked
-            !userChoicesCountry.contains($0.value.country)  // Avoid duplicated country names in userChoices
-        })
-        
-        // Unwrap optional
-        if let correctAnswer = correctAnswer {
-            userChoices[correctAnswer.key] = correctAnswer.value
-            dataAsked[correctAnswer.key] = correctAnswer.value
-            self.correctAnswer = correctAnswer
-        } else {
-            fatalError("Couldn't unwrap optional value")
-        }
-        
-        self.userChoices = userChoices
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/CityGameClass.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,104 @@
+//
+//  CityGameClass.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 29/9/22.
+//
+
+import Foundation
+import AVFAudio
+
+class CityGame: Game, ObservableObject {
+    
+    // Define type of generics
+    typealias T = CityData.City
+    
+    var data: [String: T]
+    var dataAsked = [String: T]()
+    
+    // Data
+    @Published var correctAnswer = (
+        key: String(),
+        value: T(country: String(), lat: Double(), lon: Double())
+    )
+    
+    // User
+    @Published var userChoices = [String: T]()
+    @Published var userScore = 0
+    @Published var userLives = 3
+    @Published var correctAnswers = [String: T]()
+    @Published var wrongAnswers = [String: T]()
+    
+    // Alerts
+    @Published var alertTitle = String()
+    @Published var alertMessage = String()
+    @Published var showingGameOverAlert = false
+    @Published var showingEndGameAlert = false
+    @Published var showingWrongAnswerAlert = false
+    @Published var showingExitGameAlert = false
+    
+    // Animations
+    @Published var scoreScaleAmount = 1.0
+    @Published var livesScaleAmount = 1.0
+    
+    // Sound effects
+    @Published var player: AVAudioPlayer?
+    
+    init() {
+        let data: CityData = load("cities.json")
+        self.data = data.cities
+        
+        let user = User()
+        userLives = user.settings.numberOfLives
+        
+        if let userSettings = UserDefaults.standard.data(forKey: "UserSettings") {
+            if let decodedUserSettings = try? JSONDecoder().decode(UserSettings.self, from: userSettings) {
+                userLives = decodedUserSettings.numberOfLives
+            }
+        }
+        
+        askQuestion {
+            selector()
+        }
+    }
+}
+
+extension CityGame {
+    func selector() {
+        
+        // Get random choices
+        var userChoices = [String: T]()
+        
+        while userChoices.count < 2 {
+            if let choice = data.randomElement() {
+                let userChoicesCountry = userChoices.map { $0.value.country }
+                
+                if !userChoicesCountry.contains(choice.value.country) {
+                    userChoices[choice.key] = choice.value
+                }
+            } else {
+                fatalError("Couldn't get a random value from data")
+            }
+        }
+        
+        // Get question asked (correct answer)
+        let userChoicesCountry = userChoices.map { $0.value.country }
+        let correctAnswer = data.first(where: {
+            !userChoices.keys.contains($0.key) &&           // Avoid duplicated cities
+            !dataAsked.keys.contains($0.key) &&             // Avoid cities already asked
+            !userChoicesCountry.contains($0.value.country)  // Avoid duplicated country names in userChoices
+        })
+        
+        // Unwrap optional
+        if let correctAnswer = correctAnswer {
+            userChoices[correctAnswer.key] = correctAnswer.value
+            dataAsked[correctAnswer.key] = correctAnswer.value
+            self.correctAnswer = correctAnswer
+        } else {
+            fatalError("Couldn't unwrap optional value")
+        }
+        
+        self.userChoices = userChoices
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/CityModel.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,22 @@
+//
+//  CityModel.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 29/9/22.
+//
+
+import Foundation
+
+struct CityData: Codable {
+    let cities: [String: City]
+    
+    struct City: Codable, Equatable {
+        let country: String
+        let lat: Double
+        let lon: Double
+        
+        static func ==(lhs: City, rhs: City) -> Bool {
+            lhs.country == rhs.country
+        }
+    }
+}
--- a/GeoQuiz/Logic/CountryGame.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-//
-//  CountryGame.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 20/9/22.
-//
-
-import Foundation
-import AVFAudio
-
-class CountryGame: Game, ObservableObject {
-    
-    // Define type of generics
-    typealias T = CountryModel.CountryData
-    
-    var data: [String: T]
-    var dataAsked = [String: T]()
-    
-    // Data
-    @Published var correctAnswer = (
-        key: String(),
-        value: T(flag: String(), currency: String(), population: Int(), capital: String())
-    )
-    
-    // User
-    @Published var userChoices = [String: T]()
-    @Published var userScore = 0
-    @Published var userLives = 3
-    @Published var correctAnswers = [String: T]()
-    @Published var wrongAnswers = [String: T]()
-    
-    // Alerts
-    @Published var alertTitle = String()
-    @Published var alertMessage = String()
-    @Published var showingGameOverAlert = false
-    @Published var showingEndGameAlert = false
-    @Published var showingWrongAnswerAlert = false
-    @Published var showingExitGameAlert = false
-    
-    // Animations
-    @Published var scoreScaleAmount = 1.0
-    @Published var livesScaleAmount = 1.0
-    
-    // Sound effects
-    @Published var player: AVAudioPlayer?
-    
-    init() {
-        let data: CountryModel = load("countries.json")
-        self.data = data.countries
-        
-        if let userSettings = UserDefaults.standard.data(forKey: "UserSettings") {
-            if let decodedUserSettings = try? JSONDecoder().decode(UserSettingsModel.self, from: userSettings) {
-                userLives = decodedUserSettings.numberOfLives
-            }
-        }
-        
-        askQuestion {
-            selector()
-        }
-    }
-}
-
-extension CountryGame {
-    func selector() {
-        
-        // Get random choices
-        var userChoices = [String: T]()
-        
-        while userChoices.count < 2 {
-            if let choice = data.randomElement() {
-                userChoices[choice.key] = choice.value
-            } else {
-                fatalError("Couldn't get a random value from data")
-            }
-        }
-        
-        // Get question asked (correct answer)
-        let correctAnswer = data.first(where: {
-            !userChoices.keys.contains($0.key) &&  // Avoid duplicated countries
-            !dataAsked.keys.contains($0.key)       // Avoid countries already asked
-        })
-        
-        // Unwrap optional
-        if let correctAnswer = correctAnswer {
-            userChoices[correctAnswer.key] = correctAnswer.value
-            dataAsked[correctAnswer.key] = correctAnswer.value
-            self.correctAnswer = correctAnswer
-        } else {
-            fatalError("Couldn't unwrap optional value")
-        }
-        
-        self.userChoices = userChoices
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/CountryGameClass.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,97 @@
+//
+//  CountryGameClass.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 20/9/22.
+//
+
+import Foundation
+import AVFAudio
+
+class CountryGame: Game, ObservableObject {
+    
+    // Define type of generics
+    typealias T = CountryData.Country
+    
+    var data: [String: T]
+    var dataAsked = [String: T]()
+    
+    // Data
+    @Published var correctAnswer = (
+        key: String(),
+        value: T(flag: String(), currency: String(), population: Int(), capital: String())
+    )
+    
+    // User
+    @Published var userChoices = [String: T]()
+    @Published var userScore = 0
+    @Published var userLives = 3
+    @Published var correctAnswers = [String: T]()
+    @Published var wrongAnswers = [String: T]()
+    
+    // Alerts
+    @Published var alertTitle = String()
+    @Published var alertMessage = String()
+    @Published var showingGameOverAlert = false
+    @Published var showingEndGameAlert = false
+    @Published var showingWrongAnswerAlert = false
+    @Published var showingExitGameAlert = false
+    
+    // Animations
+    @Published var scoreScaleAmount = 1.0
+    @Published var livesScaleAmount = 1.0
+    
+    // Sound effects
+    @Published var player: AVAudioPlayer?
+    
+    init() {
+        let data: CountryData = load("countries.json")
+        self.data = data.countries
+        
+        let user = User()
+        userLives = user.settings.numberOfLives
+        
+        if let userSettings = UserDefaults.standard.data(forKey: "UserSettings") {
+            if let decodedUserSettings = try? JSONDecoder().decode(UserSettings.self, from: userSettings) {
+                userLives = decodedUserSettings.numberOfLives
+            }
+        }
+        
+        askQuestion {
+            selector()
+        }
+    }
+}
+
+extension CountryGame {
+    func selector() {
+        
+        // Get random choices
+        var userChoices = [String: T]()
+        
+        while userChoices.count < 2 {
+            if let choice = data.randomElement() {
+                userChoices[choice.key] = choice.value
+            } else {
+                fatalError("Couldn't get a random value from data")
+            }
+        }
+        
+        // Get question asked (correct answer)
+        let correctAnswer = data.first(where: {
+            !userChoices.keys.contains($0.key) &&  // Avoid duplicated countries
+            !dataAsked.keys.contains($0.key)       // Avoid countries already asked
+        })
+        
+        // Unwrap optional
+        if let correctAnswer = correctAnswer {
+            userChoices[correctAnswer.key] = correctAnswer.value
+            dataAsked[correctAnswer.key] = correctAnswer.value
+            self.correctAnswer = correctAnswer
+        } else {
+            fatalError("Couldn't unwrap optional value")
+        }
+        
+        self.userChoices = userChoices
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/CountryModel.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,26 @@
+//
+//  CountryModel.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 29/9/22.
+//
+
+import Foundation
+
+struct CountryData: Codable {
+    let countries: [String: Country]
+    
+    struct Country: Codable, Equatable, Hashable {
+        let flag: String
+        let currency: String
+        let population: Int
+        let capital: String
+        
+        static func ==(lhs: Country, rhs: Country) -> Bool {
+            lhs.flag == rhs.flag &&
+            lhs.currency == rhs.currency &&
+            lhs.population == rhs.population &&
+            lhs.capital == rhs.capital
+        }
+    }
+}
--- a/GeoQuiz/Logic/Game.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-//
-//  GameProtocol.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 18/9/22.
-//
-
-import Foundation
-import SwiftUI
-import AVFAudio
-
-protocol Game: ObservableObject {
-    
-    // Define generic type
-    associatedtype T: Equatable
-    
-    // Game
-    var data: [String: T] { get set}
-    var dataAsked: [String: T] { get set }
-    var correctAnswer: (key: String, value: T) { get set }
-    
-    // User
-    var userChoices: [String: T] { get set }
-    var userScore: Int { get set }
-    var userLives: Int { get set }
-    var correctAnswers: [String: T] { get set }
-    var wrongAnswers: [String: T] { get set }
-    
-    // Alerts
-    var alertTitle: String { get set }
-    var alertMessage: String { get set }
-    var showingGameOverAlert: Bool { get set }
-    var showingEndGameAlert: Bool { get set }
-    var showingWrongAnswerAlert: Bool { get set }
-    var showingExitGameAlert: Bool { get set }
-    
-    // Animations
-    var scoreScaleAmount: Double { get set }
-    var livesScaleAmount: Double { get set }
-    
-    // Sound effects
-    var player: AVAudioPlayer? { get set }
-    
-    func selector()
-}
-
-extension Game {
-    var questionCounter: Int {
-       dataAsked.count
-    }
-    
-    func askQuestion(selector: () -> Void) {
-        guard questionCounter < data.count else {
-            alertTitle = "⭐️ Congratulations ⭐️"
-            alertMessage = "You completed the game."
-            showingEndGameAlert = true
-            
-            return
-        }
-        
-        selector()
-    }
-    
-    func answer(_ choice: (key: String, value: T), selector: () -> Void) {
-        var haptics = Haptics()
-        
-        if correctAnswer == choice {
-            haptics.success()
-            playSound("correctAnswer")
-            
-            withAnimation(.easeIn(duration: 0.5)) {
-                scoreScaleAmount += 1
-                userScore += 1
-            }
-            
-            correctAnswers[correctAnswer.key] = correctAnswer.value
-            askQuestion {
-                selector()
-            }
-        } else {
-            haptics.error()
-            playSound("wrongAnswer")
-
-            withAnimation(.easeIn(duration: 0.5)) {
-                livesScaleAmount += 1
-                userLives -= 1
-            }
-            
-            wrongAnswers[choice.key] = choice.value
-            
-            if userLives == 0 {
-                alertTitle = "🤕 Game over 🤕"
-                alertMessage = "Get up and try again."
-                showingGameOverAlert = true
-            } else {
-                alertTitle = "🔴 Wrong 🔴"
-                alertMessage = "You have \(userLives) lives left."
-                showingWrongAnswerAlert = true
-            }
-        }
-        
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in
-            withAnimation(.easeIn(duration: 0.5)) {
-                scoreScaleAmount = 1
-                livesScaleAmount = 1
-            }
-        }
-    }
-    
-    func reset(selector: () -> Void) {
-        dataAsked = [String: T]()
-        userScore = 0
-        userLives = 3
-        correctAnswers = [String: T]()
-        wrongAnswers = [String: T]()
-        askQuestion {
-            selector()
-        }
-    }
-    
-    private func playSound(_ filename: String) {
-        let user = User()
-        
-        if user.settings.sound {
-            guard let soundFileURL = Bundle.main.url(forResource: filename, withExtension: "wav") else {
-                fatalError("Sound file \(filename) couldn't be found")
-            }
-            
-            do {
-                try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
-                try AVAudioSession.sharedInstance().setActive(true)
-            } catch {
-                fatalError("Couldn't activate session")
-            }
-            
-            do {
-                player = try AVAudioPlayer(contentsOf: soundFileURL)
-                player?.play()
-            } catch {
-                fatalError("Couldn't play sound effect")
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/GameProtocol+Extension.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,144 @@
+//
+//  GameProtocol+Extension.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 18/9/22.
+//
+
+import Foundation
+import SwiftUI
+import AVFAudio
+
+protocol Game: ObservableObject {
+    
+    // Define generic type
+    associatedtype T: Equatable
+    
+    // Game
+    var data: [String: T] { get set}
+    var dataAsked: [String: T] { get set }
+    var correctAnswer: (key: String, value: T) { get set }
+    
+    // User
+    var userChoices: [String: T] { get set }
+    var userScore: Int { get set }
+    var userLives: Int { get set }
+    var correctAnswers: [String: T] { get set }
+    var wrongAnswers: [String: T] { get set }
+    
+    // Alerts
+    var alertTitle: String { get set }
+    var alertMessage: String { get set }
+    var showingGameOverAlert: Bool { get set }
+    var showingEndGameAlert: Bool { get set }
+    var showingWrongAnswerAlert: Bool { get set }
+    var showingExitGameAlert: Bool { get set }
+    
+    // Animations
+    var scoreScaleAmount: Double { get set }
+    var livesScaleAmount: Double { get set }
+    
+    // Sound effects
+    var player: AVAudioPlayer? { get set }
+    
+    func selector()
+}
+
+extension Game {
+    var questionCounter: Int {
+       dataAsked.count
+    }
+    
+    func askQuestion(selector: () -> Void) {
+        guard questionCounter < data.count else {
+            alertTitle = "⭐️ Congratulations ⭐️"
+            alertMessage = "You completed the game."
+            showingEndGameAlert = true
+            
+            return
+        }
+        
+        selector()
+    }
+    
+    func answer(_ choice: (key: String, value: T), selector: () -> Void) {
+        let haptics = Haptics()
+        
+        if correctAnswer == choice {
+            haptics.success()
+            playSound("correctAnswer")
+            
+            withAnimation(.easeIn(duration: 0.5)) {
+                scoreScaleAmount += 1
+                userScore += 1
+            }
+            
+            correctAnswers[correctAnswer.key] = correctAnswer.value
+            askQuestion {
+                selector()
+            }
+        } else {
+            haptics.error()
+            playSound("wrongAnswer")
+
+            withAnimation(.easeIn(duration: 0.5)) {
+                livesScaleAmount += 1
+                userLives -= 1
+            }
+            
+            wrongAnswers[choice.key] = choice.value
+            
+            if userLives == 0 {
+                alertTitle = "🤕 Game over 🤕"
+                alertMessage = "Get up and try again."
+                showingGameOverAlert = true
+            } else {
+                alertTitle = "🔴 Wrong 🔴"
+                alertMessage = "You have \(userLives) lives left."
+                showingWrongAnswerAlert = true
+            }
+        }
+        
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in
+            withAnimation(.easeIn(duration: 0.5)) {
+                scoreScaleAmount = 1
+                livesScaleAmount = 1
+            }
+        }
+    }
+    
+    func reset(selector: () -> Void) {
+        dataAsked = [String: T]()
+        userScore = 0
+        userLives = 3
+        correctAnswers = [String: T]()
+        wrongAnswers = [String: T]()
+        askQuestion {
+            selector()
+        }
+    }
+    
+    private func playSound(_ filename: String) {
+        let user = User()
+        
+        if user.settings.sound {
+            guard let soundFileURL = Bundle.main.url(forResource: filename, withExtension: "wav") else {
+                fatalError("Sound file \(filename) couldn't be found")
+            }
+            
+            do {
+                try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
+                try AVAudioSession.sharedInstance().setActive(true)
+            } catch {
+                fatalError("Couldn't activate session")
+            }
+            
+            do {
+                player = try AVAudioPlayer(contentsOf: soundFileURL)
+                player?.play()
+            } catch {
+                fatalError("Couldn't play sound effect")
+            }
+        }
+    }
+}
--- a/GeoQuiz/Logic/Haptics.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-//
-//  Haptics.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 18/9/22.
-//
-
-import Foundation
-import SwiftUI
-
-class Haptics {
-    private var user = User()
-    
-    func success() {
-        if user.settings.haptics {
-            let generator = UINotificationFeedbackGenerator()
-            generator.notificationOccurred(.success)
-        }
-    }
-
-    func error() {
-        if user.settings.haptics {
-            let generator = UINotificationFeedbackGenerator()
-            generator.notificationOccurred(.error)
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/HapticsClass.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,27 @@
+//
+//  HapticsClass.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 18/9/22.
+//
+
+import Foundation
+import SwiftUI
+
+class Haptics {
+    private var user = User()
+    
+    func success() {
+        if user.settings.haptics {
+            let generator = UINotificationFeedbackGenerator()
+            generator.notificationOccurred(.success)
+        }
+    }
+
+    func error() {
+        if user.settings.haptics {
+            let generator = UINotificationFeedbackGenerator()
+            generator.notificationOccurred(.error)
+        }
+    }
+}
--- a/GeoQuiz/Logic/Load.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-//
-//  Load.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 7/9/22.
-//
-
-import Foundation
-
-func load<T: Decodable>(_ filename: String) -> T {
-    let data: Data
-
-    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
-    else {
-        fatalError("Couldn't find \(filename) in main bundle.")
-    }
-
-    do {
-        data = try Data(contentsOf: file)
-    } catch {
-        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
-    }
-
-    do {
-        let decoder = JSONDecoder()
-        return try decoder.decode(T.self, from: data)
-    } catch {
-        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/LoadFunc.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,30 @@
+//
+//  LoadFunc.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 7/9/22.
+//
+
+import Foundation
+
+func load<T: Decodable>(_ filename: String) -> T {
+    let data: Data
+
+    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
+    else {
+        fatalError("Couldn't find \(filename) in main bundle.")
+    }
+
+    do {
+        data = try Data(contentsOf: file)
+    } catch {
+        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
+    }
+
+    do {
+        let decoder = JSONDecoder()
+        return try decoder.decode(T.self, from: data)
+    } catch {
+        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
+    }
+}
--- a/GeoQuiz/Logic/User.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-//
-//  User.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 7/10/22.
-//
-
-import Foundation
-
-class User: ObservableObject {
-    @Published var settings = UserSettingsModel() {
-        didSet {
-            if let userSettingsEncoded = try? JSONEncoder().encode(settings) {
-                UserDefaults.standard.set(userSettingsEncoded, forKey: "UserSettings")
-            }
-        }
-    }
-    
-    
-    init() {
-        if let userSettings = UserDefaults.standard.data(forKey: "UserSettings") {
-            if let decodedUserSettings = try? JSONDecoder().decode(UserSettingsModel.self, from: userSettings) {
-                settings = decodedUserSettings
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/UserClass.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,27 @@
+//
+//  UserClass.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 7/10/22.
+//
+
+import Foundation
+
+class User: ObservableObject {
+    @Published var settings = UserSettings() {
+        didSet {
+            if let userSettingsEncoded = try? JSONEncoder().encode(settings) {
+                UserDefaults.standard.set(userSettingsEncoded, forKey: "UserSettings")
+            }
+        }
+    }
+    
+    
+    init() {
+        if let userSettings = UserDefaults.standard.data(forKey: "UserSettings") {
+            if let decodedUserSettings = try? JSONDecoder().decode(UserSettings.self, from: userSettings) {
+                settings = decodedUserSettings
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/UserSettingsModel.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -0,0 +1,14 @@
+//
+//  UserSettingsModel.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 7/10/22.
+//
+
+import Foundation
+
+struct UserSettings: Codable {
+    var haptics: Bool = true
+    var sound: Bool = true
+    var numberOfLives: Int = 25
+}
--- a/GeoQuiz/Models/CityModel.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-//
-//  CityModel.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 29/9/22.
-//
-
-import Foundation
-
-struct CityModel: Codable {
-    let cities: [String: CityData]
-    
-    struct CityData: Codable, Equatable {
-        let country: String
-        let lat: Double
-        let lon: Double
-        
-        static func ==(lhs: CityData, rhs: CityData) -> Bool {
-            lhs.country == rhs.country
-        }
-    }
-}
--- a/GeoQuiz/Models/CountryModel.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-//
-//  CountryModel.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 29/9/22.
-//
-
-import Foundation
-
-struct CountryModel: Codable {
-    let countries: [String: CountryData]
-    
-    struct CountryData: Codable, Equatable, Hashable {
-        let flag: String
-        let currency: String
-        let population: Int
-        let capital: String
-        
-        static func ==(lhs: CountryData, rhs: CountryData) -> Bool {
-            lhs.flag == rhs.flag &&
-            lhs.currency == rhs.currency &&
-            lhs.population == rhs.population &&
-            lhs.capital == rhs.capital
-        }
-    }
-}
--- a/GeoQuiz/Models/UserSettingsModel.swift	Fri Oct 07 18:50:38 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-//
-//  UserSettingsModel.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 7/10/22.
-//
-
-import Foundation
-
-struct UserSettingsModel: Codable {
-    var haptics: Bool = true
-    var sound: Bool = true
-    var numberOfLives: Int = 3
-}
--- a/GeoQuiz/SettingsModalView.swift	Fri Oct 07 18:50:38 2022 +0200
+++ b/GeoQuiz/SettingsModalView.swift	Sat Oct 08 21:36:40 2022 +0200
@@ -10,19 +10,30 @@
 struct SettingsModalView: View {
     @Environment(\.dismiss) var dismiss
     @StateObject var user = User()
+
+    var lives: [Int] {
+        var lives = [Int]()
+        for i in stride(from: 5, to: 55, by: 5) {
+            lives.append(i)
+        }
+        
+        return lives
+    }
     
     var body: some View {
         NavigationView {
             Form {
                 Section {
-                    Picker("Number of lives", selection: $user.settings.numberOfLives) {
-                        ForEach(1..<11) { numberOfLives in
+                    Picker("❤️ Lives", selection: $user.settings.numberOfLives) {
+                        ForEach(lives, id: \.self) { numberOfLives in
                             Text("\(numberOfLives)")
                                 .tag(numberOfLives)
                         }
                     }
                 } header: {
                     Text("Game")
+                } footer: {
+                    Text("Number of lives at the beginning of each game.")
                 }
                 
                 Section {