├── CursoiOS.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── xcshareddata │ └── xcschemes │ │ └── CursoiOS.xcscheme └── xcuserdata │ └── aris.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── CursoiOS ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── BackgroundApp.colorset │ │ └── Contents.json │ ├── BackgroundComponent.colorset │ │ └── Contents.json │ ├── BackgroundComponentSelected.colorset │ │ └── Contents.json │ ├── Contents.json │ ├── material-symbols--10k.imageset │ │ ├── Contents.json │ │ └── material-symbols--10k.svg │ └── swift.imageset │ │ ├── Contents.json │ │ └── swiftui-96x96_2x.png ├── Components │ ├── ButtonExample.swift │ ├── CustomDialog.swift │ ├── ImageExample.swift │ ├── LabelExample.swift │ ├── ListExample.swift │ ├── MapExample.swift │ ├── TextExample.swift │ └── TextFieldExample.swift ├── CursoiOSApp.swift ├── Exercises │ └── Exercise1.swift ├── FavPlaces │ ├── FavPlaces.swift │ └── model │ │ └── Place.swift ├── IMC │ ├── IMCResult.swift │ └── IMCView.swift ├── MainView.swift ├── MenuView.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── Superhero │ ├── ApiNetwork.swift │ ├── SuperheroDetail.swift │ └── SuperheroSearcher.swift └── sintaxis │ └── CursoiOS.playground │ ├── Contents.swift │ ├── contents.xcplayground │ └── playground.xcworkspace │ └── contents.xcworkspacedata └── README.md /CursoiOS.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0B2A595D2BF5125500D5D1DA /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2A595C2BF5125500D5D1DA /* MenuView.swift */; }; 11 | 0B2A59602BF517B800D5D1DA /* IMCView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2A595F2BF517B800D5D1DA /* IMCView.swift */; }; 12 | 0B42B2A42BE28F5800FC1CEC /* TextExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B42B2A32BE28F5800FC1CEC /* TextExample.swift */; }; 13 | 0B42B2A62BE294B500FC1CEC /* ImageExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B42B2A52BE294B500FC1CEC /* ImageExample.swift */; }; 14 | 0B42B2A82BE29C9400FC1CEC /* LabelExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B42B2A72BE29C9400FC1CEC /* LabelExample.swift */; }; 15 | 0B42B2AA2BE29F3500FC1CEC /* ButtonExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B42B2A92BE29F3500FC1CEC /* ButtonExample.swift */; }; 16 | 0B42B2AC2BE2A3F400FC1CEC /* TextFieldExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B42B2AB2BE2A3F400FC1CEC /* TextFieldExample.swift */; }; 17 | 0B78446C2BDE93FB003D7B3C /* CursoiOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B78446B2BDE93FB003D7B3C /* CursoiOSApp.swift */; }; 18 | 0B78446E2BDE93FB003D7B3C /* Exercise1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B78446D2BDE93FB003D7B3C /* Exercise1.swift */; }; 19 | 0B7844702BDE93FC003D7B3C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0B78446F2BDE93FC003D7B3C /* Assets.xcassets */; }; 20 | 0B7844732BDE93FC003D7B3C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0B7844722BDE93FC003D7B3C /* Preview Assets.xcassets */; }; 21 | 0B78447B2BDEB2D2003D7B3C /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B78447A2BDEB2D2003D7B3C /* MainView.swift */; }; 22 | 0B815B5C2C034CC500DAE145 /* SuperheroSearcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B815B5B2C034CC500DAE145 /* SuperheroSearcher.swift */; }; 23 | 0B815B5E2C03562A00DAE145 /* ApiNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B815B5D2C03562A00DAE145 /* ApiNetwork.swift */; }; 24 | 0B815B612C03675A00DAE145 /* SDWebImageSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 0B815B602C03675A00DAE145 /* SDWebImageSwiftUI */; }; 25 | 0BB9962C2C03AF16000759C0 /* SuperheroDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB9962B2C03AF16000759C0 /* SuperheroDetail.swift */; }; 26 | 0BCDB2732C07AE0000DF1C7F /* MapExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCDB2722C07AE0000DF1C7F /* MapExample.swift */; }; 27 | 0BCDB2762C07BB6400DF1C7F /* FavPlaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCDB2752C07BB6400DF1C7F /* FavPlaces.swift */; }; 28 | 0BCDB2792C07BD5F00DF1C7F /* Place.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCDB2782C07BD5F00DF1C7F /* Place.swift */; }; 29 | 0BCDB27B2C07C03300DF1C7F /* CustomDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCDB27A2C07C03300DF1C7F /* CustomDialog.swift */; }; 30 | 0BCEA58C2C01032D0059D1D1 /* IMCResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCEA58B2C01032D0059D1D1 /* IMCResult.swift */; }; 31 | 0BCEA58E2C010E030059D1D1 /* ListExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCEA58D2C010E030059D1D1 /* ListExample.swift */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 0B2A595C2BF5125500D5D1DA /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = ""; }; 36 | 0B2A595F2BF517B800D5D1DA /* IMCView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMCView.swift; sourceTree = ""; }; 37 | 0B42B2A32BE28F5800FC1CEC /* TextExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextExample.swift; sourceTree = ""; }; 38 | 0B42B2A52BE294B500FC1CEC /* ImageExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageExample.swift; sourceTree = ""; }; 39 | 0B42B2A72BE29C9400FC1CEC /* LabelExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelExample.swift; sourceTree = ""; }; 40 | 0B42B2A92BE29F3500FC1CEC /* ButtonExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonExample.swift; sourceTree = ""; }; 41 | 0B42B2AB2BE2A3F400FC1CEC /* TextFieldExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldExample.swift; sourceTree = ""; }; 42 | 0B7844682BDE93FB003D7B3C /* CursoiOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CursoiOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 0B78446B2BDE93FB003D7B3C /* CursoiOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CursoiOSApp.swift; sourceTree = ""; }; 44 | 0B78446D2BDE93FB003D7B3C /* Exercise1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exercise1.swift; sourceTree = ""; }; 45 | 0B78446F2BDE93FC003D7B3C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 46 | 0B7844722BDE93FC003D7B3C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 47 | 0B78447A2BDEB2D2003D7B3C /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 48 | 0B815B5B2C034CC500DAE145 /* SuperheroSearcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuperheroSearcher.swift; sourceTree = ""; }; 49 | 0B815B5D2C03562A00DAE145 /* ApiNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiNetwork.swift; sourceTree = ""; }; 50 | 0BB9962B2C03AF16000759C0 /* SuperheroDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuperheroDetail.swift; sourceTree = ""; }; 51 | 0BCDB2722C07AE0000DF1C7F /* MapExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapExample.swift; sourceTree = ""; }; 52 | 0BCDB2752C07BB6400DF1C7F /* FavPlaces.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavPlaces.swift; sourceTree = ""; }; 53 | 0BCDB2782C07BD5F00DF1C7F /* Place.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Place.swift; sourceTree = ""; }; 54 | 0BCDB27A2C07C03300DF1C7F /* CustomDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDialog.swift; sourceTree = ""; }; 55 | 0BCEA58B2C01032D0059D1D1 /* IMCResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMCResult.swift; sourceTree = ""; }; 56 | 0BCEA58D2C010E030059D1D1 /* ListExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListExample.swift; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | 0B7844652BDE93FB003D7B3C /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | 0B815B612C03675A00DAE145 /* SDWebImageSwiftUI in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 0B2A595E2BF5178B00D5D1DA /* IMC */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 0B2A595F2BF517B800D5D1DA /* IMCView.swift */, 75 | 0BCEA58B2C01032D0059D1D1 /* IMCResult.swift */, 76 | ); 77 | path = IMC; 78 | sourceTree = ""; 79 | }; 80 | 0B78445F2BDE93FB003D7B3C = { 81 | isa = PBXGroup; 82 | children = ( 83 | 0B78446A2BDE93FB003D7B3C /* CursoiOS */, 84 | 0B7844692BDE93FB003D7B3C /* Products */, 85 | ); 86 | sourceTree = ""; 87 | }; 88 | 0B7844692BDE93FB003D7B3C /* Products */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 0B7844682BDE93FB003D7B3C /* CursoiOS.app */, 92 | ); 93 | name = Products; 94 | sourceTree = ""; 95 | }; 96 | 0B78446A2BDE93FB003D7B3C /* CursoiOS */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 0BCDB2742C07BB3600DF1C7F /* FavPlaces */, 100 | 0B815B5A2C034CB400DAE145 /* Superhero */, 101 | 0B2A595E2BF5178B00D5D1DA /* IMC */, 102 | 0B78447C2BDEB2F1003D7B3C /* Components */, 103 | 0B7844792BDEB27C003D7B3C /* Exercises */, 104 | 0B78446B2BDE93FB003D7B3C /* CursoiOSApp.swift */, 105 | 0B78447A2BDEB2D2003D7B3C /* MainView.swift */, 106 | 0B2A595C2BF5125500D5D1DA /* MenuView.swift */, 107 | 0B78446F2BDE93FC003D7B3C /* Assets.xcassets */, 108 | 0B7844712BDE93FC003D7B3C /* Preview Content */, 109 | ); 110 | path = CursoiOS; 111 | sourceTree = ""; 112 | }; 113 | 0B7844712BDE93FC003D7B3C /* Preview Content */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 0B7844722BDE93FC003D7B3C /* Preview Assets.xcassets */, 117 | ); 118 | path = "Preview Content"; 119 | sourceTree = ""; 120 | }; 121 | 0B7844792BDEB27C003D7B3C /* Exercises */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 0B78446D2BDE93FB003D7B3C /* Exercise1.swift */, 125 | ); 126 | path = Exercises; 127 | sourceTree = ""; 128 | }; 129 | 0B78447C2BDEB2F1003D7B3C /* Components */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 0B42B2A32BE28F5800FC1CEC /* TextExample.swift */, 133 | 0B42B2A52BE294B500FC1CEC /* ImageExample.swift */, 134 | 0B42B2A72BE29C9400FC1CEC /* LabelExample.swift */, 135 | 0B42B2A92BE29F3500FC1CEC /* ButtonExample.swift */, 136 | 0B42B2AB2BE2A3F400FC1CEC /* TextFieldExample.swift */, 137 | 0BCEA58D2C010E030059D1D1 /* ListExample.swift */, 138 | 0BCDB2722C07AE0000DF1C7F /* MapExample.swift */, 139 | 0BCDB27A2C07C03300DF1C7F /* CustomDialog.swift */, 140 | ); 141 | path = Components; 142 | sourceTree = ""; 143 | }; 144 | 0B815B5A2C034CB400DAE145 /* Superhero */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 0B815B5B2C034CC500DAE145 /* SuperheroSearcher.swift */, 148 | 0B815B5D2C03562A00DAE145 /* ApiNetwork.swift */, 149 | 0BB9962B2C03AF16000759C0 /* SuperheroDetail.swift */, 150 | ); 151 | path = Superhero; 152 | sourceTree = ""; 153 | }; 154 | 0BCDB2742C07BB3600DF1C7F /* FavPlaces */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 0BCDB2772C07BD4C00DF1C7F /* model */, 158 | 0BCDB2752C07BB6400DF1C7F /* FavPlaces.swift */, 159 | ); 160 | path = FavPlaces; 161 | sourceTree = ""; 162 | }; 163 | 0BCDB2772C07BD4C00DF1C7F /* model */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 0BCDB2782C07BD5F00DF1C7F /* Place.swift */, 167 | ); 168 | path = model; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | 0B7844672BDE93FB003D7B3C /* CursoiOS */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = 0B7844762BDE93FC003D7B3C /* Build configuration list for PBXNativeTarget "CursoiOS" */; 177 | buildPhases = ( 178 | 0B7844642BDE93FB003D7B3C /* Sources */, 179 | 0B7844652BDE93FB003D7B3C /* Frameworks */, 180 | 0B7844662BDE93FB003D7B3C /* Resources */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | ); 186 | name = CursoiOS; 187 | packageProductDependencies = ( 188 | 0B815B602C03675A00DAE145 /* SDWebImageSwiftUI */, 189 | ); 190 | productName = CursoiOS; 191 | productReference = 0B7844682BDE93FB003D7B3C /* CursoiOS.app */; 192 | productType = "com.apple.product-type.application"; 193 | }; 194 | /* End PBXNativeTarget section */ 195 | 196 | /* Begin PBXProject section */ 197 | 0B7844602BDE93FB003D7B3C /* Project object */ = { 198 | isa = PBXProject; 199 | attributes = { 200 | BuildIndependentTargetsInParallel = 1; 201 | LastSwiftUpdateCheck = 1530; 202 | LastUpgradeCheck = 1530; 203 | TargetAttributes = { 204 | 0B7844672BDE93FB003D7B3C = { 205 | CreatedOnToolsVersion = 15.3; 206 | }; 207 | }; 208 | }; 209 | buildConfigurationList = 0B7844632BDE93FB003D7B3C /* Build configuration list for PBXProject "CursoiOS" */; 210 | compatibilityVersion = "Xcode 14.0"; 211 | developmentRegion = en; 212 | hasScannedForEncodings = 0; 213 | knownRegions = ( 214 | en, 215 | Base, 216 | ); 217 | mainGroup = 0B78445F2BDE93FB003D7B3C; 218 | packageReferences = ( 219 | 0B815B5F2C03675A00DAE145 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */, 220 | ); 221 | productRefGroup = 0B7844692BDE93FB003D7B3C /* Products */; 222 | projectDirPath = ""; 223 | projectRoot = ""; 224 | targets = ( 225 | 0B7844672BDE93FB003D7B3C /* CursoiOS */, 226 | ); 227 | }; 228 | /* End PBXProject section */ 229 | 230 | /* Begin PBXResourcesBuildPhase section */ 231 | 0B7844662BDE93FB003D7B3C /* Resources */ = { 232 | isa = PBXResourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 0B7844732BDE93FC003D7B3C /* Preview Assets.xcassets in Resources */, 236 | 0B7844702BDE93FC003D7B3C /* Assets.xcassets in Resources */, 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | /* End PBXResourcesBuildPhase section */ 241 | 242 | /* Begin PBXSourcesBuildPhase section */ 243 | 0B7844642BDE93FB003D7B3C /* Sources */ = { 244 | isa = PBXSourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | 0B78446E2BDE93FB003D7B3C /* Exercise1.swift in Sources */, 248 | 0BCDB2762C07BB6400DF1C7F /* FavPlaces.swift in Sources */, 249 | 0B42B2AA2BE29F3500FC1CEC /* ButtonExample.swift in Sources */, 250 | 0B42B2A82BE29C9400FC1CEC /* LabelExample.swift in Sources */, 251 | 0B42B2A42BE28F5800FC1CEC /* TextExample.swift in Sources */, 252 | 0B815B5C2C034CC500DAE145 /* SuperheroSearcher.swift in Sources */, 253 | 0BCDB2732C07AE0000DF1C7F /* MapExample.swift in Sources */, 254 | 0BCEA58E2C010E030059D1D1 /* ListExample.swift in Sources */, 255 | 0BCEA58C2C01032D0059D1D1 /* IMCResult.swift in Sources */, 256 | 0B2A595D2BF5125500D5D1DA /* MenuView.swift in Sources */, 257 | 0B78447B2BDEB2D2003D7B3C /* MainView.swift in Sources */, 258 | 0B42B2A62BE294B500FC1CEC /* ImageExample.swift in Sources */, 259 | 0B42B2AC2BE2A3F400FC1CEC /* TextFieldExample.swift in Sources */, 260 | 0BB9962C2C03AF16000759C0 /* SuperheroDetail.swift in Sources */, 261 | 0B2A59602BF517B800D5D1DA /* IMCView.swift in Sources */, 262 | 0BCDB2792C07BD5F00DF1C7F /* Place.swift in Sources */, 263 | 0B78446C2BDE93FB003D7B3C /* CursoiOSApp.swift in Sources */, 264 | 0B815B5E2C03562A00DAE145 /* ApiNetwork.swift in Sources */, 265 | 0BCDB27B2C07C03300DF1C7F /* CustomDialog.swift in Sources */, 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | /* End PBXSourcesBuildPhase section */ 270 | 271 | /* Begin XCBuildConfiguration section */ 272 | 0B7844742BDE93FC003D7B3C /* Debug */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 277 | CLANG_ANALYZER_NONNULL = YES; 278 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 279 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 280 | CLANG_ENABLE_MODULES = YES; 281 | CLANG_ENABLE_OBJC_ARC = YES; 282 | CLANG_ENABLE_OBJC_WEAK = YES; 283 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 284 | CLANG_WARN_BOOL_CONVERSION = YES; 285 | CLANG_WARN_COMMA = YES; 286 | CLANG_WARN_CONSTANT_CONVERSION = YES; 287 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 288 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 289 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 290 | CLANG_WARN_EMPTY_BODY = YES; 291 | CLANG_WARN_ENUM_CONVERSION = YES; 292 | CLANG_WARN_INFINITE_RECURSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 296 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 297 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 298 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 299 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 300 | CLANG_WARN_STRICT_PROTOTYPES = YES; 301 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 302 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 303 | CLANG_WARN_UNREACHABLE_CODE = YES; 304 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 305 | COPY_PHASE_STRIP = NO; 306 | DEBUG_INFORMATION_FORMAT = dwarf; 307 | ENABLE_STRICT_OBJC_MSGSEND = YES; 308 | ENABLE_TESTABILITY = YES; 309 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 310 | GCC_C_LANGUAGE_STANDARD = gnu17; 311 | GCC_DYNAMIC_NO_PIC = NO; 312 | GCC_NO_COMMON_BLOCKS = YES; 313 | GCC_OPTIMIZATION_LEVEL = 0; 314 | GCC_PREPROCESSOR_DEFINITIONS = ( 315 | "DEBUG=1", 316 | "$(inherited)", 317 | ); 318 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 319 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 320 | GCC_WARN_UNDECLARED_SELECTOR = YES; 321 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 322 | GCC_WARN_UNUSED_FUNCTION = YES; 323 | GCC_WARN_UNUSED_VARIABLE = YES; 324 | IPHONEOS_DEPLOYMENT_TARGET = 17.4; 325 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 326 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 327 | MTL_FAST_MATH = YES; 328 | ONLY_ACTIVE_ARCH = YES; 329 | SDKROOT = iphoneos; 330 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 331 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 332 | }; 333 | name = Debug; 334 | }; 335 | 0B7844752BDE93FC003D7B3C /* Release */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | ALWAYS_SEARCH_USER_PATHS = NO; 339 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 340 | CLANG_ANALYZER_NONNULL = YES; 341 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 343 | CLANG_ENABLE_MODULES = YES; 344 | CLANG_ENABLE_OBJC_ARC = YES; 345 | CLANG_ENABLE_OBJC_WEAK = YES; 346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 347 | CLANG_WARN_BOOL_CONVERSION = YES; 348 | CLANG_WARN_COMMA = YES; 349 | CLANG_WARN_CONSTANT_CONVERSION = YES; 350 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 351 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 352 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 353 | CLANG_WARN_EMPTY_BODY = YES; 354 | CLANG_WARN_ENUM_CONVERSION = YES; 355 | CLANG_WARN_INFINITE_RECURSION = YES; 356 | CLANG_WARN_INT_CONVERSION = YES; 357 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 358 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 359 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 360 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 361 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 362 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 363 | CLANG_WARN_STRICT_PROTOTYPES = YES; 364 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 365 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 366 | CLANG_WARN_UNREACHABLE_CODE = YES; 367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 368 | COPY_PHASE_STRIP = NO; 369 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 370 | ENABLE_NS_ASSERTIONS = NO; 371 | ENABLE_STRICT_OBJC_MSGSEND = YES; 372 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 373 | GCC_C_LANGUAGE_STANDARD = gnu17; 374 | GCC_NO_COMMON_BLOCKS = YES; 375 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 376 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 377 | GCC_WARN_UNDECLARED_SELECTOR = YES; 378 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 379 | GCC_WARN_UNUSED_FUNCTION = YES; 380 | GCC_WARN_UNUSED_VARIABLE = YES; 381 | IPHONEOS_DEPLOYMENT_TARGET = 17.4; 382 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 383 | MTL_ENABLE_DEBUG_INFO = NO; 384 | MTL_FAST_MATH = YES; 385 | SDKROOT = iphoneos; 386 | SWIFT_COMPILATION_MODE = wholemodule; 387 | VALIDATE_PRODUCT = YES; 388 | }; 389 | name = Release; 390 | }; 391 | 0B7844772BDE93FC003D7B3C /* Debug */ = { 392 | isa = XCBuildConfiguration; 393 | buildSettings = { 394 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 395 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 396 | CODE_SIGN_STYLE = Automatic; 397 | CURRENT_PROJECT_VERSION = 1; 398 | DEVELOPMENT_ASSET_PATHS = "\"CursoiOS/Preview Content\""; 399 | ENABLE_PREVIEWS = YES; 400 | GENERATE_INFOPLIST_FILE = YES; 401 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 402 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 403 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 404 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 405 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 406 | LD_RUNPATH_SEARCH_PATHS = ( 407 | "$(inherited)", 408 | "@executable_path/Frameworks", 409 | ); 410 | MARKETING_VERSION = 1.0; 411 | PRODUCT_BUNDLE_IDENTIFIER = com.aristidevs.CursoiOS; 412 | PRODUCT_NAME = "$(TARGET_NAME)"; 413 | SWIFT_EMIT_LOC_STRINGS = YES; 414 | SWIFT_VERSION = 5.0; 415 | TARGETED_DEVICE_FAMILY = "1,2"; 416 | }; 417 | name = Debug; 418 | }; 419 | 0B7844782BDE93FC003D7B3C /* Release */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 423 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 424 | CODE_SIGN_STYLE = Automatic; 425 | CURRENT_PROJECT_VERSION = 1; 426 | DEVELOPMENT_ASSET_PATHS = "\"CursoiOS/Preview Content\""; 427 | ENABLE_PREVIEWS = YES; 428 | GENERATE_INFOPLIST_FILE = YES; 429 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 430 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 431 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 432 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 433 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 434 | LD_RUNPATH_SEARCH_PATHS = ( 435 | "$(inherited)", 436 | "@executable_path/Frameworks", 437 | ); 438 | MARKETING_VERSION = 1.0; 439 | PRODUCT_BUNDLE_IDENTIFIER = com.aristidevs.CursoiOS; 440 | PRODUCT_NAME = "$(TARGET_NAME)"; 441 | SWIFT_EMIT_LOC_STRINGS = YES; 442 | SWIFT_VERSION = 5.0; 443 | TARGETED_DEVICE_FAMILY = "1,2"; 444 | }; 445 | name = Release; 446 | }; 447 | /* End XCBuildConfiguration section */ 448 | 449 | /* Begin XCConfigurationList section */ 450 | 0B7844632BDE93FB003D7B3C /* Build configuration list for PBXProject "CursoiOS" */ = { 451 | isa = XCConfigurationList; 452 | buildConfigurations = ( 453 | 0B7844742BDE93FC003D7B3C /* Debug */, 454 | 0B7844752BDE93FC003D7B3C /* Release */, 455 | ); 456 | defaultConfigurationIsVisible = 0; 457 | defaultConfigurationName = Release; 458 | }; 459 | 0B7844762BDE93FC003D7B3C /* Build configuration list for PBXNativeTarget "CursoiOS" */ = { 460 | isa = XCConfigurationList; 461 | buildConfigurations = ( 462 | 0B7844772BDE93FC003D7B3C /* Debug */, 463 | 0B7844782BDE93FC003D7B3C /* Release */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | 470 | /* Begin XCRemoteSwiftPackageReference section */ 471 | 0B815B5F2C03675A00DAE145 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */ = { 472 | isa = XCRemoteSwiftPackageReference; 473 | repositoryURL = "https://github.com/SDWebImage/SDWebImageSwiftUI"; 474 | requirement = { 475 | kind = upToNextMajorVersion; 476 | minimumVersion = 3.0.4; 477 | }; 478 | }; 479 | /* End XCRemoteSwiftPackageReference section */ 480 | 481 | /* Begin XCSwiftPackageProductDependency section */ 482 | 0B815B602C03675A00DAE145 /* SDWebImageSwiftUI */ = { 483 | isa = XCSwiftPackageProductDependency; 484 | package = 0B815B5F2C03675A00DAE145 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */; 485 | productName = SDWebImageSwiftUI; 486 | }; 487 | /* End XCSwiftPackageProductDependency section */ 488 | }; 489 | rootObject = 0B7844602BDE93FB003D7B3C /* Project object */; 490 | } 491 | -------------------------------------------------------------------------------- /CursoiOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CursoiOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CursoiOS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "3f7bccddd9f7a6da7c38f78f12dc05fb594b560bb42e698a68570a70f4650e54", 3 | "pins" : [ 4 | { 5 | "identity" : "sdwebimage", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/SDWebImage/SDWebImage.git", 8 | "state" : { 9 | "revision" : "5642d1ffe3dbe628592443bd14154e31929727b4", 10 | "version" : "5.19.2" 11 | } 12 | }, 13 | { 14 | "identity" : "sdwebimageswiftui", 15 | "kind" : "remoteSourceControl", 16 | "location" : "https://github.com/SDWebImage/SDWebImageSwiftUI", 17 | "state" : { 18 | "revision" : "b7af5e6bd9c2987e41730400d1baad13d74a141a", 19 | "version" : "3.0.4" 20 | } 21 | } 22 | ], 23 | "version" : 3 24 | } 25 | -------------------------------------------------------------------------------- /CursoiOS.xcodeproj/xcshareddata/xcschemes/CursoiOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /CursoiOS.xcodeproj/xcuserdata/aris.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /CursoiOS.xcodeproj/xcuserdata/aris.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CursoiOS.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 0B7844672BDE93FB003D7B3C 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/BackgroundApp.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.125", 9 | "green" : "0.043", 10 | "red" : "0.055" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/BackgroundComponent.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.322", 9 | "green" : "0.153", 10 | "red" : "0.145" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/BackgroundComponentSelected.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.157", 9 | "green" : "0.090", 10 | "red" : "0.078" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/material-symbols--10k.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "material-symbols--10k.svg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/material-symbols--10k.imageset/material-symbols--10k.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/swift.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "swiftui-96x96_2x.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /CursoiOS/Assets.xcassets/swift.imageset/swiftui-96x96_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArisGuimera/iOS-Expert/ad31448caa1a9ec91e406ecb5f3930c6b9c51674/CursoiOS/Assets.xcassets/swift.imageset/swiftui-96x96_2x.png -------------------------------------------------------------------------------- /CursoiOS/Components/ButtonExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ButtonExample.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 1/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ButtonExample: View { 11 | 12 | var body: some View { 13 | Button("Hola") { 14 | print("Holiwi") 15 | } 16 | Button(action: {print("holiwi")}, label: { 17 | Text("Hola") 18 | .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/, height: 50) 19 | .foregroundColor(.white) 20 | .background(.blue) 21 | .cornerRadius(10) 22 | }) 23 | } 24 | } 25 | 26 | struct Counter:View { 27 | @State var subscribersNumber = 0 28 | var body: some View { 29 | Button(action: { 30 | subscribersNumber += 1 31 | }, label: { 32 | Text("Suscriptores: \(subscribersNumber)") 33 | .bold() 34 | .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/) 35 | .frame(height: 50) 36 | .foregroundColor(.white) 37 | .background(.red) 38 | .cornerRadius(10) 39 | }) 40 | } 41 | } 42 | 43 | #Preview { 44 | Counter() 45 | } 46 | -------------------------------------------------------------------------------- /CursoiOS/Components/CustomDialog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomDialog.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 29/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CustomDialog: View { 11 | 12 | let closeDialog:() -> Void 13 | let onDismissOutside:Bool 14 | let content:Content 15 | 16 | 17 | var body: some View { 18 | ZStack{ 19 | Rectangle().fill(.gray.opacity(0.7)) 20 | .ignoresSafeArea() 21 | .onTapGesture { 22 | if onDismissOutside{ 23 | withAnimation{ 24 | closeDialog() 25 | } 26 | } 27 | } 28 | 29 | content 30 | .frame(width: UIScreen.main.bounds.size.width-100, height: 300) 31 | .padding() 32 | .background(.white) 33 | .cornerRadius(16) 34 | .overlay(alignment: .topTrailing){ 35 | Button(action: { 36 | withAnimation{ 37 | closeDialog() 38 | } 39 | }, label: { 40 | Image(systemName: "xmark.circle") 41 | }).foregroundColor(.gray).padding(16) 42 | } 43 | 44 | 45 | }.ignoresSafeArea() 46 | .frame(width: UIScreen.main.bounds.size.width, 47 | height: UIScreen.main.bounds.size.height, 48 | alignment: .center) 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /CursoiOS/Components/ImageExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageExample.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 1/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ImageExample: View { 11 | var body: some View { 12 | Image("swift") 13 | .resizable() 14 | .scaledToFit() 15 | .frame(width: 50, height: 90) 16 | 17 | Image(systemName: "figure.walk") 18 | .resizable() 19 | } 20 | } 21 | 22 | #Preview { 23 | ImageExample() 24 | } 25 | -------------------------------------------------------------------------------- /CursoiOS/Components/LabelExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LabelExample.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 1/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct LabelExample: View { 11 | var body: some View { 12 | Label("SUSCRIBETE", image: "swift") 13 | Label("SUSCRIBETE", systemImage: "figure.badminton") 14 | Label( 15 | title: { /*@START_MENU_TOKEN@*/Text("Label")/*@END_MENU_TOKEN@*/ }, 16 | icon: { Image("swift") 17 | .resizable() 18 | .scaledToFit() 19 | .frame(height: 30) } 20 | ) 21 | } 22 | } 23 | 24 | #Preview { 25 | LabelExample() 26 | } 27 | -------------------------------------------------------------------------------- /CursoiOS/Components/ListExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListExample.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 24/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | var pokemons = [ 11 | Pokemon(name: "Pikachu"), 12 | Pokemon(name: "Charmander"), 13 | Pokemon(name: "Charmilion"), 14 | Pokemon(name: "Charizard"), 15 | Pokemon(name: "AristiDevs") 16 | ] 17 | var digimons = [ 18 | Digimon(name: "Agumon"), 19 | Digimon(name: "Graymon"), 20 | Digimon(name: "AristiDevsMon"), 21 | Digimon(name: "AristiDevsMon"), 22 | Digimon(name: "Supermon"), 23 | 24 | ] 25 | 26 | struct ListExample: View { 27 | var body: some View { 28 | // List{ 29 | // Text("Prueba") 30 | // Text("Prueba") 31 | // Text("Prueba") 32 | // } 33 | 34 | // List{ 35 | // ForEach(pokemons, id:\.name) { pokemon in 36 | // /*@START_MENU_TOKEN@*/Text(pokemon.name)/*@END_MENU_TOKEN@*/ 37 | // } 38 | // } 39 | 40 | // List(digimons){ digimon in 41 | // Text(digimon.name) 42 | // } 43 | 44 | // List{ 45 | // ForEach(digimons){digimon in 46 | // Text(digimon.name) 47 | // 48 | // } 49 | // } 50 | 51 | List{ 52 | Section(header: Text("Pokemons")) { 53 | ForEach(pokemons, id:\.name) { pokemon in 54 | /*@START_MENU_TOKEN@*/Text(pokemon.name)/*@END_MENU_TOKEN@*/ 55 | } 56 | } 57 | Section(header: Text("Digimons")) { 58 | ForEach(digimons){digimon in 59 | Text(digimon.name) 60 | } 61 | } 62 | }.listStyle(.automatic) 63 | 64 | } 65 | } 66 | 67 | struct Pokemon{ 68 | let name:String 69 | } 70 | 71 | struct Digimon: Identifiable{ 72 | var id = UUID() 73 | let name:String 74 | } 75 | 76 | #Preview { 77 | ListExample() 78 | } 79 | -------------------------------------------------------------------------------- /CursoiOS/Components/MapExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MapExample.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 29/5/24. 6 | // 7 | 8 | import SwiftUI 9 | import MapKit 10 | 11 | struct MapExample: View { 12 | 13 | @State var position = MapCameraPosition.region( 14 | MKCoordinateRegion( 15 | center: CLLocationCoordinate2D(latitude:28.4765824, longitude:-16.336624), 16 | span: MKCoordinateSpan(latitudeDelta: 0.05 17 | , longitudeDelta: 0.05) 18 | ) 19 | ) 20 | 21 | var body: some View { 22 | ZStack{ 23 | MapReader{ proxy in 24 | 25 | Map(position: $position){ 26 | // Marker("Pollito frito", coordinate: CLLocationCoordinate2D(latitude:28.4765824, longitude:-16.336624)) 27 | 28 | Annotation("Pollito Frito", coordinate: CLLocationCoordinate2D(latitude:28.4765824, longitude:-16.336624)){ 29 | Circle().frame(height: 30) 30 | }.annotationTitles(.visible) 31 | } 32 | .mapStyle(.hybrid(elevation: .realistic, showsTraffic: true)) 33 | // .onMapCameraChange { context in 34 | // print("Estamos en: \(context.region)") 35 | // } 36 | .onMapCameraChange(frequency: .continuous) { context in 37 | print("Estamos en: \(context.region)") 38 | } 39 | .onTapGesture { coord in 40 | if let coordinates = proxy.convert(coord, from: .local){ 41 | withAnimation{ 42 | position = MapCameraPosition.region( 43 | MKCoordinateRegion( 44 | center: CLLocationCoordinate2D(latitude:coordinates.latitude, longitude:coordinates.longitude), 45 | span: MKCoordinateSpan(latitudeDelta: 0.05 46 | , longitudeDelta: 0.05) 47 | ) 48 | ) 49 | } 50 | } 51 | } 52 | } 53 | 54 | 55 | VStack{ 56 | Spacer() 57 | HStack{ 58 | Button("Ir al sur"){ 59 | withAnimation{ 60 | position = MapCameraPosition.region( 61 | MKCoordinateRegion( 62 | center: CLLocationCoordinate2D(latitude:28.0444416, longitude:-16.5376432), 63 | span: MKCoordinateSpan(latitudeDelta: 0.05 64 | , longitudeDelta: 0.05) 65 | ) 66 | ) 67 | } 68 | }.padding(32).background(.white).padding() 69 | Button("Ir al norte"){ 70 | withAnimation{ 71 | position = MapCameraPosition.region( 72 | MKCoordinateRegion( 73 | center: CLLocationCoordinate2D(latitude:28.4765824, longitude:-16.336624), 74 | span: MKCoordinateSpan(latitudeDelta: 0.05 75 | , longitudeDelta: 0.05) 76 | ) 77 | ) 78 | } 79 | 80 | }.padding(32).background(.white).padding() 81 | } 82 | } 83 | } 84 | 85 | } 86 | } 87 | 88 | #Preview { 89 | MapExample() 90 | } 91 | -------------------------------------------------------------------------------- /CursoiOS/Components/TextExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextExample.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 1/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct TextExample: View { 11 | var body: some View { 12 | VStack{ 13 | Text("Hello, World!").font(.headline) 14 | Text("Custom") 15 | .font(.system(size: 40, weight: .light, design: .monospaced)) 16 | .italic() 17 | .bold() 18 | .underline() 19 | .foregroundColor(/*@START_MENU_TOKEN@*/.blue/*@END_MENU_TOKEN@*/) 20 | .background(.red) 21 | Text("aris aris aris aris aris aris") 22 | .frame(width: 150) 23 | .lineLimit(3) 24 | .lineSpacing(125) 25 | } 26 | } 27 | } 28 | 29 | #Preview { 30 | TextExample() 31 | } 32 | -------------------------------------------------------------------------------- /CursoiOS/Components/TextFieldExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextFieldExample.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 1/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct TextFieldExample: View { 11 | @State var email = "" 12 | @State var password = "" 13 | var body: some View { 14 | 15 | VStack { 16 | TextField("Escribe tu email", text: $email) 17 | .keyboardType(.emailAddress) 18 | .padding(16) 19 | .background(.gray.opacity(0.2)) 20 | .cornerRadius(16) 21 | .padding(.horizontal, 32) 22 | .onChange(of: email) { oldValue, newValue in 23 | print("El antiguo valor era \(oldValue) y el nuevo es \(newValue)") 24 | } 25 | SecureField("Escribe tu contraseña", text: $password) 26 | .keyboardType(.emailAddress) 27 | .padding(16) 28 | .background(.gray.opacity(0.2)) 29 | .cornerRadius(16) 30 | .padding(.horizontal, 32) 31 | .onChange(of: password) { oldValue, newValue in 32 | print("El antiguo valor era \(oldValue) y el nuevo es \(newValue)") 33 | } 34 | } 35 | } 36 | } 37 | 38 | #Preview { 39 | TextFieldExample() 40 | } 41 | -------------------------------------------------------------------------------- /CursoiOS/CursoiOSApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CursoiOSApp.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 28/4/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct CursoiOSApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | MainView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CursoiOS/Exercises/Exercise1.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 28/4/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct Exercise1: View { 11 | var body: some View { 12 | VStack { 13 | HStack{ 14 | Rectangle() 15 | .foregroundColor(.blue) 16 | Rectangle() 17 | .foregroundColor(.orange) 18 | Rectangle() 19 | .foregroundColor(.yellow) 20 | }.frame(height: 100) 21 | Rectangle() 22 | .frame(height: 100) 23 | .foregroundColor(.orange) 24 | HStack{ 25 | Circle() 26 | .foregroundColor(.green) 27 | Rectangle() 28 | Circle() 29 | .foregroundColor(.indigo) 30 | }.frame(height: 250) 31 | Rectangle() 32 | .frame(height: 100) 33 | .foregroundColor(.orange) 34 | HStack{ 35 | Rectangle() 36 | .foregroundColor(.blue) 37 | Rectangle() 38 | .foregroundColor(.orange) 39 | Rectangle() 40 | .foregroundColor(.yellow) 41 | }.frame(height: 100) 42 | } 43 | .background(.red) 44 | } 45 | } 46 | 47 | 48 | #Preview { 49 | Exercise1() 50 | } 51 | -------------------------------------------------------------------------------- /CursoiOS/FavPlaces/FavPlaces.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FavPlaces.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 29/5/24. 6 | // 7 | 8 | import SwiftUI 9 | import MapKit 10 | 11 | struct FavPlaces: View { 12 | 13 | @State var position = MapCameraPosition.region( 14 | MKCoordinateRegion( 15 | center: CLLocationCoordinate2D(latitude: 40.419969, longitude: -3.702561), 16 | span:MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1) 17 | ) 18 | ) 19 | 20 | @State var places:[Place] = [] 21 | @State var showPopUp:CLLocationCoordinate2D? = nil 22 | @State var name:String = "" 23 | @State var fav:Bool = false 24 | @State var showSheet = false 25 | 26 | let height = stride(from: 0.3, through: 0.3, by: 0.1).map{ PresentationDetent.fraction($0)} 27 | 28 | var body: some View { 29 | ZStack{ 30 | MapReader{ proxy in 31 | Map(position: $position){ 32 | ForEach(places){ place in 33 | Annotation(place.name, coordinate: place.coordinates) { 34 | let color = if place.fav { Color.yellow }else{ Color.black } 35 | 36 | Circle() 37 | .stroke(color, lineWidth: 3) 38 | .fill(.white) 39 | .frame(width: 35, height: 35) 40 | } 41 | } 42 | } 43 | .onTapGesture { coord in 44 | if let coordinates = proxy.convert(coord, from: .local){ 45 | showPopUp = coordinates 46 | } 47 | } 48 | .overlay{ 49 | VStack{ 50 | 51 | Button("Show list"){ 52 | showSheet = true 53 | } 54 | .padding(.horizontal, 16) 55 | .padding(.vertical, 8) 56 | .background(.white) 57 | .cornerRadius(16) 58 | .padding(16) 59 | 60 | Spacer() 61 | } 62 | } 63 | } 64 | 65 | if showPopUp != nil{ 66 | let view = VStack{ 67 | Text("Añadir localización").font(.title2).bold() 68 | Spacer() 69 | TextField("Nombre", text: $name).padding(.bottom, 8) 70 | Toggle("¿Es un lugar favorito?", isOn: $fav) 71 | Spacer() 72 | Button("Guardar"){ 73 | savePlace(name: name, fav: fav, coordinates: showPopUp!) 74 | clearForm() 75 | } 76 | } 77 | 78 | withAnimation{ 79 | CustomDialog(closeDialog: { 80 | showPopUp = nil 81 | }, onDismissOutside: false, content: view) 82 | } 83 | } 84 | 85 | }.sheet(isPresented: $showSheet) { 86 | 87 | ScrollView(.horizontal){ 88 | LazyHStack{ 89 | ForEach(places){ place in 90 | let color = if place.fav{ Color.yellow.opacity(0.5) }else{ Color.black.opacity(0.5)} 91 | VStack{ 92 | Text(place.name).font(.title3).bold() 93 | }.frame(width: 150, height: 100).overlay{ 94 | RoundedRectangle(cornerRadius: 20).stroke(color, lineWidth: 1) 95 | }.shadow(radius: 5).padding(.horizontal, 8) 96 | .onTapGesture { 97 | animateCamera(coordinates: place.coordinates) 98 | showSheet = false 99 | } 100 | } 101 | } 102 | }.presentationDetents(Set(height)) 103 | }.onAppear{ 104 | loadPlaces() 105 | } 106 | } 107 | 108 | func animateCamera(coordinates:CLLocationCoordinate2D){ 109 | withAnimation{ 110 | position = MapCameraPosition.region( 111 | MKCoordinateRegion( 112 | center:coordinates, 113 | span:MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1) 114 | ) 115 | ) 116 | } 117 | } 118 | 119 | func savePlace(name:String, fav:Bool, coordinates:CLLocationCoordinate2D){ 120 | let place = Place(name: name, coordinates: coordinates, fav: fav) 121 | places.append(place) 122 | savePlaces() 123 | } 124 | 125 | func clearForm(){ 126 | name = "" 127 | fav = false 128 | showPopUp = nil 129 | } 130 | 131 | } 132 | 133 | #Preview { 134 | FavPlaces() 135 | } 136 | 137 | extension FavPlaces{ 138 | 139 | func savePlaces(){ 140 | if let encodeData = try? JSONEncoder().encode(places){ 141 | UserDefaults.standard.set(encodeData, forKey: "places") 142 | } 143 | } 144 | 145 | func loadPlaces(){ 146 | if let savedPlaces = UserDefaults.standard.data(forKey: "places"), 147 | let decodedPlaces = try? JSONDecoder().decode([Place].self, from: savedPlaces){ 148 | places = decodedPlaces 149 | } 150 | 151 | } 152 | 153 | 154 | 155 | } 156 | -------------------------------------------------------------------------------- /CursoiOS/FavPlaces/model/Place.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Place.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 29/5/24. 6 | // 7 | 8 | import Foundation 9 | import MapKit 10 | 11 | struct Place:Identifiable, Codable{ 12 | var id = UUID() 13 | var name:String 14 | var coordinates:CLLocationCoordinate2D 15 | var fav:Bool 16 | 17 | enum CodingKeys:CodingKey{ 18 | case id, name, fav, latitude, longitude 19 | } 20 | 21 | init(id: UUID = UUID(), name: String, coordinates: CLLocationCoordinate2D, fav: Bool) { 22 | self.id = id 23 | self.name = name 24 | self.coordinates = coordinates 25 | self.fav = fav 26 | } 27 | 28 | init(from decoder: Decoder) throws { 29 | let container = try decoder.container(keyedBy: CodingKeys.self) 30 | let latitude = try container.decode(CLLocationDegrees.self, forKey: .latitude) 31 | let longitude = try container.decode(CLLocationDegrees.self, forKey: .longitude) 32 | 33 | coordinates = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) 34 | name = try container.decode(String.self, forKey: .name) 35 | fav = try container.decode(Bool.self, forKey: .fav) 36 | id = try container.decode(UUID.self, forKey: .id) 37 | } 38 | 39 | func encode(to encoder: Encoder) throws { 40 | var container = encoder.container(keyedBy: CodingKeys.self) 41 | try container.encode(coordinates.latitude, forKey: .latitude) 42 | try container.encode(coordinates.longitude, forKey: .longitude) 43 | try container.encode(name, forKey: .name) 44 | try container.encode(fav, forKey: .fav) 45 | try container.encode(id, forKey: .id) 46 | } 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /CursoiOS/IMC/IMCResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IMCResult.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 24/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct IMCResult: View { 11 | let userWeight:Double 12 | let userHeight:Double 13 | var body: some View { 14 | VStack{ 15 | Text("Tu resultado").font(.title).bold().foregroundColor(.white) 16 | let result = calculateImc(weight: userWeight, height: userHeight) 17 | InformationView(result:result) 18 | }.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity).background(.backgroundApp) 19 | } 20 | } 21 | 22 | func calculateImc(weight:Double, height:Double) -> Double{ 23 | let result = weight/((height/100)*(height/100)) 24 | return result 25 | } 26 | 27 | struct InformationView:View { 28 | let result:Double 29 | var body: some View { 30 | 31 | let information = getImcResult(result: result) 32 | 33 | VStack{ 34 | Spacer() 35 | Text(information.0).foregroundColor(information.2).font(.title).bold() 36 | Spacer() 37 | Text("\(result, specifier: "%.2f")").font(.system(size: 80)).bold().foregroundColor(.white) 38 | Spacer() 39 | Text(information.1).foregroundColor(.white).font(.title2).padding(.horizontal, 8) 40 | Spacer() 41 | 42 | }.frame(maxWidth: .infinity, maxHeight: .infinity).background(.backgroundComponent).cornerRadius(16).padding(16) 43 | } 44 | } 45 | 46 | func getImcResult(result:Double) -> (String, String, Color){ 47 | let title:String 48 | let description:String 49 | let color:Color 50 | 51 | switch result{ 52 | case 0.00...19.99: 53 | title = "Peso bajo" 54 | description = "Estás por debajo del peso recomendado según el IMC." 55 | color = .yellow 56 | case 20.00...24.99: 57 | title = "Peso Normal" 58 | description = "Estás en el peso recomendado según el IMC." 59 | color = .green 60 | case 25.00...29.99: 61 | title = "Sobrepeso" 62 | description = "Estás por encima del peso recomendado según el IMC." 63 | color = .orange 64 | case 30.00...100: 65 | title = "Obesidad" 66 | description = "Estás muy por encima del peso recomendado según el IMC." 67 | color = .red 68 | default: 69 | title = "ERROR" 70 | description = "Ha ocurrido un error" 71 | color = Color.gray 72 | } 73 | 74 | return (title, description, color) 75 | } 76 | 77 | #Preview { 78 | IMCResult(userWeight: 80, userHeight: 190) 79 | } 80 | -------------------------------------------------------------------------------- /CursoiOS/IMC/IMCView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IMCView.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 15/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct IMCView: View { 11 | 12 | // init(){ 13 | // UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.white] 14 | // } 15 | 16 | @State var gender:Int = 0 17 | @State var age:Int = 18 18 | @State var weight:Int = 80 19 | @State var height:Double = 150 20 | 21 | var body: some View { 22 | VStack{ 23 | HStack{ 24 | ToggleButton(text: "Hombre", imageName: "heart.fill", gender: 0, selectedGender: $gender ) 25 | ToggleButton(text: "Mujer", imageName: "star.fill", gender: 1, selectedGender: $gender) 26 | } 27 | HeightCalculator(selectedHeight: $height) 28 | HStack{ 29 | CounterButton(text: "Edad", number: $age) 30 | CounterButton(text: "Peso", number: $weight) 31 | } 32 | IMCCalculateButton(userWeight: Double(weight), userHeight: height) 33 | }.frame(maxWidth: .infinity, maxHeight: .infinity) 34 | .background(.backgroundApp) 35 | .toolbar{ 36 | ToolbarItem(placement: .principal) { 37 | Text("IMC Calculator").bold().foregroundColor(.white) 38 | } 39 | } 40 | // .navigationBarBackButtonHidden() 41 | // .navigationTitle("Imc Calculator") 42 | } 43 | } 44 | 45 | struct IMCCalculateButton:View { 46 | let userWeight:Double 47 | let userHeight:Double 48 | 49 | var body: some View { 50 | NavigationStack{ 51 | NavigationLink(destination:{IMCResult(userWeight: userWeight, userHeight: userHeight)}){ 52 | Text("Calcular").font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/).bold().foregroundColor(.purple) 53 | .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: 100).background(.backgroundComponent) 54 | } 55 | } 56 | } 57 | } 58 | 59 | struct ToggleButton:View { 60 | let text:String 61 | let imageName:String 62 | let gender:Int 63 | @Binding var selectedGender:Int 64 | 65 | var body: some View { 66 | 67 | let color = if(gender == selectedGender){ 68 | Color.backgroundComponentSelected 69 | }else{ 70 | Color.backgroundComponent 71 | } 72 | 73 | Button(action: { 74 | selectedGender = gender 75 | }) { 76 | VStack{ 77 | Image(systemName: imageName) 78 | .resizable() 79 | .scaledToFit() 80 | .frame(height: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/) 81 | .foregroundColor(.white) 82 | InformationText(text: text) 83 | }.frame(maxWidth: .infinity, maxHeight: .infinity).background(color) 84 | } 85 | 86 | } 87 | } 88 | 89 | struct InformationText:View { 90 | let text:String 91 | var body: some View { 92 | Text(text).font(.largeTitle).bold().foregroundColor(.white) 93 | } 94 | } 95 | 96 | struct TitleText:View { 97 | let text:String 98 | 99 | var body: some View { 100 | Text(text).font(.title2).foregroundColor(.gray) 101 | } 102 | } 103 | 104 | struct HeightCalculator:View { 105 | @Binding var selectedHeight:Double 106 | 107 | var body: some View { 108 | VStack{ 109 | TitleText(text: "Altura") 110 | InformationText(text: "\(Int(selectedHeight)) cm") 111 | Slider(value: $selectedHeight, in:100...220, step: 1).accentColor(.purple).padding(.horizontal, 16) 112 | }.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity).background(.backgroundComponent) 113 | } 114 | } 115 | 116 | struct CounterButton:View { 117 | let text:String 118 | @Binding var number:Int 119 | var body: some View { 120 | VStack{ 121 | TitleText(text: text) 122 | InformationText(text: String(number)) 123 | HStack{ 124 | Button(action:{ 125 | if(number > 0){ 126 | number -= 1 127 | } 128 | }){ 129 | ZStack{ 130 | Circle() 131 | .frame(width: 70, height: 70) 132 | .foregroundColor(.purple) 133 | Image(systemName: "minus") 134 | .resizable() 135 | .scaledToFit() 136 | .foregroundColor(.white) 137 | .frame(width: 25, height: 25) 138 | 139 | } 140 | } 141 | Button(action:{ 142 | if(number < 100){ 143 | number += 1 144 | } 145 | }){ 146 | ZStack{ 147 | Circle() 148 | .frame(width: 70, height: 70) 149 | .foregroundColor(.purple) 150 | Image(systemName: "plus") 151 | .resizable() 152 | .foregroundColor(.white) 153 | .frame(width: 25, height: 25) 154 | 155 | } 156 | } 157 | } 158 | }.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity).background(.backgroundComponent) 159 | } 160 | } 161 | 162 | #Preview { 163 | // ToggleButton(text: "Aris", imageName: "heart.fill", index: 0) 164 | IMCView() 165 | } 166 | -------------------------------------------------------------------------------- /CursoiOS/MainView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainView.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 28/4/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MainView: View { 11 | var body: some View { 12 | MenuView() 13 | } 14 | } 15 | 16 | #Preview { 17 | MainView() 18 | } 19 | -------------------------------------------------------------------------------- /CursoiOS/MenuView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuView.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 15/5/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MenuView: View { 11 | var body: some View { 12 | NavigationStack{ 13 | List{ 14 | NavigationLink(destination:IMCView()){ 15 | Text("IMC Calculator") 16 | } 17 | NavigationLink(destination:SuperheroSearcher()){ 18 | Text("Superhero finder") 19 | } 20 | NavigationLink(destination: FavPlaces()){ 21 | Text("Fav Places") 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | MenuView() 30 | } 31 | -------------------------------------------------------------------------------- /CursoiOS/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CursoiOS/Superhero/ApiNetwork.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ApiNetwork.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 26/5/24. 6 | // 7 | 8 | import Foundation 9 | 10 | class ApiNetwork{ 11 | 12 | struct Wrapper:Codable{ 13 | let response:String 14 | let results:[Superhero] 15 | } 16 | 17 | struct Superhero:Codable, Identifiable{ 18 | let id:String 19 | let name:String 20 | let image:ImageSuperhero 21 | } 22 | 23 | struct ImageSuperhero:Codable{ 24 | let url:String 25 | } 26 | 27 | struct SuperheroCompleted:Codable{ 28 | let id:String 29 | let name:String 30 | let image:ImageSuperhero 31 | let powerstats:Powerstats 32 | let biography:Biography 33 | } 34 | 35 | struct Powerstats:Codable{ 36 | let intelligence:String 37 | let strength:String 38 | let speed:String 39 | let durability:String 40 | let power:String 41 | let combat:String 42 | } 43 | 44 | struct Biography:Codable{ 45 | let alignment:String 46 | let publisher:String 47 | let aliases:[String] 48 | let fullName:String 49 | 50 | enum CodingKeys:String, CodingKey{ 51 | case fullName = "full-name" 52 | case alignment = "alignment" 53 | case publisher = "publisher" 54 | case aliases = "aliases" 55 | } 56 | } 57 | 58 | func getHeroesByQuery(query:String) async throws -> Wrapper{ 59 | let url = URL(string: "https://superheroapi.com/api/79c99fda9894cf4017793cdb40721cb6/search/\(query)")! 60 | 61 | let (data, _) = try await URLSession.shared.data(from: url) 62 | 63 | let wrapper = try JSONDecoder().decode(Wrapper.self, from: data) 64 | return wrapper 65 | } 66 | 67 | func getHeroById(id:String) async throws -> SuperheroCompleted{ 68 | let url = URL(string: "https://superheroapi.com/api/79c99fda9894cf4017793cdb40721cb6/\(id)")! 69 | 70 | let (data, _) = try await URLSession.shared.data(from: url) 71 | 72 | return try JSONDecoder().decode(SuperheroCompleted.self, from: data) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /CursoiOS/Superhero/SuperheroDetail.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SuperheroDetail.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 26/5/24. 6 | // 7 | 8 | import SwiftUI 9 | import SDWebImageSwiftUI 10 | import Charts 11 | 12 | struct SuperheroDetail: View { 13 | let id:String 14 | 15 | @State var superhero:ApiNetwork.SuperheroCompleted? = nil 16 | @State var loading:Bool = true 17 | 18 | var body: some View { 19 | VStack{ 20 | if loading{ 21 | ProgressView().tint(.white) 22 | }else if let superhero = superhero{ 23 | WebImage(url: URL(string: superhero.image.url)) 24 | .resizable() 25 | .scaledToFill() 26 | .frame(height: 250) 27 | .clipped() 28 | Text(superhero.name).bold().font(.title).foregroundColor(.white) 29 | ForEach(superhero.biography.aliases, id: \.self){ alias in 30 | Text(alias).foregroundColor(.gray).italic() 31 | } 32 | SuperheroStats(stats: superhero.powerstats) 33 | Spacer() 34 | } 35 | }.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity) 36 | .background(.backgroundApp) 37 | .onAppear{ 38 | Task{ 39 | do{ 40 | superhero = try await ApiNetwork().getHeroById(id: id) 41 | }catch{ 42 | superhero = nil 43 | } 44 | loading = false 45 | } 46 | } 47 | } 48 | } 49 | 50 | struct SuperheroStats:View { 51 | let stats:ApiNetwork.Powerstats 52 | var body: some View { 53 | VStack{ 54 | 55 | Chart{ 56 | SectorMark(angle: .value("Count",Int(stats.combat) ?? 0), 57 | innerRadius: .ratio(0.6), 58 | angularInset: 5 59 | ).cornerRadius(5) 60 | .foregroundStyle(by: .value("Category", "Combat")) 61 | 62 | SectorMark(angle: .value("Count",Int(stats.durability) ?? 0), 63 | innerRadius: .ratio(0.6), 64 | angularInset: 5 65 | ).cornerRadius(5) 66 | .foregroundStyle(by: .value("Category", "Durability")) 67 | 68 | SectorMark(angle: .value("Count",Int(stats.intelligence) ?? 0), 69 | innerRadius: .ratio(0.6), 70 | angularInset: 5 71 | ).cornerRadius(5) 72 | .foregroundStyle(by: .value("Category", "Intelligence")) 73 | 74 | SectorMark(angle: .value("Count",Int(stats.power) ?? 0), 75 | innerRadius: .ratio(0.6), 76 | angularInset: 5 77 | ).cornerRadius(5) 78 | .foregroundStyle(by: .value("Category", "Power")) 79 | 80 | SectorMark(angle: .value("Count",Int(stats.speed) ?? 0), 81 | innerRadius: .ratio(0.6), 82 | angularInset: 5 83 | ).cornerRadius(5) 84 | .foregroundStyle(by: .value("Category", "Speed")) 85 | 86 | SectorMark(angle: .value("Count",Int(stats.strength) ?? 0), 87 | innerRadius: .ratio(0.6), 88 | angularInset: 5 89 | ).cornerRadius(5) 90 | .foregroundStyle(by: .value("Category", "Strength")) 91 | } 92 | 93 | }.padding(16).frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: 350) 94 | .background(.white) 95 | .cornerRadius(16) 96 | .padding(24) 97 | } 98 | } 99 | 100 | #Preview { 101 | SuperheroDetail(id:"1") 102 | } 103 | -------------------------------------------------------------------------------- /CursoiOS/Superhero/SuperheroSearcher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SuperheroSearcher.swift 3 | // CursoiOS 4 | // 5 | // Created by Arístides Guimerá Orozco on 26/5/24. 6 | // 7 | 8 | import SwiftUI 9 | import SDWebImageSwiftUI 10 | 11 | struct SuperheroSearcher: View { 12 | @State var superheroName:String = "" 13 | @State var wrapper:ApiNetwork.Wrapper? = nil 14 | @State var loading:Bool = false 15 | var body: some View { 16 | VStack{ 17 | 18 | TextField("", text: $superheroName, prompt: Text("Superman...").font(.title2).bold().foregroundColor(.gray)).font(.title2) 19 | .bold() 20 | .foregroundColor(.white) 21 | .padding(16) 22 | .border(.purple, width: 1.5) 23 | .padding(8) 24 | .autocorrectionDisabled() 25 | .onSubmit { 26 | loading = true 27 | print(superheroName) 28 | Task{ 29 | do{ 30 | wrapper = try await ApiNetwork().getHeroesByQuery(query: superheroName) 31 | }catch{ 32 | print("Error") 33 | } 34 | loading = false 35 | } 36 | 37 | 38 | } 39 | 40 | if loading{ 41 | ProgressView().tint(.white) 42 | } 43 | 44 | NavigationStack{ 45 | List(wrapper?.results ?? []){ superhero in 46 | ZStack{ 47 | SuperheroItem(superhero: superhero) 48 | NavigationLink(destination: SuperheroDetail(id: superhero.id)){EmptyView()}.opacity(0) 49 | }.listRowBackground(Color.backgroundApp) 50 | 51 | }.listStyle(.plain) 52 | } 53 | Spacer() 54 | }.frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: .infinity).background(.backgroundApp) 55 | } 56 | } 57 | 58 | struct SuperheroItem:View { 59 | let superhero:ApiNetwork.Superhero 60 | var body: some View { 61 | ZStack{ 62 | WebImage(url: URL(string: superhero.image.url)) 63 | .resizable() 64 | .indicator(.activity) 65 | .scaledToFill() 66 | .frame(height: 200) 67 | 68 | VStack{ 69 | Spacer() 70 | Text(superhero.name).foregroundColor(.white) 71 | .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/) 72 | .bold() 73 | .padding() 74 | .frame(maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/) 75 | .background(.white.opacity(0.5)) 76 | } 77 | }.frame(height: 200).cornerRadius(32) 78 | 79 | } 80 | } 81 | 82 | #Preview { 83 | SuperheroSearcher() 84 | } 85 | -------------------------------------------------------------------------------- /CursoiOS/sintaxis/CursoiOS.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | var greeting = "Hello, playground" 4 | var name = "Aris" 5 | let name2 = "Aris" 6 | var age = "30" 7 | age = "31" 8 | 9 | // TIPOS DE VARIABLES 10 | 11 | //CHAR 12 | var symbol:Character = "e" 13 | var symbol2:Character = "\u{2665}" 14 | print(symbol2) 15 | 16 | //STRING 17 | var dogName:String = "Bimbo" 18 | 19 | //INT 20 | var year:Int = 2024 21 | 22 | //FLOAT 23 | var piFloat:Float = 3.1421312312412421412445125125215 24 | print(piFloat) 25 | 26 | //DOUBLE 27 | var piDouble:Double = 3.1421312312412421412445125125215 28 | print(piDouble) 29 | 30 | //Boolean BOOL 31 | var imHappy = true 32 | 33 | //Operadores aritmeticos 34 | var a:Int = 5 35 | let b:Int = 10 36 | 37 | var sum = a + b //Suma 38 | var subtract = a - b //Resta 39 | var multiply = a * b //Multiplicación 40 | var divide = a / b //Division 41 | var module = a % b //Módulo 42 | 43 | //Operadores de asignación 44 | var example = 5 45 | 46 | example += 10 //Suma 47 | example -= 10 //Resta 48 | example *= 10 //Multiplicacion 49 | example /= 10 //División 50 | example %= 10 //Modulo 51 | 52 | //Operadores lógicos comparación 53 | let age2 = 18 54 | 55 | let isOlder = age2 > 18 56 | let isYounger = age2 < 18 57 | let isEqual = age2 == 35 58 | let isNotEqual = age2 != 35 59 | let isOlderOrEqual = age2 >= 18 60 | let isYoungerOrEqual = age2 <= 18 61 | 62 | let isSunny:Bool = true 63 | let temperature:Int = 26 64 | 65 | let isPleasant:Bool = temperature > 25 && isSunny //AND 66 | let goToBeach:Bool = temperature > 25 || isSunny //OR 67 | let wearHat:Bool = !isSunny 68 | 69 | //Conversiones 70 | let integerNumber:Int = 34 71 | let decimalNumber:Double = 25.65 72 | let superNumber:Double = Double(integerNumber) + decimalNumber 73 | let superNumber2:Int = integerNumber + Int(decimalNumber) 74 | print(superNumber) 75 | 76 | /**Ejercicio 1 77 | Registro de Asistencia: Declara una variable asistencias y asígnale un número de asistencias a una clase. 78 | Declara una variable totalClases y asígnale el número total de clases. 79 | Calcula el porcentaje de asistencia utilizando la fórmula: Porcentaje = (Asistencias / TotalClases) * 100. 80 | Imprime el porcentaje de asistencia. */ 81 | 82 | let asistencias = 10 83 | let totalClases = 20 84 | let resultadoAsistencia:Double = (Double(asistencias)/Double(totalClases)) * 100 85 | print("El resultado de asistencia es \(resultadoAsistencia)") 86 | 87 | 88 | /** Ejercicio 2 89 | Calculadora de IMC (Índice de Masa Corporal): 90 | Declara dos variables: peso (en kilogramos) y altura (en metros). 91 | Calcula el IMC utilizando la fórmula: IMC = peso / (altura * altura). 92 | Imprime el resultado.*/ 93 | 94 | let peso:Float = 88 95 | let altura:Float = 1.88 96 | let resultadoIMC = peso/(altura * altura) 97 | print("Tu IMC es de \(resultadoIMC)") 98 | 99 | 100 | /** Ejercicio 3 101 | Cálculo de Descuento: 102 | Declara dos variables: precioOriginal y porcentajeDescuento. 103 | Calcula el precio después del descuento utilizando la fórmula: PrecioDescuento = PrecioOriginal - (PrecioOriginal * PorcentajeDescuento / 100). 104 | Imprime el precio original y el precio con descuento.*/ 105 | 106 | let precioOriginal:Double = 17.99 107 | let porcentajeDescuento:Double = 20 108 | 109 | let precioConDescuento = precioOriginal - (precioOriginal * porcentajeDescuento/100) 110 | print("El precio original es de \(precioOriginal) y con el descuento del \(porcentajeDescuento)% tu producto se queda en \(precioConDescuento)") 111 | 112 | 113 | //Funciones 114 | 115 | func showMyName(){ 116 | print("Hola, es mi primera funcion") 117 | } 118 | 119 | showMyName() 120 | 121 | func showMyCustomName(nombre:String){ 122 | print("Hola \(nombre)") 123 | } 124 | 125 | showMyCustomName(nombre: "Aris") 126 | 127 | func calculate(a:Int, b:Int){ 128 | let result = a + b 129 | print("El resultado es \(result)") 130 | } 131 | 132 | calculate(a: 10, b: 20) 133 | 134 | func calculate2(_ a:Int, _ b:Int){ 135 | let result = a + b 136 | print("El resultado es \(result)") 137 | } 138 | 139 | calculate2(20, 2) 140 | 141 | func calculate3(a:Int, b:Int) -> Int{ 142 | let result = a + b 143 | return result 144 | } 145 | 146 | let mySuperResult:Int = calculate3(a: 5, b: 10) 147 | print(mySuperResult) 148 | 149 | 150 | //IF-ELSE 151 | let userAge = 8 152 | 153 | if userAge >= 18 { 154 | print("Eres mayor de edad") 155 | }else{ 156 | print("Eres menor de edad") 157 | } 158 | 159 | func greeting(_ hour:Int){ 160 | if hour < 12{ 161 | print("Buenos días") 162 | }else if hour < 18{ 163 | print("Buenas tardes") 164 | }else{ 165 | print("Buenas noches") 166 | } 167 | } 168 | 169 | greeting(16) 170 | 171 | func getMonth(month:Int){ 172 | if month == 1{ 173 | print("Enero") 174 | }else if month == 2{ 175 | print("Febrero") 176 | }else if month == 3{ 177 | print("Marzo") 178 | }else if month == 4{ 179 | print("Abril") 180 | }else if month == 5{ 181 | print("Mayo") 182 | }else if month == 6{ 183 | print("Junio") 184 | }else if month == 7{ 185 | print("Julio") 186 | }else if month == 8{ 187 | print("Agosto") 188 | }else if month == 9{ 189 | print("Septiembre") 190 | }else if month == 10{ 191 | print("Octubre") 192 | }else if month == 11{ 193 | print("Noviembre") 194 | }else if month == 12{ 195 | print("Diciembre") 196 | }else{ 197 | print("Número invalido, añade otro") 198 | } 199 | } 200 | 201 | getMonth(month: 12) 202 | 203 | //SWITCH 204 | func getMonthWithSwitch(_ month:Int){ 205 | switch month{ 206 | case 1: print("Enero") 207 | case 2: print("Febrero") 208 | case 3: print("Marzo") 209 | case 4: print("Abril") 210 | case 5: print("Mayo") 211 | case 6: print("Junio") 212 | case 7: print("Julio") 213 | case 8: print("Agosto") 214 | case 9: print("Septiembre") 215 | case 10: print("Octubre") 216 | case 11: print("Noviembre") 217 | case 12: print("Diciembre") 218 | default: print("Introduce un mes válido") 219 | } 220 | } 221 | 222 | getMonthWithSwitch(3) 223 | 224 | func getTrimester(_ month:Int){ 225 | switch month{ 226 | case 1, 2, 3: print("Primer trimestre") 227 | case 4, 5, 6: print("Segundo trimestre") 228 | case 7, 8, 9: print("Tercer trimestre") 229 | case 10, 11, 12: print("Cuarto trimestre") 230 | default: print("Introduce un mes válido") 231 | } 232 | } 233 | 234 | getTrimester(2) 235 | 236 | func getSemester(_ month:Int){ 237 | switch month{ 238 | case 1...6: print("Primer trimestre") 239 | case 7...12: print("Tercer trimestre") 240 | default: print("Introduce un mes válido") 241 | } 242 | } 243 | 244 | /** Ejercicio 4 245 | Calcula el área de un círculo: 246 | Crea una función que reciba el radio de un círculo y devuelva su área (PI * Radio * Radio). 247 | Luego pinta el resultado por pantalla. */ 248 | 249 | func calculateCircleArea(_ radius:Double) -> Double{ 250 | return Double.pi * radius * radius 251 | } 252 | 253 | let radius:Double = 10 254 | let result = calculateCircleArea(radius) 255 | print("El área de un círculo con un radio de \(radius) es de \(result)") 256 | 257 | /** Ejercicio 5 258 | Crea una función que reciba un número y con la ayuda de un IF pinte en pantalla si el número 259 | es positivo, negativo o cero */ 260 | 261 | func positiveOrNegative(_ number:Int){ 262 | if number > 0{ 263 | print("Positivo") 264 | } else if number < 0{ 265 | print("Negativo") 266 | }else{ 267 | print("Es cero") 268 | } 269 | } 270 | 271 | /** Ejercicio 6 272 | Crea una función que reciba un número y con la ayuda de un SWITCH pinte en pantalla si el número 273 | es positivo, negativo o cero */ 274 | 275 | func positiveOrNegativeSwitch(_ number:Int){ 276 | switch number{ 277 | case let x where x > 0: print("Positivo") 278 | case let x where x < 0: print("Negativo") 279 | default:print("Es cero") 280 | } 281 | } 282 | 283 | //ARRAYS 284 | var daysOfWeek:[String] = ["Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"] 285 | 286 | print(daysOfWeek[3]) 287 | daysOfWeek[3] = "Juernes" 288 | print(daysOfWeek[3]) 289 | 290 | print(daysOfWeek[0]) 291 | daysOfWeek.remove(at: 0) 292 | print(daysOfWeek[0]) 293 | 294 | daysOfWeek.append("AristiDevs") 295 | 296 | //BUCLES 297 | 298 | var daysOfWeek2:[String] = ["Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"] 299 | 300 | for day in daysOfWeek2{ 301 | if day == "Jueves"{ 302 | print("Está el jueves en el listado") 303 | } 304 | } 305 | 306 | var count = 0 307 | while count < 10{ 308 | print("Hola! soy un contador y valgo \(count)") 309 | count += 1 310 | } 311 | 312 | var count2 = 5 313 | repeat { 314 | print("PEPE") 315 | } while count2 < 0 316 | 317 | for day in daysOfWeek2{ 318 | if day == "Jueves"{ 319 | print("Es jueves") 320 | break 321 | }else{ 322 | print("NO es jueves") 323 | } 324 | } 325 | 326 | for day in daysOfWeek2{ 327 | print("------------") 328 | if day == "Jueves"{ 329 | print("Es jueves") 330 | continue 331 | } 332 | print("XXXXXXXXXXXXXX") 333 | } 334 | 335 | /** Ejercicio 7 336 | Escribe una función que reciba un númera e imprima su tabla de multiplicar del 1 al 10. 337 | */ 338 | func multiplication(_ number:Int){ 339 | for i in 1...10{ 340 | print("\(number) por \(i) es \(i*number)") 341 | } 342 | } 343 | 344 | multiplication(6) 345 | 346 | /** Ejercicio 8 347 | Escribe un programa que calcule la suma de todos los números pares del 1 al 100 y muestre el resultado. 348 | Para saber si un número es par se tiene que dar la siguiente condificón (número % 2 == 0) 349 | */ 350 | 351 | var totalSum = 0 352 | for i in 1...100{ 353 | if(i % 2 == 0){ 354 | totalSum += i 355 | } 356 | } 357 | print("El resultado es \(totalSum)") 358 | 359 | var totalSum2 = 0 360 | for i in 1...100{ 361 | if(i % 2 != 0){ 362 | continue 363 | } 364 | totalSum2 += i 365 | } 366 | 367 | print("El resultado2 es \(totalSum2)") 368 | 369 | /** Ejercicio 9 370 | Escribe una función que cuente el número de vocales en una palabra y lo pinte. 371 | TIP: Las palabras (strings) puedes recorrerse con bucle for. 372 | */ 373 | 374 | func vocalCounter(_ text:String){ 375 | var totalVocal:Int = 0 376 | for caracter in text{ 377 | switch caracter.lowercased() { 378 | case "a", "e", "i", "o", "u": totalVocal += 1 379 | default: continue 380 | } 381 | } 382 | print("El número de vocales para \(text) es de \(totalVocal)") 383 | } 384 | 385 | vocalCounter("Aris") 386 | 387 | 388 | //TUPLAS 389 | 390 | var tupla = ("Aris", 31, true, "Calle mi casa", 666666666, 1.87) 391 | 392 | print(tupla.4) 393 | 394 | 395 | //Diccionarios 396 | 397 | var dicc:[String: Any] = ["name": "Aris", "age": 31, "imHappy": true, "address": "Calle mi casa"] 398 | var myDiccionaryName:String = dicc["name"] as? String ?? "Pepito" 399 | print(myDiccionaryName) 400 | 401 | for (key, value) in dicc{ 402 | print("La clave \(key) contiene \(value)") 403 | } 404 | 405 | //NULLABILIDAD 406 | 407 | var stringReal:String = "Loquesea" 408 | var stringNil:String? = nil 409 | 410 | print(stringReal) 411 | print(stringNil) 412 | 413 | func ejemploNil(_ text:String){ 414 | //me da igual 415 | } 416 | 417 | ejemploNil(stringReal) 418 | ejemploNil(stringNil ?? "ejemplo") 419 | // ejemploNil(stringNil!) 420 | 421 | func ejemploNil2(_ text:String?){ 422 | 423 | if let example = text { 424 | print(example) 425 | }else{ 426 | print("Introduce un nombre para continuar") 427 | } 428 | 429 | guard let example2 = text else { 430 | 431 | return 432 | } 433 | 434 | print("Hola \(example2)") 435 | } 436 | 437 | ejemploNil2(stringReal) 438 | ejemploNil2(stringNil) 439 | 440 | //CLASES 441 | 442 | class Persona { 443 | 444 | var name:String 445 | var age:Int 446 | 447 | init(name: String, age: Int) { 448 | self.name = name 449 | self.age = age 450 | } 451 | 452 | func greetings(){ 453 | print("Hola, soy \(name) y tengo \(age) años.") 454 | } 455 | 456 | } 457 | 458 | var aris:Persona = Persona(name: "AristiDevs", age: 31) 459 | var pepe:Persona = Persona(name: "Pepito", age: 86) 460 | 461 | aris.greetings() 462 | pepe.greetings() 463 | 464 | struct ExampleStruct{ 465 | var name:String 466 | var age:Int 467 | } 468 | 469 | var exampleStruct:ExampleStruct = ExampleStruct(name: "Aris", age: 31) 470 | exampleStruct.age 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | -------------------------------------------------------------------------------- /CursoiOS/sintaxis/CursoiOS.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /CursoiOS/sintaxis/CursoiOS.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS-Expert 2 | 3 |

4 |

5 | 6 | Aprende a programar aplicaciones iOS sin conocimientos previos. Empezaremos desde lo más básico hasta conseguir desarrollar varias aplicaciones completas. 7 | 8 | ## Aprende a PROGRAMAR aplicaciones iOS en SWIFT desde CERO con SWIFTUI. 9 | 10 | Temario: 11 |
12 | - [Introducción](https://youtu.be/f6WtmTBFNGM?si=CVOfaL9WZu-b3oC6) 13 | - [xCode](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=259) 14 | - [Variables](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=867) 15 | - [Operaciones](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=2071) 16 | - [Conversiones](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=3156) 17 | - [Ejercicios #1](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=3486) 18 | - [Funciones](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=4176) 19 | - [Sentencias If](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=4796) 20 | - [Switch](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=5318) 21 | - [Ejercicios #2](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=5775) 22 | - [Array](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=6213) 23 | - [Bucles](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=6670) 24 | - [Ejercicios #3](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=7458) 25 | - [Tuplas y diccionarios](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=8150) 26 | - [Nulabilidad](https://youtu.be/f6WtmTBFNGM?si=hDML5mWkMpzZfvuO&t=8660) 27 | - [Clases y Structs](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=9155s) 28 | - [Introducción a xCode](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=9732s) 29 | - [Introducción a SwiftUI](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=10486s) 30 | - [HStack, VStack y ZStack](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=10879s) 31 | - [Ejercicios #4](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=11415s) 32 | - [Organización del proyecto](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=11958s) 33 | - [**Componentes**]() 34 | - [Componente Text](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=12158s) 35 | - [Componente Image](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=12594s) 36 | - [Componente Label](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=13207s) 37 | - [Componente Button](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=13393s) 38 | - [States](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=13645s) 39 | - [Componente TextField](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=13917s) 40 | - [Navegación básica](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=14519s) 41 | - [**IMC App**](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=15004s) 42 | - [Colores](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=15258s) 43 | - [Toolbar](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=15703s) 44 | - [Toggle](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=16022s) 45 | - [Slider](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=17023s) 46 | - [Counter](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=17489s) 47 | - [Ejercicio #5](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=18076s) 48 | - [Botón de continuar](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=18180s) 49 | - [Pantalla resultado](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=18447s) 50 | - [Listas](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=19860s) 51 | - [**Superhero App**](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=20587s) 52 | - [API REST](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=21268s) 53 | - [Consumiendo API](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=21875s) 54 | - [Personalizando listas](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=22750s) 55 | - [Cargando imágenes desde URL](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=23354s) 56 | - [Perfilando detalles](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=23787s) 57 | - [Pantalla detalle](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=24144s) 58 | - [Gráficas](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=25537s) 59 | - [Mapas](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=26171s) 60 | - [**Fav Places App**](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=27554s) 61 | - [Diálogos](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=28115s) 62 | - [Guardando places](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=29283s) 63 | - [Markers](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=29598s) 64 | - [Componente Sheet](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=29962s) 65 | - [Listado places](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=30312s) 66 | - [Persistencia de datos](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=30856s) 67 | - [Despedida](https://www.youtube.com/watch?v=f6WtmTBFNGM&t=32187s) 68 | 69 | --- 70 | 71 | ## Aplicaciones desarrolladas durante el curso. 72 | 73 | ### Calculador IMC. 74 | 75 | | Pantalla principal | Resultado | 76 | |:------------------------------------------------------------------------------:|:------------------------------------------------------------------------------:| 77 | | | | 78 | 79 | 80 | ### Buscador de superhéroes. 81 | 82 | | Pantalla principal | Añadiendo tareas | 83 | |:----------------------------------------------------------------------------:|:----------------------------------------------------------------------------:| 84 | | | | 85 | 86 | ### Localizador lugares. 87 | 88 | | Pantalla principal | Añadiendo tareas | 89 | |:----------------------------------------------------------------------------:|:----------------------------------------------------------------------------:| 90 | | | | 91 | 92 | --- 93 | 94 | ## Preguntas habituales. 95 | 96 | * **¿Necesito saber programar?** 97 | * NO, este curso es realmente DESDE CERO. 98 | 99 | * **¿Habrán ejercicios?** 100 | * Al final de la clase se pondrán ejercicios que se resolverán al inicio de la clase siguiente. 101 | 102 | * **¿Y si tengo dudas?** 103 | * Tienes un canal exclusivo para dudas del curso en el [DISCORD](https://discord.com/invite/SVBExkcGyV?fbclid=IwAR02ojS9ErZfGhl3DQjEZHoX92LX8WWj98JYLVAn7OgMXVrrtf86kfYtvhE) llamado **-ios**. 104 | 105 | --- 106 | 107 | ## COLABORA. 108 | 109 | Este proyecto es totalmente GRATUITO por lo que puedes aportar tu grano de arena de múltiples formas. 110 | 111 | - Dale a FAV al proyecto (Star) 112 | - Comparte el [Curso]() para que llegue a más gente 113 | - Sígueme en mis [redes sociales](https://aristi.dev) 114 | - Nomíname a [GITHUB STAR](https://stars.github.com/nominate/) 115 | --------------------------------------------------------------------------------