diff --git a/Swift Code Challenge.xcodeproj/project.pbxproj b/Swift Code Challenge.xcodeproj/project.pbxproj index 6663a69..99277be 100644 --- a/Swift Code Challenge.xcodeproj/project.pbxproj +++ b/Swift Code Challenge.xcodeproj/project.pbxproj @@ -14,6 +14,15 @@ 1E05E8E02868F16400B12456 /* Swift_Code_ChallengeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E05E8DF2868F16400B12456 /* Swift_Code_ChallengeTests.swift */; }; 1E05E8EA2868F16400B12456 /* Swift_Code_ChallengeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E05E8E92868F16400B12456 /* Swift_Code_ChallengeUITests.swift */; }; 1E05E8EC2868F16400B12456 /* Swift_Code_ChallengeUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E05E8EB2868F16400B12456 /* Swift_Code_ChallengeUITestsLaunchTests.swift */; }; + 384EB99B286D00F200A2FE3C /* UsersListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384EB99A286D00F200A2FE3C /* UsersListView.swift */; }; + 384EB99F286DC53A00A2FE3C /* UserDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384EB99E286DC53A00A2FE3C /* UserDetailsView.swift */; }; + 384EB9A1286DC56E00A2FE3C /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384EB9A0286DC56E00A2FE3C /* MapView.swift */; }; + 384EB9A4286DC5BC00A2FE3C /* VisualEffectsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384EB9A3286DC5BC00A2FE3C /* VisualEffectsView.swift */; }; + 384EB9A6286DC5EB00A2FE3C /* CircleImageComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384EB9A5286DC5EB00A2FE3C /* CircleImageComponent.swift */; }; + 388650AE286CEF6E009A16EA /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388650AD286CEF6E009A16EA /* UserModel.swift */; }; + 3889CF77286E2EC00047D955 /* ApiRequestAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3889CF76286E2EC00047D955 /* ApiRequestAsync.swift */; }; + 3889CF79286E2FE80047D955 /* UsersListViewModelAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3889CF78286E2FE80047D955 /* UsersListViewModelAsync.swift */; }; + 3889CF7B286E31BA0047D955 /* TestAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3889CF7A286E31BA0047D955 /* TestAsync.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -45,6 +54,16 @@ 1E05E8E92868F16400B12456 /* Swift_Code_ChallengeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Swift_Code_ChallengeUITests.swift; sourceTree = ""; }; 1E05E8EB2868F16400B12456 /* Swift_Code_ChallengeUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Swift_Code_ChallengeUITestsLaunchTests.swift; sourceTree = ""; }; 1E05E8F82868F24600B12456 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 384EB99A286D00F200A2FE3C /* UsersListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersListView.swift; sourceTree = ""; }; + 384EB99E286DC53A00A2FE3C /* UserDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsView.swift; sourceTree = ""; }; + 384EB9A0286DC56E00A2FE3C /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = ""; }; + 384EB9A3286DC5BC00A2FE3C /* VisualEffectsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisualEffectsView.swift; sourceTree = ""; }; + 384EB9A5286DC5EB00A2FE3C /* CircleImageComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleImageComponent.swift; sourceTree = ""; }; + 384EB9A7286DCA4C00A2FE3C /* Swift-Code-Challenge-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Swift-Code-Challenge-Info.plist"; sourceTree = SOURCE_ROOT; }; + 388650AD286CEF6E009A16EA /* UserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; + 3889CF76286E2EC00047D955 /* ApiRequestAsync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiRequestAsync.swift; sourceTree = ""; }; + 3889CF78286E2FE80047D955 /* UsersListViewModelAsync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersListViewModelAsync.swift; sourceTree = ""; }; + 3889CF7A286E31BA0047D955 /* TestAsync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAsync.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -96,6 +115,11 @@ 1E05E8CD2868F16300B12456 /* Swift Code Challenge */ = { isa = PBXGroup; children = ( + 384EB9A7286DCA4C00A2FE3C /* Swift-Code-Challenge-Info.plist */, + 388650B2286CEF96009A16EA /* Services */, + 388650B1286CEF8F009A16EA /* ViewModels */, + 388650B0286CEF89009A16EA /* Views */, + 388650AF286CEF83009A16EA /* Models */, 1E05E8CE2868F16300B12456 /* Swift_Code_ChallengeApp.swift */, 1E05E8D02868F16300B12456 /* ContentView.swift */, 1E05E8D22868F16400B12456 /* Assets.xcassets */, @@ -129,6 +153,51 @@ path = "Swift Code ChallengeUITests"; sourceTree = ""; }; + 384EB9A2286DC59B00A2FE3C /* Components */ = { + isa = PBXGroup; + children = ( + 384EB9A5286DC5EB00A2FE3C /* CircleImageComponent.swift */, + ); + path = Components; + sourceTree = ""; + }; + 388650AF286CEF83009A16EA /* Models */ = { + isa = PBXGroup; + children = ( + 388650AD286CEF6E009A16EA /* UserModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + 388650B0286CEF89009A16EA /* Views */ = { + isa = PBXGroup; + children = ( + 384EB9A2286DC59B00A2FE3C /* Components */, + 384EB99A286D00F200A2FE3C /* UsersListView.swift */, + 384EB99E286DC53A00A2FE3C /* UserDetailsView.swift */, + 384EB9A0286DC56E00A2FE3C /* MapView.swift */, + 384EB9A3286DC5BC00A2FE3C /* VisualEffectsView.swift */, + 3889CF7A286E31BA0047D955 /* TestAsync.swift */, + ); + path = Views; + sourceTree = ""; + }; + 388650B1286CEF8F009A16EA /* ViewModels */ = { + isa = PBXGroup; + children = ( + 3889CF78286E2FE80047D955 /* UsersListViewModelAsync.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; + 388650B2286CEF96009A16EA /* Services */ = { + isa = PBXGroup; + children = ( + 3889CF76286E2EC00047D955 /* ApiRequestAsync.swift */, + ); + path = Services; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -259,7 +328,16 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 384EB9A4286DC5BC00A2FE3C /* VisualEffectsView.swift in Sources */, + 384EB99F286DC53A00A2FE3C /* UserDetailsView.swift in Sources */, + 384EB9A1286DC56E00A2FE3C /* MapView.swift in Sources */, + 384EB9A6286DC5EB00A2FE3C /* CircleImageComponent.swift in Sources */, 1E05E8D12868F16300B12456 /* ContentView.swift in Sources */, + 3889CF77286E2EC00047D955 /* ApiRequestAsync.swift in Sources */, + 388650AE286CEF6E009A16EA /* UserModel.swift in Sources */, + 3889CF79286E2FE80047D955 /* UsersListViewModelAsync.swift in Sources */, + 384EB99B286D00F200A2FE3C /* UsersListView.swift in Sources */, + 3889CF7B286E31BA0047D955 /* TestAsync.swift in Sources */, 1E05E8CF2868F16300B12456 /* Swift_Code_ChallengeApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -419,12 +497,12 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Swift Code Challenge/Preview Content\""; - DEVELOPMENT_TEAM = Q6CQVYDYZ4; + DEVELOPMENT_TEAM = YM283LC5H4; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "Swift-Code-Challenge-Info.plist"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = ( @@ -448,12 +526,12 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Swift Code Challenge/Preview Content\""; - DEVELOPMENT_TEAM = Q6CQVYDYZ4; + DEVELOPMENT_TEAM = YM283LC5H4; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "Swift-Code-Challenge-Info.plist"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Swift Code Challenge.xcodeproj/project.xcworkspace/xcuserdata/luizeduardomr.xcuserdatad/UserInterfaceState.xcuserstate b/Swift Code Challenge.xcodeproj/project.xcworkspace/xcuserdata/luizeduardomr.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..b9c8aab Binary files /dev/null and b/Swift Code Challenge.xcodeproj/project.xcworkspace/xcuserdata/luizeduardomr.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Swift Code Challenge.xcodeproj/xcuserdata/luizeduardomr.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Swift Code Challenge.xcodeproj/xcuserdata/luizeduardomr.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..0c2131b --- /dev/null +++ b/Swift Code Challenge.xcodeproj/xcuserdata/luizeduardomr.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/Swift Code Challenge.xcodeproj/xcuserdata/luizeduardomr.xcuserdatad/xcschemes/xcschememanagement.plist b/Swift Code Challenge.xcodeproj/xcuserdata/luizeduardomr.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..9a1d4ab --- /dev/null +++ b/Swift Code Challenge.xcodeproj/xcuserdata/luizeduardomr.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Swift Code Challenge.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/100.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/100.png new file mode 100644 index 0000000..15c4015 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/100.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/1024.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000..bfe8ab8 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/114.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/114.png new file mode 100644 index 0000000..351fcf0 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/114.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/120.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/120.png new file mode 100644 index 0000000..5d49ca8 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/120.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/128.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/128.png new file mode 100644 index 0000000..cfc656f Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/128.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/144.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/144.png new file mode 100644 index 0000000..5ee4d14 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/144.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/152.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/152.png new file mode 100644 index 0000000..1d59121 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/152.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/16.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/16.png new file mode 100644 index 0000000..c66926f Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/16.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/167.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/167.png new file mode 100644 index 0000000..146c74e Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/167.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/172.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/172.png new file mode 100644 index 0000000..6c5ea2e Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/172.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/180.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/180.png new file mode 100644 index 0000000..5665d31 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/180.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/196.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/196.png new file mode 100644 index 0000000..70fdd1c Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/196.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/20.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/20.png new file mode 100644 index 0000000..d842e08 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/20.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/216.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/216.png new file mode 100644 index 0000000..2a1b5e1 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/216.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/256.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/256.png new file mode 100644 index 0000000..874b7e4 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/256.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/29.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/29.png new file mode 100644 index 0000000..7c98cbb Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/29.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/32.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/32.png new file mode 100644 index 0000000..e63a1c3 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/32.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/40.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/40.png new file mode 100644 index 0000000..bd60f10 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/40.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/48.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/48.png new file mode 100644 index 0000000..9251b11 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/48.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/50.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/50.png new file mode 100644 index 0000000..2c4e83d Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/50.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/512.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/512.png new file mode 100644 index 0000000..51c618a Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/512.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/55.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/55.png new file mode 100644 index 0000000..fc7a0be Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/55.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/57.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/57.png new file mode 100644 index 0000000..6fd36b8 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/57.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/58.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 0000000..0c44f6c Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/58.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/60.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/60.png new file mode 100644 index 0000000..a6c8bb2 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/60.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/64.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/64.png new file mode 100644 index 0000000..6b341ec Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/64.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/72.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/72.png new file mode 100644 index 0000000..02b4834 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/72.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/76.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/76.png new file mode 100644 index 0000000..d12799d Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/76.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/80.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/80.png new file mode 100644 index 0000000..1886a34 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/80.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/87.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/87.png new file mode 100644 index 0000000..d4b9595 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/87.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/88.png b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/88.png new file mode 100644 index 0000000..c49d9a7 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/88.png differ diff --git a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/Contents.json b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/Contents.json index 9221b9b..04de9d4 100644 --- a/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Swift Code Challenge/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,94 +1,326 @@ { "images" : [ { + "filename" : "40.png", "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { + "filename" : "60.png", "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { + "filename" : "29.png", + "idiom" : "iphone", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "58.png", "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { + "filename" : "87.png", "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { + "filename" : "80.png", "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { + "filename" : "120.png", "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { + "filename" : "57.png", + "idiom" : "iphone", + "scale" : "1x", + "size" : "57x57" + }, + { + "filename" : "114.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "57x57" + }, + { + "filename" : "120.png", "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { + "filename" : "180.png", "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { + "filename" : "20.png", "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { + "filename" : "40.png", "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { + "filename" : "29.png", "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { + "filename" : "58.png", "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { + "filename" : "40.png", "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { + "filename" : "80.png", "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { + "filename" : "50.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "50x50" + }, + { + "filename" : "100.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "50x50" + }, + { + "filename" : "72.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "72x72" + }, + { + "filename" : "144.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "72x72" + }, + { + "filename" : "76.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { + "filename" : "152.png", "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { + "filename" : "167.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { + "filename" : "1024.png", "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" + }, + { + "filename" : "48.png", + "idiom" : "watch", + "role" : "notificationCenter", + "scale" : "2x", + "size" : "24x24", + "subtype" : "38mm" + }, + { + "filename" : "55.png", + "idiom" : "watch", + "role" : "notificationCenter", + "scale" : "2x", + "size" : "27.5x27.5", + "subtype" : "42mm" + }, + { + "filename" : "58.png", + "idiom" : "watch", + "role" : "companionSettings", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "87.png", + "idiom" : "watch", + "role" : "companionSettings", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "watch", + "role" : "notificationCenter", + "scale" : "2x", + "size" : "33x33", + "subtype" : "45mm" + }, + { + "filename" : "80.png", + "idiom" : "watch", + "role" : "appLauncher", + "scale" : "2x", + "size" : "40x40", + "subtype" : "38mm" + }, + { + "filename" : "88.png", + "idiom" : "watch", + "role" : "appLauncher", + "scale" : "2x", + "size" : "44x44", + "subtype" : "40mm" + }, + { + "idiom" : "watch", + "role" : "appLauncher", + "scale" : "2x", + "size" : "46x46", + "subtype" : "41mm" + }, + { + "filename" : "100.png", + "idiom" : "watch", + "role" : "appLauncher", + "scale" : "2x", + "size" : "50x50", + "subtype" : "44mm" + }, + { + "idiom" : "watch", + "role" : "appLauncher", + "scale" : "2x", + "size" : "51x51", + "subtype" : "45mm" + }, + { + "filename" : "172.png", + "idiom" : "watch", + "role" : "quickLook", + "scale" : "2x", + "size" : "86x86", + "subtype" : "38mm" + }, + { + "filename" : "196.png", + "idiom" : "watch", + "role" : "quickLook", + "scale" : "2x", + "size" : "98x98", + "subtype" : "42mm" + }, + { + "filename" : "216.png", + "idiom" : "watch", + "role" : "quickLook", + "scale" : "2x", + "size" : "108x108", + "subtype" : "44mm" + }, + { + "idiom" : "watch", + "role" : "quickLook", + "scale" : "2x", + "size" : "117x117", + "subtype" : "45mm" + }, + { + "filename" : "1024.png", + "idiom" : "watch-marketing", + "scale" : "1x", + "size" : "1024x1024" + }, + { + "filename" : "16.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "32.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "32.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "64.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "128.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "256.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "256.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "512.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "512.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "1024.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" } ], "info" : { diff --git a/Swift Code Challenge/Assets.xcassets/LaunchScreenBackground.colorset/Contents.json b/Swift Code Challenge/Assets.xcassets/LaunchScreenBackground.colorset/Contents.json new file mode 100644 index 0000000..fed604c --- /dev/null +++ b/Swift Code Challenge/Assets.xcassets/LaunchScreenBackground.colorset/Contents.json @@ -0,0 +1,28 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "ios", + "reference" : "darkTextColor" + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "platform" : "ios", + "reference" : "darkTextColor" + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/Contents.json b/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/Contents.json new file mode 100644 index 0000000..8823b40 --- /dev/null +++ b/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "icon-removebg-preview.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icon-removebg-preview-1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icon-removebg-preview-2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview-1.png b/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview-1.png new file mode 100644 index 0000000..b5586e0 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview-1.png differ diff --git a/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview-2.png b/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview-2.png new file mode 100644 index 0000000..b5586e0 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview-2.png differ diff --git a/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview.png b/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview.png new file mode 100644 index 0000000..b5586e0 Binary files /dev/null and b/Swift Code Challenge/Assets.xcassets/LaunchScreenLogo.imageset/icon-removebg-preview.png differ diff --git a/Swift Code Challenge/ContentView.swift b/Swift Code Challenge/ContentView.swift index e93e548..a966b67 100644 --- a/Swift Code Challenge/ContentView.swift +++ b/Swift Code Challenge/ContentView.swift @@ -8,9 +8,10 @@ import SwiftUI struct ContentView: View { + @ObservedObject var viewModel: UsersListViewModelAsync = UsersListViewModelAsync() + var body: some View { - Text("Hello, world!") - .padding() + UsersListView() } } diff --git a/Swift Code Challenge/Models/UserModel.swift b/Swift Code Challenge/Models/UserModel.swift new file mode 100644 index 0000000..fe221cf --- /dev/null +++ b/Swift Code Challenge/Models/UserModel.swift @@ -0,0 +1,52 @@ +// +// UserModel.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 29/06/22. +// + +import Foundation + +struct ID: Equatable, Hashable, Decodable { + let value: String? +} + +struct Name: Equatable, Decodable { + let first: String? + let last: String? +} + +struct Picture: Equatable, Decodable{ + let large: String? + let medium: String? + let thumbnail: String? +} + +struct coordinates: Equatable, Decodable{ + let latitude: String? + let longitude: String? +} + +struct location: Equatable, Decodable{ + let street: street? + let city: String? + let state: String? + let country: String? + let coordinates: coordinates? +} + +struct street: Equatable, Decodable{ + let number: Int? + let name: String? +} + + +struct Person: Identifiable, Equatable, Decodable { + let id: ID + let name: Name + let picture: Picture + let email: String + let phone: String + let location: location + +} diff --git a/Swift Code Challenge/Services/ApiRequestAsync.swift b/Swift Code Challenge/Services/ApiRequestAsync.swift new file mode 100644 index 0000000..9535200 --- /dev/null +++ b/Swift Code Challenge/Services/ApiRequestAsync.swift @@ -0,0 +1,26 @@ +// +// ApiRequestAsync.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 30/06/22. +// + +import Foundation + +class ApiRequestAsync { + + static func fetchUser() async throws -> [Person] { + guard let url = URL(string: "https://randomuser.me/api/?results=10") else { return [] } + let request = URLRequest(url: url) + + let (data, _) = try await URLSession.shared.data(for: request) + + struct Response: Decodable { + let results: [Person] + } + + let response = try JSONDecoder().decode(Response.self, from: data) + return response.results + //filter { $0.id.value != nil} + } +} diff --git a/Swift Code Challenge/ViewModels/UsersListViewModelAsync.swift b/Swift Code Challenge/ViewModels/UsersListViewModelAsync.swift new file mode 100644 index 0000000..1fdca66 --- /dev/null +++ b/Swift Code Challenge/ViewModels/UsersListViewModelAsync.swift @@ -0,0 +1,34 @@ +// +// UsersListViewModelAsync.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 30/06/22. +// +import Foundation +import SwiftUI + +class UsersListViewModelAsync: ObservableObject { + @Published var personList: [Person] = [] + + init() { + getPersonList() + } + + func getPersonList() { + Task { + do { + let requestApi = try await ApiRequestAsync.fetchUser() + + DispatchQueue.main.async { + self.personList = requestApi + } + } catch { + print(error) + } + } + } +} + + + + diff --git a/Swift Code Challenge/Views/Components/CircleImageComponent.swift b/Swift Code Challenge/Views/Components/CircleImageComponent.swift new file mode 100644 index 0000000..ccdeec4 --- /dev/null +++ b/Swift Code Challenge/Views/Components/CircleImageComponent.swift @@ -0,0 +1,20 @@ +// +// CircleImageComponent.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 30/06/22. +// + +import SwiftUI + +struct CircleImage: View { + var userImage: String + var body: some View { + AsyncImage(url: URL(string: userImage)) + .aspectRatio(contentMode: .fit) + .frame(width: 128, height: 128) + .clipShape(Circle()) + .overlay(Circle().stroke(Color.gray, lineWidth: 2)) + .shadow(radius: 10) + } +} diff --git a/Swift Code Challenge/Views/MapView.swift b/Swift Code Challenge/Views/MapView.swift new file mode 100644 index 0000000..96c7734 --- /dev/null +++ b/Swift Code Challenge/Views/MapView.swift @@ -0,0 +1,28 @@ +// +// MapView.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 30/06/22. +// + +import SwiftUI +import MapKit + +struct MapView: UIViewRepresentable { + + var lat: String? + var long: String? + + func makeUIView(context: UIViewRepresentableContext) -> MKMapView { + + MKMapView() + } + func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext) { + let coordinate = CLLocationCoordinate2D(latitude: Double(lat ?? "33.213") ?? 323.123, longitude: Double(long ?? "23.213") ?? 34.131) + let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) + let region = MKCoordinateRegion(center: coordinate, span: span) + uiView.setRegion(region, animated: true) + } + + +} diff --git a/Swift Code Challenge/Views/TestAsync.swift b/Swift Code Challenge/Views/TestAsync.swift new file mode 100644 index 0000000..eb2e79b --- /dev/null +++ b/Swift Code Challenge/Views/TestAsync.swift @@ -0,0 +1,28 @@ +// +// TestAsync.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 30/06/22. +// + +import SwiftUI + +struct TestAsync: View { + @StateObject var viewModel: UsersListViewModelAsync + + + var body: some View { + if(viewModel.personList.isEmpty){ + ProgressView() + .progressViewStyle(CircularProgressViewStyle()) + } + else{ + List{ + ForEach(Array(zip(viewModel.personList.indices, viewModel.personList)), id: \.0) {index, user in + Text(user.name.first ?? "Luiz") + } + } + } + + } +} diff --git a/Swift Code Challenge/Views/UserDetailsView.swift b/Swift Code Challenge/Views/UserDetailsView.swift new file mode 100644 index 0000000..6a2b234 --- /dev/null +++ b/Swift Code Challenge/Views/UserDetailsView.swift @@ -0,0 +1,119 @@ +// +// UserDetailsView.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 30/06/22. +// + +import SwiftUI +import MessageUI + +struct UserDetailsView: View { + @State var user: Person + var body: some View { + VStack{ + MapView(lat: user.location.coordinates?.latitude, long: user.location.coordinates?.latitude) + .frame(height: 200) + .ignoresSafeArea(edges: .top) + VStack{ + CircleImage(userImage: user.picture.large ?? "") + + contentBody(user: user) + } + .offset(y: -200) + .padding(.bottom, -130) + + Spacer() + + Text("made by @luizmello.dev - click me!") + .onTapGesture { + openInstagram(instagramHandle: "luizmello.dev") + } + .padding(.vertical) + } + } + func openInstagram(instagramHandle: String) { + guard let url = URL(string: "https://instagram.com/\(instagramHandle)") else { return } + if UIApplication.shared.canOpenURL(url) { + if #available(iOS 10.0, *) { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } else { + UIApplication.shared.openURL(url) + } + } + } +} + +struct contentBody: View { + @State var result: Result? = nil + @State var isShowingMailView = false + var user: Person + + var body: some View { + VStack(spacing: 5) { + Text("\(user.name.first ?? "Luiz") \(user.name.last ?? "Mello")") + .bold() + .font(.title) + HStack() { + Text("\(user.location.street?.name ?? "SADSAD"),") + .font(.body) + .foregroundColor(.secondary) + Text("\(user.location.city ?? "asdsad") - \(user.location.country ?? "asdad")") + .font(.body) + .bold() + .foregroundColor(.secondary) + } + .padding(.bottom, 70) + + Button(action: { + let tel = "mailto:" + var formattedString = tel + user.email + let url: NSURL = URL(string: formattedString)! as NSURL + + UIApplication.shared.open(url as URL)}) { + HStack { + Image(systemName: "mail") + .font(.body) + Text(user.email) + .fontWeight(.semibold) + .font(.body) + } + .padding() + .foregroundColor(.white) + .background(Color.blue) + .cornerRadius(40) + } + .padding() + + Button(action: { + + // validation of phone number not included + let dash = CharacterSet(charactersIn: "-") + + let cleanString = + user.phone.trimmingCharacters(in: dash) + + let tel = "tel://" + var formattedString = tel + cleanString + let url: NSURL = URL(string: formattedString)! as NSURL + + UIApplication.shared.open(url as URL) + }) { + HStack { + Image(systemName: "phone") + .font(.body) + Text(user.phone) + .fontWeight(.semibold) + .font(.body) + } + .padding() + .foregroundColor(.white) + .background(Color.cyan) + .cornerRadius(40) + } + } + } +} + + + diff --git a/Swift Code Challenge/Views/UsersListView.swift b/Swift Code Challenge/Views/UsersListView.swift new file mode 100644 index 0000000..e733b58 --- /dev/null +++ b/Swift Code Challenge/Views/UsersListView.swift @@ -0,0 +1,108 @@ +// +// UsersListView.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 29/06/22. +// + +import SwiftUI + +struct UsersListView: View { + @ObservedObject var viewModel: UsersListViewModelAsync = UsersListViewModelAsync() + @State private var showDevice = false + @State private var selection: Person? = nil + + + var body: some View { + ZStack{ + NavigationView{ + if(viewModel.personList.isEmpty){ + ProgressView() + .progressViewStyle(CircularProgressViewStyle()) + } + else{ + VStack{ + ListComponent(viewModel: viewModel) + + NewUsersButton(viewModel: viewModel) + } + .toolbar { + EditButton() + } + } + } .navigationViewStyle(StackNavigationViewStyle()) + if showDevice { + VisualEffectView(effect: UIBlurEffect(style: .dark)) + .ignoresSafeArea() + VStack{ + Text("Real Device") + .font(.largeTitle.bold()) + .foregroundColor(.white) + Text("Use it on real device to best experience") + .foregroundColor(.white) + .font(.body) + } + } + } + .onAppear(){ + self.showDevice = true + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + self.showDevice = false + } + } + } +} + +struct ListComponent: View{ + @ObservedObject var viewModel: UsersListViewModelAsync + + var body: some View{ + List{ + ForEach(Array(zip(viewModel.personList.indices, viewModel.personList)), id: \.0) {index, user in + NavigationLink(destination: UserDetailsView(user: user)) { + HStack{ + AsyncImage(url: URL(string: user.picture.thumbnail ?? "")) + .frame(width: 40, height: 40) + .scaledToFill() + .clipShape(Circle()).padding(.horizontal) + Text("\(user.name.first ?? "Luiz") \(user.name.last ?? "Mello")") + } + } + .navigationTitle("Users") + } + .onDelete(perform: removeRows) + .onMove(perform: move) + } + .refreshable { + viewModel.getPersonList() + } + } + + func move(from source: IndexSet, to destination: Int) { + viewModel.personList.move(fromOffsets: source, toOffset: destination) + } + + func removeRows(at offsets: IndexSet) { + viewModel.personList.remove(atOffsets: offsets) + } +} + +struct NewUsersButton: View{ + @ObservedObject var viewModel: UsersListViewModelAsync + var body: some View{ + Button { + viewModel.getPersonList() + } label: { + Group{ + HStack { + Image(systemName: "person.3.sequence.fill") + .font(.body) + Text("Update for new users") + .fontWeight(.semibold) + .font(.body) + } + } + .padding(.vertical) + } + } +} diff --git a/Swift Code Challenge/Views/VisualEffectsView.swift b/Swift Code Challenge/Views/VisualEffectsView.swift new file mode 100644 index 0000000..7f1d390 --- /dev/null +++ b/Swift Code Challenge/Views/VisualEffectsView.swift @@ -0,0 +1,16 @@ +// +// VisualEffectsView.swift +// Swift Code Challenge +// +// Created by Luiz Eduardo Mello dos Reis on 30/06/22. +// + +import Foundation +import SwiftUI + +struct VisualEffectView: UIViewRepresentable { + var effect: UIVisualEffect? + func makeUIView(context: UIViewRepresentableContext) -> UIVisualEffectView { UIVisualEffectView() } + func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext) { uiView.effect = effect } +} + diff --git a/Swift-Code-Challenge-Info.plist b/Swift-Code-Challenge-Info.plist new file mode 100644 index 0000000..836bb03 --- /dev/null +++ b/Swift-Code-Challenge-Info.plist @@ -0,0 +1,13 @@ + + + + + UILaunchScreen + + UIColorName + LaunchScreenBackground + UIImageName + LaunchScreenLogo + + +