changeset 27:3f4b366d476d

add flag layout settings
author Dennis C. M. <dennis@denniscm.com>
date Thu, 10 Nov 2022 09:26:48 +0100
parents 425078c01194
children f51b70c2cccc
files GeoQuiz.xcodeproj/project.pbxproj GeoQuiz/Assets.xcassets/LaunchScreenLogo.imageset/Contents.json GeoQuiz/Assets.xcassets/LaunchScreenLogo.imageset/LaunchScreenLogo.png GeoQuiz/ContentView.swift GeoQuiz/GuessTheCapitalView.swift GeoQuiz/GuessTheCountryView.swift GeoQuiz/GuessTheFlagView-ViewModel.swift GeoQuiz/GuessTheFlagView.swift GeoQuiz/GuessThePopulationView.swift GeoQuiz/Helpers/FormLink.swift GeoQuiz/Helpers/SettingsRow.swift GeoQuiz/LaunchScreen.storyboard GeoQuiz/Models/Controllers/GameProtocol+Extension.swift GeoQuiz/Models/Controllers/GameViewProtocol+Extension.swift GeoQuiz/Models/UserDataModel.swift GeoQuiz/SettingsModalView-ViewModel.swift GeoQuiz/SettingsModalView.swift
diffstat 17 files changed, 258 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/GeoQuiz.xcodeproj/project.pbxproj	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz.xcodeproj/project.pbxproj	Thu Nov 10 09:26:48 2022 +0100
@@ -249,7 +249,7 @@
 		957822482918F445005F2D50 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 957822472918F445005F2D50 /* Extensions.swift */; };
 		9590359528E098FF00B24560 /* ProfileModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9590359428E098FF00B24560 /* ProfileModalView.swift */; };
 		95919DB628F076BF00F21F8F /* UserController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95919DB528F076BF00F21F8F /* UserController.swift */; };
-		95919DBC28F08D0600F21F8F /* FormLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95919DBB28F08D0600F21F8F /* FormLink.swift */; };
+		95919DBC28F08D0600F21F8F /* SettingsRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95919DBB28F08D0600F21F8F /* SettingsRow.swift */; };
 		95A4F42929040E350018DFAC /* CoreDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A4F42829040E350018DFAC /* CoreDataController.swift */; };
 		95A4F42B29043DC00018DFAC /* UserImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A4F42A29043DC00018DFAC /* UserImage.swift */; };
 		95AF322A28DF293900023ACC /* GuessTheCountryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AF322928DF293900023ACC /* GuessTheCountryView.swift */; };
@@ -265,6 +265,10 @@
 		95C6459B28FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C6459928FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift */; };
 		95C6459D290003E1000CD570 /* RecentGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C6459C290003E1000CD570 /* RecentGame.swift */; };
 		95CA295028F6BB4500CE0B7A /* ActivityAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CA294F28F6BB4500CE0B7A /* ActivityAlert.swift */; };
+		95D8BF32291BAF8C006FC606 /* SettingsModalView-ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D8BF31291BAF8C006FC606 /* SettingsModalView-ViewModel.swift */; };
+		95D8BF36291BB1F7006FC606 /* GameViewProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D8BF35291BB1F7006FC606 /* GameViewProtocol+Extension.swift */; };
+		95D8BF38291BBB3D006FC606 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 95D8BF37291BBB3D006FC606 /* LaunchScreen.storyboard */; };
+		95D8BF3A291BC5DA006FC606 /* GuessTheFlagView-ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D8BF39291BC5DA006FC606 /* GuessTheFlagView-ViewModel.swift */; };
 		95DB7C01290492FC007D01D8 /* GameInfoModel+Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95DB7C00290492FC007D01D8 /* GameInfoModel+Protocol.swift */; };
 		95DB7C032904A968007D01D8 /* MapController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95DB7C022904A968007D01D8 /* MapController.swift */; };
 		95FA409A28D9876B00129B60 /* GuessTheFlagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FA409928D9876B00129B60 /* GuessTheFlagView.swift */; };
@@ -515,7 +519,7 @@
 		957822472918F445005F2D50 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
 		9590359428E098FF00B24560 /* ProfileModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileModalView.swift; sourceTree = "<group>"; };
 		95919DB528F076BF00F21F8F /* UserController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserController.swift; sourceTree = "<group>"; };
-		95919DBB28F08D0600F21F8F /* FormLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLink.swift; sourceTree = "<group>"; };
+		95919DBB28F08D0600F21F8F /* SettingsRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRow.swift; sourceTree = "<group>"; };
 		95A4F42829040E350018DFAC /* CoreDataController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataController.swift; sourceTree = "<group>"; };
 		95A4F42A29043DC00018DFAC /* UserImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserImage.swift; sourceTree = "<group>"; };
 		95AF322928DF293900023ACC /* GuessTheCountryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuessTheCountryView.swift; sourceTree = "<group>"; };
@@ -531,6 +535,10 @@
 		95C6459928FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PlayedGame+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		95C6459C290003E1000CD570 /* RecentGame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentGame.swift; sourceTree = "<group>"; };
 		95CA294F28F6BB4500CE0B7A /* ActivityAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityAlert.swift; sourceTree = "<group>"; };
+		95D8BF31291BAF8C006FC606 /* SettingsModalView-ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SettingsModalView-ViewModel.swift"; sourceTree = "<group>"; };
+		95D8BF35291BB1F7006FC606 /* GameViewProtocol+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GameViewProtocol+Extension.swift"; sourceTree = "<group>"; };
+		95D8BF37291BBB3D006FC606 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
+		95D8BF39291BC5DA006FC606 /* GuessTheFlagView-ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GuessTheFlagView-ViewModel.swift"; sourceTree = "<group>"; };
 		95DB7C00290492FC007D01D8 /* GameInfoModel+Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GameInfoModel+Protocol.swift"; sourceTree = "<group>"; };
 		95DB7C022904A968007D01D8 /* MapController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapController.swift; sourceTree = "<group>"; };
 		95E6188428DDDB5C003359ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
@@ -818,14 +826,17 @@
 				95E6188428DDDB5C003359ED /* Info.plist */,
 				9539829628C51EDF00B70973 /* Assets.xcassets */,
 				95C6457528FFC934000CD570 /* GeoQuiz.xcdatamodeld */,
+				95D8BF37291BBB3D006FC606 /* LaunchScreen.storyboard */,
 				9539829228C51EDE00B70973 /* GeoQuizApp.swift */,
 				95C4315528C64A8C00212131 /* ContentView.swift */,
 				95FA409928D9876B00129B60 /* GuessTheFlagView.swift */,
+				95D8BF39291BC5DA006FC606 /* GuessTheFlagView-ViewModel.swift */,
 				951B630128D1A87C004F9877 /* GuessTheCapitalView.swift */,
 				95AF322928DF293900023ACC /* GuessTheCountryView.swift */,
 				9509A8E128E5A3D700CFCDBA /* GuessThePopulationView.swift */,
 				950C535228F2FA3300179C78 /* BuyPremiumModalView.swift */,
 				952E41EC28DC658900198643 /* SettingsModalView.swift */,
+				95D8BF31291BAF8C006FC606 /* SettingsModalView-ViewModel.swift */,
 				9590359428E098FF00B24560 /* ProfileModalView.swift */,
 				95C6457128FFC4DC000CD570 /* ProfileEditModalView.swift */,
 				957822462918EED3005F2D50 /* Helpers */,
@@ -865,7 +876,7 @@
 				95030CE928D1BA4D001AA3A1 /* AnswerButton.swift */,
 				955A658028D703EB00CEEC6D /* GameToolbar.swift */,
 				95BC392C28EC42570049AB49 /* CityMap.swift */,
-				95919DBB28F08D0600F21F8F /* FormLink.swift */,
+				95919DBB28F08D0600F21F8F /* SettingsRow.swift */,
 				95CA294F28F6BB4500CE0B7A /* ActivityAlert.swift */,
 				95C6456D28FE8C04000CD570 /* UserProfile.swift */,
 				95A4F42A29043DC00018DFAC /* UserImage.swift */,
@@ -880,6 +891,7 @@
 		959303AC2918F58F00E3E099 /* Controllers */ = {
 			isa = PBXGroup;
 			children = (
+				95D8BF35291BB1F7006FC606 /* GameViewProtocol+Extension.swift */,
 				955A658228D733E400CEEC6D /* GameProtocol+Extension.swift */,
 				95FA409B28D9881100129B60 /* CountryGameController.swift */,
 				951AFAF028E5735400A4A4BD /* CityGameController.swift */,
@@ -1020,6 +1032,7 @@
 				951DCE94291A424900BAE20C /* sl.png in Resources */,
 				951DCF46291A424A00BAE20C /* mg.png in Resources */,
 				951DCF62291A424A00BAE20C /* aw.png in Resources */,
+				95D8BF38291BBB3D006FC606 /* LaunchScreen.storyboard in Resources */,
 				951DCEBC291A424A00BAE20C /* do.png in Resources */,
 				951DCF1F291A424A00BAE20C /* cz.png in Resources */,
 				951DCF2C291A424A00BAE20C /* ph.png in Resources */,
@@ -1212,14 +1225,17 @@
 				9539829328C51EDE00B70973 /* GeoQuizApp.swift in Sources */,
 				95AF322A28DF293900023ACC /* GuessTheCountryView.swift in Sources */,
 				95DB7C032904A968007D01D8 /* MapController.swift in Sources */,
-				95919DBC28F08D0600F21F8F /* FormLink.swift in Sources */,
+				95919DBC28F08D0600F21F8F /* SettingsRow.swift in Sources */,
 				951AFAEF28E565FE00A4A4BD /* CountryModel.swift in Sources */,
 				95030CEA28D1BA4D001AA3A1 /* AnswerButton.swift in Sources */,
 				95FA409C28D9881100129B60 /* CountryGameController.swift in Sources */,
 				95CA295028F6BB4500CE0B7A /* ActivityAlert.swift in Sources */,
+				95D8BF32291BAF8C006FC606 /* SettingsModalView-ViewModel.swift in Sources */,
+				95D8BF3A291BC5DA006FC606 /* GuessTheFlagView-ViewModel.swift in Sources */,
 				955A658128D703EB00CEEC6D /* GameToolbar.swift in Sources */,
 				957822482918F445005F2D50 /* Extensions.swift in Sources */,
 				95C6457728FFC934000CD570 /* GeoQuiz.xcdatamodeld in Sources */,
+				95D8BF36291BB1F7006FC606 /* GameViewProtocol+Extension.swift in Sources */,
 				9590359528E098FF00B24560 /* ProfileModalView.swift in Sources */,
 				95C6456C28FE87E4000CD570 /* UserDataModel.swift in Sources */,
 				95C6459B28FFE5A3000CD570 /* PlayedGame+CoreDataProperties.swift in Sources */,
@@ -1366,6 +1382,7 @@
 				INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
 				INFOPLIST_KEY_UILaunchScreen_Generation = YES;
+				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen.storyboard;
 				INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
 				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
 				IPHONEOS_DEPLOYMENT_TARGET = 16.0;
@@ -1401,6 +1418,7 @@
 				INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
 				INFOPLIST_KEY_UILaunchScreen_Generation = YES;
+				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen.storyboard;
 				INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
 				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
 				IPHONEOS_DEPLOYMENT_TARGET = 16.0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Assets.xcassets/LaunchScreenLogo.imageset/Contents.json	Thu Nov 10 09:26:48 2022 +0100
@@ -0,0 +1,12 @@
+{
+  "images" : [
+    {
+      "filename" : "LaunchScreenLogo.png",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
Binary file GeoQuiz/Assets.xcassets/LaunchScreenLogo.imageset/LaunchScreenLogo.png has changed
--- a/GeoQuiz/ContentView.swift	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz/ContentView.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -56,7 +56,7 @@
                 .navigationDestination(for: GameType.self) { gameMode in
                     switch gameMode {
                     case .guessTheFlag:
-                        GuessTheFlagView()
+                        GuessTheFlagView(userController: userController)
                     case .guessTheCapital:
                         GuessTheCapitalView()
                     case .guessTheCountry:
--- a/GeoQuiz/GuessTheCapitalView.swift	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz/GuessTheCapitalView.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -7,7 +7,7 @@
 
 import SwiftUI
 
-struct GuessTheCapitalView: View {
+struct GuessTheCapitalView: View, GameView {
     @StateObject var gameController = CountryGameController()
     
     @Environment(\.managedObjectContext) var moc
@@ -35,8 +35,8 @@
                      Using `UIImage(contentsOfFile: path)` images aren't cached.
                      */
                     
-                    let flag = gameController.correctAnswer.value.flag
-                    let flagPath = Bundle.main.path(forResource: flag, ofType: "png")!
+                    let flagPath = getFlagPath(forName: gameController.correctAnswer.value.flag)
+                    
                     Image(uiImage: UIImage(contentsOfFile: flagPath)!)
                         .renderingMode(.original)
                         .resizable()
--- a/GeoQuiz/GuessTheCountryView.swift	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz/GuessTheCountryView.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -7,7 +7,7 @@
 
 import SwiftUI
 
-struct GuessTheCountryView: View {
+struct GuessTheCountryView: View, GameView {
     @StateObject var gameController = CityGameController()
     
     @Environment(\.managedObjectContext) var moc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/GuessTheFlagView-ViewModel.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -0,0 +1,54 @@
+//
+//  GuessTheFlagView-ViewModel.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 9/11/22.
+//
+
+import Foundation
+import SwiftUI
+
+extension GuessTheFlagView {
+    
+    class Layout {
+        
+        static func showFlag(in flagPath: String, geo: GeometryProxy, _ userController: UserController) -> some View {
+            switch userController.data.guessTheFlagShape {
+            case .respectAspectRatio:
+                return AnyView(
+                    RoundedRectangle(cornerRadius: 20)
+                        .foregroundColor(.white.opacity(0.5))
+                        .frame(width: geo.size.height * 0.3, height: geo.size.height * 0.15)
+                        .overlay(
+                            Image(uiImage: UIImage(contentsOfFile: flagPath)!)
+                                .resizable()
+                                .scaledToFit()
+                                .cornerRadius(20)
+                                .shadow(radius: 10)
+                                .padding()
+                        )
+                )
+            case .circular:
+                return AnyView(
+                    Image(uiImage: UIImage(contentsOfFile: flagPath)!)
+                        .renderingMode(.original)
+                        .resizable()
+                        .scaledToFit()
+                        .frame(height: geo.size.height * 0.16)
+                        .clipShape(Circle())
+                        .shadow(radius: 10)
+                )
+            case .rectangular:
+                return AnyView(
+                    Image(uiImage: UIImage(contentsOfFile: flagPath)!)
+                        .renderingMode(.original)
+                        .resizable()
+                        .scaledToFill()
+                        .frame(width: geo.size.height * 0.3, height: geo.size.height * 0.15)
+                        .clipShape(RoundedRectangle(cornerRadius: 20))
+                        .shadow(radius: 10)
+                )
+            }
+        }
+    }
+}
--- a/GeoQuiz/GuessTheFlagView.swift	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz/GuessTheFlagView.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -7,7 +7,9 @@
 
 import SwiftUI
 
-struct GuessTheFlagView: View {
+struct GuessTheFlagView: View, GameView {
+    @ObservedObject var userController: UserController
+    
     @StateObject var gameController = CountryGameController()
     
     @Environment(\.managedObjectContext) var moc
@@ -61,21 +63,9 @@
                                  THE SOLUTION:
                                  Using `UIImage(contentsOfFile: path)` images aren't cached.
                                  */
-                                
-                                let flag = gameController.data[countryName]!.flag
-                                let flagPath = Bundle.main.path(forResource: flag, ofType: "png")!
-                                
-                                RoundedRectangle(cornerRadius: 20)
-                                    .foregroundColor(.white.opacity(0.5))
-                                    .frame(width: geo.size.height * 0.3, height: geo.size.height * 0.15)
-                                    .overlay(
-                                        Image(uiImage: UIImage(contentsOfFile: flagPath)!)
-                                            .resizable()
-                                            .scaledToFit()
-                                            .cornerRadius(20)
-                                            .shadow(radius: 10)
-                                            .padding()
-                                    )
+                             
+                                let flagPath = getFlagPath(forName: gameController.data[countryName]!.flag)
+                                Layout.showFlag(in: flagPath, geo: geo, userController)
                             }
                         }
                     }
@@ -92,6 +82,6 @@
 
 struct GuessTheFlagView_Previews: PreviewProvider {
     static var previews: some View {
-        GuessTheFlagView()
+        GuessTheFlagView(userController: UserController())
     }
 }
--- a/GeoQuiz/GuessThePopulationView.swift	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz/GuessThePopulationView.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -7,7 +7,7 @@
 
 import SwiftUI
 
-struct GuessThePopulationView: View {
+struct GuessThePopulationView: View, GameView {
     @StateObject var gameController = CountryGameController()
     
     @Environment(\.managedObjectContext) var moc
@@ -35,8 +35,8 @@
                      Using `UIImage(contentsOfFile: path)` images aren't cached.
                      */
                     
-                    let flag = gameController.correctAnswer.value.flag
-                    let flagPath = Bundle.main.path(forResource: flag, ofType: "png")!
+                    let flagPath = getFlagPath(forName: gameController.correctAnswer.value.flag)
+                    
                     Image(uiImage: UIImage(contentsOfFile: flagPath)!)
                         .renderingMode(.original)
                         .resizable()
--- a/GeoQuiz/Helpers/FormLink.swift	Wed Nov 09 10:30:01 2022 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-//
-//  FormLink.swift
-//  GeoQuiz
-//
-//  Created by Dennis Concepción Martín on 7/10/22.
-//
-
-import SwiftUI
-
-struct FormLink: View {
-    var color: Color
-    var symbol: 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: symbol)
-                    .imageScale(.large)
-                    .foregroundColor(color)
-                
-                Text(text)
-                    .foregroundColor(.primary)
-            }
-        }
-    }
-}
-
-struct FormLink_Previews: PreviewProvider {
-    static var previews: some View {
-        FormLink(
-            color: .mayaBlue,
-            symbol: "info.circle.fill",
-            text: "About",
-            url: URL(string: "https://dennistech.io")!
-        )
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Helpers/SettingsRow.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -0,0 +1,45 @@
+//
+//  SettingsRow.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 7/10/22.
+//
+
+import SwiftUI
+
+struct SettingsRow: View {
+    var color: Color
+    var symbol: String
+    var text: String
+    var url: URL
+    
+    @Environment(\.openURL) var openURL
+    
+    var body: some View {
+        Link(destination: url) {
+            HStack(alignment: .center, spacing: 20) {
+                RoundedRectangle(cornerRadius: 5)
+                    .frame(width: 30, height: 30)
+                    .foregroundColor(color)
+                    .overlay(
+                        Image(systemName: symbol)
+                            .foregroundColor(.white)
+                    )
+                
+                Text(text)
+                    .foregroundColor(.primary)
+            }
+        }
+    }
+}
+
+struct SettingsRow_Previews: PreviewProvider {
+    static var previews: some View {
+        SettingsRow(
+            color: .mayaBlue,
+            symbol: "info",
+            text: "About",
+            url: URL(string: "https://dennistech.io")!
+        )
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/LaunchScreen.storyboard	Thu Nov 10 09:26:48 2022 +0100
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <device id="retina6_72" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="430" height="932"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="LaunchScreenLogo" translatesAutoresizingMaskIntoConstraints="NO" id="grE-pc-N9e">
+                                <rect key="frame" x="95" y="402" width="240" height="128"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
+                            </imageView>
+                        </subviews>
+                        <viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="51.627906976744185" y="374.03433476394855"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="LaunchScreenLogo" width="1024" height="1024"/>
+    </resources>
+</document>
--- a/GeoQuiz/Models/Controllers/GameProtocol+Extension.swift	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz/Models/Controllers/GameProtocol+Extension.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -140,7 +140,7 @@
             }
             
             do {
-                try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
+                try AVAudioSession.sharedInstance().setCategory(.ambient)
                 try AVAudioSession.sharedInstance().setActive(true)
             } catch {
                 fatalError("Couldn't activate session")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Models/Controllers/GameViewProtocol+Extension.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -0,0 +1,19 @@
+//
+//  GameViewProtocol+Extension.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 9/11/22.
+//
+
+import Foundation
+
+protocol GameView {
+
+}
+
+extension GameView {
+    func getFlagPath(forName flagName: String) -> String {
+        return Bundle.main.path(forResource: flagName, ofType: "png")!
+    }
+    
+}
--- a/GeoQuiz/Models/UserDataModel.swift	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz/Models/UserDataModel.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -14,6 +14,7 @@
     var haptics: Bool = true
     var sound: Bool = true
     var numberOfLives: Int = 25
+    var guessTheFlagShape: GuessTheFlagShape = .respectAspectRatio
     
     // Profile
     var username: String = "Unnamed"
@@ -24,3 +25,11 @@
         return UIImage(data: imageData)
     }
 }
+
+enum GuessTheFlagShape: String, Codable, CaseIterable {
+    case respectAspectRatio = "Original"
+    case circular = "Circular"
+    case rectangular = "Rectangular"
+    
+    var localizedName: LocalizedStringKey { LocalizedStringKey(rawValue) }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/SettingsModalView-ViewModel.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -0,0 +1,14 @@
+//
+//  SettingsModalView-ViewModel.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 9/11/22.
+//
+
+import Foundation
+
+extension SettingsModalView {
+    func getVersion() -> String? {
+        return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
+    }
+}
--- a/GeoQuiz/SettingsModalView.swift	Wed Nov 09 10:30:01 2022 +0100
+++ b/GeoQuiz/SettingsModalView.swift	Thu Nov 10 09:26:48 2022 +0100
@@ -32,12 +32,23 @@
                         }
                     }
                 } header: {
-                    Text("Game")
+                    Text("General")
                 } footer: {
                     Text("Number of lives at the beginning of each game.")
                 }
                 
                 Section {
+                    Picker("Flag shape", selection: $userController.data.guessTheFlagShape) {
+                        ForEach(GuessTheFlagShape.allCases, id: \.self) { shape in
+                            Text(shape.localizedName)
+                                .tag(shape)
+                        }
+                    }
+                } header: {
+                    Text("Guess the flag game")
+                }
+                
+                Section {
                     Toggle("Haptics", isOn: $userController.data.haptics)
                     Toggle("Sound effects", isOn: $userController.data.sound)
                 } header: {
@@ -45,28 +56,42 @@
                 }
                 
                 Section {
-                    FormLink(
+                    SettingsRow(
                         color: .mayaBlue,
-                        symbol: "info.circle.fill",
+                        symbol: "person.fill",
                         text: "About",
                         url: URL(string: "https://dennistech.io")!
                     )
                     
-                    FormLink(
+                    SettingsRow(
                         color: .atomicTangerine,
-                        symbol: "ant.circle.fill",
+                        symbol: "ant.fill",
                         text: "Report bugs",
                         url: URL(string: "mailto:dmartin@dennistech.io")!
                     )
                     
-                    FormLink(
+                    SettingsRow(
                         color: .blueBell,
-                        symbol: "message.circle.fill",
+                        symbol: "message.fill",
                         text: "Twitter",
                         url: URL(string: "https://twitter.com/dennistech_")!
                     )
                 } header: {
                     Text("Get in touch")
+                } footer: {
+                    HStack {
+                        Spacer()
+                        VStack {
+                            Text("© 2022 Dennis Technologies Ltd.")
+                            Text("Proud to be indie.")
+                            
+                            if let versionNumber = getVersion() {
+                                Text("Version \(versionNumber)")
+                            }
+                        }
+                        Spacer()
+                    }
+                    .padding(.top)
                 }
             }
             .navigationTitle("Settings")