From 79225b262810427dc093571d51d8a1c4a3e98a78 Mon Sep 17 00:00:00 2001 From: yao Date: Thu, 26 Oct 2023 13:49:04 -0500 Subject: [PATCH] add graphql project --- app/build.gradle | 5 + app/src/main/AndroidManifest.xml | 26 +- .../GetLaunchesPast.graphql | 16 - .../getAllContinents.graphql | 6 + .../getCountriesList.graphql | 11 + .../schema.graphqls | 1098 ----------------- .../jetpack_compose_all_in_one/schema.sdl | 83 ++ .../graph_ql_country_list/ApiService.kt | 5 - .../model/GraphQlBuilder.kt | 16 + .../graph_ql_country_list/model/Repository.kt | 14 + .../view/ContinentsScreen.kt | 68 + .../view/MainActivity.kt | 44 + .../view/ui/theme/Color.kt | 11 + .../view/ui/theme/Theme.kt | 70 ++ .../view/ui/theme/Type.kt | 34 + .../viewmodel/ContinentsViewModel.kt | 49 + .../viewmodel/ViewModelFactory.kt | 14 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/themes.xml | 3 +- 19 files changed, 441 insertions(+), 1133 deletions(-) delete mode 100644 app/src/main/graphql/com/example/jetpack_compose_all_in_one/GetLaunchesPast.graphql create mode 100644 app/src/main/graphql/com/example/jetpack_compose_all_in_one/getAllContinents.graphql create mode 100644 app/src/main/graphql/com/example/jetpack_compose_all_in_one/getCountriesList.graphql delete mode 100644 app/src/main/graphql/com/example/jetpack_compose_all_in_one/schema.graphqls create mode 100644 app/src/main/graphql/com/example/jetpack_compose_all_in_one/schema.sdl delete mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/ApiService.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/model/GraphQlBuilder.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/model/Repository.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ContinentsScreen.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/MainActivity.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Color.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Theme.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Type.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/viewmodel/ContinentsViewModel.kt create mode 100644 app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/viewmodel/ViewModelFactory.kt diff --git a/app/build.gradle b/app/build.gradle index c57e8d43..41ecade0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -94,6 +94,10 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0' implementation 'com.google.accompanist:accompanist-webview:0.31.3-beta' + implementation platform('androidx.compose:compose-bom:2023.03.00') + implementation 'androidx.compose.ui:ui-graphics' + implementation 'androidx.benchmark:benchmark-macro:1.2.0' + implementation 'com.google.android.ads:mediation-test-suite:3.0.0' testImplementation 'junit:junit:4.13.2' @@ -104,6 +108,7 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" + androidTestImplementation platform('androidx.compose:compose-bom:2023.03.00') debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index aceafac6..f2055735 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,8 +10,7 @@ - + @@ -21,7 +20,6 @@ + + android:exported="false" /> - + - - - - - - - diff --git a/app/src/main/graphql/com/example/jetpack_compose_all_in_one/GetLaunchesPast.graphql b/app/src/main/graphql/com/example/jetpack_compose_all_in_one/GetLaunchesPast.graphql deleted file mode 100644 index 8ea33bed..00000000 --- a/app/src/main/graphql/com/example/jetpack_compose_all_in_one/GetLaunchesPast.graphql +++ /dev/null @@ -1,16 +0,0 @@ -query GetLaunchesPast($limit: Int = 10) { - launchesPast(limit: $limit){ - id - details - mission_name - launch_date_utc - rocket { - rocket_name - } - links { - article_link - video_link - wikipedia - } - } -} \ No newline at end of file diff --git a/app/src/main/graphql/com/example/jetpack_compose_all_in_one/getAllContinents.graphql b/app/src/main/graphql/com/example/jetpack_compose_all_in_one/getAllContinents.graphql new file mode 100644 index 00000000..aa8c53b4 --- /dev/null +++ b/app/src/main/graphql/com/example/jetpack_compose_all_in_one/getAllContinents.graphql @@ -0,0 +1,6 @@ +query GetContinents{ + continents { + code + name + } +} \ No newline at end of file diff --git a/app/src/main/graphql/com/example/jetpack_compose_all_in_one/getCountriesList.graphql b/app/src/main/graphql/com/example/jetpack_compose_all_in_one/getCountriesList.graphql new file mode 100644 index 00000000..68094d2c --- /dev/null +++ b/app/src/main/graphql/com/example/jetpack_compose_all_in_one/getCountriesList.graphql @@ -0,0 +1,11 @@ +query FindCountriesOfAContinent($code:ID!){ + continent(code: $code) { + countries { + name + native + phone + currency + emoji + } + } +} \ No newline at end of file diff --git a/app/src/main/graphql/com/example/jetpack_compose_all_in_one/schema.graphqls b/app/src/main/graphql/com/example/jetpack_compose_all_in_one/schema.graphqls deleted file mode 100644 index 01fdf8c4..00000000 --- a/app/src/main/graphql/com/example/jetpack_compose_all_in_one/schema.graphqls +++ /dev/null @@ -1,1098 +0,0 @@ -directive @contact( - # Contact title of the subgraph owner - name: String! - # URL where the subgraph's owner can be reached - url: String - # Other relevant notes can be included here; supports markdown links - description: String -) on SCHEMA - -type Address { - address: String - city: String - state: String -} - -type Capsule { - dragon: Dragon - @deprecated( - reason: "This is not available in the REST API after MongoDB has been deprecated" - ) - id: ID - landings: Int - missions: [CapsuleMission] - original_launch: Date - reuse_count: Int - status: String - type: String -} - -type CapsuleMission { - flight: Int - name: String -} - -input CapsulesFind { - id: ID - landings: Int - mission: String - original_launch: Date - reuse_count: Int - status: String - type: String -} - -# conflict action -enum conflict_action { - # ignore the insert on this row - ignore - # update the row with the given values - update -} - -type Core { - asds_attempts: Int - asds_landings: Int - block: Int - id: ID - missions: [CapsuleMission] - original_launch: Date - reuse_count: Int - rtls_attempts: Int - rtls_landings: Int - status: String - water_landing: Boolean -} - -type CoreMission { - flight: Int - name: String -} - -input CoresFind { - asds_attempts: Int - asds_landings: Int - block: Int - id: String - missions: String - original_launch: Date - reuse_count: Int - rtls_attempts: Int - rtls_landings: Int - status: String - water_landing: Boolean -} - -scalar Date - -type Distance { - feet: Float - meters: Float -} - -type Dragon { - active: Boolean - crew_capacity: Int - description: String - diameter: Distance - dry_mass_kg: Int - dry_mass_lb: Int - first_flight: String - heat_shield: DragonHeatShield - height_w_trunk: Distance - id: ID - launch_payload_mass: Mass - launch_payload_vol: Volume - name: String - orbit_duration_yr: Int - pressurized_capsule: DragonPressurizedCapsule - return_payload_mass: Mass - return_payload_vol: Volume - sidewall_angle_deg: Float - thrusters: [DragonThrust] - trunk: DragonTrunk - type: String - wikipedia: String -} - -type DragonHeatShield { - dev_partner: String - material: String - size_meters: Float - temp_degrees: Int -} - -type DragonPressurizedCapsule { - payload_volume: Volume -} - -type DragonThrust { - amount: Int - fuel_1: String - fuel_2: String - pods: Int - thrust: Force - type: String -} - -type DragonTrunk { - cargo: DragonTrunkCargo - trunk_volume: Volume -} - -type DragonTrunkCargo { - solar_array: Int - unpressurized_cargo: Boolean -} - -type Force { - kN: Float - lbf: Float -} - -type HistoriesResult { - data: [History] - result: Result -} - -type History { - details: String - event_date_unix: Date - event_date_utc: Date - flight: Launch - id: ID - links: Link - title: String -} - -input HistoryFind { - end: Date - flight_number: Int - id: ID - start: Date -} - -type Info { - ceo: String - coo: String - cto: String - cto_propulsion: String - employees: Int - founded: Int - founder: String - headquarters: Address - launch_sites: Int - links: InfoLinks - name: String - summary: String - test_sites: Int - valuation: Float - vehicles: Int -} - -type InfoLinks { - elon_twitter: String - flickr: String - twitter: String - website: String -} - -type Landpad { - attempted_landings: String - details: String - full_name: String - id: ID - landing_type: String - location: Location - status: String - successful_landings: String - wikipedia: String -} - -type Launch { - details: String - id: ID! - is_tentative: Boolean - launch_date_local: Date - launch_date_unix: Date - launch_date_utc: String! - launch_site: LaunchSite - launch_success: Boolean - launch_year: String - links: LaunchLinks! - mission_id: [String] - mission_name: String! - rocket: LaunchRocket! - ships: [Ship] - static_fire_date_unix: Date - static_fire_date_utc: Date - telemetry: LaunchTelemetry - tentative_max_precision: String - upcoming: Boolean -} - -type LaunchesPastResult { - data: [Launch] - result: Result -} - -input LaunchFind { - apoapsis_km: Float - block: Int - cap_serial: String - capsule_reuse: String - core_flight: Int - core_reuse: String - core_serial: String - customer: String - eccentricity: Float - end: Date - epoch: Date - fairings_recovered: String - fairings_recovery_attempt: String - fairings_reuse: String - fairings_reused: String - fairings_ship: String - gridfins: String - id: ID - inclination_deg: Float - land_success: String - landing_intent: String - landing_type: String - landing_vehicle: String - launch_date_local: Date - launch_date_utc: Date - launch_success: String - launch_year: String - legs: String - lifespan_years: Float - longitude: Float - manufacturer: String - mean_motion: Float - mission_id: String - mission_name: String - nationality: String - norad_id: Int - orbit: String - payload_id: String - payload_type: String - periapsis_km: Float - period_min: Float - raan: Float - reference_system: String - regime: String - reused: String - rocket_id: String - rocket_name: String - rocket_type: String - second_stage_block: String - semi_major_axis_km: Float - ship: String - side_core1_reuse: String - side_core2_reuse: String - site_id: String - site_name_long: String - site_name: String - start: Date - tbd: String - tentative_max_precision: String - tentative: String -} - -type LaunchLinks { - article_link: String! - flickr_images: [String] - mission_patch: String - mission_patch_small: String - presskit: String - reddit_campaign: String - reddit_launch: String - reddit_media: String - reddit_recovery: String - video_link: String! - wikipedia: String! -} - -type Launchpad { - attempted_launches: Int - details: String - id: ID - location: Location - name: String - status: String - successful_launches: Int - vehicles_launched: [Rocket] - wikipedia: String -} - -type LaunchRocket { - fairings: LaunchRocketFairings - first_stage: LaunchRocketFirstStage - rocket: Rocket - rocket_name: String! - rocket_type: String - second_stage: LaunchRocketSecondStage -} - -type LaunchRocketFairings { - recovered: Boolean - recovery_attempt: Boolean - reused: Boolean - ship: String -} - -type LaunchRocketFirstStage { - cores: [LaunchRocketFirstStageCore] -} - -type LaunchRocketFirstStageCore { - block: Int - core: Core - flight: Int - gridfins: Boolean - land_success: Boolean - landing_intent: Boolean - landing_type: String - landing_vehicle: String - legs: Boolean - reused: Boolean -} - -type LaunchRocketSecondStage { - block: Int - payloads: [Payload] -} - -type LaunchSite { - site_id: String - site_name: String - site_name_long: String -} - -type LaunchTelemetry { - flight_club: String -} - -type Link { - article: String - reddit: String - wikipedia: String -} - -type Location { - latitude: Float - longitude: Float - name: String - region: String -} - -type Mass { - kg: Int - lb: Int -} - -type Mission { - description: String - id: ID - manufacturers: [String] - name: String - payloads: [Payload] - twitter: String - website: String - wikipedia: String -} - -type MissionResult { - data: [Mission] - result: Result -} - -input MissionsFind { - id: ID - manufacturer: String - name: String - payload_id: String -} - -type Mutation { - # delete data from the table: "users" - delete_users( - # filter the rows which have to be deleted - where: users_bool_exp! - ): users_mutation_response - # insert data into the table: "users" - insert_users( - # the rows to be inserted - objects: [users_insert_input!]! - # on conflict condition - on_conflict: users_on_conflict - ): users_mutation_response - # update data of the table: "users" - update_users( - # sets the columns of the filtered rows to the given values - _set: users_set_input - # filter the rows which have to be updated - where: users_bool_exp! - ): users_mutation_response -} - -scalar ObjectID - -# column ordering options -enum order_by { - # in the ascending order, nulls last - asc - # in the ascending order, nulls first - asc_nulls_first - # in the ascending order, nulls last - asc_nulls_last - # in the descending order, nulls first - desc - # in the descending order, nulls first - desc_nulls_first - # in the descending order, nulls last - desc_nulls_last -} - -type Payload { - customers: [String] - id: ID - manufacturer: String - nationality: String - norad_id: [Int] - orbit: String - orbit_params: PayloadOrbitParams - payload_mass_kg: Float - payload_mass_lbs: Float - payload_type: String - reused: Boolean -} - -type PayloadOrbitParams { - apoapsis_km: Float - arg_of_pericenter: Float - eccentricity: Float - epoch: Date - inclination_deg: Float - lifespan_years: Float - longitude: Float - mean_anomaly: Float - mean_motion: Float - periapsis_km: Float - period_min: Float - raan: Float - reference_system: String - regime: String - semi_major_axis_km: Float -} - -input PayloadsFind { - apoapsis_km: Float - customer: String - eccentricity: Float - epoch: Date - inclination_deg: Float - lifespan_years: Float - longitude: Float - manufacturer: String - mean_motion: Float - nationality: String - norad_id: Int - orbit: String - payload_id: ID - payload_type: String - periapsis_km: Float - period_min: Float - raan: Float - reference_system: String - regime: String - reused: Boolean - semi_major_axis_km: Float -} - -type Query { - capsule(id: ID!): Capsule - capsules( - find: CapsulesFind - limit: Int - offset: Int - order: String - sort: String - ): [Capsule] - capsulesPast( - find: CapsulesFind - limit: Int - offset: Int - order: String - sort: String - ): [Capsule] - capsulesUpcoming( - find: CapsulesFind - limit: Int - offset: Int - order: String - sort: String - ): [Capsule] - company: Info - core(id: ID!): Core - cores( - find: CoresFind - limit: Int - offset: Int - order: String - sort: String - ): [Core] - coresPast( - find: CoresFind - limit: Int - offset: Int - order: String - sort: String - ): [Core] - coresUpcoming( - find: CoresFind - limit: Int - offset: Int - order: String - sort: String - ): [Core] - dragon(id: ID!): Dragon - dragons(limit: Int, offset: Int): [Dragon] - histories( - find: HistoryFind - limit: Int - offset: Int - order: String - sort: String - ): [History] - historiesResult( - find: HistoryFind - limit: Int - offset: Int - order: String - sort: String - ): HistoriesResult - history(id: ID!): History - landpad(id: ID!): Landpad - landpads(limit: Int, offset: Int): [Landpad] - launch(id: ID!): Launch - launchLatest(offset: Int): Launch - launchNext(offset: Int): Launch - launches( - find: LaunchFind - limit: Int - offset: Int - order: String - sort: String - ): [Launch] - launchesPast( - find: LaunchFind - limit: Int - offset: Int - order: String - sort: String - ): [Launch!] - launchesPastResult( - find: LaunchFind - limit: Int - offset: Int - order: String - sort: String - ): LaunchesPastResult - launchesUpcoming( - find: LaunchFind - limit: Int - offset: Int - order: String - sort: String - ): [Launch] - launchpad(id: ID!): Launchpad - launchpads(limit: Int, offset: Int): [Launchpad] - mission(id: ID!): Mission - @deprecated( - reason: "Mission is not available on REST API after MongoDB deprecation" - ) - missions(find: MissionsFind, limit: Int, offset: Int): [Mission] - @deprecated( - reason: "Mission is not available on REST API after MongoDB deprecation" - ) - missionsResult(find: MissionsFind, limit: Int, offset: Int): MissionResult - @deprecated( - reason: "Mission is not available on REST API after MongoDB deprecation" - ) - payload(id: ID!): Payload - payloads( - find: PayloadsFind - limit: Int - offset: Int - order: String - sort: String - ): [Payload] - roadster: Roadster - rocket(id: ID!): Rocket - rockets(limit: Int, offset: Int): [Rocket] - rocketsResult(limit: Int, offset: Int): RocketsResult - ship(id: ID!): Ship - ships( - find: ShipsFind - limit: Int - offset: Int - order: String - sort: String - ): [Ship] - shipsResult( - find: ShipsFind - limit: Int - offset: Int - order: String - sort: String - ): ShipsResult - # fetch data from the table: "users" - users( - # distinct select on columns - distinct_on: [users_select_column!] - # limit the nuber of rows returned - limit: Int - # skip the first n rows. Use only with order_by - offset: Int - # sort the rows by one or more columns - order_by: [users_order_by!] - # filter the rows returned - where: users_bool_exp - ): [users!]! - # fetch aggregated fields from the table: "users" - users_aggregate( - # distinct select on columns - distinct_on: [users_select_column!] - # limit the nuber of rows returned - limit: Int - # skip the first n rows. Use only with order_by - offset: Int - # sort the rows by one or more columns - order_by: [users_order_by!] - # filter the rows returned - where: users_bool_exp - ): users_aggregate! - # fetch data from the table: "users" using primary key columns - users_by_pk(id: uuid!): users -} - -type Result { - totalCount: Int -} - -type Roadster { - apoapsis_au: Float - details: String - earth_distance_km: Float - earth_distance_mi: Float - eccentricity: Float - epoch_jd: Float - inclination: Float - launch_date_unix: Date - launch_date_utc: Date - launch_mass_kg: Int - launch_mass_lbs: Int - longitude: Float - mars_distance_km: Float - mars_distance_mi: Float - name: String - norad_id: Int - orbit_type: Float - periapsis_arg: Float - periapsis_au: Float - period_days: Float - semi_major_axis_au: Float - speed_kph: Float - speed_mph: Float - wikipedia: String -} - -type Rocket { - active: Boolean - boosters: Int - company: String - cost_per_launch: Int - country: String - description: String - diameter: Distance - engines: RocketEngines - first_flight: Date - first_stage: RocketFirstStage - height: Distance - id: ID - landing_legs: RocketLandingLegs - mass: Mass - name: String - payload_weights: [RocketPayloadWeight] - second_stage: RocketSecondStage - stages: Int - success_rate_pct: Int - type: String - wikipedia: String -} - -type RocketEngines { - engine_loss_max: String - layout: String - number: Int - propellant_1: String - propellant_2: String - thrust_sea_level: Force - thrust_to_weight: Float - thrust_vacuum: Force - type: String - version: String -} - -type RocketFirstStage { - burn_time_sec: Int - engines: Int - fuel_amount_tons: Float - reusable: Boolean - thrust_sea_level: Force - thrust_vacuum: Force -} - -type RocketLandingLegs { - material: String - number: Int -} - -type RocketPayloadWeight { - id: String - kg: Int - lb: Int - name: String -} - -type RocketSecondStage { - burn_time_sec: Int - engines: Int - fuel_amount_tons: Float - payloads: RocketSecondStagePayloads - thrust: Force -} - -type RocketSecondStagePayloadCompositeFairing { - diameter: Distance - height: Distance -} - -type RocketSecondStagePayloads { - composite_fairing: RocketSecondStagePayloadCompositeFairing - option_1: String -} - -type RocketsResult { - data: [Rocket] - result: Result -} - -type Ship { - abs: Int - active: Boolean - attempted_landings: Int - class: Int - course_deg: Int - home_port: String - id: ID - image: String - imo: Int - missions: [ShipMission] - mmsi: Int - model: String - name: String - position: ShipLocation - roles: [String] - speed_kn: Float - status: String - successful_landings: Int - type: String - url: String - weight_kg: Int - weight_lbs: Int - year_built: Int -} - -type ShipLocation { - latitude: Float - longitude: Float -} - -type ShipMission { - flight: String - name: String -} - -input ShipsFind { - id: ID - name: String - model: String - type: String - role: String - active: Boolean - imo: Int - mmsi: Int - abs: Int - class: Int - weight_lbs: Int - weight_kg: Int - year_built: Int - home_port: String - status: String - speed_kn: Int - course_deg: Int - latitude: Float - longitude: Float - successful_landings: Int - attempted_landings: Int - mission: String -} - -type ShipsResult { - data: [Ship] - result: Result -} - -# expression to compare columns of type String. All fields are combined with logical 'AND'. -input String_comparison_exp { - _eq: String - _gt: String - _gte: String - _ilike: String - _in: [String!] - _is_null: Boolean - _like: String - _lt: String - _lte: String - _neq: String - _nilike: String - _nin: [String!] - _nlike: String - _nsimilar: String - _similar: String -} - -type Subscription { - # fetch data from the table: "users" - users( - # distinct select on columns - distinct_on: [users_select_column!] - # limit the nuber of rows returned - limit: Int - # skip the first n rows. Use only with order_by - offset: Int - # sort the rows by one or more columns - order_by: [users_order_by!] - # filter the rows returned - where: users_bool_exp - ): [users!]! - # fetch aggregated fields from the table: "users" - users_aggregate( - # distinct select on columns - distinct_on: [users_select_column!] - # limit the nuber of rows returned - limit: Int - # skip the first n rows. Use only with order_by - offset: Int - # sort the rows by one or more columns - order_by: [users_order_by!] - # filter the rows returned - where: users_bool_exp - ): users_aggregate! - # fetch data from the table: "users" using primary key columns - users_by_pk(id: uuid!): users -} - -scalar timestamptz - -# expression to compare columns of type timestamptz. All fields are combined with logical 'AND'. -input timestamptz_comparison_exp { - _eq: timestamptz - _gt: timestamptz - _gte: timestamptz - _in: [timestamptz!] - _is_null: Boolean - _lt: timestamptz - _lte: timestamptz - _neq: timestamptz - _nin: [timestamptz!] -} - -# columns and relationships of "users" -type users { - id: uuid! - name: String - rocket: String - timestamp: timestamptz! - twitter: String -} - -# aggregated selection of "users" -type users_aggregate { - aggregate: users_aggregate_fields - nodes: [users!]! -} - -# aggregate fields of "users" -type users_aggregate_fields { - count(columns: [users_select_column!], distinct: Boolean): Int - max: users_max_fields - min: users_min_fields -} - -# order by aggregate values of table "users" -input users_aggregate_order_by { - count: order_by - max: users_max_order_by - min: users_min_order_by -} - -# input type for inserting array relation for remote table "users" -input users_arr_rel_insert_input { - data: [users_insert_input!]! - on_conflict: users_on_conflict -} - -# Boolean expression to filter rows from the table "users". All fields are combined with a logical 'AND'. -input users_bool_exp { - _and: [users_bool_exp] - _not: users_bool_exp - _or: [users_bool_exp] - id: uuid_comparison_exp - name: String_comparison_exp - rocket: String_comparison_exp - timestamp: timestamptz_comparison_exp - twitter: String_comparison_exp -} - -# unique or primary key constraints on table "users" -enum users_constraint { - unique - or - primary - key - constraint - users_pkey -} - -# input type for inserting data into table "users" -input users_insert_input { - id: uuid - name: String - rocket: String - timestamp: timestamptz - twitter: String -} - -# aggregate max on columns -type users_max_fields { - name: String - rocket: String - timestamp: timestamptz - twitter: String -} - -# order by max() on columns of table "users" -input users_max_order_by { - name: order_by - rocket: order_by - timestamp: order_by - twitter: order_by -} - -# aggregate min on columns -type users_min_fields { - name: String - rocket: String - timestamp: timestamptz - twitter: String -} - -# order by min() on columns of table "users" -input users_min_order_by { - name: order_by - rocket: order_by - timestamp: order_by - twitter: order_by -} - -# response of any mutation on the table "users" -type users_mutation_response { - # number of affected rows by the mutation - affected_rows: Int! - # data of the affected rows by the mutation - returning: [users!]! -} - -# input type for inserting object relation for remote table "users" -input users_obj_rel_insert_input { - data: users_insert_input! - on_conflict: users_on_conflict -} - -# on conflict condition type for table "users" -input users_on_conflict { - constraint: users_constraint! - update_columns: [users_update_column!]! -} - -# ordering options when selecting data from "users" -input users_order_by { - id: order_by - name: order_by - rocket: order_by - timestamp: order_by - twitter: order_by -} - -# select columns of table "users" -enum users_select_column { - column - name - id - rocket - timestamp - twitter -} - -# input type for updating data in table "users" -input users_set_input { - id: uuid - name: String - rocket: String - timestamp: timestamptz - twitter: String -} - -# update columns of table "users" -enum users_update_column { - column - name - id - rocket - timestamp - twitter -} - -scalar uuid - -# expression to compare columns of type uuid. All fields are combined with logical 'AND'. -input uuid_comparison_exp { - _eq: uuid - _gt: uuid - _gte: uuid - _in: [uuid!] - _is_null: Boolean - _lt: uuid - _lte: uuid - _neq: uuid - _nin: [uuid!] -} - -type Volume { - cubic_feet: Int - cubic_meters: Int -} - diff --git a/app/src/main/graphql/com/example/jetpack_compose_all_in_one/schema.sdl b/app/src/main/graphql/com/example/jetpack_compose_all_in_one/schema.sdl new file mode 100644 index 00000000..a5f4f6d5 --- /dev/null +++ b/app/src/main/graphql/com/example/jetpack_compose_all_in_one/schema.sdl @@ -0,0 +1,83 @@ +# Exposes a URL that specifies the behavior of this scalar. +directive @specifiedBy( + # The URL that specifies the behavior of this scalar. + url: String! +) on SCALAR +type Continent { + code: ID! + countries: [Country!]! + name: String! +} + +input ContinentFilterInput { + code: StringQueryOperatorInput +} + +type Country { + awsRegion: String! + capital: String + code: ID! + continent: Continent! + currencies: [String!]! + currency: String + emoji: String! + emojiU: String! + languages: [Language!]! + name(lang: String): String! + native: String! + phone: String! + phones: [String!]! + states: [State!]! + subdivisions: [Subdivision!]! +} + +input CountryFilterInput { + code: StringQueryOperatorInput + continent: StringQueryOperatorInput + currency: StringQueryOperatorInput + name: StringQueryOperatorInput +} + +type Language { + code: ID! + name: String! + native: String! + rtl: Boolean! +} + +input LanguageFilterInput { + code: StringQueryOperatorInput +} + +type Query { + continent(code: ID!): Continent + continents(filter: ContinentFilterInput = {} +): [Continent!]! + countries(filter: CountryFilterInput = {} +): [Country!]! + country(code: ID!): Country + language(code: ID!): Language + languages(filter: LanguageFilterInput = {} +): [Language!]! +} + +type State { + code: String + country: Country! + name: String! +} + +input StringQueryOperatorInput { + eq: String + in: [String!] + ne: String + nin: [String!] + regex: String +} + +type Subdivision { + code: ID! + emoji: String + name: String! +} + diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/ApiService.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/ApiService.kt deleted file mode 100644 index fd4c27ce..00000000 --- a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/ApiService.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list - -interface ApiService { - -} \ No newline at end of file diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/model/GraphQlBuilder.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/model/GraphQlBuilder.kt new file mode 100644 index 00000000..5c7f504b --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/model/GraphQlBuilder.kt @@ -0,0 +1,16 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.model + +import com.apollographql.apollo3.ApolloClient +import com.apollographql.apollo3.network.okHttpClient +import okhttp3.OkHttpClient + +object GraphQlBuilder { + + fun provideApolloClient(okHttpClient: OkHttpClient): ApolloClient { + return ApolloClient.Builder() + .serverUrl("https://countries.trevorblades.com") + .okHttpClient(okHttpClient) + .build() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/model/Repository.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/model/Repository.kt new file mode 100644 index 00000000..082433ea --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/model/Repository.kt @@ -0,0 +1,14 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.model + +import com.apollographql.apollo3.ApolloClient +import com.example.jetpack_compose_all_in_one.FindCountriesOfAContinentQuery +import com.example.jetpack_compose_all_in_one.GetContinentsQuery + +class Repository(private val apolloClient: ApolloClient) { + suspend fun getContinents() = + apolloClient.query(GetContinentsQuery()).execute() + + suspend fun getCountriesOfSelectedContinent(continentCode: String) = apolloClient.query( + FindCountriesOfAContinentQuery(continentCode) + ).execute() +} \ No newline at end of file diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ContinentsScreen.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ContinentsScreen.kt new file mode 100644 index 00000000..fe941beb --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ContinentsScreen.kt @@ -0,0 +1,68 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.view + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Divider +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.example.jetpack_compose_all_in_one.FindCountriesOfAContinentQuery +import com.example.jetpack_compose_all_in_one.GetContinentsQuery +import com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.viewmodel.ContinentsViewModel + +@Composable +fun ContinentsScreen(viewModel: ContinentsViewModel) { + val continents by viewModel.continents.observeAsState(emptyList()) + val countries by viewModel.countriesInContinent.observeAsState(emptyList()) + val error by viewModel.error.observeAsState(null) + + Column { + error?.let { + Text(text = it, color = Color.Red, modifier = Modifier.padding(8.dp)) + } + + LazyColumn(modifier = Modifier.weight(1f)) { + items(continents) { continent -> + ContinentItem(continent, onClick = { + viewModel.fetchCountriesOfSelectedContinent(continent.code) + }) + } + } + + Divider() + + LazyColumn(modifier = Modifier.weight(1f)) { + items(countries) { country -> + CountryItem(country) + } + } + } +} + +@Composable +fun ContinentItem(continent: GetContinentsQuery.Continent, onClick: () -> Unit) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onClick) + .padding(8.dp) + ) { + Text(text = continent.name) + } +} + +@Composable +fun CountryItem(country: FindCountriesOfAContinentQuery.Country) { + Row(modifier = Modifier.fillMaxWidth().padding(8.dp)) { + Text(text = country.name) + } +} diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/MainActivity.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/MainActivity.kt new file mode 100644 index 00000000..dffea3e7 --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/MainActivity.kt @@ -0,0 +1,44 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.view + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.viewModels +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.ViewModelProvider +import com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.model.GraphQlBuilder +import com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.model.Repository +import com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.view.ui.theme.JetpackComposeAllInOneTheme +import com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.viewmodel.ContinentsViewModel +import com.google.android.ads.mediationtestsuite.viewmodels.ViewModelFactory +import okhttp3.OkHttpClient + +class MainActivity : ComponentActivity() { + + private val viewModel: ContinentsViewModel by viewModels { + com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.viewmodel.ViewModelFactory( + Repository(GraphQlBuilder.provideApolloClient(OkHttpClient())) + ) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + JetpackComposeAllInOneTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + ContinentsScreen(viewModel) + } + } + } + } +} + diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Color.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Color.kt new file mode 100644 index 00000000..116114c0 --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.view.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) \ No newline at end of file diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Theme.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Theme.kt new file mode 100644 index 00000000..a0160abc --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Theme.kt @@ -0,0 +1,70 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.view.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 JetpackComposeAllInOneTheme( + 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 + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Type.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Type.kt new file mode 100644 index 00000000..60b7c178 --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/view/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.view.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 + ) + */ +) \ No newline at end of file diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/viewmodel/ContinentsViewModel.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/viewmodel/ContinentsViewModel.kt new file mode 100644 index 00000000..5f273997 --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/viewmodel/ContinentsViewModel.kt @@ -0,0 +1,49 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.jetpack_compose_all_in_one.FindCountriesOfAContinentQuery +import com.example.jetpack_compose_all_in_one.GetContinentsQuery +import com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.model.Repository +import kotlinx.coroutines.launch + +class ContinentsViewModel(private val repository: Repository) : ViewModel() { + + private val _continents = MutableLiveData>() + val continents: LiveData> get() = _continents + + private val _countriesInContinent = MutableLiveData>() + val countriesInContinent: LiveData> get() = _countriesInContinent + + private val _error = MutableLiveData() + val error: LiveData get() = _error + + init { + fetchContinents() + } + + private fun fetchContinents() { + viewModelScope.launch { + val response = repository.getContinents() + if (response.hasErrors() || response.data == null) { + _error.value = response.errors?.firstOrNull()?.message ?: "Unknown error" + } else { + _continents.value = response.data!!.continents + } + } + } + + fun fetchCountriesOfSelectedContinent(continentCode: String) { + viewModelScope.launch { + val response = repository.getCountriesOfSelectedContinent(continentCode) + if (response.hasErrors() || response.data == null) { + _error.value = response.errors?.firstOrNull()?.message ?: "Unknown error" + } else { + _countriesInContinent.value = response.data!!.continent?.countries + } + } + } +} + diff --git a/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/viewmodel/ViewModelFactory.kt b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/viewmodel/ViewModelFactory.kt new file mode 100644 index 00000000..d972328d --- /dev/null +++ b/app/src/main/java/com/example/jetpack_compose_all_in_one/third_party_lib/graph_ql_country_list/viewmodel/ViewModelFactory.kt @@ -0,0 +1,14 @@ +package com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.jetpack_compose_all_in_one.third_party_lib.graph_ql_country_list.model.Repository + +class ViewModelFactory(private val repository: Repository) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(ContinentsViewModel::class.java)) { + return ContinentsViewModel(repository) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0790de24..f8abcd9d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -209,4 +209,5 @@ TikTok Back + MainActivity \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 0acce301..0393a0c9 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -2,6 +2,7 @@