feat: graphql (#14)

Co-authored-by: Florent Champigny <florent@bere.al>
This commit is contained in:
Florent CHAMPIGNY 2025-07-31 23:09:40 +02:00 committed by GitHub
parent 7b502a21d0
commit cf1f96bc3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
81 changed files with 2539 additions and 155 deletions

View file

@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.ksp)
alias(libs.plugins.apollo)
id("com.google.protobuf")
}
@ -22,13 +23,11 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
val githubToken = System.getenv("GITHUB_TOKEN_GRPC") ?: ""
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
debug {
buildConfigField("String", "GITHUB_TOKEN", "\"$githubToken\"")
}
}
compileOptions {
@ -40,6 +39,7 @@ android {
}
buildFeatures {
compose = true
buildConfig = true
}
}
@ -50,10 +50,12 @@ dependencies {
implementation("io.github.openflocon:flocon:$floconVersion")
implementation("io.github.openflocon:flocon-grpc-interceptor:$floconVersion")
implementation("io.github.openflocon:flocon-okhttp-interceptor:$floconVersion")
implementation("io.github.openflocon:flocon-graphql-interceptor:$floconVersion")
} else {
implementation(project(":core"))
implementation(project(":okhttp-interceptor"))
implementation(project(":grpc-interceptor"))
implementation(project(":graphql-interceptor"))
}
@ -96,6 +98,17 @@ dependencies {
ksp(libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx)
// endregion
// region graphql
implementation(libs.apollo.runtime)
//implementation(libs.apollo.http.okhttprealization)
// endregion
}
apollo {
service("github") {
packageName.set("com.github")
}
}
protobuf {

View file

@ -0,0 +1,11 @@
query GetUserInfo($user: String!) {
user(login: $user) {
id
name
avatarUrl
email
company
location
bio
}
}

View file

@ -0,0 +1,21 @@
query GetUserRepositories($user: String!, $first: Int!, $endCursor: String) {
user(login: $user) {
repositories(first: $first, after: $endCursor) {
edges {
cursor
node {
id
name
stargazerCount
description
}
}
totalCount
pageInfo {
endCursor
hasNextPage
startCursor
}
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -5,24 +5,28 @@ import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import io.github.openflocon.flocon.Flocon
import io.github.openflocon.flocon.myapplication.dashboard.initializeDashboard
import io.github.openflocon.flocon.myapplication.database.initializeDatabases
import io.github.openflocon.flocon.myapplication.deeplinks.initializeDeeplinks
import io.github.openflocon.flocon.myapplication.graphql.GraphQlTester
import io.github.openflocon.flocon.myapplication.grpc.GrpcController
import io.github.openflocon.flocon.myapplication.images.initializeImages
import io.github.openflocon.flocon.myapplication.sharedpreferences.initializeSharedPreferences
import io.github.openflocon.flocon.myapplication.table.initializeTable
import io.github.openflocon.flocon.myapplication.ui.ImagesListView
import io.github.openflocon.flocon.myapplication.ui.theme.MyApplicationTheme
import io.github.openflocon.flocon.Flocon
import io.github.openflocon.flocon.okhttp.FloconOkhttpInterceptor
import io.github.openflocon.flocon.plugins.analytics.analytics
import io.github.openflocon.flocon.plugins.analytics.model.AnalyticsEvent
@ -62,58 +66,71 @@ class MainActivity : ComponentActivity() {
setContent {
MyApplicationTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(Modifier.fillMaxSize()) {
Button(
modifier = Modifier.padding(all = 20.dp),
onClick = {
dummyHttpCaller.call()
}
Column(Modifier.fillMaxSize().padding(innerPadding)) {
FlowRow(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp),
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalArrangement = Arrangement.spacedBy(6.dp),
) {
Text("okhttp test")
}
Button(
modifier = Modifier.padding(all = 20.dp),
onClick = {
GlobalScope.launch {
GrpcController.sayHello()
Button(
onClick = {
dummyHttpCaller.call()
}
) {
Text("okhttp test")
}
) {
Text("grpc test")
}
Button(
modifier = Modifier.padding(all = 20.dp),
onClick = {
val value = Random.nextInt(from = 0, until = 1000).toString()
Flocon.table("analytics").log(
"name" toParam "new name $value",
"value1" toParam "value1 $value",
"value2" toParam "value2 $value",
)
Button(
onClick = {
GlobalScope.launch {
GraphQlTester.fetchViewerInfo()
}
}
) {
Text("graphql test")
}
) {
Text("send table event")
}
Button(
modifier = Modifier.padding(all = 20.dp),
onClick = {
Flocon.analytics("firebase").logEvents(
AnalyticsEvent(
eventName = "clicked user",
"userId" analyticsProperty "1024",
"username" analyticsProperty "florent",
"index" analyticsProperty "3",
),
AnalyticsEvent(
eventName = "opened profile",
"userId" analyticsProperty "2048",
"username" analyticsProperty "kevin",
"age" analyticsProperty "34",
),
)
Button(
onClick = {
GlobalScope.launch {
GrpcController.sayHello()
}
}
) {
Text("grpc test")
}
Button(
onClick = {
val value = Random.nextInt(from = 0, until = 1000).toString()
Flocon.table("analytics").log(
"name" toParam "new name $value",
"value1" toParam "value1 $value",
"value2" toParam "value2 $value",
)
}
) {
Text("send table event")
}
Button(
onClick = {
Flocon.analytics("firebase").logEvents(
AnalyticsEvent(
eventName = "clicked user",
"userId" analyticsProperty "1024",
"username" analyticsProperty "florent",
"index" analyticsProperty "3",
),
AnalyticsEvent(
eventName = "opened profile",
"userId" analyticsProperty "2048",
"username" analyticsProperty "kevin",
"age" analyticsProperty "34",
),
)
}
) {
Text("send analytics event")
}
) {
Text("send analytics event")
}
ImagesListView(modifier = Modifier.fillMaxSize())

View file

@ -0,0 +1,54 @@
package io.github.openflocon.flocon.myapplication.graphql
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.api.http.HttpRequest
import com.apollographql.apollo.api.http.HttpResponse
import com.apollographql.apollo.network.http.HttpInterceptor
import com.apollographql.apollo.network.http.HttpInterceptorChain
import com.github.GetUserInfoQuery
import io.github.openflocon.flocon.myapplication.BuildConfig
import io.github.openflocon.flocon.okhttp.FloconApolloInterceptor
object GraphQlTester {
private const val GITHUB_TOKEN = BuildConfig.GITHUB_TOKEN
val githubApolloClient by lazy {
ApolloClient.Builder()
.serverUrl("https://api.github.com/graphql")
.addHttpInterceptor(object : HttpInterceptor {
override suspend fun intercept(
request: HttpRequest,
chain: HttpInterceptorChain
): HttpResponse {
return chain.proceed(
request.newBuilder()
.addHeader("Authorization", "Bearer $GITHUB_TOKEN")
.build()
)
}
})
.addHttpInterceptor(FloconApolloInterceptor()) // Ajoute votre intercepteur ici
.build()
}
suspend fun fetchViewerInfo() {
// Exécute la requête générée par Apollo
val response = githubApolloClient
.query(GetUserInfoQuery("florent37"))
.execute()
// Traite la réponse
if (response.data != null) {
val viewerName = response.data?.user?.name
val avatarUrl = response.data?.user?.avatarUrl
val bio = response.data?.user?.bio
println("Nom : $viewerName, avatarUrl : $avatarUrl, bio : $bio")
} else if (response.hasErrors()) {
println("Erreurs: ${response.errors?.joinToString { it.message }}")
}
}
}