Frequently Asked Questions

Features & Capabilities

What features does Hygraph offer for building event apps?

Hygraph provides a GraphQL-native headless CMS that enables you to create, manage, and deliver content for event apps. Key features include content federation (blending data from multiple sources), remote source integration (REST or GraphQL APIs), flexible data modeling, and a powerful GraphQL API for efficient querying. You can define custom data models for events, locations, and categories, and fetch or combine data from external APIs like PredictHQ. For more, see the Hygraph Features page.

Does Hygraph support integration with external APIs and remote sources?

Yes, Hygraph supports integration with external REST and GraphQL APIs through its remote sources feature. This allows you to connect to third-party data providers (such as PredictHQ for event data) and blend their data into your content models. You can define custom schemas and map external data to your app's requirements. Learn more at Remote Sources Guide.

What integrations are available with Hygraph?

Hygraph offers a wide range of integrations, including hosting and deployment (Netlify, Vercel), eCommerce (BigCommerce, commercetools, Shopify), localization (Lokalise, Crowdin, EasyTranslate, Smartling), digital asset management (Aprimo, AWS S3, Bynder, Cloudinary, Mux, Scaleflex Filerobot), personalization and AB testing (Ninetailed), artificial intelligence (AltText.ai), and more. For a full list, visit the Hygraph Integrations page.

Does Hygraph provide an API for content management and delivery?

Yes, Hygraph provides a powerful GraphQL API that allows you to fetch, manage, and deliver content efficiently to your applications. This API supports advanced querying, filtering, and aggregation, making it ideal for dynamic event apps. For more details, see the Hygraph API Reference.

What is Hygraph's App Framework?

Hygraph's App Framework allows you to seamlessly integrate external apps and build custom functionalities, such as Shopify's product picker, directly into the Hygraph interface. This enables you to extend Hygraph's capabilities to fit your unique requirements. Learn more at the App Framework documentation.

Technical Requirements

What are the prerequisites for building an event app with Hygraph?

To build an event app with Hygraph, you need a Hygraph account, the latest version of Android Studio (Electric Eel or newer), and access to a third-party event data provider like PredictHQ (free-tier API). You'll also need basic knowledge of GraphQL, Kotlin, and Android app development. See the tutorial prerequisites for more details.

How do I set up authentication and API access in Hygraph?

To secure your Hygraph project, navigate to Project Settings > ACCESS > API Access > Permanent Auth Tokens to create an authentication token. Assign the appropriate permissions (e.g., Read for Content API) to control access. This ensures only authorized apps can make requests to your content. For more, see the Authorization Guide.

Where can I find technical documentation for Hygraph?

Comprehensive technical documentation for Hygraph is available at Hygraph Documentation. It covers everything from getting started, API references, integration guides, to advanced topics like schema modeling and remote sources.

Use Cases & Benefits

What problems does Hygraph solve for event app developers?

Hygraph addresses challenges such as managing dynamic data from multiple sources, blending and federating content, and delivering high-performance, scalable event apps. Its headless architecture separates content from presentation, making it easier to deploy to multiple platforms. Hygraph also reduces reliance on developers for content updates and streamlines workflows for both technical and non-technical users. For more, see the product page.

Who can benefit from using Hygraph?

Hygraph is ideal for developers, IT decision-makers, content creators, project/program managers, agencies, and technology partners. It is especially beneficial for modern software companies, enterprises seeking to modernize their tech stack, and brands aiming to scale digital experiences across geographies or re-platform from legacy systems. See case studies for industry examples.

What business impact can customers expect from using Hygraph?

Customers can expect faster speed-to-market, reduced operational costs, improved scalability, and enhanced customer experience. For example, Komax achieved a 3X faster time to market, and Autoweb saw a 20% increase in website monetization. Samsung improved customer engagement with a scalable platform, and Dr. Oetker enhanced their digital experience using MACH architecture. Explore more success stories.

What industries are represented in Hygraph's case studies?

Hygraph's case studies span industries such as food and beverage (Dr. Oetker), consumer electronics (Samsung), automotive (AutoWeb), healthcare (Vision Healthcare), travel and hospitality (HolidayCheck), media and publishing, eCommerce, SaaS (Bellhop), marketplace, education technology, and wellness and fitness. See all case studies.

Pricing & Plans

What is Hygraph's pricing model?

Hygraph offers a free forever Hobby plan, a Growth plan starting at $199/month, and custom Enterprise plans. For full details and feature breakdowns, visit the Hygraph Pricing page.

Support & Implementation

How easy is it to get started with Hygraph?

Hygraph is designed for ease of use, with an intuitive interface praised by customers as 'super easy to set up and use.' Even non-technical users can start right away. You can sign up for a free account and access onboarding guides, documentation, and video tutorials. For example, Top Villas launched a new project in just 2 months. See Hygraph Documentation for resources.

What support and training does Hygraph provide?

Hygraph offers 24/7 support via chat, email, and phone. Enterprise customers receive dedicated onboarding and expert guidance. All users have access to detailed documentation, video tutorials, webinars, and a community Slack channel. Customer Success Managers are available to assist during onboarding. For more, visit the Hygraph Contact Page.

How does Hygraph handle maintenance, upgrades, and troubleshooting?

Hygraph provides 24/7 support for maintenance, upgrades, and troubleshooting. Enterprise customers receive dedicated onboarding and expert guidance, while all users can access documentation and the community Slack channel for additional help. See Hygraph Contact Page for support options.

Security & Compliance

What security and compliance certifications does Hygraph have?

Hygraph is SOC 2 Type 2 Compliant, ISO 27001 Certified, and GDPR compliant. These certifications ensure enterprise-grade security and data protection. For more details, visit the Hygraph Security Features page.

How does Hygraph ensure data security and compliance?

Hygraph provides robust security features including SSO integrations, audit logs, encryption at rest and in transit, and sandbox environments. These measures help protect sensitive data and meet regulatory standards. For more, see Hygraph Security Features.

Product Information

What is the primary purpose of Hygraph?

Hygraph's primary purpose is to unify data and enable content federation, empowering businesses to create impactful digital experiences. Its GraphQL-native architecture removes traditional content management pain points, offering scalability, flexibility, and efficient data querying. Learn more at About Us.

How does Hygraph optimize content delivery performance?

Hygraph is optimized for rapid content delivery, which improves user experience, engagement, and search engine rankings. Fast content distribution and responsiveness help reduce bounce rates and increase conversions. For more details, visit this page.

Customer Success & Proof

Who are some of Hygraph's customers?

Hygraph is trusted by leading brands such as Sennheiser, HolidayCheck, Ancestry, Samsung, Dr. Oetker, Epic Games, Bandai Namco, Gamescom, Leo Vegas, and Clayton Homes. For more, see Hygraph Case Studies.

Can you share specific customer success stories using Hygraph?

Yes. Komax achieved a 3X faster time to market, Autoweb saw a 20% increase in website monetization, Samsung improved customer engagement with a scalable platform, and Dr. Oetker enhanced their digital experience using MACH architecture. Explore more customer stories.

Webinar Event: How to Avoid Personalization Tech Traps

How to build an event app with Hygraph

In this article, you will learn how to build an event app with Hygraph.
Dedan Ndungu

Written by Dedan 

Jun 08, 2023
Mobile image

Building applications with dynamic data retrieved from different sources is a challenging task. Figuring out how to manage, mix, and blend the content as well as choosing which data to display to end users contributes to the complexity. Luckily, headless content management systems (CMS) like Hygraph that separate content from their presentation are able to manage different content while deploying to multiple applications.

For example, a Hygraph e-commerce site enables you to collect and manage customer data, display relevant product ads, and optimize your users' shopping experience on a single API. Or if you need a high-performant inventory and catalog management system, Hygraph offers a controlled environment to house your content while unifying it from different sources. Do you also need structured content that is easy to scale and adaptable to serve different purposes? Then Hygraph really is your one-stop place to provide quality digital experiences for your users.

In this article, you will learn how to build an event app with Hygraph. You'll start by creating models for your content, fetching data from an external API, and combining it with more content on Hygraph to serve your app. You'll then build an application that will consume this data through a GraphQL API.

#Project overview

In this tutorial, you are going to build a mobile app with which a user can search events by category and location.

The app will retrieve content from a Hygraph backend that will contain three models: event data, location data, and category data. Both the events and location data will be fetched from a remote source, PredictHQ, and the category content will be added in Hygraph.

Finally, you will use Hygraph's GraphQL APIs to load the content into your app.

Here's a simple architectural diagram for the project:

Architecture diagram

You can find the complete app for this tutorial in this GitHub repository.

#Prerequisites

To follow this tutorial, you will need the following installations and accounts:

#Create a Hygraph project

After you create an account on Hygraph, the next step is to create a project to store and fetch your data. Hygraph offers some starter and schema templates such as a commerce shop and a travel site to speed up your development. However, for this tutorial, you will create a new blank project.

On the Hygraph dashboard, select Add Project, fill in your desired details, and select your region, as shown in the screenshot below:

Screenshot 2023-06-07 at 23.04.07.png

#Add Remote Sources

A remote source is a connector to other REST or GraphQL APIs whose data you would need to be integrated into your model.

The first thing you need to do is figure out which data the PredictHQ events API contains. PredictHQ offers two endpoints that you can hit to analyze their responses. To access these APIs, you need an access token, which you can acquire by following these instructions.

Using Postman, make a GET request to the events endpoint. You should receive a response similar to the screenshot below:

Events API

You need to transform the above response into a schema that GraphQL can understand, namely Schema Definition Language (SDL). You can use this tool to convert the JSON above to an SDL.

However, the generated SDL needs a few tweaks before it can be used in Hygraph. Update the generated SDL as follows:

  • Replace all instances of JSON with Json.
  • Rename the ROOT type to EventsResult and the Result to Event. This is to make your schema more readable.
  • Replace all instances of DateTime with String.

Note: Hygraph does support DateTime. However, to use this schema on an Android app, you need to write custom code to consume it. Changing it to String makes things easier.

The final SDL schema should be as follows:

type Entity {
entity_id: String
formatted_address: String
name: String
type: String
}
type Geometry {
coordinates: [Float]
type: String
}
type Geo {
geometry: Geometry
placekey: String
}
type ParentEvent {
parent_event_id: String
}
type Event {
aviation_rank: Int
brand_safe: Boolean
category: String
country: String
description: String
duration: Int
end: String
entities: [Entity]
first_seen: String
geo: Geo
id: String
labels: [String]
local_rank: Int
location: [Float]
parent_event: ParentEvent
phq_attendance: Int
place_hierarchies: [[String]]
private: Boolean
rank: Int
relevance: Int
scope: String
start: String
state: String
timezone: String
title: String
updated: String
}
type EventsResult {
count: Int
next: String
overflow: Boolean
previous: Json
results: [Event]
}

You can now add the schema to your Hygraph project. Navigate to Schema | REMOTE SOURCES and press the Add button.

Fill in the details of the remote source and select the type as REST. Next, add https://api.predicthq.com/v1 as the base URL. In the Headers section, add the following:

"Authorization":"Bearer <The access token you created in predictHQ>
"Content-Type":"application/json;charset=utf-8"

Here's a screenshot of how that will look like:

Screenshot 2023-06-07 at 23.28.50.png

Lastly, in the Custom type definition section, add the schemas generated above.

Since your app will filter events by location, PredictHQ provides another endpoint to get location identifiers. Repeat the Postman procedure above to get the data format and convert the JSON into an SDL. Tweak the generated SDL as follows:

  • Replace all instances of JSON with Json.
  • Rename the ROOT type to LocationsResult and the Result to Location. This is to make your schema more readable.

The final SDL schema should be as shown below:

type Location {
country: String
country_alpha2: String
country_alpha3: String
county: Json
id: String
location: [Float]
name: String
region: String
type: String
}
type LocationsResult {
count: Int
next: Json
previous: Json
results: [Location]
}

Since both endpoints share the same base URL, you will not create a new remote source. Add the above schema to the previous remote source and save.

#Create data models

Models are the building blocks for your data. They define the data contained in your content and its types.

Events data model

To add an events model, navigate to Schema | MODELS and press Add. Fill in the name of the model—in this case, listEvent—and save.

On the resulting screen, you need to add fields that will hold your data. The events model will hold a REST field type and a String. Scroll down on the pane on your right until you find the REST field type and select it.

In the window that pops up, add the details about the endpoint. Please note that the Method will be GET and the return type will be EventsResult. This endpoint also takes in arguments that should be added in the Input arguments section. Finally, set the path of the remote source, making sure to include all arguments. In the end, your form should resemble the screenshots below:

Screenshot 2023-06-07 at 23.34.26.png

Screenshot 2023-06-07 at 23.40.54.png

Lastly, add a Single line text field and name it desc.

Your model dashboard should resemble the following screenshot:

Screenshot 2023-06-07 at 23.44.53.png

Location data model

Repeating the same steps as above, create a new model named EventLocation with a REST field named Places and a Single line text field named desc.

The REST field should have a GET method with the return type being LocationsResult and a single argument. The bottom part of the form should resemble the screenshot below:

Screenshot 2023-06-07 at 23.53.32.png

Category model

Your events app will filter events based on category. You must define these categories as a model on Hygraph.

Create a new model named EventCategory with a Single line text field named categories. Since there are many categories to use, make sure to tick the Allow multiple values checkbox and save.

#Add content

Now that the data models of your app are ready to use, you will add content to them so you can display it to your users.

Select the Content tab on the left pane. You should see your models listed in the DEFAULT VIEWS section.

Select the EventCategory followed by the ADD ENTRY button on the top right. Add the following categories to the list:

  • sports
  • academics
  • concerts
  • conferences
  • expos
  • festivals

Finally, click Save & Publish.

Select EventLocation followed by the ADD ENTRY button. Fill in the desc field and click Save & Publish. Repeat this process for listEvent also.

#Set up Hygraph authentication

You can now access your Hygraph project contents from a single API. However, to make sure only authorized apps make requests, you need to set up authorization.

Navigate to Project settings | ACCESS | API Access | Permanent Auth Tokens to create an authentication token.

After you create a token, the permissions screen will pop up. In the Content API section, click Add Permission. Select the Read permission, as shown below, and save.

Screenshot 2023-06-07 at 23.57.11.png

This will allow only read requests on all your models at all stages.

#Building an Android app

You are going to build an Android app that will query content from Hygraph and display it to users.

Follow these steps to set up an Android project on Android Studio:

  • Open Android Studio and create an Empty Compose Activity project.
  • Provide the name of the app—in this case Events—press Finish, and wait for the project to load.

Android project creation

Add project dependencies

To query a GraphQL API, you can use the Apollo GraphQL library, which assists you in writing GraphQL queries and generating data models for their responses.

To handle making API requests asynchronously, you also need to add the Kotlin coroutine dependencies. Open the app/build.gradle file and add the following dependencies:

implementation("com.apollographql.apollo3:apollo-runtime:3.7.5")
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"

In the same file, update the plugins section to include the Apollo library. The section should be similar to this:

plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id("com.apollographql.apollo3").version("3.7.5")
}

Finally, you need to configure where the Apollo library will store its generated files. To do this, add the following code at the bottom of the app/build.gradle file:

apollo {
service("service") {
packageName.set("com.example.events.models")
}
}

Add internet permissions

Since the application will be making API requests over the Internet, you need to specify this permission so that the Android framework can request the user for it.

To do this, navigate to the AndroidManifest.xml file and add the internet permission shown below:

<manifest>
<!--Add the line below -->
<uses-permission android:name="android.permission.INTERNET"/>
<application>
</application>
</manifest>

Add the GraphQL schema

The Apollo library needs to know the type of data you intend to query and the available fields to generate the necessary code. Create a new schema.graphqls file in app/src/main/graphql/, which will hold the GraphQL schema of the Hygraph content.

You need to add the SDL schema generated in the Add Remote Source section to the new file. Your file should now contain the following:

type Location {
country: String
country_alpha2: String
country_alpha3: String
county: String
id: String
location: [Float]
name: String
region: String
type: String
}
type LocationsResult {
count: Int
next: Int
previous: Int
results: [Location]
}
type Entity {
entity_id: String
formatted_address: String
name: String
type: String
}
type Geometry {
coordinates: [Float]
type: String
}
type Geo {
geometry: Geometry
placekey: String
}
type ParentEvent {
parent_event_id: String
}
type Event {
aviation_rank: Int
brand_safe: Boolean
category: String
country: String
description: String
duration: Int
end: String
entities: [Entity]
first_seen: String
geo: Geo
id: String
labels: [String]
local_rank: Int
location: [Float]
parent_event: ParentEvent
phq_attendance: Int
place_hierarchies: [[String]]
private: Boolean
rank: Int
relevance: Int
scope: String
start: String
state: String
timezone: String
title: String
updated: String
}
type EventsResult {
count: Int
next: String
overflow: Boolean
previous: Int
results: [Event]
}

With the above schema, the Apollo library will understand the kind of content that your GraphQL API returns when queried.

Write GraphQL queries

With the schema ready, you can now write some queries to fetch data from the Hygraph endpoint.

The Hygraph API Playground

Hygraph provides a handy API playground where you can write and test queries while viewing their response. You can tweak various fields to return only the content you need.

For instance, to query events, you need to pass in the category as well as the location_id to get a result. You can write a query similar to the screenshot below in the API playground, which will return events with only the defined subset of fields.

txpWhQb.png

Write app GraphQL queries

After testing your queries in the playground, you can add them to the app.

Create a new file named AppQuery.graphql on the same level as your schema file. Save the file in app/src/main/graphql/. Add the following queries for query event categories, locations, and filter events:

query LocationQuery($location: String!) {
eventLocations {
places(location: $location) {
count
next
previous
results {
country
id
location
name
}
}
}
}
query EventsQuery($category: String!, $location_id: Int!) {
listEvents {
allEvents(category: $category, location_id: $location_id) {
count
next
previous
results {
country
start
duration
entities {
name
}
title
}
}
}
}
query CategoryQuery {
eventCategories {
categories
}
}

After you add the above queries, Android Studio will display some compilation errors. This is because the previous schema file does not contain all the fields that the queries have. To solve this, you need to update the schema file with the following content:

type Query{
eventLocations:[EventLocations]
listEvents:[ListEvents]
eventCategories:[CategoryResult]
}
type CategoryResult{
categories:[String!]
}
type EventLocations{
places(location:String):LocationsResult
}
type ListEvents{
allEvents(category:String!, location_id: Int):EventsResult
}

With the above schema and query, the Apollo library can generate code that you can use to make requests. To generate the code, build your project again.

Note: Every time you change your schema and queries, rebuild the code so that the Apollo library can regenerate the code.

Build the events screen

The content and queries are all ready. How about enabling users to search and view events around them? This section discusses just that.

Set up the Apollo Client

You need to initialize and configure an ApolloClient that you will use in the app to make GraphQL requests. You will need the API endpoint from Hygraph, which you can get by navigating to Project Settings | ACCESS | API Access in the Content API section. You also need the access token created in the previous section.

In your com/project_org/project_name folder, create a file named ApolloClient.kt and add the following code to it:

import android.util.Log
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.api.ApolloRequest
import com.apollographql.apollo3.api.ApolloResponse
import com.apollographql.apollo3.api.Operation
import com.apollographql.apollo3.interceptor.ApolloInterceptor
import com.apollographql.apollo3.interceptor.ApolloInterceptorChain
import com.apollographql.apollo3.network.okHttpClient
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onEach
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.IOException
class LoggingApolloInterceptor: ApolloInterceptor {
override fun <D : Operation.Data> intercept(
request: ApolloRequest<D>,
chain: ApolloInterceptorChain
): Flow<ApolloResponse<D>> {
return chain.proceed(request).onEach { response ->
Log.d("Apollo: ","Received response for ${request.operation.name()}: ${response.data}")
}
}
}
internal class HttpInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
val t1 = System.nanoTime()
Log.i("REQUEST: ", request.method+" "+request.url.toString())
val response: Response = chain.proceed(request)
Log.i("response:",response.code.toString()+" "+response.networkResponse?.message+" "+response.message)
return response
}
}
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(HttpInterceptor())
.build()
const val authToken="<Auth Token Created On Hygraph"
val apolloClient = ApolloClient.Builder()
.serverUrl("<Content API URL From Hygraph>")
.addInterceptor(LoggingApolloInterceptor())
.okHttpClient(okHttpClient = okHttpClient)
.addHttpHeader("Authorization", "Bearer $authToken")
.build()

The code above contains an interceptor and okHttpClient, which are used to manipulate the requests as well as log the response. The ApolloClient has an addHTTPHeader function that is used to add the authorization token.

Build the ViewModel

Your Android app will use a ViewModel to make an API request and update the screen once a response is received. In your com/project_org/project_name/viewmodels folder, create a file named MainViewModel.kt and add the following code to it:

import android.util.Log
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.apollographql.apollo3.exception.ApolloException
import com.example.events.apolloClient
import com.example.events.models.CategoryQuery
import com.example.events.models.EventsQuery
import com.example.events.models.LocationQuery
import kotlinx.coroutines.launch
class MainViewModel : ViewModel() {
val categoryData: MutableState<List<String>> = mutableStateOf(emptyList())
val locationData: MutableState<
List<LocationQuery.Result?>> = mutableStateOf(emptyList())
val loadingCategory: MutableState<Boolean> = mutableStateOf(false)
val loadingEvents: MutableState<Boolean> = mutableStateOf(false)
val eventsData: MutableState<List<EventsQuery.Result?>> = mutableStateOf(emptyList())
fun fetchCategories() {
try {
loadingCategory.value = true
viewModelScope.launch {
categoryData.value = apolloClient
.query(CategoryQuery())
.execute().dataAssertNoErrors.eventCategories?.first()?.categories
?: emptyList()
loadingCategory.value = false
}
} catch (exception: ApolloException) {
exception.localizedMessage?.let { Log.e("Apollo: ", it) }
loadingCategory.value = false
}
}
fun searchLocations(location: String) {
try {
viewModelScope.launch {
locationData.value = apolloClient
.query(LocationQuery(location = location))
.execute().dataAssertNoErrors.eventLocations?.first()?.places?.results
?: emptyList()
}
} catch (exception: ApolloException) {
exception.localizedMessage?.let { Log.e("Apollo: ", it) }
}
}
fun fetchEvents(selectedCategory: Set<String>, location_id: String) {
try {
if (selectedCategory.isNotEmpty()) {
locationData.value = emptyList()
loadingEvents.value = true
var category: String = ""
selectedCategory.forEach {
if (category.isEmpty()) {
category = "$category$it"
} else {
category = "$category,$it"
}
}
viewModelScope.launch {
eventsData.value = apolloClient
.query(EventsQuery(category, location_id.toInt()))
.execute().dataAssertNoErrors.listEvents?.first()?.allEvents?.results
?: emptyList()
loadingEvents.value = false
}
}
} catch (exception: ApolloException) {
exception.localizedMessage?.let { Log.e("Apollo: ", it) }
loadingEvents.value = false
}
}
fun resetLocationResults() {
locationData.value = emptyList()
}
}

Create the Events App UI

Your app will have a single screen where a user can select an event category and search a location to get events that match those values.

Replace the code in your MainActivity.kt file with the following:

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.Clear
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.*
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import com.example.events.ui.theme.EventsTheme
import com.example.events.viewmodels.MainViewModel
class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
EventsTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
MyScreen(viewModel)
}
}
}
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun MyScreen(viewModel: MainViewModel = MainViewModel()) {
val isLoadingCategory by viewModel.loadingCategory
val isLoadingEvents by viewModel.loadingEvents
val categories by viewModel.categoryData
val locationResults by viewModel.locationData
val eventResults by viewModel.eventsData
if(categories.isEmpty()) {
LaunchedEffect(viewModel) {
viewModel.fetchCategories()
}
}
var selectedChips by remember { mutableStateOf(setOf<String>()) }
var searchText by remember { mutableStateOf("") }
val scaffoldState = rememberScaffoldState()
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = { Text("Events") },
)
},
content = {it->
Column(
modifier = Modifier
.padding(it)
.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(5.dp),
horizontalAlignment = Alignment.CenterHorizontally
){
if(isLoadingCategory){
CircularProgressIndicator(modifier = Modifier
.padding(6.dp)
.size(size = 32.dp),
color = androidx.compose.ui.graphics.Color.Magenta,
)
}else if(categories.isNotEmpty()) {
if(selectedChips.isEmpty()) {
selectedChips = selectedChips.plus(categories.first())
}
LazyRow(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(categories.size) { index ->
val category = categories.elementAt(index)
FilterChip(
selectedIcon = {
Icon(imageVector = Icons.Default.CheckCircle, contentDescription = "Checked Icon")
},
onClick = {
if (!selectedChips.contains(category)) {
selectedChips = selectedChips.plus(category)
} else {
if (selectedChips.size > 1) {
selectedChips = selectedChips.minus(category)
}
}
},
selected = selectedChips.contains(category),
) {
Text(text = category)
}
}
}
}
OutlinedTextField(
value = searchText,
onValueChange ={
searchText=it
if(searchText.length>3){
viewModel.searchLocations(searchText)
}
},
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
.onFocusChanged { focused ->
if (focused.isFocused && locationResults.isEmpty()) {
}
},
label = { Text(text = "Search City or Country")},
trailingIcon = {
IconButton(onClick = {
searchText = ""
viewModel.resetLocationResults()
}) {
Icon(Icons.Filled.Clear, contentDescription = "Clear")
}
},
)
// Search results
if (locationResults.isNotEmpty()) {
Box(
modifier = Modifier
.fillMaxWidth()
.offset(y = 120.dp)
.align(Alignment.CenterHorizontally)
) {
Popup(
alignment = Alignment.Center,
properties = PopupProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true
),
content = {
Box(
modifier = Modifier
.padding(16.dp)
.height(250.dp)
.background(MaterialTheme.colors.background)
) {
LazyColumn(
modifier = Modifier.fillMaxWidth(1f)
) {
items(locationResults.size) { index ->
val location = locationResults.elementAt(index)
ListItem(
text = { Text(location?.name + "," + location?.country) },
modifier = Modifier.clickable {
location?.id?.let { it1 ->
viewModel.fetchEvents(
selectedChips,
it1
)
}
}
)
}
}
}
},
onDismissRequest = {}
)
}
}
if (isLoadingEvents) {
CircularProgressIndicator(modifier = Modifier
.padding(6.dp)
.size(size = 32.dp),
color = androidx.compose.ui.graphics.Color.Magenta,
)
}
else if (eventResults.isNotEmpty()) {
LazyColumn(
modifier = Modifier.fillMaxWidth(1f)
) {
items(eventResults.size) { index ->
val event=eventResults.elementAt(index)
var desc= "Start: ${event?.start}"
if(event?.entities!=null && event.entities.isNotEmpty()){
desc=desc+"\nVenue: "+event.entities.first()?.name
}
ListItem(
text = { event?.title?.let { it1 -> Text(it1) } },
secondaryText = {
Text(text = desc)
},
trailing = {
if (event?.duration != null) {
Text(text = "Duration: ${event.duration}")
}
},
modifier = Modifier.padding(16.dp)
)
}
}
}
else {
// Show loading indicator
Text(text="NO EVENTS DATA",modifier = Modifier
.fillMaxWidth()
.align(Alignment.CenterHorizontally)
.padding(16.dp))
}
}
})
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
EventsTheme {
}
}

The code above renders a user interface where users can select the category and location of events they would like to see. The app makes an API request to Hygraph with the chosen filters and returns a filtered result that is presented to the user.

With this in place, you can now build your app to test and validate the content.

You can find the complete app for this tutorial in this GitHub repository. Here's a video of how the app works:

ezgif.com-resize (1).gif

#Conclusion

In this article, you have learned how to model data to SDL schemas that can be used in GraphQL queries. You have also learned how to write GraphQL queries and fetch only the required data for your application needs. Lastly, you have used Hygraph to host your content and built an Android application to display it to users using GraphQL APIs.

Hygraph's GraphQL approach to collating and managing content enables you to build diverse, high-performant, and scalable applications with minimal friction between data sources. Its ability to handle remote sources lets you blend data from different providers into a single source of truth, leading to more stable and resilient applications. Create a free forever account now and take this project for a spin.

Blog Author

Dedan Ndungu

Dedan Ndungu

Technical Writer

Dedan Ndungu is a software engineer with experience in mobile app development using Java, Kotlin, and Flutter. He's also experienced integrating Firebase services to deliver quality and scalable mobile applications.

Share with others

Sign up for our newsletter!

Be the first to know about releases and industry news and insights.