diff --git a/.gitignore b/.gitignore index 9298b749f..2d87192e8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ xcuserdata \#* .\#* .*.sw[nop] -*.xcscmblueprint /default.profraw Utilities/Docker/*.tar.gz .swiftpm @@ -96,6 +95,9 @@ fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/test_output +fastlane/screenshots +fastlane/readme.md + # Code Injection # @@ -179,13 +181,6 @@ freeline.py freeline/ freeline_project_description.json -# fastlane -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -fastlane/test_output -fastlane/readme.md - # Version control vcs.xml @@ -198,3 +193,24 @@ lint/tmp/ # Android Profiling *.hprof + +# Android Studio generated files and folders +.externalNativeBuild/ +output.json + +# IntelliJ +.idea/ +.idea/* +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Other +.cxx diff --git a/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.pbxproj b/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.pbxproj deleted file mode 100644 index 7b3949a77..000000000 --- a/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.pbxproj +++ /dev/null @@ -1,374 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 55; - objects = { - -/* Begin PBXBuildFile section */ - 315562662734184C00E1C17C /* Challenge_Alpha_iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3155623E2734184A00E1C17C /* Challenge_Alpha_iOSApp.swift */; }; - 315562682734184C00E1C17C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3155623F2734184A00E1C17C /* ContentView.swift */; }; - 3155626A2734184C00E1C17C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 315562402734184C00E1C17C /* Assets.xcassets */; }; - 315615CD27343C55009FF312 /* HUGraphQL in Frameworks */ = {isa = PBXBuildFile; productRef = 315615CC27343C55009FF312 /* HUGraphQL */; }; - 315615CF27343D42009FF312 /* Manager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315615CE27343D42009FF312 /* Manager.swift */; }; - 315615D1273441F3009FF312 /* ResultRenderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315615D0273441F3009FF312 /* ResultRenderView.swift */; }; - 315615D32734444A009FF312 /* ResultRenderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315615D22734444A009FF312 /* ResultRenderViewModel.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 3155623E2734184A00E1C17C /* Challenge_Alpha_iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Challenge_Alpha_iOSApp.swift; sourceTree = ""; }; - 3155623F2734184A00E1C17C /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; - 315562402734184C00E1C17C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 315562452734184C00E1C17C /* Challenge Alpha iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Challenge Alpha iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 315615CA27343C13009FF312 /* HUNetwork */ = {isa = PBXFileReference; lastKnownFileType = folder; name = HUNetwork; path = Modules/HUNetwork; sourceTree = ""; }; - 315615CE27343D42009FF312 /* Manager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Manager.swift; sourceTree = ""; }; - 315615D0273441F3009FF312 /* ResultRenderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultRenderView.swift; sourceTree = ""; }; - 315615D22734444A009FF312 /* ResultRenderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultRenderViewModel.swift; sourceTree = ""; }; - 31DB70752739692600F8663E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../README.md; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 315562422734184C00E1C17C /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 315615CD27343C55009FF312 /* HUGraphQL in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 315562382734184A00E1C17C = { - isa = PBXGroup; - children = ( - 31DB70752739692600F8663E /* README.md */, - 3155623D2734184A00E1C17C /* Shared */, - 315615C927343C12009FF312 /* Packages */, - 315562462734184C00E1C17C /* Products */, - 315615CB27343C54009FF312 /* Frameworks */, - ); - sourceTree = ""; - }; - 3155623D2734184A00E1C17C /* Shared */ = { - isa = PBXGroup; - children = ( - 3155623E2734184A00E1C17C /* Challenge_Alpha_iOSApp.swift */, - 3155623F2734184A00E1C17C /* ContentView.swift */, - 315562402734184C00E1C17C /* Assets.xcassets */, - 315615CE27343D42009FF312 /* Manager.swift */, - 315615D0273441F3009FF312 /* ResultRenderView.swift */, - 315615D22734444A009FF312 /* ResultRenderViewModel.swift */, - ); - path = Shared; - sourceTree = ""; - }; - 315562462734184C00E1C17C /* Products */ = { - isa = PBXGroup; - children = ( - 315562452734184C00E1C17C /* Challenge Alpha iOS.app */, - ); - name = Products; - sourceTree = ""; - }; - 315615C927343C12009FF312 /* Packages */ = { - isa = PBXGroup; - children = ( - 315615CA27343C13009FF312 /* HUNetwork */, - ); - name = Packages; - sourceTree = ""; - }; - 315615CB27343C54009FF312 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 315562442734184C00E1C17C /* Challenge Alpha iOS (iOS) */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3155626E2734184C00E1C17C /* Build configuration list for PBXNativeTarget "Challenge Alpha iOS (iOS)" */; - buildPhases = ( - 315562412734184C00E1C17C /* Sources */, - 315562422734184C00E1C17C /* Frameworks */, - 315562432734184C00E1C17C /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Challenge Alpha iOS (iOS)"; - packageProductDependencies = ( - 315615CC27343C55009FF312 /* HUGraphQL */, - ); - productName = "Challenge Alpha iOS (iOS)"; - productReference = 315562452734184C00E1C17C /* Challenge Alpha iOS.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 315562392734184A00E1C17C /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1310; - LastUpgradeCheck = 1310; - TargetAttributes = { - 315562442734184C00E1C17C = { - CreatedOnToolsVersion = 13.1; - }; - }; - }; - buildConfigurationList = 3155623C2734184A00E1C17C /* Build configuration list for PBXProject "Challenge Alpha iOS" */; - compatibilityVersion = "Xcode 13.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 315562382734184A00E1C17C; - productRefGroup = 315562462734184C00E1C17C /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 315562442734184C00E1C17C /* Challenge Alpha iOS (iOS) */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 315562432734184C00E1C17C /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3155626A2734184C00E1C17C /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 315562412734184C00E1C17C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 315562682734184C00E1C17C /* ContentView.swift in Sources */, - 315615D32734444A009FF312 /* ResultRenderViewModel.swift in Sources */, - 315615CF27343D42009FF312 /* Manager.swift in Sources */, - 315562662734184C00E1C17C /* Challenge_Alpha_iOSApp.swift in Sources */, - 315615D1273441F3009FF312 /* ResultRenderView.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 3155626C2734184C00E1C17C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 3155626D2734184C00E1C17C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 3155626F2734184C00E1C17C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - 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"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "hurb.com.Challenge-Alpha-iOS"; - PRODUCT_NAME = "Challenge Alpha iOS"; - SDKROOT = iphoneos; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 315562702734184C00E1C17C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - 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"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "hurb.com.Challenge-Alpha-iOS"; - PRODUCT_NAME = "Challenge Alpha iOS"; - SDKROOT = iphoneos; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 3155623C2734184A00E1C17C /* Build configuration list for PBXProject "Challenge Alpha iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3155626C2734184C00E1C17C /* Debug */, - 3155626D2734184C00E1C17C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 3155626E2734184C00E1C17C /* Build configuration list for PBXNativeTarget "Challenge Alpha iOS (iOS)" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3155626F2734184C00E1C17C /* Debug */, - 315562702734184C00E1C17C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCSwiftPackageProductDependency section */ - 315615CC27343C55009FF312 /* HUGraphQL */ = { - isa = XCSwiftPackageProductDependency; - productName = HUGraphQL; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 315562392734184A00E1C17C /* Project object */; -} diff --git a/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Projects/Challenge Alpha iOS/Challenge Alpha iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Package.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Package.swift deleted file mode 100644 index 40729c39a..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Package.swift +++ /dev/null @@ -1,39 +0,0 @@ -// swift-tools-version:5.5 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "HUNetwork", - defaultLocalization: "en", - platforms: [ - .iOS(.v13), - .macOS(.v10_15), - ], - products: [ - .executable(name: "ApolloCodegen", targets: ["ApolloCodegen"]), - .library(name: "HUGraphQL", targets: ["HUGraphQL"]), - ], - dependencies: [ - .package(name: "Apollo", url: "https://github.com/apollographql/apollo-ios.git", .upToNextMinor(from: "0.49.0")), - .package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "0.5.0")), - ], - targets: [ - .target( - name: "HUGraphQL", - dependencies: [ - .product(name: "Apollo", package: "Apollo"), - .product(name: "ApolloWebSocket", package: "Apollo"), - ], - exclude: ["Queries"] - ), - .executableTarget( - name: "ApolloCodegen", - dependencies: [ - .product(name: "ApolloCodegenLib", package: "Apollo"), - .product(name: "ArgumentParser", package: "swift-argument-parser") - ], - exclude: ["ApolloCLI"]) - ], - swiftLanguageVersions: [.v5] -) diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/README.md b/Projects/Challenge Alpha iOS/Modules/HUNetwork/README.md deleted file mode 100644 index 408a82510..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# HUGraphQL - -A description of this package. diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/ApolloCodegen/FileStructure.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/ApolloCodegen/FileStructure.swift deleted file mode 100644 index f6fbd3af2..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/ApolloCodegen/FileStructure.swift +++ /dev/null @@ -1,38 +0,0 @@ -import Foundation -import ApolloCodegenLib - -// An object representing the filesystem structure. Allows you to grab references to folders in the filesystem without having to pass them through as environment variables. -struct FileStructure { - - let huGraphQLRootURL: URL - let sourceRootURL: URL - let cliFolderURL: URL - - init() throws { - // Grab the parent folder of this file on the filesystem - let parentFolderOfScriptFile = FileFinder.findParentFolder() - CodegenLogger.log("Parent folder of script file: \(parentFolderOfScriptFile)") - - // Use that to calculate the source root for both your main project and this codegen project. - // NOTE: You may need to change this if your project has a different structure than the suggested structure. - self.sourceRootURL = parentFolderOfScriptFile.apollo.parentFolderURL() - - self.huGraphQLRootURL = parentFolderOfScriptFile - .apollo.parentFolderURL() // Result: Sources folder - .apollo.childFolderURL(folderName: "HUGraphQL") // Result: HUGraphQL folder - - // Set up the folder where you want the typescript CLI to download. - self.cliFolderURL = sourceRootURL - .apollo.childFolderURL(folderName: "ApolloCodegen") - .apollo.childFolderURL(folderName: "ApolloCLI") - } -} - -extension FileStructure: CustomDebugStringConvertible { - var debugDescription: String { - """ - Source root URL: \(self.sourceRootURL) - CLI folder URL: \(self.cliFolderURL) - """ - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/ApolloCodegen/main.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/ApolloCodegen/main.swift deleted file mode 100644 index 6c3501928..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/ApolloCodegen/main.swift +++ /dev/null @@ -1,86 +0,0 @@ -import Foundation -import ApolloCodegenLib -import ArgumentParser - -// An outer structure to hold all commands and sub-commands handled by this script. -struct SwiftScript: ParsableCommand { - - static var projectFolderName = "HotelUrbano" - static var generatedFolder = "GraphQL" - static let endpoint = "http://localhost:8010/graphql" - - static var configuration = CommandConfiguration( - abstract: """ - A swift-based utility for performing Apollo-related tasks. - - NOTE: If running from a compiled binary, prefix subcommands with `swift-script`. Otherwise use `swift run ApolloCodegen [subcommand]`. - """, - subcommands: [DownloadSchema.self, GenerateCode.self]) - - /// The sub-command to download a schema from a provided endpoint. - struct DownloadSchema: ParsableCommand { - static var configuration = CommandConfiguration( - commandName: "downloadSchema", - abstract: "Downloads the schema with the settings you've set up in the `DownloadSchema` command in `main.swift`.") - - mutating func run() throws { - let fileStructure = try FileStructure() - CodegenLogger.log("File structure: \(fileStructure)") - - // Set up the URL you want to use to download the project - let endpoint = URL(string: SwiftScript.endpoint)! - - - // Calculate where you want to create the folder where the schema will be downloaded by the ApolloCodegenLib framework. - let folderForDownloadedSchema = fileStructure - .huGraphQLRootURL - - // Make sure the folder is created before trying to download something to it. - try FileManager.default.apollo.createFolderIfNeeded(at: folderForDownloadedSchema) - - // Create an options object for downloading the schema. Provided code will download the schema via an introspection query to the provided URL as JSON to a file called "schema.json". For full options check out https://www.apollographql.com/docs/ios/api/ApolloCodegenLib/structs/ApolloSchemaOptions/ - let schemaConfiguration = ApolloSchemaDownloadConfiguration(using: .introspection(endpointURL: endpoint), timeout: 20, headers: [], outputFolderURL: folderForDownloadedSchema, schemaFilename: "schema") - - // Actually attempt to download the schema. - try ApolloSchemaDownloader.fetch(with: schemaConfiguration) - } - } - - /// The sub-command to actually generate code. - struct GenerateCode: ParsableCommand { - static var configuration = CommandConfiguration( - commandName: "generate", - abstract: "Generates swift code from your schema + your operations based on information set up in the `GenerateCode` command.") - - mutating func run() throws { - let fileStructure = try FileStructure() - CodegenLogger.log("File structure: \(fileStructure)") - - // Get the root of the target for which you want to generate code. - let targetRootURL = fileStructure.huGraphQLRootURL - - let schemeURL = targetRootURL.appendingPathComponent("schema.graphqls") - - let pathToGenerate = fileStructure.huGraphQLRootURL.appendingPathComponent("Generated") - - // Make sure the folder exists before trying to generate code. - try FileManager.default.apollo.createFolderIfNeeded(at: pathToGenerate) - - // Create the Codegen options object. This default setup assumes `schema.json` is in the target root folder, all queries are in some kind of subfolder of the target folder and will output as a single file to `API.swift` in the target folder. For alternate setup options, check out https://www.apollographql.com/docs/ios/api/ApolloCodegenLib/structs/ApolloCodegenOptions/ - let codegenOptions = ApolloCodegenOptions( - modifier: .internal, - namespace: "HUGraphQL", - outputFormat: .multipleFiles(inFolderAtURL: pathToGenerate), - customScalarFormat: .passthroughWithPrefix("HUGScalar"), - urlToSchemaFile: schemeURL) - - // Actually attempt to generate code. - try ApolloCodegen.run(from: targetRootURL, - with: fileStructure.cliFolderURL, - options: codegenOptions) - } - } -} - -// This will set up the command and parse the arguments when this executable is run. -SwiftScript.main() diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Common/HUGLogger.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Common/HUGLogger.swift deleted file mode 100644 index e878689f7..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Common/HUGLogger.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// File.swift -// -// -// Created by Theo Mendes on 04/11/21. -// - -import Foundation -import os.log - -/// Contains pre-defined OSLog categories -struct HUGLoggerCategory { - /// Generic app logging category - static var module: String { return "HUNetwork | HUGraphQL" } - /// Networking logging category - static var networking: String { return "HUNetwork | Networking" } - /// Lifecycle logging category - static var lifecycle: String { return "HUNetwork | Lifecycle" } -} - -/// Wrapper class for os_log function -struct HUGLogger { - /// Create OSLog with subsystem and category - static func osLog(subsystem: String = "br.com.hotelurbano.HUNetwork", category: String) -> OSLog { - return OSLog(subsystem: subsystem, category: category) - } - - /// Create app log - static func moduleLog() -> OSLog { - return OSLog(subsystem: "com.hurb.HUNetwork", category: HUGLoggerCategory.module) - } - - /// Create networking log - static func networkingLog() -> OSLog { - return OSLog(subsystem: "com.hurb.HUNetwork", category: HUGLoggerCategory.networking) - } - - /// Create lifecycle log - static func lifecycleLog() -> OSLog { - return OSLog(subsystem: "com.hurb.HUNetwork", category: HUGLoggerCategory.lifecycle) - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Common/HUGScalars.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Common/HUGScalars.swift deleted file mode 100644 index 3d9e70509..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Common/HUGScalars.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// HUGScalars.swift -// -// -// Created by Theo Mendes on 04/11/21. -// - -import Foundation -import Apollo - -public typealias HUGScalarSKU = String -public typealias HUGScalarNonNegativeInt = Int -public typealias HUGScalarPositiveInt = Int -public typealias HUGScalarDate = Date -public typealias HUGScalarPosID = String -public typealias HUGScalarLocale = String - -extension HUGScalarDate: JSONDecodable, JSONEncodable { - public init(jsonValue value: JSONValue) throws { - guard let string = value as? String else { - throw JSONDecodingError.couldNotConvert(value: value, to: String.self) - } - guard let date = ISO8601DateFormatter().date(from: string) else { - throw JSONDecodingError.couldNotConvert(value: value, to: Date.self) - } - self = date - } - public var jsonValue: JSONValue { - let dateFormatter = DateFormatter() - // Set Date Format - dateFormatter.dateFormat = "yyyy-MM-dd" - return dateFormatter.string(from: self) - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Extensions/Alpha+Data.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Extensions/Alpha+Data.swift deleted file mode 100644 index 2e87f1187..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Extensions/Alpha+Data.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// Alpha+Data.swift -// -// -// Created by Theo Mendes on 04/11/21. -// - -import Foundation - -internal extension Data { - var prettyJson: String? { - guard let object = try? JSONSerialization.jsonObject(with: self, options: []), - let data = try? JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted]), - let prettyPrintedString = String(data: data, encoding:.utf8) else { return nil } - - return prettyPrintedString - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/Search.graphql.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/Search.graphql.swift deleted file mode 100644 index 56627160c..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/Search.graphql.swift +++ /dev/null @@ -1,1284 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -/// HUGraphQL namespace -public extension HUGraphQL { - final class SearchQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query search($q: String!, $pagination: SearchInputPagination) { - search(q: $q, pagination: $pagination) { - __typename - pagination { - __typename - count - current - hasNext - } - filters { - __typename - productType { - __typename - label - filter - count - } - cities { - __typename - label - filter - count - } - stars { - __typename - label - filter - count - } - prices { - __typename - min - maxExclusive - filter - count - } - } - meta { - __typename - count - countWithAvailability - countHotel - countTicket - countPackage - } - results { - __typename - id - sku - name - url - category - description - smallDescription - isAvailable - price { - __typename - currency - amount - originalAmount - taxes { - __typename - originalAmount - originalCurrency - } - } - address { - __typename - city - state - country - geoLocation { - __typename - lat - lon - } - } - tags { - __typename - label - slug - } - gallery(limit: 10) { - __typename - url(quality: HIGH, resolution: ORIGINAL) - description - } - amenities(limit: 10) { - __typename - name - category - } - } - } - } - """ - - public let operationName: String = "search" - - public var q: String - public var pagination: SearchInputPagination? - - public init(q: String, pagination: SearchInputPagination? = nil) { - self.q = q - self.pagination = pagination - } - - public var variables: GraphQLMap? { - return ["q": q, "pagination": pagination] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("search", arguments: ["q": GraphQLVariable("q"), "pagination": GraphQLVariable("pagination")], type: .object(Search.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(search: Search? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "search": search.flatMap { (value: Search) -> ResultMap in value.resultMap }]) - } - - /// Fetches products in Search API. - public var search: Search? { - get { - return (resultMap["search"] as? ResultMap).flatMap { Search(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "search") - } - } - - public struct Search: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Search"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("pagination", type: .object(Pagination.selections)), - GraphQLField("filters", type: .object(Filter.selections)), - GraphQLField("meta", type: .nonNull(.object(Metum.selections))), - GraphQLField("results", type: .list(.nonNull(.object(Result.selections)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(pagination: Pagination? = nil, filters: Filter? = nil, meta: Metum, results: [Result]? = nil) { - self.init(unsafeResultMap: ["__typename": "Search", "pagination": pagination.flatMap { (value: Pagination) -> ResultMap in value.resultMap }, "filters": filters.flatMap { (value: Filter) -> ResultMap in value.resultMap }, "meta": meta.resultMap, "results": results.flatMap { (value: [Result]) -> [ResultMap] in value.map { (value: Result) -> ResultMap in value.resultMap } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Necessary info to construct a pagination. - public var pagination: Pagination? { - get { - return (resultMap["pagination"] as? ResultMap).flatMap { Pagination(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "pagination") - } - } - - /// Filters available. - public var filters: Filter? { - get { - return (resultMap["filters"] as? ResultMap).flatMap { Filter(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "filters") - } - } - - /// Meta-information from search results. - public var meta: Metum { - get { - return Metum(unsafeResultMap: resultMap["meta"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "meta") - } - } - - /// Results found. - public var results: [Result]? { - get { - return (resultMap["results"] as? [ResultMap]).flatMap { (value: [ResultMap]) -> [Result] in value.map { (value: ResultMap) -> Result in Result(unsafeResultMap: value) } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Result]) -> [ResultMap] in value.map { (value: Result) -> ResultMap in value.resultMap } }, forKey: "results") - } - } - - public struct Pagination: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchPagination"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(HUGScalarNonNegativeInt.self))), - GraphQLField("current", type: .nonNull(.scalar(HUGScalarNonNegativeInt.self))), - GraphQLField("hasNext", type: .nonNull(.scalar(Bool.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(count: HUGScalarNonNegativeInt, current: HUGScalarNonNegativeInt, hasNext: Bool) { - self.init(unsafeResultMap: ["__typename": "SearchPagination", "count": count, "current": current, "hasNext": hasNext]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Number of pages. - public var count: HUGScalarNonNegativeInt { - get { - return resultMap["count"]! as! HUGScalarNonNegativeInt - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - - /// Inform current page. - public var current: HUGScalarNonNegativeInt { - get { - return resultMap["current"]! as! HUGScalarNonNegativeInt - } - set { - resultMap.updateValue(newValue, forKey: "current") - } - } - - /// Inform if exists a next page. - public var hasNext: Bool { - get { - return resultMap["hasNext"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "hasNext") - } - } - } - - public struct Filter: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchFilters"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("productType", type: .list(.object(ProductType.selections))), - GraphQLField("cities", type: .list(.object(City.selections))), - GraphQLField("stars", type: .list(.object(Star.selections))), - GraphQLField("prices", type: .list(.object(Price.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(productType: [ProductType?]? = nil, cities: [City?]? = nil, stars: [Star?]? = nil, prices: [Price?]? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchFilters", "productType": productType.flatMap { (value: [ProductType?]) -> [ResultMap?] in value.map { (value: ProductType?) -> ResultMap? in value.flatMap { (value: ProductType) -> ResultMap in value.resultMap } } }, "cities": cities.flatMap { (value: [City?]) -> [ResultMap?] in value.map { (value: City?) -> ResultMap? in value.flatMap { (value: City) -> ResultMap in value.resultMap } } }, "stars": stars.flatMap { (value: [Star?]) -> [ResultMap?] in value.map { (value: Star?) -> ResultMap? in value.flatMap { (value: Star) -> ResultMap in value.resultMap } } }, "prices": prices.flatMap { (value: [Price?]) -> [ResultMap?] in value.map { (value: Price?) -> ResultMap? in value.flatMap { (value: Price) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Product type filter. - public var productType: [ProductType?]? { - get { - return (resultMap["productType"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [ProductType?] in value.map { (value: ResultMap?) -> ProductType? in value.flatMap { (value: ResultMap) -> ProductType in ProductType(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [ProductType?]) -> [ResultMap?] in value.map { (value: ProductType?) -> ResultMap? in value.flatMap { (value: ProductType) -> ResultMap in value.resultMap } } }, forKey: "productType") - } - } - - /// Cities filter. - public var cities: [City?]? { - get { - return (resultMap["cities"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [City?] in value.map { (value: ResultMap?) -> City? in value.flatMap { (value: ResultMap) -> City in City(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [City?]) -> [ResultMap?] in value.map { (value: City?) -> ResultMap? in value.flatMap { (value: City) -> ResultMap in value.resultMap } } }, forKey: "cities") - } - } - - /// Star filter. - public var stars: [Star?]? { - get { - return (resultMap["stars"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Star?] in value.map { (value: ResultMap?) -> Star? in value.flatMap { (value: ResultMap) -> Star in Star(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Star?]) -> [ResultMap?] in value.map { (value: Star?) -> ResultMap? in value.flatMap { (value: Star) -> ResultMap in value.resultMap } } }, forKey: "stars") - } - } - - /// Price filter. - public var prices: [Price?]? { - get { - return (resultMap["prices"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Price?] in value.map { (value: ResultMap?) -> Price? in value.flatMap { (value: ResultMap) -> Price in Price(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Price?]) -> [ResultMap?] in value.map { (value: Price?) -> ResultMap? in value.flatMap { (value: Price) -> ResultMap in value.resultMap } } }, forKey: "prices") - } - } - - public struct ProductType: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct City: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Star: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Price: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchPriceGroupFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("min", type: .nonNull(.scalar(Int.self))), - GraphQLField("maxExclusive", type: .nonNull(.scalar(Int.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(min: Int, maxExclusive: Int, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchPriceGroupFilter", "min": min, "maxExclusive": maxExclusive, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Min range value. - public var min: Int { - get { - return resultMap["min"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "min") - } - } - - /// Max range value (exclusive). - public var maxExclusive: Int { - get { - return resultMap["maxExclusive"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "maxExclusive") - } - } - - /// The range group represented as a term to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - } - - public struct Metum: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchMeta"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - GraphQLField("countWithAvailability", type: .scalar(Int.self)), - GraphQLField("countHotel", type: .scalar(Int.self)), - GraphQLField("countTicket", type: .scalar(Int.self)), - GraphQLField("countPackage", type: .scalar(Int.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(count: Int, countWithAvailability: Int? = nil, countHotel: Int? = nil, countTicket: Int? = nil, countPackage: Int? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchMeta", "count": count, "countWithAvailability": countWithAvailability, "countHotel": countHotel, "countTicket": countTicket, "countPackage": countPackage]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Quantity of products found. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - - /// Quantity of products found with availability. - public var countWithAvailability: Int? { - get { - return resultMap["countWithAvailability"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countWithAvailability") - } - } - - /// Quantity of hotels found. - public var countHotel: Int? { - get { - return resultMap["countHotel"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countHotel") - } - } - - /// Quantity of tickets found. - public var countTicket: Int? { - get { - return resultMap["countTicket"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countTicket") - } - } - - /// Quantity of packages found. - public var countPackage: Int? { - get { - return resultMap["countPackage"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countPackage") - } - } - } - - public struct Result: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultHotelItem", "SearchResultPackageItem", "SearchResultTicketItem"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .scalar(GraphQLID.self)), - GraphQLField("sku", type: .nonNull(.scalar(HUGScalarSKU.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("url", type: .nonNull(.scalar(String.self))), - GraphQLField("category", type: .nonNull(.scalar(String.self))), - GraphQLField("description", type: .nonNull(.scalar(String.self))), - GraphQLField("smallDescription", type: .nonNull(.scalar(String.self))), - GraphQLField("isAvailable", type: .nonNull(.scalar(Bool.self))), - GraphQLField("price", type: .nonNull(.object(Price.selections))), - GraphQLField("address", type: .object(Address.selections)), - GraphQLField("tags", type: .nonNull(.list(.nonNull(.object(Tag.selections))))), - GraphQLField("gallery", arguments: ["limit": 10], type: .nonNull(.list(.nonNull(.object(Gallery.selections))))), - GraphQLField("amenities", arguments: ["limit": 10], type: .nonNull(.list(.nonNull(.object(Amenity.selections))))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeSearchResultHotelItem(id: GraphQLID? = nil, sku: HUGScalarSKU, name: String, url: String, category: String, description: String, smallDescription: String, isAvailable: Bool, price: Price, address: Address? = nil, tags: [Tag], gallery: [Gallery], amenities: [Amenity]) -> Result { - return Result(unsafeResultMap: ["__typename": "SearchResultHotelItem", "id": id, "sku": sku, "name": name, "url": url, "category": category, "description": description, "smallDescription": smallDescription, "isAvailable": isAvailable, "price": price.resultMap, "address": address.flatMap { (value: Address) -> ResultMap in value.resultMap }, "tags": tags.map { (value: Tag) -> ResultMap in value.resultMap }, "gallery": gallery.map { (value: Gallery) -> ResultMap in value.resultMap }, "amenities": amenities.map { (value: Amenity) -> ResultMap in value.resultMap }]) - } - - public static func makeSearchResultPackageItem(id: GraphQLID? = nil, sku: HUGScalarSKU, name: String, url: String, category: String, description: String, smallDescription: String, isAvailable: Bool, price: Price, address: Address? = nil, tags: [Tag], gallery: [Gallery], amenities: [Amenity]) -> Result { - return Result(unsafeResultMap: ["__typename": "SearchResultPackageItem", "id": id, "sku": sku, "name": name, "url": url, "category": category, "description": description, "smallDescription": smallDescription, "isAvailable": isAvailable, "price": price.resultMap, "address": address.flatMap { (value: Address) -> ResultMap in value.resultMap }, "tags": tags.map { (value: Tag) -> ResultMap in value.resultMap }, "gallery": gallery.map { (value: Gallery) -> ResultMap in value.resultMap }, "amenities": amenities.map { (value: Amenity) -> ResultMap in value.resultMap }]) - } - - public static func makeSearchResultTicketItem(id: GraphQLID? = nil, sku: HUGScalarSKU, name: String, url: String, category: String, description: String, smallDescription: String, isAvailable: Bool, price: Price, address: Address? = nil, tags: [Tag], gallery: [Gallery], amenities: [Amenity]) -> Result { - return Result(unsafeResultMap: ["__typename": "SearchResultTicketItem", "id": id, "sku": sku, "name": name, "url": url, "category": category, "description": description, "smallDescription": smallDescription, "isAvailable": isAvailable, "price": price.resultMap, "address": address.flatMap { (value: Address) -> ResultMap in value.resultMap }, "tags": tags.map { (value: Tag) -> ResultMap in value.resultMap }, "gallery": gallery.map { (value: Gallery) -> ResultMap in value.resultMap }, "amenities": amenities.map { (value: Amenity) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Product id. - public var id: GraphQLID? { - get { - return resultMap["id"] as? GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// Product sku. - public var sku: HUGScalarSKU { - get { - return resultMap["sku"]! as! HUGScalarSKU - } - set { - resultMap.updateValue(newValue, forKey: "sku") - } - } - - /// Product name. - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Product url. - public var url: String { - get { - return resultMap["url"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "url") - } - } - - /// Product category. - public var category: String { - get { - return resultMap["category"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "category") - } - } - - /// Product description. - public var description: String { - get { - return resultMap["description"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "description") - } - } - - /// Product short description. - public var smallDescription: String { - get { - return resultMap["smallDescription"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "smallDescription") - } - } - - /// Inform if the product is available - public var isAvailable: Bool { - get { - return resultMap["isAvailable"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "isAvailable") - } - } - - /// Product price. - public var price: Price { - get { - return Price(unsafeResultMap: resultMap["price"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "price") - } - } - - /// Product address. - public var address: Address? { - get { - return (resultMap["address"] as? ResultMap).flatMap { Address(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "address") - } - } - - /// Product tags. - public var tags: [Tag] { - get { - return (resultMap["tags"] as! [ResultMap]).map { (value: ResultMap) -> Tag in Tag(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Tag) -> ResultMap in value.resultMap }, forKey: "tags") - } - } - - /// List of product images. - public var gallery: [Gallery] { - get { - return (resultMap["gallery"] as! [ResultMap]).map { (value: ResultMap) -> Gallery in Gallery(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Gallery) -> ResultMap in value.resultMap }, forKey: "gallery") - } - } - - /// List of product amenities. - public var amenities: [Amenity] { - get { - return (resultMap["amenities"] as! [ResultMap]).map { (value: ResultMap) -> Amenity in Amenity(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Amenity) -> ResultMap in value.resultMap }, forKey: "amenities") - } - } - - public struct Price: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["ProductPrice"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("currency", type: .scalar(String.self)), - GraphQLField("amount", type: .nonNull(.scalar(Double.self))), - GraphQLField("originalAmount", type: .scalar(Double.self)), - GraphQLField("taxes", type: .nonNull(.list(.nonNull(.object(Tax.selections))))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(currency: String? = nil, amount: Double, originalAmount: Double? = nil, taxes: [Tax]) { - self.init(unsafeResultMap: ["__typename": "ProductPrice", "currency": currency, "amount": amount, "originalAmount": originalAmount, "taxes": taxes.map { (value: Tax) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Price currency. - public var currency: String? { - get { - return resultMap["currency"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "currency") - } - } - - /// Price amount. - public var amount: Double { - get { - return resultMap["amount"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "amount") - } - } - - /// Original price amount. - public var originalAmount: Double? { - get { - return resultMap["originalAmount"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "originalAmount") - } - } - - /// Price taxes - public var taxes: [Tax] { - get { - return (resultMap["taxes"] as! [ResultMap]).map { (value: ResultMap) -> Tax in Tax(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Tax) -> ResultMap in value.resultMap }, forKey: "taxes") - } - } - - public struct Tax: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["ProductPriceTaxes"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("originalAmount", type: .nonNull(.scalar(Double.self))), - GraphQLField("originalCurrency", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(originalAmount: Double, originalCurrency: String) { - self.init(unsafeResultMap: ["__typename": "ProductPriceTaxes", "originalAmount": originalAmount, "originalCurrency": originalCurrency]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Original tax amount - public var originalAmount: Double { - get { - return resultMap["originalAmount"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "originalAmount") - } - } - - /// Original tax currency - public var originalCurrency: String { - get { - return resultMap["originalCurrency"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "originalCurrency") - } - } - } - } - - public struct Address: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemAddress"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("city", type: .scalar(String.self)), - GraphQLField("state", type: .scalar(String.self)), - GraphQLField("country", type: .scalar(String.self)), - GraphQLField("geoLocation", type: .object(GeoLocation.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(city: String? = nil, state: String? = nil, country: String? = nil, geoLocation: GeoLocation? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemAddress", "city": city, "state": state, "country": country, "geoLocation": geoLocation.flatMap { (value: GeoLocation) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Product city. - public var city: String? { - get { - return resultMap["city"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "city") - } - } - - /// Product state. - public var state: String? { - get { - return resultMap["state"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "state") - } - } - - /// Product country. - public var country: String? { - get { - return resultMap["country"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "country") - } - } - - /// Product geolocation. - public var geoLocation: GeoLocation? { - get { - return (resultMap["geoLocation"] as? ResultMap).flatMap { GeoLocation(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "geoLocation") - } - } - - public struct GeoLocation: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Coordinates"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("lat", type: .nonNull(.scalar(Double.self))), - GraphQLField("lon", type: .nonNull(.scalar(Double.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(lat: Double, lon: Double) { - self.init(unsafeResultMap: ["__typename": "Coordinates", "lat": lat, "lon": lon]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var lat: Double { - get { - return resultMap["lat"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "lat") - } - } - - public var lon: Double { - get { - return resultMap["lon"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "lon") - } - } - } - } - - public struct Tag: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemTag"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("slug", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, slug: String) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemTag", "label": label, "slug": slug]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Label of the product tag. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// Slug of the product tag. - public var slug: String { - get { - return resultMap["slug"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "slug") - } - } - } - - public struct Gallery: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemGalleryImage"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("url", arguments: ["quality": "HIGH", "resolution": "ORIGINAL"], type: .scalar(String.self)), - GraphQLField("description", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(url: String? = nil, description: String? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemGalleryImage", "url": url, "description": description]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Gallery image url. - public var url: String? { - get { - return resultMap["url"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "url") - } - } - - /// Gallery image description. - public var description: String? { - get { - return resultMap["description"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "description") - } - } - } - - public struct Amenity: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemAmenity"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("category", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, category: String? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemAmenity", "name": name, "category": category]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Amenity name. - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Amenity category. - public var category: String? { - get { - return resultMap["category"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "category") - } - } - } - } - } - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SearchHotelQuery.graphql.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SearchHotelQuery.graphql.swift deleted file mode 100644 index 58b558799..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SearchHotelQuery.graphql.swift +++ /dev/null @@ -1,1701 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -/// HUGraphQL namespace -public extension HUGraphQL { - final class SearchHotelQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query searchHotel($q: String!, $filters: SearchHotelInputFilters, $pagination: SearchInputPagination, $l10n: InputL10n, $checkin: Date, $checkout: Date, $rooms: [SearchInputRooms!]) { - searchHotel( - q: $q - filters: $filters - pagination: $pagination - l10n: $l10n - checkin: $checkin - checkout: $checkout - rooms: $rooms - ) { - __typename - filters { - __typename - amenities { - __typename - label - filter - count - } - cities { - __typename - label - filter - count - } - states { - __typename - label - filter - count - } - countries { - __typename - label - filter - count - } - food { - __typename - label - filter - count - } - people { - __typename - label - filter - count - } - priceInterval { - __typename - min - max - } - prices { - __typename - min - maxExclusive - filter - count - } - stars { - __typename - label - filter - count - } - } - results { - __typename - id - sku - name - url - category - description - smallDescription - price { - __typename - currency - amount - originalAmount - taxes { - __typename - currency - } - } - address { - __typename - city - state - country - geoLocation { - __typename - lat - lon - } - } - tags { - __typename - label - slug - } - gallery { - __typename - url - description - } - amenities { - __typename - name - category - } - isAvailable - stars - huFreeCancellation - } - meta { - __typename - count - countWithAvailability - countHotel - countPackage - countTicket - } - pagination { - __typename - count - current - hasNext - hasPrevious - } - } - } - """ - - public let operationName: String = "searchHotel" - - public var q: String - public var filters: SearchHotelInputFilters? - public var pagination: SearchInputPagination? - public var l10n: InputL10n? - public var checkin: HUGScalarDate? - public var checkout: HUGScalarDate? - public var rooms: [SearchInputRooms]? - - public init(q: String, filters: SearchHotelInputFilters? = nil, pagination: SearchInputPagination? = nil, l10n: InputL10n? = nil, checkin: HUGScalarDate? = nil, checkout: HUGScalarDate? = nil, rooms: [SearchInputRooms]?) { - self.q = q - self.filters = filters - self.pagination = pagination - self.l10n = l10n - self.checkin = checkin - self.checkout = checkout - self.rooms = rooms - } - - public var variables: GraphQLMap? { - return ["q": q, "filters": filters, "pagination": pagination, "l10n": l10n, "checkin": checkin, "checkout": checkout, "rooms": rooms] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("searchHotel", arguments: ["q": GraphQLVariable("q"), "filters": GraphQLVariable("filters"), "pagination": GraphQLVariable("pagination"), "l10n": GraphQLVariable("l10n"), "checkin": GraphQLVariable("checkin"), "checkout": GraphQLVariable("checkout"), "rooms": GraphQLVariable("rooms")], type: .object(SearchHotel.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(searchHotel: SearchHotel? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "searchHotel": searchHotel.flatMap { (value: SearchHotel) -> ResultMap in value.resultMap }]) - } - - /// Fetches products in Search API. - public var searchHotel: SearchHotel? { - get { - return (resultMap["searchHotel"] as? ResultMap).flatMap { SearchHotel(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "searchHotel") - } - } - - public struct SearchHotel: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchHotel"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("filters", type: .object(Filter.selections)), - GraphQLField("results", type: .list(.nonNull(.object(Result.selections)))), - GraphQLField("meta", type: .nonNull(.object(Metum.selections))), - GraphQLField("pagination", type: .object(Pagination.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(filters: Filter? = nil, results: [Result]? = nil, meta: Metum, pagination: Pagination? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchHotel", "filters": filters.flatMap { (value: Filter) -> ResultMap in value.resultMap }, "results": results.flatMap { (value: [Result]) -> [ResultMap] in value.map { (value: Result) -> ResultMap in value.resultMap } }, "meta": meta.resultMap, "pagination": pagination.flatMap { (value: Pagination) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filters available. - public var filters: Filter? { - get { - return (resultMap["filters"] as? ResultMap).flatMap { Filter(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "filters") - } - } - - /// Results found. - public var results: [Result]? { - get { - return (resultMap["results"] as? [ResultMap]).flatMap { (value: [ResultMap]) -> [Result] in value.map { (value: ResultMap) -> Result in Result(unsafeResultMap: value) } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Result]) -> [ResultMap] in value.map { (value: Result) -> ResultMap in value.resultMap } }, forKey: "results") - } - } - - /// Meta-information from search results. - public var meta: Metum { - get { - return Metum(unsafeResultMap: resultMap["meta"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "meta") - } - } - - /// Necessary info to construct a pagination. - public var pagination: Pagination? { - get { - return (resultMap["pagination"] as? ResultMap).flatMap { Pagination(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "pagination") - } - } - - public struct Filter: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchHotelFilters"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("amenities", type: .list(.object(Amenity.selections))), - GraphQLField("cities", type: .list(.object(City.selections))), - GraphQLField("states", type: .list(.object(State.selections))), - GraphQLField("countries", type: .list(.object(Country.selections))), - GraphQLField("food", type: .list(.object(Food.selections))), - GraphQLField("people", type: .list(.object(Person.selections))), - GraphQLField("priceInterval", type: .object(PriceInterval.selections)), - GraphQLField("prices", type: .list(.object(Price.selections))), - GraphQLField("stars", type: .list(.object(Star.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(amenities: [Amenity?]? = nil, cities: [City?]? = nil, states: [State?]? = nil, countries: [Country?]? = nil, food: [Food?]? = nil, people: [Person?]? = nil, priceInterval: PriceInterval? = nil, prices: [Price?]? = nil, stars: [Star?]? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchHotelFilters", "amenities": amenities.flatMap { (value: [Amenity?]) -> [ResultMap?] in value.map { (value: Amenity?) -> ResultMap? in value.flatMap { (value: Amenity) -> ResultMap in value.resultMap } } }, "cities": cities.flatMap { (value: [City?]) -> [ResultMap?] in value.map { (value: City?) -> ResultMap? in value.flatMap { (value: City) -> ResultMap in value.resultMap } } }, "states": states.flatMap { (value: [State?]) -> [ResultMap?] in value.map { (value: State?) -> ResultMap? in value.flatMap { (value: State) -> ResultMap in value.resultMap } } }, "countries": countries.flatMap { (value: [Country?]) -> [ResultMap?] in value.map { (value: Country?) -> ResultMap? in value.flatMap { (value: Country) -> ResultMap in value.resultMap } } }, "food": food.flatMap { (value: [Food?]) -> [ResultMap?] in value.map { (value: Food?) -> ResultMap? in value.flatMap { (value: Food) -> ResultMap in value.resultMap } } }, "people": people.flatMap { (value: [Person?]) -> [ResultMap?] in value.map { (value: Person?) -> ResultMap? in value.flatMap { (value: Person) -> ResultMap in value.resultMap } } }, "priceInterval": priceInterval.flatMap { (value: PriceInterval) -> ResultMap in value.resultMap }, "prices": prices.flatMap { (value: [Price?]) -> [ResultMap?] in value.map { (value: Price?) -> ResultMap? in value.flatMap { (value: Price) -> ResultMap in value.resultMap } } }, "stars": stars.flatMap { (value: [Star?]) -> [ResultMap?] in value.map { (value: Star?) -> ResultMap? in value.flatMap { (value: Star) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Product amenity filter - public var amenities: [Amenity?]? { - get { - return (resultMap["amenities"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Amenity?] in value.map { (value: ResultMap?) -> Amenity? in value.flatMap { (value: ResultMap) -> Amenity in Amenity(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Amenity?]) -> [ResultMap?] in value.map { (value: Amenity?) -> ResultMap? in value.flatMap { (value: Amenity) -> ResultMap in value.resultMap } } }, forKey: "amenities") - } - } - - /// Cities filter. - public var cities: [City?]? { - get { - return (resultMap["cities"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [City?] in value.map { (value: ResultMap?) -> City? in value.flatMap { (value: ResultMap) -> City in City(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [City?]) -> [ResultMap?] in value.map { (value: City?) -> ResultMap? in value.flatMap { (value: City) -> ResultMap in value.resultMap } } }, forKey: "cities") - } - } - - /// States filter. - public var states: [State?]? { - get { - return (resultMap["states"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [State?] in value.map { (value: ResultMap?) -> State? in value.flatMap { (value: ResultMap) -> State in State(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [State?]) -> [ResultMap?] in value.map { (value: State?) -> ResultMap? in value.flatMap { (value: State) -> ResultMap in value.resultMap } } }, forKey: "states") - } - } - - /// Countries filter. - public var countries: [Country?]? { - get { - return (resultMap["countries"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Country?] in value.map { (value: ResultMap?) -> Country? in value.flatMap { (value: ResultMap) -> Country in Country(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Country?]) -> [ResultMap?] in value.map { (value: Country?) -> ResultMap? in value.flatMap { (value: Country) -> ResultMap in value.resultMap } } }, forKey: "countries") - } - } - - /// Food filter. - public var food: [Food?]? { - get { - return (resultMap["food"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Food?] in value.map { (value: ResultMap?) -> Food? in value.flatMap { (value: ResultMap) -> Food in Food(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Food?]) -> [ResultMap?] in value.map { (value: Food?) -> ResultMap? in value.flatMap { (value: Food) -> ResultMap in value.resultMap } } }, forKey: "food") - } - } - - /// People filter. - public var people: [Person?]? { - get { - return (resultMap["people"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Person?] in value.map { (value: ResultMap?) -> Person? in value.flatMap { (value: ResultMap) -> Person in Person(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Person?]) -> [ResultMap?] in value.map { (value: Person?) -> ResultMap? in value.flatMap { (value: Person) -> ResultMap in value.resultMap } } }, forKey: "people") - } - } - - /// Price interval filter. - public var priceInterval: PriceInterval? { - get { - return (resultMap["priceInterval"] as? ResultMap).flatMap { PriceInterval(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "priceInterval") - } - } - - /// Price filter. - public var prices: [Price?]? { - get { - return (resultMap["prices"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Price?] in value.map { (value: ResultMap?) -> Price? in value.flatMap { (value: ResultMap) -> Price in Price(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Price?]) -> [ResultMap?] in value.map { (value: Price?) -> ResultMap? in value.flatMap { (value: Price) -> ResultMap in value.resultMap } } }, forKey: "prices") - } - } - - /// Star filter. - public var stars: [Star?]? { - get { - return (resultMap["stars"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Star?] in value.map { (value: ResultMap?) -> Star? in value.flatMap { (value: ResultMap) -> Star in Star(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Star?]) -> [ResultMap?] in value.map { (value: Star?) -> ResultMap? in value.flatMap { (value: Star) -> ResultMap in value.resultMap } } }, forKey: "stars") - } - } - - public struct Amenity: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct City: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct State: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Country: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Food: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Person: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct PriceInterval: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchIntervalFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("min", type: .nonNull(.scalar(Double.self))), - GraphQLField("max", type: .nonNull(.scalar(Double.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(min: Double, max: Double) { - self.init(unsafeResultMap: ["__typename": "SearchIntervalFilter", "min": min, "max": max]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Min interval value. - public var min: Double { - get { - return resultMap["min"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "min") - } - } - - /// Max interval value. - public var max: Double { - get { - return resultMap["max"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "max") - } - } - } - - public struct Price: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchPriceGroupFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("min", type: .nonNull(.scalar(Int.self))), - GraphQLField("maxExclusive", type: .nonNull(.scalar(Int.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(min: Int, maxExclusive: Int, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchPriceGroupFilter", "min": min, "maxExclusive": maxExclusive, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Min range value. - public var min: Int { - get { - return resultMap["min"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "min") - } - } - - /// Max range value (exclusive). - public var maxExclusive: Int { - get { - return resultMap["maxExclusive"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "maxExclusive") - } - } - - /// The range group represented as a term to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Star: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - } - - public struct Result: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultHotelItem"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .scalar(GraphQLID.self)), - GraphQLField("sku", type: .nonNull(.scalar(HUGScalarSKU.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("url", type: .nonNull(.scalar(String.self))), - GraphQLField("category", type: .nonNull(.scalar(String.self))), - GraphQLField("description", type: .nonNull(.scalar(String.self))), - GraphQLField("smallDescription", type: .nonNull(.scalar(String.self))), - GraphQLField("price", type: .nonNull(.object(Price.selections))), - GraphQLField("address", type: .object(Address.selections)), - GraphQLField("tags", type: .nonNull(.list(.nonNull(.object(Tag.selections))))), - GraphQLField("gallery", type: .nonNull(.list(.nonNull(.object(Gallery.selections))))), - GraphQLField("amenities", type: .nonNull(.list(.nonNull(.object(Amenity.selections))))), - GraphQLField("isAvailable", type: .nonNull(.scalar(Bool.self))), - GraphQLField("stars", type: .nonNull(.scalar(Int.self))), - GraphQLField("huFreeCancellation", type: .nonNull(.scalar(Bool.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(id: GraphQLID? = nil, sku: HUGScalarSKU, name: String, url: String, category: String, description: String, smallDescription: String, price: Price, address: Address? = nil, tags: [Tag], gallery: [Gallery], amenities: [Amenity], isAvailable: Bool, stars: Int, huFreeCancellation: Bool) { - self.init(unsafeResultMap: ["__typename": "SearchResultHotelItem", "id": id, "sku": sku, "name": name, "url": url, "category": category, "description": description, "smallDescription": smallDescription, "price": price.resultMap, "address": address.flatMap { (value: Address) -> ResultMap in value.resultMap }, "tags": tags.map { (value: Tag) -> ResultMap in value.resultMap }, "gallery": gallery.map { (value: Gallery) -> ResultMap in value.resultMap }, "amenities": amenities.map { (value: Amenity) -> ResultMap in value.resultMap }, "isAvailable": isAvailable, "stars": stars, "huFreeCancellation": huFreeCancellation]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Product id. - public var id: GraphQLID? { - get { - return resultMap["id"] as? GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// Product sku. - public var sku: HUGScalarSKU { - get { - return resultMap["sku"]! as! HUGScalarSKU - } - set { - resultMap.updateValue(newValue, forKey: "sku") - } - } - - /// Product name. - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Product url. - public var url: String { - get { - return resultMap["url"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "url") - } - } - - /// Product category. - public var category: String { - get { - return resultMap["category"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "category") - } - } - - /// Product description. - public var description: String { - get { - return resultMap["description"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "description") - } - } - - /// Product short description. - public var smallDescription: String { - get { - return resultMap["smallDescription"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "smallDescription") - } - } - - /// Product price. - public var price: Price { - get { - return Price(unsafeResultMap: resultMap["price"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "price") - } - } - - /// Product address. - public var address: Address? { - get { - return (resultMap["address"] as? ResultMap).flatMap { Address(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "address") - } - } - - /// Product tags. - public var tags: [Tag] { - get { - return (resultMap["tags"] as! [ResultMap]).map { (value: ResultMap) -> Tag in Tag(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Tag) -> ResultMap in value.resultMap }, forKey: "tags") - } - } - - /// List of product images. - public var gallery: [Gallery] { - get { - return (resultMap["gallery"] as! [ResultMap]).map { (value: ResultMap) -> Gallery in Gallery(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Gallery) -> ResultMap in value.resultMap }, forKey: "gallery") - } - } - - /// List of product amenities. - public var amenities: [Amenity] { - get { - return (resultMap["amenities"] as! [ResultMap]).map { (value: ResultMap) -> Amenity in Amenity(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Amenity) -> ResultMap in value.resultMap }, forKey: "amenities") - } - } - - /// Inform if the product is available - public var isAvailable: Bool { - get { - return resultMap["isAvailable"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "isAvailable") - } - } - - /// Hotel rating in stars. - public var stars: Int { - get { - return resultMap["stars"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "stars") - } - } - - /// Whether the Hotel has a free cancellation policy - public var huFreeCancellation: Bool { - get { - return resultMap["huFreeCancellation"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "huFreeCancellation") - } - } - - public struct Price: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["ProductPrice"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("currency", type: .scalar(String.self)), - GraphQLField("amount", type: .nonNull(.scalar(Double.self))), - GraphQLField("originalAmount", type: .scalar(Double.self)), - GraphQLField("taxes", type: .nonNull(.list(.nonNull(.object(Tax.selections))))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(currency: String? = nil, amount: Double, originalAmount: Double? = nil, taxes: [Tax]) { - self.init(unsafeResultMap: ["__typename": "ProductPrice", "currency": currency, "amount": amount, "originalAmount": originalAmount, "taxes": taxes.map { (value: Tax) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Price currency. - public var currency: String? { - get { - return resultMap["currency"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "currency") - } - } - - /// Price amount. - public var amount: Double { - get { - return resultMap["amount"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "amount") - } - } - - /// Original price amount. - public var originalAmount: Double? { - get { - return resultMap["originalAmount"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "originalAmount") - } - } - - /// Price taxes - public var taxes: [Tax] { - get { - return (resultMap["taxes"] as! [ResultMap]).map { (value: ResultMap) -> Tax in Tax(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Tax) -> ResultMap in value.resultMap }, forKey: "taxes") - } - } - - public struct Tax: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["ProductPriceTaxes"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("currency", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(currency: String) { - self.init(unsafeResultMap: ["__typename": "ProductPriceTaxes", "currency": currency]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Tax currency - public var currency: String { - get { - return resultMap["currency"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "currency") - } - } - } - } - - public struct Address: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemAddress"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("city", type: .scalar(String.self)), - GraphQLField("state", type: .scalar(String.self)), - GraphQLField("country", type: .scalar(String.self)), - GraphQLField("geoLocation", type: .object(GeoLocation.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(city: String? = nil, state: String? = nil, country: String? = nil, geoLocation: GeoLocation? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemAddress", "city": city, "state": state, "country": country, "geoLocation": geoLocation.flatMap { (value: GeoLocation) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Product city. - public var city: String? { - get { - return resultMap["city"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "city") - } - } - - /// Product state. - public var state: String? { - get { - return resultMap["state"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "state") - } - } - - /// Product country. - public var country: String? { - get { - return resultMap["country"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "country") - } - } - - /// Product geolocation. - public var geoLocation: GeoLocation? { - get { - return (resultMap["geoLocation"] as? ResultMap).flatMap { GeoLocation(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "geoLocation") - } - } - - public struct GeoLocation: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Coordinates"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("lat", type: .nonNull(.scalar(Double.self))), - GraphQLField("lon", type: .nonNull(.scalar(Double.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(lat: Double, lon: Double) { - self.init(unsafeResultMap: ["__typename": "Coordinates", "lat": lat, "lon": lon]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var lat: Double { - get { - return resultMap["lat"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "lat") - } - } - - public var lon: Double { - get { - return resultMap["lon"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "lon") - } - } - } - } - - public struct Tag: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemTag"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("slug", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, slug: String) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemTag", "label": label, "slug": slug]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Label of the product tag. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// Slug of the product tag. - public var slug: String { - get { - return resultMap["slug"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "slug") - } - } - } - - public struct Gallery: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemGalleryImage"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("url", type: .scalar(String.self)), - GraphQLField("description", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(url: String? = nil, description: String? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemGalleryImage", "url": url, "description": description]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Gallery image url. - public var url: String? { - get { - return resultMap["url"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "url") - } - } - - /// Gallery image description. - public var description: String? { - get { - return resultMap["description"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "description") - } - } - } - - public struct Amenity: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemAmenity"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("category", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, category: String? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemAmenity", "name": name, "category": category]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Amenity name. - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Amenity category. - public var category: String? { - get { - return resultMap["category"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "category") - } - } - } - } - - public struct Metum: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchMeta"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - GraphQLField("countWithAvailability", type: .scalar(Int.self)), - GraphQLField("countHotel", type: .scalar(Int.self)), - GraphQLField("countPackage", type: .scalar(Int.self)), - GraphQLField("countTicket", type: .scalar(Int.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(count: Int, countWithAvailability: Int? = nil, countHotel: Int? = nil, countPackage: Int? = nil, countTicket: Int? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchMeta", "count": count, "countWithAvailability": countWithAvailability, "countHotel": countHotel, "countPackage": countPackage, "countTicket": countTicket]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Quantity of products found. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - - /// Quantity of products found with availability. - public var countWithAvailability: Int? { - get { - return resultMap["countWithAvailability"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countWithAvailability") - } - } - - /// Quantity of hotels found. - public var countHotel: Int? { - get { - return resultMap["countHotel"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countHotel") - } - } - - /// Quantity of packages found. - public var countPackage: Int? { - get { - return resultMap["countPackage"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countPackage") - } - } - - /// Quantity of tickets found. - public var countTicket: Int? { - get { - return resultMap["countTicket"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countTicket") - } - } - } - - public struct Pagination: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchPagination"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(HUGScalarNonNegativeInt.self))), - GraphQLField("current", type: .nonNull(.scalar(HUGScalarNonNegativeInt.self))), - GraphQLField("hasNext", type: .nonNull(.scalar(Bool.self))), - GraphQLField("hasPrevious", type: .nonNull(.scalar(Bool.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(count: HUGScalarNonNegativeInt, current: HUGScalarNonNegativeInt, hasNext: Bool, hasPrevious: Bool) { - self.init(unsafeResultMap: ["__typename": "SearchPagination", "count": count, "current": current, "hasNext": hasNext, "hasPrevious": hasPrevious]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Number of pages. - public var count: HUGScalarNonNegativeInt { - get { - return resultMap["count"]! as! HUGScalarNonNegativeInt - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - - /// Inform current page. - public var current: HUGScalarNonNegativeInt { - get { - return resultMap["current"]! as! HUGScalarNonNegativeInt - } - set { - resultMap.updateValue(newValue, forKey: "current") - } - } - - /// Inform if exists a next page. - public var hasNext: Bool { - get { - return resultMap["hasNext"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "hasNext") - } - } - - /// Inform if exists a previous page. - public var hasPrevious: Bool { - get { - return resultMap["hasPrevious"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "hasPrevious") - } - } - } - } - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SearchPackageQuery.graphql.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SearchPackageQuery.graphql.swift deleted file mode 100644 index f44a1b7f1..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SearchPackageQuery.graphql.swift +++ /dev/null @@ -1,1723 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -/// HUGraphQL namespace -public extension HUGraphQL { - final class SearchPackageQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query searchPackage($q: String!, $filters: SearchPackageInputFilters, $pagination: SearchInputPagination, $l10n: InputL10n) { - searchPackage(q: $q, filters: $filters, pagination: $pagination, l10n: $l10n) { - __typename - filters { - __typename - cities { - __typename - label - filter - count - } - states { - __typename - label - filter - count - } - countries { - __typename - label - filter - count - } - departureCities { - __typename - label - filter - count - } - duration { - __typename - label - filter - count - } - food { - __typename - label - filter - count - } - people { - __typename - label - filter - count - } - priceInterval { - __typename - min - max - } - prices { - __typename - min - maxExclusive - filter - count - } - } - results { - __typename - id - sku - name - url - category - description - smallDescription - price { - __typename - currency - amount - originalAmount - } - address { - __typename - city - state - country - geoLocation { - __typename - lat - lon - } - } - tags { - __typename - label - slug - } - gallery { - __typename - url - description - } - amenities { - __typename - name - category - } - isAvailable - startDate - endDate - quantityDescriptors { - __typename - duration - nights - maxFreeChildrenAge - maxPeople - } - } - meta { - __typename - count - countWithAvailability - countHotel - countPackage - countTicket - } - pagination { - __typename - count - current - hasNext - hasPrevious - } - } - } - """ - - public let operationName: String = "searchPackage" - - public var q: String - public var filters: SearchPackageInputFilters? - public var pagination: SearchInputPagination? - public var l10n: InputL10n? - - public init(q: String, filters: SearchPackageInputFilters? = nil, pagination: SearchInputPagination? = nil, l10n: InputL10n? = nil) { - self.q = q - self.filters = filters - self.pagination = pagination - self.l10n = l10n - } - - public var variables: GraphQLMap? { - return ["q": q, "filters": filters, "pagination": pagination, "l10n": l10n] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("searchPackage", arguments: ["q": GraphQLVariable("q"), "filters": GraphQLVariable("filters"), "pagination": GraphQLVariable("pagination"), "l10n": GraphQLVariable("l10n")], type: .object(SearchPackage.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(searchPackage: SearchPackage? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "searchPackage": searchPackage.flatMap { (value: SearchPackage) -> ResultMap in value.resultMap }]) - } - - /// Fetches products in Search API. - public var searchPackage: SearchPackage? { - get { - return (resultMap["searchPackage"] as? ResultMap).flatMap { SearchPackage(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "searchPackage") - } - } - - public struct SearchPackage: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchPackage"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("filters", type: .object(Filter.selections)), - GraphQLField("results", type: .list(.nonNull(.object(Result.selections)))), - GraphQLField("meta", type: .nonNull(.object(Metum.selections))), - GraphQLField("pagination", type: .object(Pagination.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(filters: Filter? = nil, results: [Result]? = nil, meta: Metum, pagination: Pagination? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchPackage", "filters": filters.flatMap { (value: Filter) -> ResultMap in value.resultMap }, "results": results.flatMap { (value: [Result]) -> [ResultMap] in value.map { (value: Result) -> ResultMap in value.resultMap } }, "meta": meta.resultMap, "pagination": pagination.flatMap { (value: Pagination) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filters available. - public var filters: Filter? { - get { - return (resultMap["filters"] as? ResultMap).flatMap { Filter(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "filters") - } - } - - /// Results found. - public var results: [Result]? { - get { - return (resultMap["results"] as? [ResultMap]).flatMap { (value: [ResultMap]) -> [Result] in value.map { (value: ResultMap) -> Result in Result(unsafeResultMap: value) } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Result]) -> [ResultMap] in value.map { (value: Result) -> ResultMap in value.resultMap } }, forKey: "results") - } - } - - /// Meta-information from search results. - public var meta: Metum { - get { - return Metum(unsafeResultMap: resultMap["meta"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "meta") - } - } - - /// Necessary info to construct a pagination. - public var pagination: Pagination? { - get { - return (resultMap["pagination"] as? ResultMap).flatMap { Pagination(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "pagination") - } - } - - public struct Filter: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchPackageFilters"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("cities", type: .list(.object(City.selections))), - GraphQLField("states", type: .list(.object(State.selections))), - GraphQLField("countries", type: .list(.object(Country.selections))), - GraphQLField("departureCities", type: .list(.object(DepartureCity.selections))), - GraphQLField("duration", type: .list(.object(Duration.selections))), - GraphQLField("food", type: .list(.object(Food.selections))), - GraphQLField("people", type: .list(.object(Person.selections))), - GraphQLField("priceInterval", type: .object(PriceInterval.selections)), - GraphQLField("prices", type: .list(.object(Price.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(cities: [City?]? = nil, states: [State?]? = nil, countries: [Country?]? = nil, departureCities: [DepartureCity?]? = nil, duration: [Duration?]? = nil, food: [Food?]? = nil, people: [Person?]? = nil, priceInterval: PriceInterval? = nil, prices: [Price?]? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchPackageFilters", "cities": cities.flatMap { (value: [City?]) -> [ResultMap?] in value.map { (value: City?) -> ResultMap? in value.flatMap { (value: City) -> ResultMap in value.resultMap } } }, "states": states.flatMap { (value: [State?]) -> [ResultMap?] in value.map { (value: State?) -> ResultMap? in value.flatMap { (value: State) -> ResultMap in value.resultMap } } }, "countries": countries.flatMap { (value: [Country?]) -> [ResultMap?] in value.map { (value: Country?) -> ResultMap? in value.flatMap { (value: Country) -> ResultMap in value.resultMap } } }, "departureCities": departureCities.flatMap { (value: [DepartureCity?]) -> [ResultMap?] in value.map { (value: DepartureCity?) -> ResultMap? in value.flatMap { (value: DepartureCity) -> ResultMap in value.resultMap } } }, "duration": duration.flatMap { (value: [Duration?]) -> [ResultMap?] in value.map { (value: Duration?) -> ResultMap? in value.flatMap { (value: Duration) -> ResultMap in value.resultMap } } }, "food": food.flatMap { (value: [Food?]) -> [ResultMap?] in value.map { (value: Food?) -> ResultMap? in value.flatMap { (value: Food) -> ResultMap in value.resultMap } } }, "people": people.flatMap { (value: [Person?]) -> [ResultMap?] in value.map { (value: Person?) -> ResultMap? in value.flatMap { (value: Person) -> ResultMap in value.resultMap } } }, "priceInterval": priceInterval.flatMap { (value: PriceInterval) -> ResultMap in value.resultMap }, "prices": prices.flatMap { (value: [Price?]) -> [ResultMap?] in value.map { (value: Price?) -> ResultMap? in value.flatMap { (value: Price) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Cities filter. - public var cities: [City?]? { - get { - return (resultMap["cities"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [City?] in value.map { (value: ResultMap?) -> City? in value.flatMap { (value: ResultMap) -> City in City(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [City?]) -> [ResultMap?] in value.map { (value: City?) -> ResultMap? in value.flatMap { (value: City) -> ResultMap in value.resultMap } } }, forKey: "cities") - } - } - - /// States filter. - public var states: [State?]? { - get { - return (resultMap["states"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [State?] in value.map { (value: ResultMap?) -> State? in value.flatMap { (value: ResultMap) -> State in State(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [State?]) -> [ResultMap?] in value.map { (value: State?) -> ResultMap? in value.flatMap { (value: State) -> ResultMap in value.resultMap } } }, forKey: "states") - } - } - - /// Countries filter. - public var countries: [Country?]? { - get { - return (resultMap["countries"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Country?] in value.map { (value: ResultMap?) -> Country? in value.flatMap { (value: ResultMap) -> Country in Country(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Country?]) -> [ResultMap?] in value.map { (value: Country?) -> ResultMap? in value.flatMap { (value: Country) -> ResultMap in value.resultMap } } }, forKey: "countries") - } - } - - /// Departure cities filter. - public var departureCities: [DepartureCity?]? { - get { - return (resultMap["departureCities"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [DepartureCity?] in value.map { (value: ResultMap?) -> DepartureCity? in value.flatMap { (value: ResultMap) -> DepartureCity in DepartureCity(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [DepartureCity?]) -> [ResultMap?] in value.map { (value: DepartureCity?) -> ResultMap? in value.flatMap { (value: DepartureCity) -> ResultMap in value.resultMap } } }, forKey: "departureCities") - } - } - - /// Duration filter. - public var duration: [Duration?]? { - get { - return (resultMap["duration"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Duration?] in value.map { (value: ResultMap?) -> Duration? in value.flatMap { (value: ResultMap) -> Duration in Duration(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Duration?]) -> [ResultMap?] in value.map { (value: Duration?) -> ResultMap? in value.flatMap { (value: Duration) -> ResultMap in value.resultMap } } }, forKey: "duration") - } - } - - /// Food filter. - public var food: [Food?]? { - get { - return (resultMap["food"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Food?] in value.map { (value: ResultMap?) -> Food? in value.flatMap { (value: ResultMap) -> Food in Food(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Food?]) -> [ResultMap?] in value.map { (value: Food?) -> ResultMap? in value.flatMap { (value: Food) -> ResultMap in value.resultMap } } }, forKey: "food") - } - } - - /// People filter. - public var people: [Person?]? { - get { - return (resultMap["people"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Person?] in value.map { (value: ResultMap?) -> Person? in value.flatMap { (value: ResultMap) -> Person in Person(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Person?]) -> [ResultMap?] in value.map { (value: Person?) -> ResultMap? in value.flatMap { (value: Person) -> ResultMap in value.resultMap } } }, forKey: "people") - } - } - - /// Price interval filter. - public var priceInterval: PriceInterval? { - get { - return (resultMap["priceInterval"] as? ResultMap).flatMap { PriceInterval(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "priceInterval") - } - } - - /// Price filter. - public var prices: [Price?]? { - get { - return (resultMap["prices"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Price?] in value.map { (value: ResultMap?) -> Price? in value.flatMap { (value: ResultMap) -> Price in Price(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Price?]) -> [ResultMap?] in value.map { (value: Price?) -> ResultMap? in value.flatMap { (value: Price) -> ResultMap in value.resultMap } } }, forKey: "prices") - } - } - - public struct City: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct State: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Country: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct DepartureCity: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Duration: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Food: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct Person: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchTermFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchTermFilter", "label": label, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Filter label. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// The term used to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - - public struct PriceInterval: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchIntervalFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("min", type: .nonNull(.scalar(Double.self))), - GraphQLField("max", type: .nonNull(.scalar(Double.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(min: Double, max: Double) { - self.init(unsafeResultMap: ["__typename": "SearchIntervalFilter", "min": min, "max": max]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Min interval value. - public var min: Double { - get { - return resultMap["min"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "min") - } - } - - /// Max interval value. - public var max: Double { - get { - return resultMap["max"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "max") - } - } - } - - public struct Price: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchPriceGroupFilter"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("min", type: .nonNull(.scalar(Int.self))), - GraphQLField("maxExclusive", type: .nonNull(.scalar(Int.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(min: Int, maxExclusive: Int, filter: String, count: Int) { - self.init(unsafeResultMap: ["__typename": "SearchPriceGroupFilter", "min": min, "maxExclusive": maxExclusive, "filter": filter, "count": count]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Min range value. - public var min: Int { - get { - return resultMap["min"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "min") - } - } - - /// Max range value (exclusive). - public var maxExclusive: Int { - get { - return resultMap["maxExclusive"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "maxExclusive") - } - } - - /// The range group represented as a term to filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Total results that contain this term. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - } - } - - public struct Result: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultPackageItem"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .scalar(GraphQLID.self)), - GraphQLField("sku", type: .nonNull(.scalar(HUGScalarSKU.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("url", type: .nonNull(.scalar(String.self))), - GraphQLField("category", type: .nonNull(.scalar(String.self))), - GraphQLField("description", type: .nonNull(.scalar(String.self))), - GraphQLField("smallDescription", type: .nonNull(.scalar(String.self))), - GraphQLField("price", type: .nonNull(.object(Price.selections))), - GraphQLField("address", type: .object(Address.selections)), - GraphQLField("tags", type: .nonNull(.list(.nonNull(.object(Tag.selections))))), - GraphQLField("gallery", type: .nonNull(.list(.nonNull(.object(Gallery.selections))))), - GraphQLField("amenities", type: .nonNull(.list(.nonNull(.object(Amenity.selections))))), - GraphQLField("isAvailable", type: .nonNull(.scalar(Bool.self))), - GraphQLField("startDate", type: .scalar(String.self)), - GraphQLField("endDate", type: .scalar(String.self)), - GraphQLField("quantityDescriptors", type: .nonNull(.object(QuantityDescriptor.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(id: GraphQLID? = nil, sku: HUGScalarSKU, name: String, url: String, category: String, description: String, smallDescription: String, price: Price, address: Address? = nil, tags: [Tag], gallery: [Gallery], amenities: [Amenity], isAvailable: Bool, startDate: String? = nil, endDate: String? = nil, quantityDescriptors: QuantityDescriptor) { - self.init(unsafeResultMap: ["__typename": "SearchResultPackageItem", "id": id, "sku": sku, "name": name, "url": url, "category": category, "description": description, "smallDescription": smallDescription, "price": price.resultMap, "address": address.flatMap { (value: Address) -> ResultMap in value.resultMap }, "tags": tags.map { (value: Tag) -> ResultMap in value.resultMap }, "gallery": gallery.map { (value: Gallery) -> ResultMap in value.resultMap }, "amenities": amenities.map { (value: Amenity) -> ResultMap in value.resultMap }, "isAvailable": isAvailable, "startDate": startDate, "endDate": endDate, "quantityDescriptors": quantityDescriptors.resultMap]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Product id. - public var id: GraphQLID? { - get { - return resultMap["id"] as? GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// Product sku. - public var sku: HUGScalarSKU { - get { - return resultMap["sku"]! as! HUGScalarSKU - } - set { - resultMap.updateValue(newValue, forKey: "sku") - } - } - - /// Product name. - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Product url. - public var url: String { - get { - return resultMap["url"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "url") - } - } - - /// Product category. - public var category: String { - get { - return resultMap["category"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "category") - } - } - - /// Product description. - public var description: String { - get { - return resultMap["description"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "description") - } - } - - /// Product short description. - public var smallDescription: String { - get { - return resultMap["smallDescription"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "smallDescription") - } - } - - /// Product price. - public var price: Price { - get { - return Price(unsafeResultMap: resultMap["price"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "price") - } - } - - /// Product address. - public var address: Address? { - get { - return (resultMap["address"] as? ResultMap).flatMap { Address(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "address") - } - } - - /// Product tags. - public var tags: [Tag] { - get { - return (resultMap["tags"] as! [ResultMap]).map { (value: ResultMap) -> Tag in Tag(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Tag) -> ResultMap in value.resultMap }, forKey: "tags") - } - } - - /// List of product images. - public var gallery: [Gallery] { - get { - return (resultMap["gallery"] as! [ResultMap]).map { (value: ResultMap) -> Gallery in Gallery(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Gallery) -> ResultMap in value.resultMap }, forKey: "gallery") - } - } - - /// List of product amenities. - public var amenities: [Amenity] { - get { - return (resultMap["amenities"] as! [ResultMap]).map { (value: ResultMap) -> Amenity in Amenity(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Amenity) -> ResultMap in value.resultMap }, forKey: "amenities") - } - } - - /// Inform if the product is available - public var isAvailable: Bool { - get { - return resultMap["isAvailable"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "isAvailable") - } - } - - /// Start of valid period. - public var startDate: String? { - get { - return resultMap["startDate"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "startDate") - } - } - - /// End of valid period. - public var endDate: String? { - get { - return resultMap["endDate"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "endDate") - } - } - - /// Describes quantities and limits related to the product. - public var quantityDescriptors: QuantityDescriptor { - get { - return QuantityDescriptor(unsafeResultMap: resultMap["quantityDescriptors"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "quantityDescriptors") - } - } - - public struct Price: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["ProductPrice"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("currency", type: .scalar(String.self)), - GraphQLField("amount", type: .nonNull(.scalar(Double.self))), - GraphQLField("originalAmount", type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(currency: String? = nil, amount: Double, originalAmount: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "ProductPrice", "currency": currency, "amount": amount, "originalAmount": originalAmount]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Price currency. - public var currency: String? { - get { - return resultMap["currency"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "currency") - } - } - - /// Price amount. - public var amount: Double { - get { - return resultMap["amount"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "amount") - } - } - - /// Original price amount. - public var originalAmount: Double? { - get { - return resultMap["originalAmount"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "originalAmount") - } - } - } - - public struct Address: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemAddress"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("city", type: .scalar(String.self)), - GraphQLField("state", type: .scalar(String.self)), - GraphQLField("country", type: .scalar(String.self)), - GraphQLField("geoLocation", type: .object(GeoLocation.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(city: String? = nil, state: String? = nil, country: String? = nil, geoLocation: GeoLocation? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemAddress", "city": city, "state": state, "country": country, "geoLocation": geoLocation.flatMap { (value: GeoLocation) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Product city. - public var city: String? { - get { - return resultMap["city"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "city") - } - } - - /// Product state. - public var state: String? { - get { - return resultMap["state"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "state") - } - } - - /// Product country. - public var country: String? { - get { - return resultMap["country"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "country") - } - } - - /// Product geolocation. - public var geoLocation: GeoLocation? { - get { - return (resultMap["geoLocation"] as? ResultMap).flatMap { GeoLocation(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "geoLocation") - } - } - - public struct GeoLocation: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Coordinates"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("lat", type: .nonNull(.scalar(Double.self))), - GraphQLField("lon", type: .nonNull(.scalar(Double.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(lat: Double, lon: Double) { - self.init(unsafeResultMap: ["__typename": "Coordinates", "lat": lat, "lon": lon]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var lat: Double { - get { - return resultMap["lat"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "lat") - } - } - - public var lon: Double { - get { - return resultMap["lon"]! as! Double - } - set { - resultMap.updateValue(newValue, forKey: "lon") - } - } - } - } - - public struct Tag: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemTag"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("label", type: .nonNull(.scalar(String.self))), - GraphQLField("slug", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(label: String, slug: String) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemTag", "label": label, "slug": slug]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Label of the product tag. - public var label: String { - get { - return resultMap["label"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "label") - } - } - - /// Slug of the product tag. - public var slug: String { - get { - return resultMap["slug"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "slug") - } - } - } - - public struct Gallery: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemGalleryImage"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("url", type: .scalar(String.self)), - GraphQLField("description", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(url: String? = nil, description: String? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemGalleryImage", "url": url, "description": description]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Gallery image url. - public var url: String? { - get { - return resultMap["url"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "url") - } - } - - /// Gallery image description. - public var description: String? { - get { - return resultMap["description"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "description") - } - } - } - - public struct Amenity: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemAmenity"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("category", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, category: String? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemAmenity", "name": name, "category": category]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Amenity name. - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Amenity category. - public var category: String? { - get { - return resultMap["category"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "category") - } - } - } - - public struct QuantityDescriptor: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchResultItemQuantityDescriptors"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("duration", type: .nonNull(.scalar(Int.self))), - GraphQLField("nights", type: .scalar(Int.self)), - GraphQLField("maxFreeChildrenAge", type: .scalar(Int.self)), - GraphQLField("maxPeople", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(duration: Int, nights: Int? = nil, maxFreeChildrenAge: Int? = nil, maxPeople: Int) { - self.init(unsafeResultMap: ["__typename": "SearchResultItemQuantityDescriptors", "duration": duration, "nights": nights, "maxFreeChildrenAge": maxFreeChildrenAge, "maxPeople": maxPeople]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Duration of a package or ticket. - public var duration: Int { - get { - return resultMap["duration"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "duration") - } - } - - /// Number of nights for the stay. - public var nights: Int? { - get { - return resultMap["nights"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "nights") - } - } - - /// Maximum children age for free accommodation. - public var maxFreeChildrenAge: Int? { - get { - return resultMap["maxFreeChildrenAge"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "maxFreeChildrenAge") - } - } - - /// Maximum number of people on the room. - public var maxPeople: Int { - get { - return resultMap["maxPeople"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "maxPeople") - } - } - } - } - - public struct Metum: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchMeta"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(Int.self))), - GraphQLField("countWithAvailability", type: .scalar(Int.self)), - GraphQLField("countHotel", type: .scalar(Int.self)), - GraphQLField("countPackage", type: .scalar(Int.self)), - GraphQLField("countTicket", type: .scalar(Int.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(count: Int, countWithAvailability: Int? = nil, countHotel: Int? = nil, countPackage: Int? = nil, countTicket: Int? = nil) { - self.init(unsafeResultMap: ["__typename": "SearchMeta", "count": count, "countWithAvailability": countWithAvailability, "countHotel": countHotel, "countPackage": countPackage, "countTicket": countTicket]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Quantity of products found. - public var count: Int { - get { - return resultMap["count"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - - /// Quantity of products found with availability. - public var countWithAvailability: Int? { - get { - return resultMap["countWithAvailability"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countWithAvailability") - } - } - - /// Quantity of hotels found. - public var countHotel: Int? { - get { - return resultMap["countHotel"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countHotel") - } - } - - /// Quantity of packages found. - public var countPackage: Int? { - get { - return resultMap["countPackage"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countPackage") - } - } - - /// Quantity of tickets found. - public var countTicket: Int? { - get { - return resultMap["countTicket"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "countTicket") - } - } - } - - public struct Pagination: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SearchPagination"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("count", type: .nonNull(.scalar(HUGScalarNonNegativeInt.self))), - GraphQLField("current", type: .nonNull(.scalar(HUGScalarNonNegativeInt.self))), - GraphQLField("hasNext", type: .nonNull(.scalar(Bool.self))), - GraphQLField("hasPrevious", type: .nonNull(.scalar(Bool.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(count: HUGScalarNonNegativeInt, current: HUGScalarNonNegativeInt, hasNext: Bool, hasPrevious: Bool) { - self.init(unsafeResultMap: ["__typename": "SearchPagination", "count": count, "current": current, "hasNext": hasNext, "hasPrevious": hasPrevious]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Number of pages. - public var count: HUGScalarNonNegativeInt { - get { - return resultMap["count"]! as! HUGScalarNonNegativeInt - } - set { - resultMap.updateValue(newValue, forKey: "count") - } - } - - /// Inform current page. - public var current: HUGScalarNonNegativeInt { - get { - return resultMap["current"]! as! HUGScalarNonNegativeInt - } - set { - resultMap.updateValue(newValue, forKey: "current") - } - } - - /// Inform if exists a next page. - public var hasNext: Bool { - get { - return resultMap["hasNext"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "hasNext") - } - } - - /// Inform if exists a previous page. - public var hasPrevious: Bool { - get { - return resultMap["hasPrevious"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "hasPrevious") - } - } - } - } - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SuggestionQuery.graphql.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SuggestionQuery.graphql.swift deleted file mode 100644 index 00a2c1214..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/SuggestionQuery.graphql.swift +++ /dev/null @@ -1,495 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -/// HUGraphQL namespace -public extension HUGraphQL { - final class SuggestionsQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query suggestions($q: String!, $limit: Int, $productType: SuggestionProductType, $l10n: InputL10n!) { - suggestions(q: $q, limit: $limit, productType: $productType, l10n: $l10n) { - __typename - results { - __typename - ... on LocationSuggestion { - text - filter - suggestionType - country - state - city - } - ... on ProductSuggestion { - text - filter - suggestionType - sku - productType - country - state - city - } - ... on TagSuggestion { - text - filter - suggestionType - } - } - total - } - } - """ - - public let operationName: String = "suggestions" - - public var q: String - public var limit: Int? - public var productType: SuggestionProductType? - public var l10n: InputL10n - - public init(q: String, limit: Int? = nil, productType: SuggestionProductType? = nil, l10n: InputL10n) { - self.q = q - self.limit = limit - self.productType = productType - self.l10n = l10n - } - - public var variables: GraphQLMap? { - return ["q": q, "limit": limit, "productType": productType, "l10n": l10n] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("suggestions", arguments: ["q": GraphQLVariable("q"), "limit": GraphQLVariable("limit"), "productType": GraphQLVariable("productType"), "l10n": GraphQLVariable("l10n")], type: .object(Suggestion.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(suggestions: Suggestion? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "suggestions": suggestions.flatMap { (value: Suggestion) -> ResultMap in value.resultMap }]) - } - - /// Fetches suggestions in Search API. - public var suggestions: Suggestion? { - get { - return (resultMap["suggestions"] as? ResultMap).flatMap { Suggestion(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "suggestions") - } - } - - public struct Suggestion: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["SuggestionPayload"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("results", type: .nonNull(.list(.nonNull(.object(Result.selections))))), - GraphQLField("total", type: .nonNull(.scalar(Int.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(results: [Result], total: Int) { - self.init(unsafeResultMap: ["__typename": "SuggestionPayload", "results": results.map { (value: Result) -> ResultMap in value.resultMap }, "total": total]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Results found. - public var results: [Result] { - get { - return (resultMap["results"] as! [ResultMap]).map { (value: ResultMap) -> Result in Result(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: Result) -> ResultMap in value.resultMap }, forKey: "results") - } - } - - /// Total results counter. - public var total: Int { - get { - return resultMap["total"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "total") - } - } - - public struct Result: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["LocationSuggestion", "ProductSuggestion", "TagSuggestion"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["LocationSuggestion": AsLocationSuggestion.selections, "ProductSuggestion": AsProductSuggestion.selections, "TagSuggestion": AsTagSuggestion.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeLocationSuggestion(text: String, filter: String, suggestionType: String, country: String? = nil, state: String? = nil, city: String? = nil) -> Result { - return Result(unsafeResultMap: ["__typename": "LocationSuggestion", "text": text, "filter": filter, "suggestionType": suggestionType, "country": country, "state": state, "city": city]) - } - - public static func makeProductSuggestion(text: String, filter: String, suggestionType: String, sku: HUGScalarSKU, productType: String, country: String? = nil, state: String? = nil, city: String? = nil) -> Result { - return Result(unsafeResultMap: ["__typename": "ProductSuggestion", "text": text, "filter": filter, "suggestionType": suggestionType, "sku": sku, "productType": productType, "country": country, "state": state, "city": city]) - } - - public static func makeTagSuggestion(text: String, filter: String, suggestionType: String) -> Result { - return Result(unsafeResultMap: ["__typename": "TagSuggestion", "text": text, "filter": filter, "suggestionType": suggestionType]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var asLocationSuggestion: AsLocationSuggestion? { - get { - if !AsLocationSuggestion.possibleTypes.contains(__typename) { return nil } - return AsLocationSuggestion(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsLocationSuggestion: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["LocationSuggestion"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("text", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("suggestionType", type: .nonNull(.scalar(String.self))), - GraphQLField("country", type: .scalar(String.self)), - GraphQLField("state", type: .scalar(String.self)), - GraphQLField("city", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(text: String, filter: String, suggestionType: String, country: String? = nil, state: String? = nil, city: String? = nil) { - self.init(unsafeResultMap: ["__typename": "LocationSuggestion", "text": text, "filter": filter, "suggestionType": suggestionType, "country": country, "state": state, "city": city]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Suggestion text. - public var text: String { - get { - return resultMap["text"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "text") - } - } - - /// Suggestion filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Suggestion Type. - public var suggestionType: String { - get { - return resultMap["suggestionType"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "suggestionType") - } - } - - /// Location suggestion country. - public var country: String? { - get { - return resultMap["country"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "country") - } - } - - /// Location suggestion state. - public var state: String? { - get { - return resultMap["state"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "state") - } - } - - /// Location suggestion city. - public var city: String? { - get { - return resultMap["city"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "city") - } - } - } - - public var asProductSuggestion: AsProductSuggestion? { - get { - if !AsProductSuggestion.possibleTypes.contains(__typename) { return nil } - return AsProductSuggestion(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsProductSuggestion: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["ProductSuggestion"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("text", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("suggestionType", type: .nonNull(.scalar(String.self))), - GraphQLField("sku", type: .nonNull(.scalar(HUGScalarSKU.self))), - GraphQLField("productType", type: .nonNull(.scalar(String.self))), - GraphQLField("country", type: .scalar(String.self)), - GraphQLField("state", type: .scalar(String.self)), - GraphQLField("city", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(text: String, filter: String, suggestionType: String, sku: HUGScalarSKU, productType: String, country: String? = nil, state: String? = nil, city: String? = nil) { - self.init(unsafeResultMap: ["__typename": "ProductSuggestion", "text": text, "filter": filter, "suggestionType": suggestionType, "sku": sku, "productType": productType, "country": country, "state": state, "city": city]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Suggestion text. - public var text: String { - get { - return resultMap["text"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "text") - } - } - - /// Suggestion filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Suggestion Type. - public var suggestionType: String { - get { - return resultMap["suggestionType"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "suggestionType") - } - } - - /// Suggestion product SKU. - public var sku: HUGScalarSKU { - get { - return resultMap["sku"]! as! HUGScalarSKU - } - set { - resultMap.updateValue(newValue, forKey: "sku") - } - } - - /// Suggestion product type. - public var productType: String { - get { - return resultMap["productType"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "productType") - } - } - - /// Suggestion product country. - public var country: String? { - get { - return resultMap["country"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "country") - } - } - - /// Suggestion product state. - public var state: String? { - get { - return resultMap["state"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "state") - } - } - - /// Suggestion product city. - public var city: String? { - get { - return resultMap["city"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "city") - } - } - } - - public var asTagSuggestion: AsTagSuggestion? { - get { - if !AsTagSuggestion.possibleTypes.contains(__typename) { return nil } - return AsTagSuggestion(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsTagSuggestion: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["TagSuggestion"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("text", type: .nonNull(.scalar(String.self))), - GraphQLField("filter", type: .nonNull(.scalar(String.self))), - GraphQLField("suggestionType", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(text: String, filter: String, suggestionType: String) { - self.init(unsafeResultMap: ["__typename": "TagSuggestion", "text": text, "filter": filter, "suggestionType": suggestionType]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Suggestion text. - public var text: String { - get { - return resultMap["text"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "text") - } - } - - /// Suggestion filter. - public var filter: String { - get { - return resultMap["filter"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filter") - } - } - - /// Suggestion Type. - public var suggestionType: String { - get { - return resultMap["suggestionType"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "suggestionType") - } - } - } - } - } - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/Types.graphql.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/Types.graphql.swift deleted file mode 100644 index 084a3ad99..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Generated/Types.graphql.swift +++ /dev/null @@ -1,615 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -/// HUGraphQL namespace -public enum HUGraphQL { - /// Represents input data for field pagination. - public struct SearchInputPagination: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - page: Current search page. - /// - limit: Limit for search results. - /// - sort: Sorts results. - /// - sortOrder: Sorts by order. - public init(page: Swift.Optional = nil, limit: Swift.Optional = nil, sort: Swift.Optional = nil, sortOrder: Swift.Optional = nil) { - graphQLMap = ["page": page, "limit": limit, "sort": sort, "sortOrder": sortOrder] - } - - /// Current search page. - public var page: Swift.Optional { - get { - return graphQLMap["page"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "page") - } - } - - /// Limit for search results. - public var limit: Swift.Optional { - get { - return graphQLMap["limit"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "limit") - } - } - - /// Sorts results. - public var sort: Swift.Optional { - get { - return graphQLMap["sort"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "sort") - } - } - - /// Sorts by order. - public var sortOrder: Swift.Optional { - get { - return graphQLMap["sortOrder"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "sortOrder") - } - } - } - - /// Sort types. - public enum SearchInputSort: RawRepresentable, Equatable, Hashable, CaseIterable, Apollo.JSONDecodable, Apollo.JSONEncodable { - public typealias RawValue = String - case score - case price - /// Auto generated constant for unknown enum values - case __unknown(RawValue) - - public init?(rawValue: RawValue) { - switch rawValue { - case "SCORE": self = .score - case "PRICE": self = .price - default: self = .__unknown(rawValue) - } - } - - public var rawValue: RawValue { - switch self { - case .score: return "SCORE" - case .price: return "PRICE" - case .__unknown(let value): return value - } - } - - public static func == (lhs: SearchInputSort, rhs: SearchInputSort) -> Bool { - switch (lhs, rhs) { - case (.score, .score): return true - case (.price, .price): return true - case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue - default: return false - } - } - - public static var allCases: [SearchInputSort] { - return [ - .score, - .price, - ] - } - } - - /// Order types. - public enum SearchInputSortOrder: RawRepresentable, Equatable, Hashable, CaseIterable, Apollo.JSONDecodable, Apollo.JSONEncodable { - public typealias RawValue = String - case asc - case desc - /// Auto generated constant for unknown enum values - case __unknown(RawValue) - - public init?(rawValue: RawValue) { - switch rawValue { - case "ASC": self = .asc - case "DESC": self = .desc - default: self = .__unknown(rawValue) - } - } - - public var rawValue: RawValue { - switch self { - case .asc: return "ASC" - case .desc: return "DESC" - case .__unknown(let value): return value - } - } - - public static func == (lhs: SearchInputSortOrder, rhs: SearchInputSortOrder) -> Bool { - switch (lhs, rhs) { - case (.asc, .asc): return true - case (.desc, .desc): return true - case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue - default: return false - } - } - - public static var allCases: [SearchInputSortOrder] { - return [ - .asc, - .desc, - ] - } - } - - /// Represents input data for field filters. - public struct SearchHotelInputFilters: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - cities: Cities filter. - /// - states: States filter. - /// - countries: Countries filter. - /// - food: Food filter. - /// - people: People filter. - /// - priceInterval: Price interval filter. - /// - prices: Price filter. - /// - stars: Star filter. - /// - sku: Product SKU filter - /// - amenities: Product amenity filter - public init(cities: Swift.Optional = nil, states: Swift.Optional = nil, countries: Swift.Optional = nil, food: Swift.Optional = nil, people: Swift.Optional = nil, priceInterval: Swift.Optional = nil, prices: Swift.Optional = nil, stars: Swift.Optional = nil, sku: Swift.Optional = nil, amenities: Swift.Optional = nil) { - graphQLMap = ["cities": cities, "states": states, "countries": countries, "food": food, "people": people, "priceInterval": priceInterval, "prices": prices, "stars": stars, "sku": sku, "amenities": amenities] - } - - /// Cities filter. - public var cities: Swift.Optional { - get { - return graphQLMap["cities"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "cities") - } - } - - /// States filter. - public var states: Swift.Optional { - get { - return graphQLMap["states"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "states") - } - } - - /// Countries filter. - public var countries: Swift.Optional { - get { - return graphQLMap["countries"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "countries") - } - } - - /// Food filter. - public var food: Swift.Optional { - get { - return graphQLMap["food"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "food") - } - } - - /// People filter. - public var people: Swift.Optional { - get { - return graphQLMap["people"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "people") - } - } - - /// Price interval filter. - public var priceInterval: Swift.Optional { - get { - return graphQLMap["priceInterval"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "priceInterval") - } - } - - /// Price filter. - public var prices: Swift.Optional { - get { - return graphQLMap["prices"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "prices") - } - } - - /// Star filter. - public var stars: Swift.Optional { - get { - return graphQLMap["stars"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "stars") - } - } - - /// Product SKU filter - public var sku: Swift.Optional { - get { - return graphQLMap["sku"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "sku") - } - } - - /// Product amenity filter - public var amenities: Swift.Optional { - get { - return graphQLMap["amenities"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "amenities") - } - } - } - - /// Represents input data for field filters. - public struct SearchInputTermFilter: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - values: Filter values. - /// - operator: Filter operator. - public init(values: [String?], `operator`: SearchFilterOperator) { - graphQLMap = ["values": values, "operator": `operator`] - } - - /// Filter values. - public var values: [String?] { - get { - return graphQLMap["values"] as! [String?] - } - set { - graphQLMap.updateValue(newValue, forKey: "values") - } - } - - /// Filter operator. - public var `operator`: SearchFilterOperator { - get { - return graphQLMap["operator"] as! SearchFilterOperator - } - set { - graphQLMap.updateValue(newValue, forKey: "operator") - } - } - } - - /// Filter Operator. - public enum SearchFilterOperator: RawRepresentable, Equatable, Hashable, CaseIterable, Apollo.JSONDecodable, Apollo.JSONEncodable { - public typealias RawValue = String - case or - case and - case not - /// Auto generated constant for unknown enum values - case __unknown(RawValue) - - public init?(rawValue: RawValue) { - switch rawValue { - case "OR": self = .or - case "AND": self = .and - case "NOT": self = .not - default: self = .__unknown(rawValue) - } - } - - public var rawValue: RawValue { - switch self { - case .or: return "OR" - case .and: return "AND" - case .not: return "NOT" - case .__unknown(let value): return value - } - } - - public static func == (lhs: SearchFilterOperator, rhs: SearchFilterOperator) -> Bool { - switch (lhs, rhs) { - case (.or, .or): return true - case (.and, .and): return true - case (.not, .not): return true - case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue - default: return false - } - } - - public static var allCases: [SearchFilterOperator] { - return [ - .or, - .and, - .not, - ] - } - } - - /// Represents input data for interval filter. - public struct SearchInputIntervalFilter: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - min: Min value. - /// - max: Max value. - public init(min: Double, max: Double) { - graphQLMap = ["min": min, "max": max] - } - - /// Min value. - public var min: Double { - get { - return graphQLMap["min"] as! Double - } - set { - graphQLMap.updateValue(newValue, forKey: "min") - } - } - - /// Max value. - public var max: Double { - get { - return graphQLMap["max"] as! Double - } - set { - graphQLMap.updateValue(newValue, forKey: "max") - } - } - } - - /// Localization information. - public struct InputL10n: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - pos: Point of sale. - /// - locale: Localization. - /// - currency: Currency code. - public init(pos: HUGScalarPosID, locale: Swift.Optional = nil, currency: Swift.Optional = nil) { - graphQLMap = ["pos": pos, "locale": locale, "currency": currency] - } - - /// Point of sale. - public var pos: HUGScalarPosID { - get { - return graphQLMap["pos"] as! HUGScalarPosID - } - set { - graphQLMap.updateValue(newValue, forKey: "pos") - } - } - - /// Localization. - public var locale: Swift.Optional { - get { - return graphQLMap["locale"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "locale") - } - } - - /// Currency code. - public var currency: Swift.Optional { - get { - return graphQLMap["currency"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "currency") - } - } - } - - /// Room information. - public struct SearchInputRooms: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - adults: Number of adults per room. - /// - children: List of children ages. - public init(adults: HUGScalarPositiveInt, children: [HUGScalarNonNegativeInt]) { - graphQLMap = ["adults": adults, "children": children] - } - - /// Number of adults per room. - public var adults: HUGScalarPositiveInt { - get { - return graphQLMap["adults"] as! HUGScalarPositiveInt - } - set { - graphQLMap.updateValue(newValue, forKey: "adults") - } - } - - /// List of children ages. - public var children: [HUGScalarNonNegativeInt] { - get { - return graphQLMap["children"] as! [HUGScalarNonNegativeInt] - } - set { - graphQLMap.updateValue(newValue, forKey: "children") - } - } - } - - /// Represents input data for field filters. - public struct SearchPackageInputFilters: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - cities: Cities filter. - /// - states: States filter. - /// - countries: Countries filter. - /// - departureCities: Departure cities filter. - /// - duration: Duration filter. - /// - food: Food filter. - /// - people: People filter. - /// - priceInterval: Price interval filter. - /// - prices: Price filter. - /// - sku: Product SKU filter - public init(cities: Swift.Optional = nil, states: Swift.Optional = nil, countries: Swift.Optional = nil, departureCities: Swift.Optional = nil, duration: Swift.Optional = nil, food: Swift.Optional = nil, people: Swift.Optional = nil, priceInterval: Swift.Optional = nil, prices: Swift.Optional = nil, sku: Swift.Optional = nil) { - graphQLMap = ["cities": cities, "states": states, "countries": countries, "departureCities": departureCities, "duration": duration, "food": food, "people": people, "priceInterval": priceInterval, "prices": prices, "sku": sku] - } - - /// Cities filter. - public var cities: Swift.Optional { - get { - return graphQLMap["cities"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "cities") - } - } - - /// States filter. - public var states: Swift.Optional { - get { - return graphQLMap["states"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "states") - } - } - - /// Countries filter. - public var countries: Swift.Optional { - get { - return graphQLMap["countries"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "countries") - } - } - - /// Departure cities filter. - public var departureCities: Swift.Optional { - get { - return graphQLMap["departureCities"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "departureCities") - } - } - - /// Duration filter. - public var duration: Swift.Optional { - get { - return graphQLMap["duration"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "duration") - } - } - - /// Food filter. - public var food: Swift.Optional { - get { - return graphQLMap["food"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "food") - } - } - - /// People filter. - public var people: Swift.Optional { - get { - return graphQLMap["people"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "people") - } - } - - /// Price interval filter. - public var priceInterval: Swift.Optional { - get { - return graphQLMap["priceInterval"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "priceInterval") - } - } - - /// Price filter. - public var prices: Swift.Optional { - get { - return graphQLMap["prices"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "prices") - } - } - - /// Product SKU filter - public var sku: Swift.Optional { - get { - return graphQLMap["sku"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "sku") - } - } - } - - /// Suggestion product types. - public enum SuggestionProductType: RawRepresentable, Equatable, Hashable, CaseIterable, Apollo.JSONDecodable, Apollo.JSONEncodable { - public typealias RawValue = String - case hotel - case package - case ticket - /// Auto generated constant for unknown enum values - case __unknown(RawValue) - - public init?(rawValue: RawValue) { - switch rawValue { - case "HOTEL": self = .hotel - case "PACKAGE": self = .package - case "TICKET": self = .ticket - default: self = .__unknown(rawValue) - } - } - - public var rawValue: RawValue { - switch self { - case .hotel: return "HOTEL" - case .package: return "PACKAGE" - case .ticket: return "TICKET" - case .__unknown(let value): return value - } - } - - public static func == (lhs: SuggestionProductType, rhs: SuggestionProductType) -> Bool { - switch (lhs, rhs) { - case (.hotel, .hotel): return true - case (.package, .package): return true - case (.ticket, .ticket): return true - case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue - default: return false - } - } - - public static var allCases: [SuggestionProductType] { - return [ - .hotel, - .package, - .ticket, - ] - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/HUGService.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/HUGService.swift deleted file mode 100644 index 148fb5e8d..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/HUGService.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// HUGService.swift -// -// -// Created by Theo Mendes on 04/11/21. -// - -import Apollo -import os.log -import Foundation - -public final class HUGService { - /// Log is enabled - private var logEnabled: Bool - private var endpoint = URL(string: "https://graphql.ghucdn.net/graphql")! - - public var client: ApolloClient { - let client = URLSessionClient() - let cache = InMemoryNormalizedCache() - let store = ApolloStore(cache: cache) - let provider = HUGNetworkInterceptorProvider(store: store, client: client, logEnabled: logEnabled) - let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: endpoint) - return ApolloClient(networkTransport: requestChainTransport, store: store) - } - - public init(enableLog: Bool = true) { - self.logEnabled = enableLog - - if enableLog { - os_log("🌐 👶 %@", log: HUGLogger.lifecycleLog(), type: .info, "\(self)") - } - } - - deinit { - if self.logEnabled { - os_log("🌐 ⚰️ %@", log: HUGLogger.lifecycleLog(), type: .info, "\(self)") - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGNetworkInterceptorProvider.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGNetworkInterceptorProvider.swift deleted file mode 100644 index 009a8a2c8..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGNetworkInterceptorProvider.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// HUGNetworkInterceptorProvider.swift -// -// -// Created by Theo Mendes on 04/11/21. -// - -import Apollo - -internal struct HUGNetworkInterceptorProvider: InterceptorProvider { - private let store: ApolloStore - private let client: URLSessionClient - private let logEnabled: Bool - - internal init(store: ApolloStore, client: URLSessionClient, logEnabled: Bool = true) { - self.store = store - self.client = client - self.logEnabled = logEnabled - } - - internal func interceptors(for operation: Operation) -> [ApolloInterceptor] { - var array: [ApolloInterceptor] = [ - MaxRetryInterceptor(), - CacheReadInterceptor(store: self.store), - NetworkFetchInterceptor(client: client), - JSONResponseParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject), - AutomaticPersistedQueryInterceptor(), - CacheWriteInterceptor(store: self.store), - ] - - if logEnabled { - array.append(HUGResponseLoggingInterceptor()) - array.append(HUGRequestLoggingInterceptor()) - } - - return array - } -} - diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGRequestLoggingInterceptor.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGRequestLoggingInterceptor.swift deleted file mode 100644 index bb01dab95..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGRequestLoggingInterceptor.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// HUGRequestLoggingInterceptor.swift -// -// -// Created by Theo Mendes on 04/11/21. -// - -import Apollo -import os.log -import Foundation - -internal final class HUGRequestLoggingInterceptor: ApolloInterceptor { - - internal func interceptAsync(chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - let jsonData = try? JSONSerialization.data(withJSONObject: request.operation.variables.jsonValue, options: []) - if let jsonString = jsonData?.prettyJson { - os_log("🌐 📤 Variables: %s", log: HUGLogger.networkingLog(), type: .debug, "\(jsonString)") - } else { - os_log("🌐 📤 Could not convert data to string", log: HUGLogger.networkingLog(), type: .error) - } - - chain.proceedAsync(request: request, - response: response, - completion: completion) - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGResponseLoggingInterceptor.swift b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGResponseLoggingInterceptor.swift deleted file mode 100644 index 2a766e0e6..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Interceptors/HUGResponseLoggingInterceptor.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// HUGResponseLoggingInterceptor.swift -// -// -// Created by Theo Mendes on 04/11/21. -// - -import Apollo -import os.log - -internal final class HUGResponseLoggingInterceptor: ApolloInterceptor { - enum ResponseLoggingError: Error { - case notYetReceived - } - - internal func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - defer { - // Even if we can't log, we still want to keep going. - chain.proceedAsync(request: request, - response: response, - completion: completion) - } - - guard let receivedResponse = response else { - chain.handleErrorAsync(ResponseLoggingError.notYetReceived, - request: request, - response: response, - completion: completion) - return - } - - os_log("🌐 📥 HTTP Response: %s", log: HUGLogger.networkingLog(), type: .debug, "\(receivedResponse.httpResponse)") - - if let stringData = receivedResponse.rawData.prettyJson { - os_log("🌐 📥 Data: %s", log: HUGLogger.networkingLog(), type: .debug, "\(stringData)") - } else { - os_log("🌐 📥 Could not convert data to string", log: HUGLogger.networkingLog(), type: .error) - } - } -} - diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/Search.graphql b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/Search.graphql deleted file mode 100644 index 8df3aa58c..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/Search.graphql +++ /dev/null @@ -1,83 +0,0 @@ -query search( - $q: String!, - $pagination: SearchInputPagination){ - search(q: $q, pagination: $pagination) { - pagination { - count - current - hasNext - } - filters { - productType { - label - filter - count - } - cities { - label - filter - count - } - stars { - label - filter - count - } - prices { - min - maxExclusive - filter - count - } - } - meta { - count - countWithAvailability - countHotel - countTicket - countPackage - } - results { - id - sku - name - url - category - description - smallDescription - isAvailable - price { - currency - amount - originalAmount - taxes { - originalAmount - originalCurrency - } - } - address { - city - state - country - geoLocation { - lat - lon - } - } - tags { - label - slug - } - gallery(limit: 10) { - # Quality: LOW, MEDIUM, HIGH - # Resolution: LOW, LOWER, ORIGINAL - url(quality: HIGH, resolution: ORIGINAL) - description - } - amenities(limit: 10) { - name - category - } - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SearchHotelQuery.graphql b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SearchHotelQuery.graphql deleted file mode 100644 index c9df98b82..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SearchHotelQuery.graphql +++ /dev/null @@ -1,120 +0,0 @@ -query searchHotel( - $q: String! - $filters: SearchHotelInputFilters - $pagination: SearchInputPagination - $l10n: InputL10n - $checkin: Date - $checkout: Date - $rooms: [SearchInputRooms!] -) { -searchHotel( - q: $q, - filters: $filters, - pagination: $pagination, - l10n: $l10n, - checkin: $checkin, - checkout: $checkout, - rooms: $rooms - ) { - filters { - amenities { - label - filter - count - } - cities { - label - filter - count - } - states { - label - filter - count - } - countries { - label - filter - count - } - food { - label - filter - count - } - people { - label - filter - count - } - priceInterval { - min - max - } - prices { - min - maxExclusive - filter - count - } - stars { - label - filter - count - } - } - results { - id - sku - name - url - category - description - smallDescription - price { - currency - amount - originalAmount - taxes { - currency - } - } - address { - city - state - country - geoLocation { - lat - lon - } - } - tags { - label - slug - } - gallery { - url - description - } - amenities { - name - category - } - isAvailable - stars - huFreeCancellation - } - meta { - count - countWithAvailability - countHotel countPackage - countTicket - } - pagination { - count - current - hasNext - hasPrevious - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SearchPackageQuery.graphql b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SearchPackageQuery.graphql deleted file mode 100644 index 99c0f9ab8..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SearchPackageQuery.graphql +++ /dev/null @@ -1,118 +0,0 @@ -query searchPackage( - $q: String! - $filters: SearchPackageInputFilters - $pagination: SearchInputPagination - $l10n: InputL10n -) { - searchPackage( - q: $q, - filters: $filters, - pagination:$pagination, - l10n: $l10n - ) { - filters { - cities { - label - filter - count - } - states { - label - filter - count - } - countries { - label - filter - count - } - departureCities { - label - filter - count - } - duration { - label - filter - count - } - food { - label - filter - count - } - people { - label - filter - count - } - priceInterval { - min - max - } - prices { - min - maxExclusive - filter - count - } - } - results { - id - sku - name - url - category - description - smallDescription - price { - currency - amount - originalAmount - } - address { - city - state - country - geoLocation { - lat - lon - } - } - tags { - label - slug - } - gallery { - url - description - } - amenities { - name - category - } - isAvailable - startDate - endDate - quantityDescriptors { - duration - nights - maxFreeChildrenAge - maxPeople - } - } - meta { - count - countWithAvailability - countHotel - countPackage - countTicket - } - pagination { - count - current - hasNext - hasPrevious - } - } -} diff --git a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SuggestionQuery.graphql b/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SuggestionQuery.graphql deleted file mode 100644 index 69277d340..000000000 --- a/Projects/Challenge Alpha iOS/Modules/HUNetwork/Sources/HUGraphQL/Queries/SuggestionQuery.graphql +++ /dev/null @@ -1,38 +0,0 @@ -query suggestions( - $q: String! - $limit: Int - $productType: SuggestionProductType - $l10n: InputL10n!) { - suggestions( - q: $q, - limit: $limit, - productType: $productType, - l10n: $l10n) { - results { - ... on LocationSuggestion { - text - filter - suggestionType - country - state - city - } - ... on ProductSuggestion { - text - filter - suggestionType - sku - productType - country - state - city - } - ... on TagSuggestion { - text - filter - suggestionType - } - } - total - } -} diff --git a/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/AccentColor.colorset/Contents.json b/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb8789700..000000000 --- a/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json b/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index c136eaff7..000000000 --- a/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/Contents.json b/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Projects/Challenge Alpha iOS/Shared/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Projects/Challenge Alpha iOS/Shared/Challenge_Alpha_iOSApp.swift b/Projects/Challenge Alpha iOS/Shared/Challenge_Alpha_iOSApp.swift deleted file mode 100644 index 19050149b..000000000 --- a/Projects/Challenge Alpha iOS/Shared/Challenge_Alpha_iOSApp.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// Challenge_Alpha_iOSApp.swift -// Shared -// -// Created by Theo Mendes on 04/11/21. -// - -import SwiftUI - -@main -struct Challenge_Alpha_iOSApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - } -} diff --git a/Projects/Challenge Alpha iOS/Shared/ContentView.swift b/Projects/Challenge Alpha iOS/Shared/ContentView.swift deleted file mode 100644 index 8b9edcf0d..000000000 --- a/Projects/Challenge Alpha iOS/Shared/ContentView.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// ContentView.swift -// Shared -// -// Created by Theo Mendes on 04/11/21. -// - -import SwiftUI -import Combine - -struct ContentView: View { - @State private var selection: String? = nil - - var body: some View { - NavigationView { - VStack(alignment: .center) { - NavigationLink(destination: ResultRenderView(type: .search)) { - Text("Search") - .fontWeight(.bold) - .font(.title) - .padding() - .background(Color.blue) - .cornerRadius(40) - .foregroundColor(.white) - .padding(10) - }.buttonStyle(PlainButtonStyle()) - - NavigationLink(destination: ResultRenderView(type: .searchPackage)) { - Text("Search Package") - .fontWeight(.bold) - .font(.title) - .padding() - .background(Color.blue) - .cornerRadius(40) - .foregroundColor(.white) - .padding(10) - }.buttonStyle(PlainButtonStyle()) - - NavigationLink(destination: ResultRenderView(type: .searchHotel)) { - Text("Search Hotel") - .fontWeight(.bold) - .font(.title) - .padding() - .background(Color.blue) - .cornerRadius(40) - .foregroundColor(.white) - .padding(10) - }.buttonStyle(PlainButtonStyle()) - - NavigationLink(destination: ResultRenderView(type: .suggestion)) { - Text("Suggestion") - .fontWeight(.bold) - .font(.title) - .padding() - .background(Color.blue) - .cornerRadius(40) - .foregroundColor(.white) - .padding(10) - }.buttonStyle(PlainButtonStyle()) - } - } - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/Projects/Challenge Alpha iOS/Shared/Manager.swift b/Projects/Challenge Alpha iOS/Shared/Manager.swift deleted file mode 100644 index 2bc4741af..000000000 --- a/Projects/Challenge Alpha iOS/Shared/Manager.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// Manager.swift -// Challenge Alpha iOS (iOS) -// -// Created by Theo Mendes on 04/11/21. -// - -import Foundation -import HUGraphQL -import Combine - -// DISCLAIMER: ESTE MANAGER É SOMENTE PARA REFERÊNCIA, NÃO DEVE SER USADO NO DESAFIO FINAL. - -internal final class Manager { - internal typealias SearchResult = HUGraphQL.SearchQuery.Data.Search? - internal typealias SearchPackageResult = HUGraphQL.SearchPackageQuery.Data.SearchPackage? - internal typealias SearchHotelResult = HUGraphQL.SearchHotelQuery.Data.SearchHotel? - internal typealias SuggestionResult = HUGraphQL.SuggestionsQuery.Data.Suggestion? - - private let service = HUGService(enableLog: true) - internal static let shared = Manager() - - private init() {} - - internal func performSearch(query: String, pagination: HUGraphQL.SearchInputPagination? = nil) -> AnyPublisher { - let subject = PassthroughSubject() - - let query = HUGraphQL.SearchQuery(q: query, pagination: pagination) - - service.client.fetch(query: query) { res in - switch res { - case .failure(let error): - subject.send(completion: .failure(error)) - case .success(let graphQLValue): -// if let errors = graphQLValue.errors { -// // HANDLE CUSTOM ERROR -// subject.send(completion: .failure(errors)) -// } - subject.send(graphQLValue.data?.search) - subject.send(completion: .finished) - } - } - - return subject.eraseToAnyPublisher() - } - - internal func performPackageSearch(query: String, pagination: HUGraphQL.SearchInputPagination? = nil) -> AnyPublisher { - let subject = PassthroughSubject() - - let query = HUGraphQL.SearchPackageQuery(q: "", filters: nil, pagination: pagination, l10n: .init(pos: "br", locale: "pt", currency: "BRL")) - - service.client.fetch(query: query) { res in - switch res { - case .failure(let error): - subject.send(completion: .failure(error)) - case .success(let graphQLValue): -// if let errors = graphQLValue.errors { -// // HANDLE CUSTOM ERROR -// subject.send(completion: .failure(errors)) -// } - subject.send(graphQLValue.data?.searchPackage) - subject.send(completion: .finished) - } - } - - return subject.eraseToAnyPublisher() - } - - internal func performHotelSearch(query: String, pagination: HUGraphQL.SearchInputPagination? = nil) -> AnyPublisher { - let subject = PassthroughSubject() - - let query = HUGraphQL.SearchHotelQuery( - q: query, - filters: nil, - pagination: pagination, - l10n: .init(pos: "br", locale: "pt", currency: "BRL"), - checkin: Date(), - checkout: nil, - rooms: nil) - - service.client.fetch(query: query) { res in - switch res { - case .failure(let error): - subject.send(completion: .failure(error)) - - case .success(let graphQLValue): -// if let errors = graphQLValue.errors { -// // HANDLE CUSTOM ERROR -// subject.send(completion: .failure(errors)) -// } - subject.send(graphQLValue.data?.searchHotel) - subject.send(completion: .finished) - } - } - - return subject.eraseToAnyPublisher() - } - - internal func performSuggestion(query: String, pagination: HUGraphQL.SearchInputPagination? = nil, productType: HUGraphQL.SuggestionProductType? = nil) -> AnyPublisher { - let subject = PassthroughSubject() - - let query = HUGraphQL.SuggestionsQuery( - q: query, - limit: 20, - productType: productType, - l10n: .init(pos: "br", locale: "pt", currency: "BRL")) - - service.client.fetch(query: query) { res in - switch res { - case .failure(let error): - subject.send(completion: .failure(error)) - - case .success(let graphQLValue): -// if let errors = graphQLValue.errors { -// // HANDLE CUSTOM ERROR -// subject.send(completion: .failure(errors)) -// } - subject.send(graphQLValue.data?.suggestions) - subject.send(completion: .finished) - } - } - - return subject.eraseToAnyPublisher() - } -} diff --git a/Projects/Challenge Alpha iOS/Shared/ResultRenderView.swift b/Projects/Challenge Alpha iOS/Shared/ResultRenderView.swift deleted file mode 100644 index 81c7cd1af..000000000 --- a/Projects/Challenge Alpha iOS/Shared/ResultRenderView.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// ResultRenderView.swift -// Challenge Alpha iOS (iOS) -// -// Created by Theo Mendes on 04/11/21. -// - -import SwiftUI -import Combine - -enum ResultRenderViewType { - case search - case searchPackage - case searchHotel - case suggestion -} - -struct ResultRenderView: View { - private let type: ResultRenderViewType - private var subscriptions = Set() - @ObservedObject var viewModel = ResultRenderViewModel() - - init(type: ResultRenderViewType) { - self.type = type - } - - var body: some View { - Text(String(format:"%@", viewModel.resultText)) - .font(.headline) - .lineLimit(nil) - .padding() - .onAppear { - switch self.type { - case .search: viewModel.performSearch() - case .searchHotel: viewModel.performSearchHotel() - case .searchPackage: viewModel.performSearchPackage() - case .suggestion: - viewModel.performSuggestion() - } - } - .navigationTitle("Result") - } -} - -struct ResultRenderView_Previews: PreviewProvider { - static var previews: some View { - ResultRenderView(type: .search) - } -} diff --git a/Projects/Challenge Alpha iOS/Shared/ResultRenderViewModel.swift b/Projects/Challenge Alpha iOS/Shared/ResultRenderViewModel.swift deleted file mode 100644 index b4aecc519..000000000 --- a/Projects/Challenge Alpha iOS/Shared/ResultRenderViewModel.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// ResultRenderViewModel.swift -// Challenge Alpha iOS (iOS) -// -// Created by Theo Mendes on 04/11/21. -// - -import Combine -import Foundation -import Apollo - -internal final class ResultRenderViewModel: ObservableObject { - private var subscriptions = Set() - @Published var resultText: String = "" - - internal func performSearch() { - Manager.shared - .performSearch( - query: "Rio de Janeiro", - pagination: .init( - page: 1, - limit: 20, - sort: .price, - sortOrder: .desc)) - .sink { completion in - if case .failure(let error) = completion { - debugPrint(error.localizedDescription) - } - } receiveValue: { [weak self] res in - let jsonData = try? JSONSerialization.data(withJSONObject: res?.jsonObject as Any, options: []) - - if let text = prettyJSON(data: jsonData) { - self?.resultText = text - } - } - .store(in: &self.subscriptions) - - } - - internal func performSearchPackage() { - Manager.shared - .performHotelSearch( - query: "Rio de Janeiro", - pagination: .init( - page: 1, - limit: 20, - sort: .price, - sortOrder: .desc)) - .sink { completion in - if case .failure(let error) = completion { - debugPrint(error.localizedDescription) - } - } receiveValue: { [weak self] res in - let jsonData = try? JSONSerialization.data(withJSONObject: res?.jsonObject as Any, options: []) - - if let text = prettyJSON(data: jsonData) { - self?.resultText = text - } - } - .store(in: &self.subscriptions) - } - - internal func performSearchHotel() { - Manager.shared - .performHotelSearch( - query: "Rio de Janeiro", - pagination: .init( - page: 1, - limit: 20, - sort: .price, - sortOrder: .desc)) - .sink { completion in - if case .failure(let error) = completion { - debugPrint(error.localizedDescription) - } - } receiveValue: { [weak self] res in - let jsonData = try? JSONSerialization.data(withJSONObject: res?.jsonObject as Any, options: []) - - if let text = prettyJSON(data: jsonData) { - self?.resultText = text - } - } - .store(in: &self.subscriptions) - } - - internal func performSuggestion() { - Manager.shared - .performSuggestion( - query: "Rio de Janeiro", - pagination: .init( - page: 1, - limit: 20, - sort: .price, - sortOrder: .desc), - productType: .hotel) - .sink { completion in - if case .failure(let error) = completion { - debugPrint(error.localizedDescription) - } - } receiveValue: { [weak self] res in - let jsonData = try? JSONSerialization.data(withJSONObject: res?.jsonObject as Any, options: []) - if let text = prettyJSON(data: jsonData) { - self?.resultText = text - } - } - .store(in: &self.subscriptions) - } -} - -fileprivate func prettyJSON(data: Data?) -> String? { - guard let data = data else { return nil } - guard let object = try? JSONSerialization.jsonObject(with: data, options: []), - let data = try? JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted]), - let prettyPrintedString = String(data: data, encoding:.utf8) else { return nil } - - return prettyPrintedString -} diff --git a/README_VINI.md b/README_VINI.md new file mode 100644 index 000000000..00f092772 --- /dev/null +++ b/README_VINI.md @@ -0,0 +1,7 @@ +## Sobre o projeto + +- Arquitetura: MVVM + Clean Architecture +- DI: Koin + - Escolhi o Koin por sua simplicidade, facilidade de implementação, e por ter mais experiência com ele. O único ponto de atenção ao usar Koin é lembrar que se houver algum erro de injeção você só descobre durante runTime, o Hilt acusaria em compilationTime. Algo que pode ser remediado utilizando testes unitários para os módulos Koin. +- Network: Retrofit + OkHttp + Gson +- UI: Compose + Koil diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 000000000..9bd9a8a77 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,39 @@ +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Log/OS Files +*.log + +# Android Studio generated files and folders +captures/ +.externalNativeBuild/ +.cxx/ +*.apk +output.json + +# IntelliJ +*.iml +.idea/ +.idea/* +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Android Profiling +*.hprof + +# Other +.DS_Store +.externalNativeBuild +.cxx diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 000000000..5289e7999 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,95 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "com.vdemelo.starwarswiki" + compileSdk = 34 + + defaultConfig { + applicationId = "com.vdemelo.starwarswiki" + minSdk = 23 + //noinspection ExpiredTargetSdkVersion + targetSdk = 31 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + compose = true + } + composeOptions { + kotlinCompilerExtensionVersion = "1.4.3" + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } +} + +dependencies { + + implementation("androidx.core:core-ktx:1.12.0") + implementation("com.google.android.material:material:1.11.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") + implementation("androidx.activity:activity-compose:1.8.2") + implementation(platform("androidx.compose:compose-bom:2023.03.00")) + implementation("androidx.compose.ui:ui") + implementation("androidx.compose.ui:ui-graphics") + implementation("androidx.compose.ui:ui-tooling-preview") + implementation("androidx.compose.material3:material3") + implementation("androidx.navigation:navigation-compose:2.7.6") + + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + + androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00")) + androidTestImplementation("androidx.compose.ui:ui-test-junit4") + debugImplementation("androidx.compose.ui:ui-tooling") + debugImplementation("androidx.compose.ui:ui-test-manifest") + + //Koin + implementation("io.insert-koin:koin-android:3.5.0") + implementation("io.insert-koin:koin-androidx-navigation:3.5.0") + implementation("io.insert-koin:koin-androidx-compose:3.5.0") + testImplementation("io.insert-koin:koin-test-junit4:3.5.0") + + // Gson + implementation("com.google.code.gson:gson:2.10") + + // Retrofit + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + + // OkHttp 3 + implementation("com.squareup.okhttp3:logging-interceptor:4.10.0") + + //Coil + // https://github.com/coil-kt/coil#jetpack-compose + implementation("io.coil-kt:coil-compose:2.5.0") + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/vdemelo/starwarswiki/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/vdemelo/starwarswiki/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..38b81eecb --- /dev/null +++ b/app/src/androidTest/java/com/vdemelo/starwarswiki/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.vdemelo.starwarswiki + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.vdemelo.starwarswiki", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..75a99e102 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/vdemelo/starwarswiki/App.kt b/app/src/main/java/com/vdemelo/starwarswiki/App.kt new file mode 100644 index 000000000..4b3e0d65e --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/App.kt @@ -0,0 +1,30 @@ +package com.vdemelo.starwarswiki + +import android.app.Application +import com.vdemelo.starwarswiki.di.presentationModule +import com.vdemelo.starwarswiki.di.dataModule +import com.vdemelo.starwarswiki.di.domainModule +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.GlobalContext.startKoin + +class App: Application() { + + companion object { + lateinit var instance: App + } + + override fun onCreate() { + super.onCreate() + instance = this + + startKoin { + androidContext(androidContext = this@App) + modules( + dataModule, + domainModule, + presentationModule + ) + } + } + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/data/remote/NetworkConstants.kt b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/NetworkConstants.kt new file mode 100644 index 000000000..9245a99eb --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/NetworkConstants.kt @@ -0,0 +1,7 @@ +package com.vdemelo.starwarswiki.data.remote + +object NetworkConstants { + + const val BASE_URL = "https://swapi.dev/api/" + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/data/remote/api/StarWarsApi.kt b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/api/StarWarsApi.kt new file mode 100644 index 000000000..2d1969851 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/api/StarWarsApi.kt @@ -0,0 +1,32 @@ +package com.vdemelo.starwarswiki.data.remote.api + +import com.vdemelo.starwarswiki.data.remote.response.PlanetResponse +import com.vdemelo.starwarswiki.data.remote.response.PlanetsListResponse +import com.vdemelo.starwarswiki.data.remote.response.SpeciesListResponse +import com.vdemelo.starwarswiki.data.remote.response.SpeciesResponse +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface StarWarsApi { + + @GET("species") + suspend fun getSpecies( + @Query("page") page: Int? = null, + @Query("search") search: String? = null + ): SpeciesListResponse + + @GET("species/{id}") + suspend fun getSpeciesDetails(@Path("id") id: Int): SpeciesResponse + + @GET("planets") + suspend fun getPlanets( + @Query("page") page: Int? = null, + @Query("search") search: String? = null + ): PlanetsListResponse + + @GET("planets/{id}") + suspend fun getPlanetDetails(@Path("id") id: Int): PlanetResponse + + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/PlanetResponse.kt b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/PlanetResponse.kt new file mode 100644 index 000000000..880b547ba --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/PlanetResponse.kt @@ -0,0 +1,20 @@ +package com.vdemelo.starwarswiki.data.remote.response + +import com.google.gson.annotations.SerializedName + +class PlanetResponse( + @SerializedName("climate") val climate: String?, + @SerializedName("created") val created: String?, + @SerializedName("diameter") val diameter: String?, + @SerializedName("edited") val edited: String?, + @SerializedName("films") val films: List?, + @SerializedName("gravity") val gravity: String?, + @SerializedName("name") val name: String?, + @SerializedName("orbital_period") val orbitalPeriod: String?, + @SerializedName("population") val population: String?, + @SerializedName("residents") val residents: List?, + @SerializedName("rotation_period") val rotationPeriod: String?, + @SerializedName("surface_water") val surfaceWater: String?, + @SerializedName("terrain") val terrain: String?, + @SerializedName("url") val url: String? +) diff --git a/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/PlanetsListResponse.kt b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/PlanetsListResponse.kt new file mode 100644 index 000000000..fbf3dda83 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/PlanetsListResponse.kt @@ -0,0 +1,10 @@ +package com.vdemelo.starwarswiki.data.remote.response + +import com.google.gson.annotations.SerializedName + +class PlanetsListResponse( + @SerializedName("count") val count: Int?, + @SerializedName("next") val next: String?, + @SerializedName("previous") val previous: String?, + @SerializedName("results") val results: List? +) diff --git a/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/SpeciesListResponse.kt b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/SpeciesListResponse.kt new file mode 100644 index 000000000..466958e78 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/SpeciesListResponse.kt @@ -0,0 +1,10 @@ +package com.vdemelo.starwarswiki.data.remote.response + +import com.google.gson.annotations.SerializedName + +class SpeciesListResponse( + @SerializedName("count") val count: Int?, + @SerializedName("next") val next: String?, + @SerializedName("previous") val previous: String?, + @SerializedName("results") val results: List? +) diff --git a/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/SpeciesResponse.kt b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/SpeciesResponse.kt new file mode 100644 index 000000000..b377118e1 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/data/remote/response/SpeciesResponse.kt @@ -0,0 +1,21 @@ +package com.vdemelo.starwarswiki.data.remote.response + +import com.google.gson.annotations.SerializedName + +class SpeciesResponse( + @SerializedName("average_height") val averageHeight: String?, + @SerializedName("average_lifespan") val averageLifespan: String?, + @SerializedName("classification") val classification: String?, + @SerializedName("created") val created: String?, + @SerializedName("designation") val designation: String?, + @SerializedName("edited") val edited: String?, + @SerializedName("eye_colors") val eyeColors: String?, + @SerializedName("films") val films: List?, + @SerializedName("hair_colors") val hairColors: String?, + @SerializedName("homeworld") val homeWorld: String?, + @SerializedName("language") val language: String?, + @SerializedName("name") val name: String?, + @SerializedName("people") val people: List?, + @SerializedName("skin_colors") val skinColors: String?, + @SerializedName("url") val url: String? +) diff --git a/app/src/main/java/com/vdemelo/starwarswiki/data/repository/StarWarsRemoteRepositoryImpl.kt b/app/src/main/java/com/vdemelo/starwarswiki/data/repository/StarWarsRemoteRepositoryImpl.kt new file mode 100644 index 000000000..63e96313f --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/data/repository/StarWarsRemoteRepositoryImpl.kt @@ -0,0 +1,30 @@ +package com.vdemelo.starwarswiki.data.repository + +import com.vdemelo.starwarswiki.data.remote.api.StarWarsApi +import com.vdemelo.starwarswiki.data.remote.response.PlanetResponse +import com.vdemelo.starwarswiki.data.remote.response.PlanetsListResponse +import com.vdemelo.starwarswiki.data.remote.response.SpeciesListResponse +import com.vdemelo.starwarswiki.data.remote.response.SpeciesResponse +import com.vdemelo.starwarswiki.domain.repository.StarWarsRemoteRepository + +class StarWarsRemoteRepositoryImpl( + private val api: StarWarsApi +): StarWarsRemoteRepository { + + override suspend fun fetchSpecies(page: Int, search: String?): SpeciesListResponse { + return api.getSpecies(page = page, search = search) + } + + override suspend fun fetchSpeciesDetails(id: Int): SpeciesResponse { + return api.getSpeciesDetails(id) + } + + override suspend fun fetchPlanets(page: Int, search: String?): PlanetsListResponse { + return api.getPlanets(page = page, search = search) + } + + override suspend fun fetchPlanetDetails(id: Int): PlanetResponse { + return api.getPlanetDetails(id) + } + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/di/DataModule.kt b/app/src/main/java/com/vdemelo/starwarswiki/di/DataModule.kt new file mode 100644 index 000000000..fb6e58f6f --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/di/DataModule.kt @@ -0,0 +1,27 @@ +package com.vdemelo.starwarswiki.di + +import com.vdemelo.starwarswiki.data.remote.NetworkConstants.BASE_URL +import com.vdemelo.starwarswiki.data.remote.api.StarWarsApi +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +val dataModule = module { + single { + val logger = HttpLoggingInterceptor() + logger.level = HttpLoggingInterceptor.Level.BODY + + val client = OkHttpClient.Builder() + .addInterceptor(logger) + .build() + + Retrofit.Builder() + .baseUrl(BASE_URL) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(StarWarsApi::class.java) + } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/di/DomainModule.kt b/app/src/main/java/com/vdemelo/starwarswiki/di/DomainModule.kt new file mode 100644 index 000000000..62915e26a --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/di/DomainModule.kt @@ -0,0 +1,13 @@ +package com.vdemelo.starwarswiki.di + +import com.vdemelo.starwarswiki.data.repository.StarWarsRemoteRepositoryImpl +import com.vdemelo.starwarswiki.domain.usecase.ItemsUseCase +import com.vdemelo.starwarswiki.domain.usecase.PlanetsUseCase +import com.vdemelo.starwarswiki.domain.usecase.SpeciesUseCase +import org.koin.dsl.module + +val domainModule = module { + single { SpeciesUseCase(remoteRepository = StarWarsRemoteRepositoryImpl(get())) } + single { PlanetsUseCase(remoteRepository = StarWarsRemoteRepositoryImpl(get())) } + single { ItemsUseCase() } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/di/PresentationModule.kt b/app/src/main/java/com/vdemelo/starwarswiki/di/PresentationModule.kt new file mode 100644 index 000000000..1868c3dd6 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/di/PresentationModule.kt @@ -0,0 +1,15 @@ +package com.vdemelo.starwarswiki.di + +import com.vdemelo.starwarswiki.ui.screens.planets.details.PlanetDetailsViewModel +import com.vdemelo.starwarswiki.ui.screens.planets.list.PlanetListViewModel +import com.vdemelo.starwarswiki.ui.screens.species.details.SpeciesDetailsViewModel +import com.vdemelo.starwarswiki.ui.screens.species.list.SpeciesListViewModel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +val presentationModule = module { + viewModel { SpeciesListViewModel(get(), get()) } + viewModel { SpeciesDetailsViewModel(get(), get()) } + viewModel { PlanetListViewModel(get(), get()) } + viewModel { PlanetDetailsViewModel(get(), get()) } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/DefaultErrors.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/DefaultErrors.kt new file mode 100644 index 000000000..5368176ba --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/DefaultErrors.kt @@ -0,0 +1,5 @@ +package com.vdemelo.starwarswiki.domain + +enum class DefaultErrors(val message: String) { + UNKNOWN_ERROR(message = "An unknown error occurred.") +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/RequestStatus.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/RequestStatus.kt new file mode 100644 index 000000000..7e97fed38 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/RequestStatus.kt @@ -0,0 +1,9 @@ +package com.vdemelo.starwarswiki.domain.entity + +sealed class RequestStatus( + val data: T? = null, + val message: String? = null +) { + class Success(data: T) : RequestStatus(data) + class Error(data: T? = null, message: String) : RequestStatus(data, message) +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/ItemsImageUrl.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/ItemsImageUrl.kt new file mode 100644 index 000000000..f44d2be9b --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/ItemsImageUrl.kt @@ -0,0 +1,19 @@ +package com.vdemelo.starwarswiki.domain.entity.model + +enum class ItemsImageUrl( + val baseUrl: String, + val extension: String +) { + SPECIES( + baseUrl = "https://starwars-visualguide.com/assets/img/species/", + extension = ".jpg" + ), + PLANET( + baseUrl = "https://starwars-visualguide.com/assets/img/planets/", + extension = ".jpg" + ) +} + +fun ItemsImageUrl.getImageUrl(itemNumber: String): String { + return this.baseUrl + itemNumber + this.extension +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/Planet.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/Planet.kt new file mode 100644 index 000000000..b451fb011 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/Planet.kt @@ -0,0 +1,42 @@ +package com.vdemelo.starwarswiki.domain.entity.model + +import com.vdemelo.starwarswiki.data.remote.response.PlanetResponse +import com.vdemelo.starwarswiki.utils.nonNullOrEmpty + +class Planet( + val climate: String?, + val created: String?, + val diameter: String?, + val edited: String?, + val films: List, + val gravity: String?, + val name: String?, + val orbitalPeriod: String?, + val population: String?, + val residents: List?, + val rotationPeriod: String?, + val surfaceWater: String?, + val terrain: String?, + val url: String? +) { + + constructor(response: PlanetResponse) : this( + climate = response.climate, + created = response.created, + diameter = response.diameter, + edited = response.edited, + films = response.films.nonNullOrEmpty(), + gravity = response.gravity, + name = response.name, + orbitalPeriod = response.orbitalPeriod, + population = response.population, + residents = response.residents.nonNullOrEmpty(), + rotationPeriod = response.rotationPeriod, + surfaceWater = response.surfaceWater, + terrain = response.terrain, + url = response.url + ) + +} + +fun List.toModel(): List = this.map { Planet(it) } diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/PlanetsList.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/PlanetsList.kt new file mode 100644 index 000000000..465489b0b --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/PlanetsList.kt @@ -0,0 +1,20 @@ +package com.vdemelo.starwarswiki.domain.entity.model + +import com.vdemelo.starwarswiki.data.remote.response.PlanetsListResponse +import com.vdemelo.starwarswiki.utils.nonNullOrEmpty + +class PlanetsList( + val count: Int, + val next: String?, + val previous: String?, + val results: List +) { + + constructor(response: PlanetsListResponse): this( + count = response.count ?: 0, + next = response.next, + previous = response.previous, + results = response.results.nonNullOrEmpty().toModel() + ) + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/Species.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/Species.kt new file mode 100644 index 000000000..db9d10013 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/Species.kt @@ -0,0 +1,44 @@ +package com.vdemelo.starwarswiki.domain.entity.model + +import com.vdemelo.starwarswiki.data.remote.response.SpeciesResponse +import com.vdemelo.starwarswiki.utils.nonNullOrEmpty + +class Species( + val averageHeight: String?, + val averageLifespan: String?, + val classification: String?, + val created: String?, + val designation: String?, + val edited: String?, + val eyeColors: String?, + val films: List, + val hairColors: String?, + val homeWorld: String?, + val language: String?, + val name: String?, + val people: List, + val skinColors: String?, + val url: String? +) { + + constructor(response: SpeciesResponse) : this( + averageHeight = response.averageHeight, + averageLifespan = response.averageLifespan, + classification = response.classification, + created = response.created, + designation = response.designation, + edited = response.edited, + eyeColors = response.eyeColors, + films = response.films.nonNullOrEmpty(), + hairColors = response.hairColors, + homeWorld = response.homeWorld, + language = response.language, + name = response.name, + people = response.people.nonNullOrEmpty(), + skinColors = response.skinColors, + url = response.url + ) + +} + +fun List.toModel(): List = this.map { Species(it) } diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/SpeciesList.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/SpeciesList.kt new file mode 100644 index 000000000..fcb598335 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/SpeciesList.kt @@ -0,0 +1,20 @@ +package com.vdemelo.starwarswiki.domain.entity.model + +import com.vdemelo.starwarswiki.data.remote.response.SpeciesListResponse +import com.vdemelo.starwarswiki.utils.nonNullOrEmpty + +class SpeciesList( + val count: Int, + val next: String?, + val previous: String?, + val results: List +) { + + constructor(response: SpeciesListResponse): this( + count = response.count ?: 0, + next = response.next, + previous = response.previous, + results = response.results.nonNullOrEmpty().toModel() + ) + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/TextField.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/TextField.kt new file mode 100644 index 000000000..89c616281 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/entity/model/TextField.kt @@ -0,0 +1,6 @@ +package com.vdemelo.starwarswiki.domain.entity.model + +class TextField( + val label: String, + val text: String? +) diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/repository/StarWarsRemoteRepository.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/repository/StarWarsRemoteRepository.kt new file mode 100644 index 000000000..4a8fb613e --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/repository/StarWarsRemoteRepository.kt @@ -0,0 +1,18 @@ +package com.vdemelo.starwarswiki.domain.repository + +import com.vdemelo.starwarswiki.data.remote.response.PlanetResponse +import com.vdemelo.starwarswiki.data.remote.response.PlanetsListResponse +import com.vdemelo.starwarswiki.data.remote.response.SpeciesListResponse +import com.vdemelo.starwarswiki.data.remote.response.SpeciesResponse + +interface StarWarsRemoteRepository { + + suspend fun fetchSpecies(page: Int, search: String?): SpeciesListResponse + + suspend fun fetchSpeciesDetails(id: Int): SpeciesResponse + + suspend fun fetchPlanets(page: Int, search: String?): PlanetsListResponse + + suspend fun fetchPlanetDetails(id: Int): PlanetResponse + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/ItemsUseCase.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/ItemsUseCase.kt new file mode 100644 index 000000000..02f28035c --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/ItemsUseCase.kt @@ -0,0 +1,33 @@ +package com.vdemelo.starwarswiki.domain.usecase + +import com.vdemelo.starwarswiki.domain.entity.model.ItemsImageUrl +import com.vdemelo.starwarswiki.domain.entity.model.getImageUrl + +private const val SUFFIX = "/" + +class ItemsUseCase { + + // URL examples: + // species.url = https://swapi.dev/api/species/1/ + // species image = https://starwars-visualguide.com/assets/img/species/1.jpg + + fun getItemId(itemUrl: String): Int? { + val charsToDrop = if (itemUrl.endsWith(SUFFIX)) 1 else 0 + val id = try { + itemUrl.dropLast(charsToDrop).takeLastWhile { it.isDigit() }.toInt() + } catch (e: Exception) { + null + } + return id + } + + fun getSpeciesImageUrl(id: Int): String { + return ItemsImageUrl.SPECIES.getImageUrl(id.toString()) + } + + fun getPlanetImageUrl(id: Int): String { + return ItemsImageUrl.PLANET.getImageUrl(id.toString()) + } + + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/PlanetsUseCase.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/PlanetsUseCase.kt new file mode 100644 index 000000000..ec2f4ca4c --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/PlanetsUseCase.kt @@ -0,0 +1,31 @@ +package com.vdemelo.starwarswiki.domain.usecase + +import com.vdemelo.starwarswiki.domain.DefaultErrors +import com.vdemelo.starwarswiki.domain.entity.RequestStatus +import com.vdemelo.starwarswiki.domain.entity.model.Planet +import com.vdemelo.starwarswiki.domain.entity.model.PlanetsList +import com.vdemelo.starwarswiki.domain.repository.StarWarsRemoteRepository + +class PlanetsUseCase(private val remoteRepository: StarWarsRemoteRepository) { + + suspend fun fetchPlanets(page: Int = 0, search: String? = null): RequestStatus { + val response = try { + remoteRepository.fetchPlanets(page, search) + } catch (e: Exception) { + return RequestStatus.Error(message = DefaultErrors.UNKNOWN_ERROR.message) + } + val entity = PlanetsList(response) + return RequestStatus.Success(data = entity) + } + + suspend fun fetchPlanetDetails(speciesNumber: Int): RequestStatus { + val response = try { + remoteRepository.fetchPlanetDetails(speciesNumber) + } catch (e: Exception) { + return RequestStatus.Error(message = DefaultErrors.UNKNOWN_ERROR.message) + } + val entity = Planet(response) + return RequestStatus.Success(data = entity) + } + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/SpeciesUseCase.kt b/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/SpeciesUseCase.kt new file mode 100644 index 000000000..a1a897926 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/domain/usecase/SpeciesUseCase.kt @@ -0,0 +1,31 @@ +package com.vdemelo.starwarswiki.domain.usecase + +import com.vdemelo.starwarswiki.domain.DefaultErrors +import com.vdemelo.starwarswiki.domain.entity.RequestStatus +import com.vdemelo.starwarswiki.domain.entity.model.Species +import com.vdemelo.starwarswiki.domain.entity.model.SpeciesList +import com.vdemelo.starwarswiki.domain.repository.StarWarsRemoteRepository + +class SpeciesUseCase(private val remoteRepository: StarWarsRemoteRepository) { + + suspend fun fetchSpecies(page: Int = 0, search: String? = null): RequestStatus { + val response = try { + remoteRepository.fetchSpecies(page, search) + } catch (e: Exception) { + return RequestStatus.Error(message = DefaultErrors.UNKNOWN_ERROR.message) + } + val entity = SpeciesList(response) + return RequestStatus.Success(data = entity) + } + + suspend fun fetchSpeciesDetails(speciesNumber: Int): RequestStatus { + val response = try { + remoteRepository.fetchSpeciesDetails(speciesNumber) + } catch (e: Exception) { + return RequestStatus.Error(message = DefaultErrors.UNKNOWN_ERROR.message) + } + val entity = Species(response) + return RequestStatus.Success(data = entity) + } + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/MainActivity.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/MainActivity.kt new file mode 100644 index 000000000..52b1c8b6c --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/MainActivity.kt @@ -0,0 +1,28 @@ +package com.vdemelo.starwarswiki.ui + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.navigation.compose.rememberNavController +import com.vdemelo.starwarswiki.ui.nav.AppNavHost +import com.vdemelo.starwarswiki.ui.nav.NavItem +import com.vdemelo.starwarswiki.ui.theme.ComposeStarWarsTheme + +class MainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ComposeStarWarsTheme { + val navController = rememberNavController() + + AppNavHost( + navController = navController, + startDestination = NavItem.Home.route + ) + + } + } + } + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/components/ImageLoader.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/components/ImageLoader.kt new file mode 100644 index 000000000..ec07d40d8 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/components/ImageLoader.kt @@ -0,0 +1,22 @@ +package com.vdemelo.starwarswiki.ui.components + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import coil.compose.AsyncImage +import com.vdemelo.starwarswiki.R + +@Composable +fun ImageLoader( + modifier: Modifier = Modifier, + url: String?, + contentDescription: String, + placeholderRes: Int = R.drawable.image_placeholder +) { + AsyncImage( + modifier = modifier, + model = url, + contentDescription = contentDescription, + error = painterResource(id = placeholderRes) + ) +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/components/LabelAndTextData.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/components/LabelAndTextData.kt new file mode 100644 index 000000000..96a210c2d --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/components/LabelAndTextData.kt @@ -0,0 +1,35 @@ +package com.vdemelo.starwarswiki.ui.components + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.sp +import com.vdemelo.starwarswiki.R +import com.vdemelo.starwarswiki.utils.simpleCapitalize + +@Composable +fun LabelAndTextData( + label: String, + text: String? +) { + Row( + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = label, + fontSize = 16.sp, + textAlign = TextAlign.Center, + fontWeight = FontWeight.Bold + ) + Text( + text = text?.simpleCapitalize() ?: stringResource(id = R.string.common_unknown), + fontSize = 16.sp, + textAlign = TextAlign.Center + ) + } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/components/RetrySection.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/components/RetrySection.kt new file mode 100644 index 000000000..81a127ee2 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/components/RetrySection.kt @@ -0,0 +1,32 @@ +package com.vdemelo.starwarswiki.ui.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.vdemelo.starwarswiki.R + +@Composable +fun RetrySection( + error: String, + onRetry: () -> Unit +) { + Column { + Text(text = error, color = Color.Red, fontSize = 18.sp) + Spacer(modifier = Modifier.height(8.dp)) + Button( + onClick = { onRetry() }, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) { + Text(text = stringResource(id = R.string.common_retry)) + } + } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/components/SearchBar.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/components/SearchBar.kt new file mode 100644 index 000000000..db2426409 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/components/SearchBar.kt @@ -0,0 +1,70 @@ +package com.vdemelo.starwarswiki.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + +@Composable +fun SearchBar( + modifier: Modifier = Modifier, + hint: String = "", + onSearch: (String) -> Unit = {} +) { + var text by remember { + mutableStateOf("") + } + var isHintDisplayed by remember { + mutableStateOf(hint != "") + } + + Box(modifier = modifier) { + BasicTextField( + value = text, + onValueChange = { + text = it + onSearch(it) + }, + maxLines = 1, + singleLine = true, + textStyle = TextStyle(color = Color.Black), + modifier = Modifier + .fillMaxWidth() + .shadow(5.dp, CircleShape) + .background(Color.White, CircleShape) + .padding(horizontal = 20.dp, vertical = 12.dp) + .onFocusChanged { + isHintDisplayed = it.isFocused == false + } + ) + if (isHintDisplayed) { + Text( + text = hint, + color = Color.LightGray, + modifier = Modifier + .padding(horizontal = 20.dp, vertical = 12.dp) + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun DisplaySearchBar() { + SearchBar(hint = "Search...") +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/AppNavHost.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/AppNavHost.kt new file mode 100644 index 000000000..bbf485766 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/AppNavHost.kt @@ -0,0 +1,60 @@ +package com.vdemelo.starwarswiki.ui.nav + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import com.vdemelo.starwarswiki.ui.screens.home.HomeScreen +import com.vdemelo.starwarswiki.ui.screens.planets.details.PlanetDetailsScreen +import com.vdemelo.starwarswiki.ui.screens.planets.list.PlanetListScreen +import com.vdemelo.starwarswiki.ui.screens.species.details.SpeciesDetailsScreen +import com.vdemelo.starwarswiki.ui.screens.species.list.SpeciesListScreen + +@Composable +fun AppNavHost( + modifier: Modifier = Modifier, + navController: NavHostController, + startDestination: String = NavItem.Home.route +) { + NavHost( + modifier = modifier, + navController = navController, + startDestination = startDestination + ) { + composable(route = NavItem.Home.route) { + HomeScreen(navController = navController) + } + + composable(route = NavItem.SpeciesList.route) { + SpeciesListScreen(navController = navController) + } + + composable( + route = NavItem.SpeciesDetails.route, + arguments = listOf( + navArgument(NavigationArgs.ITEM_ID.name) { type = NavType.IntType } + ) + ) { + val speciesId = remember { it.arguments?.getInt(NavigationArgs.ITEM_ID.name) } + SpeciesDetailsScreen(navController = navController, id = speciesId) + } + + composable(route = NavItem.PlanetsList.route) { + PlanetListScreen(navController = navController) + } + + composable( + route = NavItem.PlanetDetails.route, + arguments = listOf( + navArgument(NavigationArgs.ITEM_ID.name) { type = NavType.IntType } + ) + ) { + val planetId = remember { it.arguments?.getInt(NavigationArgs.ITEM_ID.name) } + PlanetDetailsScreen(navController = navController, id = planetId) + } + } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/AppNavigation.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/AppNavigation.kt new file mode 100644 index 000000000..845f822da --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/AppNavigation.kt @@ -0,0 +1,36 @@ +package com.vdemelo.starwarswiki.ui.nav + +enum class Screen { + HOME, + SPECIES_LIST, + SPECIES_DETAILS, + PLANETS_LIST, + PLANET_DETAILS +} + +sealed class NavItem(val route: String) { + + object Home : NavItem(route = Screen.HOME.name) + + object SpeciesList : NavItem(route = Screen.SPECIES_LIST.name) + + object SpeciesDetails : NavItem( + route = buildComposableRouteMap( + basePath = Screen.SPECIES_DETAILS.name, + argumentNames = listOf( + NavigationArgs.ITEM_ID.name + ) + ) + ) + + object PlanetsList : NavItem(route = Screen.PLANETS_LIST.name) + + object PlanetDetails : NavItem( + route = buildComposableRouteMap( + basePath = Screen.PLANET_DETAILS.name, + argumentNames = listOf( + NavigationArgs.ITEM_ID.name + ) + ) + ) +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/NavigationArgs.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/NavigationArgs.kt new file mode 100644 index 000000000..f44d0dae3 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/NavigationArgs.kt @@ -0,0 +1,5 @@ +package com.vdemelo.starwarswiki.ui.nav + +enum class NavigationArgs { + ITEM_ID +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/Router.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/Router.kt new file mode 100644 index 000000000..307f21282 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/nav/Router.kt @@ -0,0 +1,20 @@ +package com.vdemelo.starwarswiki.ui.nav + +private const val PATH_SEPARATOR = "/" + +fun buildComposableRouteMap( + basePath: String, + argumentNames: List = listOf() +): String { + val formattedArgumentNames = argumentNames.map { "{${it}}" } + val pieces: List = listOf(basePath) + formattedArgumentNames + return pieces.joinToString(separator = PATH_SEPARATOR) +} + +fun buildSpeciesDetailsRoute(id: String): String { + return listOf(Screen.SPECIES_DETAILS.name, id).joinToString(separator = PATH_SEPARATOR) +} + +fun buildPlanetDetailsRoute(id: String): String { + return listOf(Screen.PLANET_DETAILS.name, id).joinToString(separator = PATH_SEPARATOR) +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/common/DetailsScreen.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/common/DetailsScreen.kt new file mode 100644 index 000000000..2a5078697 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/common/DetailsScreen.kt @@ -0,0 +1,89 @@ +package com.vdemelo.starwarswiki.ui.screens.common + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.vdemelo.starwarswiki.R +import com.vdemelo.starwarswiki.domain.entity.model.TextField +import com.vdemelo.starwarswiki.ui.components.ImageLoader +import com.vdemelo.starwarswiki.ui.components.LabelAndTextData +import com.vdemelo.starwarswiki.ui.theme.ComposeStarWarsTheme +import com.vdemelo.starwarswiki.utils.simpleCapitalize + +@Composable +fun DetailsScreen( + title: String, + imageUrl: String?, + fields: List +) { + + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + Column( + modifier = Modifier.padding(horizontal = 32.dp) + ) { + Spacer(modifier = Modifier.height(32.dp)) + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + text = title, + color = Color.Black, + fontSize = 24.sp + ) + Spacer(modifier = Modifier.height(32.dp)) + ImageLoader( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterHorizontally) + .heightIn(min = 0.dp, 200.dp), + url = imageUrl, + contentDescription = stringResource( + id = R.string.details_screen_image_content_description + ) + ) + fields.forEach { + Spacer(modifier = Modifier.height(32.dp)) + LabelAndTextData(label = it.label, text = it.text) + } + Spacer(modifier = Modifier.height(32.dp)) + } + } + +} + +@Preview(showBackground = true) +@Composable +fun DetailsScreenPreview( + title: String = "Titulo dos Detalhes", + imageUrl: String? = "https://starwars-visualguide.com/assets/img/species/1.jpg", + fields: List = listOf( + TextField("label top", "valor top"), + TextField("label top", "valor top"), + TextField("label top", "valor top"), + TextField("label top", "valor top") + ) +) { + ComposeStarWarsTheme { + DetailsScreen(title, imageUrl, fields) + } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/common/ErrorScreen.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/common/ErrorScreen.kt new file mode 100644 index 000000000..5cfea3b46 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/common/ErrorScreen.kt @@ -0,0 +1,63 @@ +package com.vdemelo.starwarswiki.ui.screens.common + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun ErrorScreen( + error: String, + buttonLabel: String, + onRetry: () -> Unit +) { + Surface( + color = MaterialTheme.colorScheme.background, + modifier = Modifier.fillMaxSize() + ) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text(text = error, color = Color.Red, fontSize = 18.sp) + Spacer(modifier = Modifier.height(8.dp)) + Button( + onClick = { onRetry() }, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) { + Text(text = buttonLabel) + } + } + } +} + +@Preview(showBackground = true) +@Composable +fun UnexpectedErrorRetryScreenPreview() { + ErrorScreen( + error = "An unexpected error occurred!", + buttonLabel = "Retry" + ) {} +} + +@Preview(showBackground = true) +@Composable +fun UnexpectedErrorGoBackScreenPreview() { + ErrorScreen( + error = "An unexpected error occurred!", + buttonLabel = "Go Back" + ) {} +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/home/HomeScreen.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/home/HomeScreen.kt new file mode 100644 index 000000000..c781f7235 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/home/HomeScreen.kt @@ -0,0 +1,47 @@ +package com.vdemelo.starwarswiki.ui.screens.home + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.vdemelo.starwarswiki.R +import com.vdemelo.starwarswiki.ui.nav.NavItem + +@Composable +fun HomeScreen(navController: NavController) { + Surface( + color = MaterialTheme.colorScheme.background, + modifier = Modifier.fillMaxSize() + ) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Button( + onClick = { navController.navigate(NavItem.SpeciesList.route) }, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) { + Text(text = stringResource(id = R.string.home_menu_item_species)) + } + Spacer(modifier = Modifier.height(32.dp)) + Button( + onClick = { navController.navigate(NavItem.PlanetsList.route) }, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) { + Text(text = stringResource(id = R.string.home_menu_item_planet)) + } + } + } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/details/PlanetDetailsScreen.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/details/PlanetDetailsScreen.kt new file mode 100644 index 000000000..9ad60e0ff --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/details/PlanetDetailsScreen.kt @@ -0,0 +1,85 @@ +package com.vdemelo.starwarswiki.ui.screens.planets.details + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavController +import com.vdemelo.starwarswiki.R +import com.vdemelo.starwarswiki.domain.entity.model.TextField +import com.vdemelo.starwarswiki.ui.components.RetrySection +import com.vdemelo.starwarswiki.ui.nav.NavItem +import com.vdemelo.starwarswiki.ui.screens.common.DetailsScreen +import com.vdemelo.starwarswiki.ui.screens.common.ErrorScreen +import org.koin.androidx.compose.getViewModel + +@Composable +fun PlanetDetailsScreen( + navController: NavController, + id: Int?, + viewModel: PlanetDetailsViewModel = getViewModel() +) { + val planet by remember { viewModel.planetDetails } + val loadError by remember { viewModel.loadError } + val isLoading by remember { viewModel.isLoading } + + if (id == null) { + ErrorScreen( + error = stringResource(id = R.string.common_unknown_error), + buttonLabel = stringResource(id = R.string.common_back) + ) { + navController.navigate(route = NavItem.PlanetsList.route) + } + } else { + viewModel.loadPlanetDetails(id) + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize() + ) { + if (isLoading) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } else if (planet != null) { + val imageUrl = viewModel.getPlanetImageUrl(id) + DetailsScreen( + title = stringResource(id = R.string.details_screen_title_planet), + imageUrl = imageUrl, + fields = listOf( + TextField( + label = stringResource(id = R.string.list_screen_name_label), + text = planet!!.name + ), + TextField( + label = stringResource(id = R.string.list_screen_population_label), + text = planet!!.population + ), + TextField( + label = stringResource(id = R.string.list_screen_climate_label), + text = planet!!.climate + ), + TextField( + label = stringResource(id = R.string.list_screen_diameter_label), + text = planet!!.diameter + ), + TextField( + label = stringResource(id = R.string.list_screen_rotation_period_label), + text = planet!!.rotationPeriod + ) + ) + ) + } else { + RetrySection( + error = loadError, + onRetry = { + viewModel.loadPlanetDetails(id) + } + ) + } + } + } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/details/PlanetDetailsViewModel.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/details/PlanetDetailsViewModel.kt new file mode 100644 index 000000000..9d10ed03a --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/details/PlanetDetailsViewModel.kt @@ -0,0 +1,43 @@ +package com.vdemelo.starwarswiki.ui.screens.planets.details + +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.vdemelo.starwarswiki.domain.entity.RequestStatus +import com.vdemelo.starwarswiki.domain.entity.model.Planet +import com.vdemelo.starwarswiki.domain.usecase.ItemsUseCase +import com.vdemelo.starwarswiki.domain.usecase.PlanetsUseCase +import kotlinx.coroutines.launch + +class PlanetDetailsViewModel ( + private val planetsUseCase: PlanetsUseCase, + private val itemsUseCase: ItemsUseCase +) : ViewModel() { + + var planetDetails = mutableStateOf(null) + var loadError = mutableStateOf("") + var isLoading = mutableStateOf(true) + + fun loadPlanetDetails(id: Int) { + viewModelScope.launch { + when ( + val planetRequestStatus: RequestStatus = + planetsUseCase.fetchPlanetDetails(id) + ) { + is RequestStatus.Success -> { + loadError.value = "" + isLoading.value = false + this@PlanetDetailsViewModel.planetDetails.value = planetRequestStatus.data + } + + is RequestStatus.Error -> { + loadError.value = planetRequestStatus.message!! + isLoading.value = false + } + } + } + } + + fun getPlanetImageUrl(id: Int): String = itemsUseCase.getPlanetImageUrl(id) + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/list/PlanetListScreen.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/list/PlanetListScreen.kt new file mode 100644 index 000000000..3067b6280 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/list/PlanetListScreen.kt @@ -0,0 +1,223 @@ +package com.vdemelo.starwarswiki.ui.screens.planets.list + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import com.vdemelo.starwarswiki.R +import com.vdemelo.starwarswiki.domain.entity.model.Planet +import com.vdemelo.starwarswiki.domain.entity.model.TextField +import com.vdemelo.starwarswiki.ui.components.ImageLoader +import com.vdemelo.starwarswiki.ui.components.LabelAndTextData +import com.vdemelo.starwarswiki.ui.components.RetrySection +import com.vdemelo.starwarswiki.ui.components.SearchBar +import com.vdemelo.starwarswiki.ui.nav.buildPlanetDetailsRoute +import org.koin.androidx.compose.getViewModel + +@Composable +fun PlanetListScreen( + navController: NavController, + viewModel: PlanetListViewModel = getViewModel() +) { + Surface( + color = MaterialTheme.colorScheme.background, + modifier = Modifier.fillMaxSize() + ) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Surface( + color = Color.Black, + modifier = Modifier.fillMaxWidth() + ) { + Image( + painter = painterResource(id = R.drawable.star_wars_logo), + contentDescription = stringResource(id = R.string.app_name), + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterHorizontally) + .heightIn(min = 0.dp, max = 140.dp) + ) + } + Text( + text = stringResource(id = R.string.planets_list_screen_title), + fontSize = 48.sp, + textAlign = TextAlign.Center, + fontWeight = FontWeight.Bold + ) + SearchBar( + hint = stringResource(id = R.string.list_screen_search_hint), + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + onSearch = { + viewModel.loadPlanetsPaginated(search = it) + } + ) + Spacer(modifier = Modifier.height(16.dp)) + PlanetsList(navController = navController) + } + } +} + +@Composable +fun PlanetsList( + navController: NavController, + viewModel: PlanetListViewModel = getViewModel() +) { + val list by remember { viewModel.list } + val endReached by remember { viewModel.endReached } + val loadError by remember { viewModel.loadError } + val isLoading by remember { viewModel.isLoading } + + Column( + modifier = Modifier.fillMaxSize() + ) { + if (list.isNotEmpty()) { + LazyColumn(contentPadding = PaddingValues(16.dp)) { + val itemCount = list.size + + items(itemCount) { i -> + val hasScrolledDown = i >= itemCount - 2 + if (hasScrolledDown && !endReached && !isLoading) { + viewModel.loadPlanetsPaginated() + } + PlanetItem( + planet = list[i], + navController = navController + ) + Spacer(modifier = Modifier.height(24.dp)) + } + + item { + if (isLoading) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + horizontalArrangement = Arrangement.Center + ) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } + } else if (loadError.isNotEmpty()) { + RetrySection( + error = loadError, + onRetry = { viewModel.loadPlanetsPaginated() } + ) + } + } + } + } else { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize() + ) { + if (isLoading) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } else if (loadError.isNotEmpty()) { + RetrySection( + error = loadError, + onRetry = { viewModel.loadPlanetsPaginated() } + ) + } + } + } + } +} + +@Composable +fun PlanetItem( + planet: Planet, + navController: NavController, + modifier: Modifier = Modifier, + viewModel: PlanetListViewModel = getViewModel() +) { + val id = planet.url?.let { viewModel.getPlanetId(it) } + val imageUrl = id?.let { viewModel.getPlanetImageUrl(it) } + Box( + contentAlignment = Alignment.Center, + modifier = modifier + .fillMaxWidth() + .shadow(5.dp, RoundedCornerShape(10.dp)) + .clip(RoundedCornerShape(10.dp)) + .background(MaterialTheme.colorScheme.surface) + .clickable { + id?.run { + navController.navigate( + route = buildPlanetDetailsRoute(id = id.toString()) + ) + } + } + ) { + Column( + modifier = modifier + .fillMaxWidth() + .padding(16.dp) + ) { + ImageLoader( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterHorizontally) + .size(120.dp), + url = imageUrl, + contentDescription = planet.name + ?: stringResource(id = R.string.details_screen_image_content_description) + ) + Spacer(modifier = Modifier.height(8.dp)) + detailsData(planet).forEach { + LabelAndTextData(label = it.label, text = it.text) + } + } + } +} + +@Composable +fun detailsData(planet: Planet): List { + return listOf( + TextField( + label = stringResource(id = R.string.list_screen_name_label), + text = planet.name + ), + TextField( + label = stringResource(id = R.string.list_screen_population_label), + text = planet.population + ), + TextField( + label = stringResource(id = R.string.list_screen_climate_label), + text = planet.climate + ) + ) +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/list/PlanetListViewModel.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/list/PlanetListViewModel.kt new file mode 100644 index 000000000..c60fdcc65 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/planets/list/PlanetListViewModel.kt @@ -0,0 +1,70 @@ +package com.vdemelo.starwarswiki.ui.screens.planets.list + +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.vdemelo.starwarswiki.domain.entity.RequestStatus +import com.vdemelo.starwarswiki.domain.entity.model.Planet +import com.vdemelo.starwarswiki.domain.entity.model.PlanetsList +import com.vdemelo.starwarswiki.domain.usecase.ItemsUseCase +import com.vdemelo.starwarswiki.domain.usecase.PlanetsUseCase +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +private const val STARTING_PAGE = 1 + +class PlanetListViewModel( + private val planetsUseCase: PlanetsUseCase, + private val itemsUseCase: ItemsUseCase +) : ViewModel() { + + private var currentPage = STARTING_PAGE + private var currentSearch: String? = null + private var lastJob: Job? = null + + var list = mutableStateOf>(listOf()) + var loadError = mutableStateOf("") + var isLoading = mutableStateOf(false) + var endReached = mutableStateOf(false) + + init { + loadPlanetsPaginated() + } + + fun loadPlanetsPaginated(search: String? = null) { + isLoading.value = true + lastJob?.cancel() + if (search != null && search != currentSearch) { + currentSearch = search + currentPage = STARTING_PAGE + list.value = listOf() + } + lastJob = viewModelScope.launch { + delay(500L) + when ( + val planetRequestStatus: RequestStatus = + planetsUseCase.fetchPlanets(page = currentPage, search = currentSearch) + ) { + is RequestStatus.Success -> { + endReached.value = (planetRequestStatus.data?.next == null) + val results = planetRequestStatus.data?.results ?: listOf() + currentPage++ + + loadError.value = "" + isLoading.value = false + this@PlanetListViewModel.list.value += results + } + + is RequestStatus.Error -> { + loadError.value = planetRequestStatus.message!! + isLoading.value = false + } + } + } + } + + fun getPlanetImageUrl(id: Int): String = itemsUseCase.getPlanetImageUrl(id) + fun getPlanetId(url: String): Int? = itemsUseCase.getItemId(url) + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/details/SpeciesDetailsScreen.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/details/SpeciesDetailsScreen.kt new file mode 100644 index 000000000..047c3259a --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/details/SpeciesDetailsScreen.kt @@ -0,0 +1,85 @@ +package com.vdemelo.starwarswiki.ui.screens.species.details + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavController +import com.vdemelo.starwarswiki.R +import com.vdemelo.starwarswiki.domain.entity.model.TextField +import com.vdemelo.starwarswiki.ui.components.RetrySection +import com.vdemelo.starwarswiki.ui.nav.NavItem +import com.vdemelo.starwarswiki.ui.screens.common.DetailsScreen +import com.vdemelo.starwarswiki.ui.screens.common.ErrorScreen +import org.koin.androidx.compose.getViewModel + +@Composable +fun SpeciesDetailsScreen( + navController: NavController, + id: Int?, + viewModel: SpeciesDetailsViewModel = getViewModel() +) { + val species by remember { viewModel.speciesDetails } + val loadError by remember { viewModel.loadError } + val isLoading by remember { viewModel.isLoading } + + if (id == null) { + ErrorScreen( + error = stringResource(id = R.string.common_unknown_error), + buttonLabel = stringResource(id = R.string.common_back) + ) { + navController.navigate(route = NavItem.SpeciesList.route) + } + } else { + viewModel.loadSpeciesDetails(id) + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize() + ) { + if (isLoading) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } else if (species != null) { + val imageUrl = viewModel.getSpeciesImageUrl(id) + DetailsScreen( + title = stringResource(id = R.string.details_screen_title_species), + imageUrl = imageUrl, + fields = listOf( + TextField( + label = stringResource(id = R.string.list_screen_name_label), + text = species!!.name + ), + TextField( + label = stringResource(id = R.string.list_screen_language_label), + text = species!!.language + ), + TextField( + label = stringResource(id = R.string.list_screen_classification_label), + text = species!!.classification + ), + TextField( + label = stringResource(id = R.string.list_screen_average_height_label), + text = species!!.averageHeight + ), + TextField( + label = stringResource(id = R.string.list_screen_average_lifespan_label), + text = species!!.averageLifespan + ) + ) + ) + } else { + RetrySection( + error = loadError, + onRetry = { + viewModel.loadSpeciesDetails(id) + } + ) + } + } + } +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/details/SpeciesDetailsViewModel.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/details/SpeciesDetailsViewModel.kt new file mode 100644 index 000000000..88335bd49 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/details/SpeciesDetailsViewModel.kt @@ -0,0 +1,43 @@ +package com.vdemelo.starwarswiki.ui.screens.species.details + +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.vdemelo.starwarswiki.domain.entity.RequestStatus +import com.vdemelo.starwarswiki.domain.entity.model.Species +import com.vdemelo.starwarswiki.domain.usecase.ItemsUseCase +import com.vdemelo.starwarswiki.domain.usecase.SpeciesUseCase +import kotlinx.coroutines.launch + +class SpeciesDetailsViewModel ( + private val speciesUseCase: SpeciesUseCase, + private val itemsUseCase: ItemsUseCase +) : ViewModel() { + + var speciesDetails = mutableStateOf(null) + var loadError = mutableStateOf("") + var isLoading = mutableStateOf(true) + + fun loadSpeciesDetails(id: Int) { + viewModelScope.launch { + when ( + val speciesRequestStatus: RequestStatus = + speciesUseCase.fetchSpeciesDetails(id) + ) { + is RequestStatus.Success -> { + loadError.value = "" + isLoading.value = false + this@SpeciesDetailsViewModel.speciesDetails.value = speciesRequestStatus.data + } + + is RequestStatus.Error -> { + loadError.value = speciesRequestStatus.message!! + isLoading.value = false + } + } + } + } + + fun getSpeciesImageUrl(id: Int): String = itemsUseCase.getSpeciesImageUrl(id) + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/list/SpeciesListScreen.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/list/SpeciesListScreen.kt new file mode 100644 index 000000000..f23278514 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/list/SpeciesListScreen.kt @@ -0,0 +1,221 @@ +package com.vdemelo.starwarswiki.ui.screens.species.list + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import com.vdemelo.starwarswiki.R +import com.vdemelo.starwarswiki.domain.entity.model.Species +import com.vdemelo.starwarswiki.domain.entity.model.TextField +import com.vdemelo.starwarswiki.ui.components.ImageLoader +import com.vdemelo.starwarswiki.ui.components.LabelAndTextData +import com.vdemelo.starwarswiki.ui.components.RetrySection +import com.vdemelo.starwarswiki.ui.components.SearchBar +import com.vdemelo.starwarswiki.ui.nav.buildSpeciesDetailsRoute +import org.koin.androidx.compose.getViewModel + +@Composable +fun SpeciesListScreen( + navController: NavController, + viewModel: SpeciesListViewModel = getViewModel() +) { + Surface( + color = MaterialTheme.colorScheme.background, + modifier = Modifier.fillMaxSize() + ) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Surface( + color = Color.Black, + modifier = Modifier.fillMaxWidth() + ) { + Image( + painter = painterResource(id = R.drawable.star_wars_logo), + contentDescription = stringResource(id = R.string.app_name), + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterHorizontally) + .heightIn(min = 0.dp, max = 140.dp) + ) + } + Text( + text = stringResource(id = R.string.species_list_screen_title), + fontSize = 48.sp, + textAlign = TextAlign.Center, + fontWeight = FontWeight.Bold + ) + SearchBar( + hint = stringResource(id = R.string.list_screen_search_hint), + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + onSearch = { viewModel.loadSpeciesPaginated(search = it) } + ) + Spacer(modifier = Modifier.height(16.dp)) + SpeciesList(navController = navController) + } + } +} + +@Composable +fun SpeciesList( + navController: NavController, + viewModel: SpeciesListViewModel = getViewModel() +) { + val list by remember { viewModel.speciesList } + val endReached by remember { viewModel.endReached } + val loadError by remember { viewModel.loadError } + val isLoading by remember { viewModel.isLoading } + + Column( + modifier = Modifier.fillMaxSize() + ) { + if (list.isNotEmpty()) { + LazyColumn(contentPadding = PaddingValues(16.dp)) { + val itemCount = list.size + + items(itemCount) { i -> + val hasScrolledDown = i >= itemCount - 2 + if (hasScrolledDown && !endReached && !isLoading) { + viewModel.loadSpeciesPaginated() + } + SpeciesItem( + species = list[i], + navController = navController + ) + Spacer(modifier = Modifier.height(24.dp)) + } + + item { + if (isLoading) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + horizontalArrangement = Arrangement.Center + ) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } + } else if (loadError.isNotEmpty()) { + RetrySection( + error = loadError, + onRetry = { viewModel.loadSpeciesPaginated() } + ) + } + } + } + } else { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize() + ) { + if (isLoading) { + CircularProgressIndicator(color = MaterialTheme.colorScheme.primary) + } else if (loadError.isNotEmpty()) { + RetrySection( + error = loadError, + onRetry = { viewModel.loadSpeciesPaginated() } + ) + } + } + } + } +} + +@Composable +fun SpeciesItem( + species: Species, + navController: NavController, + modifier: Modifier = Modifier, + viewModel: SpeciesListViewModel = getViewModel() +) { + val id = species.url?.let { viewModel.getSpeciesNumber(it) } + val imageUrl = id?.let { viewModel.getSpeciesImageUrl(it) } + Box( + contentAlignment = Alignment.Center, + modifier = modifier + .fillMaxWidth() + .shadow(5.dp, RoundedCornerShape(10.dp)) + .clip(RoundedCornerShape(10.dp)) + .background(MaterialTheme.colorScheme.surface) + .clickable { + id?.run { + navController.navigate( + route = buildSpeciesDetailsRoute(id = id.toString()) + ) + } + } + ) { + Column( + modifier = modifier + .fillMaxWidth() + .padding(16.dp) + ) { + ImageLoader( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterHorizontally) + .size(120.dp), + url = imageUrl, + contentDescription = species.name + ?: stringResource(id = R.string.details_screen_image_content_description) + ) + Spacer(modifier = Modifier.height(8.dp)) + detailsData(species).forEach { + LabelAndTextData(label = it.label, text = it.text) + } + } + } +} + +@Composable +fun detailsData(species: Species): List { + return listOf( + TextField( + label = stringResource(id = R.string.list_screen_name_label), + text = species.name + ), + TextField( + label = stringResource(id = R.string.list_screen_language_label), + text = species.language + ), + TextField( + label = stringResource(id = R.string.list_screen_classification_label), + text = species.classification + ) + ) +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/list/SpeciesListViewModel.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/list/SpeciesListViewModel.kt new file mode 100644 index 000000000..96a4fba6a --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/screens/species/list/SpeciesListViewModel.kt @@ -0,0 +1,70 @@ +package com.vdemelo.starwarswiki.ui.screens.species.list + +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.vdemelo.starwarswiki.domain.entity.RequestStatus +import com.vdemelo.starwarswiki.domain.entity.model.Species +import com.vdemelo.starwarswiki.domain.entity.model.SpeciesList +import com.vdemelo.starwarswiki.domain.usecase.ItemsUseCase +import com.vdemelo.starwarswiki.domain.usecase.SpeciesUseCase +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +private const val STARTING_PAGE = 1 + +class SpeciesListViewModel( + private val speciesUseCase: SpeciesUseCase, + private val itemsUseCase: ItemsUseCase +) : ViewModel() { + + private var currentPage = STARTING_PAGE + private var currentSearch: String? = null + private var lastJob: Job? = null + + var speciesList = mutableStateOf>(listOf()) + var loadError = mutableStateOf("") + var isLoading = mutableStateOf(false) + var endReached = mutableStateOf(false) + + init { + loadSpeciesPaginated() + } + + fun loadSpeciesPaginated(search: String? = null) { + isLoading.value = true + lastJob?.cancel() + if (search != null && search != currentSearch) { + currentSearch = search + currentPage = STARTING_PAGE + speciesList.value = listOf() + } + lastJob = viewModelScope.launch { + delay(500L) + when ( + val speciesRequestStatus: RequestStatus = + speciesUseCase.fetchSpecies(page = currentPage, search = currentSearch) + ) { + is RequestStatus.Success -> { + endReached.value = (speciesRequestStatus.data?.next == null) + val results = speciesRequestStatus.data?.results ?: listOf() + currentPage++ + + loadError.value = "" + isLoading.value = false + this@SpeciesListViewModel.speciesList.value += results + } + + is RequestStatus.Error -> { + loadError.value = speciesRequestStatus.message!! + isLoading.value = false + } + } + } + } + + fun getSpeciesImageUrl(id: Int): String = itemsUseCase.getSpeciesImageUrl(id) + fun getSpeciesNumber(speciesUrl: String): Int? = itemsUseCase.getItemId(speciesUrl) + +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Color.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Color.kt new file mode 100644 index 000000000..0ac3700c9 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.vdemelo.starwarswiki.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Theme.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Theme.kt new file mode 100644 index 000000000..d653a6981 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Theme.kt @@ -0,0 +1,70 @@ +package com.vdemelo.starwarswiki.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun ComposeStarWarsTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} diff --git a/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Type.kt b/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Type.kt new file mode 100644 index 000000000..daa792c18 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.vdemelo.starwarswiki.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) diff --git a/app/src/main/java/com/vdemelo/starwarswiki/utils/ExtensionFunctions.kt b/app/src/main/java/com/vdemelo/starwarswiki/utils/ExtensionFunctions.kt new file mode 100644 index 000000000..2828dccb3 --- /dev/null +++ b/app/src/main/java/com/vdemelo/starwarswiki/utils/ExtensionFunctions.kt @@ -0,0 +1,17 @@ +package com.vdemelo.starwarswiki.utils + +fun List?.nonNullOrEmpty(): List { + return if (this == null) { + emptyList() + } else { + val nonNullableListItems = mutableListOf() + this.forEach { item -> + if (item != null) { + nonNullableListItems.add(item) + } + } + nonNullableListItems + } +} + +fun String.simpleCapitalize(): String = this.replaceFirstChar(Char::titlecase) diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..07d5da9cb --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/image_placeholder.webp b/app/src/main/res/drawable/image_placeholder.webp new file mode 100644 index 000000000..e5223d8f2 Binary files /dev/null and b/app/src/main/res/drawable/image_placeholder.webp differ diff --git a/app/src/main/res/drawable/star_wars_logo.xml b/app/src/main/res/drawable/star_wars_logo.xml new file mode 100644 index 000000000..99deed546 --- /dev/null +++ b/app/src/main/res/drawable/star_wars_logo.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..6f3b755bf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..6f3b755bf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 000000000..c209e78ec Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 000000000..b2dfe3d1b Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 000000000..4f0f1d64e Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 000000000..62b611da0 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 000000000..948a3070f Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..1b9a6956b Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 000000000..28d4b77f9 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9287f5083 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 000000000..aa7d6427e Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9126ae37c Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 000000000..10ce152ac --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..c8524cd96 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,5 @@ + + + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..0c6683d52 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,41 @@ + + Star Wars Wiki + + //Home Menu + Star Wars Species + Star Wars Planets + + // List Screen + Search... + + Species List + Planets List + + Name: + Language: + Classification: + Average Height: + Average Lifespan: + Population: + Climate: + Diameter: + Rotation period: + + // Details Screen + Details + Species + Planet + + Image for this item + + Home World: %s + Language: %s + Classification: %s + + //Common + Retry + Go Back + Unknown + An unknown error occurred! + + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..b6aa15083 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,9 @@ + + + + +