From 3f01dd90bef5a5a5f0f44a51356994598fbbdb41 Mon Sep 17 00:00:00 2001 From: "Wei.He" Date: Fri, 1 Dec 2023 10:33:06 +0800 Subject: [PATCH] chore: Implement functionality of the network module --- .../core/network/PqNetworkDataSource.kt | 11 +++ .../core/network/di/FlavoredNetworkModule.kt | 19 +++++ .../picquest/core/network/di/NetworkModule.kt | 36 ++++++++++ .../core/network/model/NetworkSearchImages.kt | 70 +++++++++++++++++++ .../network/retrofit/RetrofitPqNetwork.kt | 56 +++++++++++++++ secrets.defaults.properties | 3 +- 6 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 core/network/src/main/java/com/wei/picquest/core/network/PqNetworkDataSource.kt create mode 100644 core/network/src/main/java/com/wei/picquest/core/network/di/FlavoredNetworkModule.kt create mode 100644 core/network/src/main/java/com/wei/picquest/core/network/di/NetworkModule.kt create mode 100644 core/network/src/main/java/com/wei/picquest/core/network/model/NetworkSearchImages.kt create mode 100644 core/network/src/main/java/com/wei/picquest/core/network/retrofit/RetrofitPqNetwork.kt diff --git a/core/network/src/main/java/com/wei/picquest/core/network/PqNetworkDataSource.kt b/core/network/src/main/java/com/wei/picquest/core/network/PqNetworkDataSource.kt new file mode 100644 index 0000000..16dc2ff --- /dev/null +++ b/core/network/src/main/java/com/wei/picquest/core/network/PqNetworkDataSource.kt @@ -0,0 +1,11 @@ +package com.wei.picquest.core.network + +import com.wei.picquest.core.network.model.NetworkSearchImages + +/** + * Interface representing network calls to the PicQuest backend + */ +interface PqNetworkDataSource { + + suspend fun searchImages(query: String): NetworkSearchImages +} diff --git a/core/network/src/main/java/com/wei/picquest/core/network/di/FlavoredNetworkModule.kt b/core/network/src/main/java/com/wei/picquest/core/network/di/FlavoredNetworkModule.kt new file mode 100644 index 0000000..a0d5333 --- /dev/null +++ b/core/network/src/main/java/com/wei/picquest/core/network/di/FlavoredNetworkModule.kt @@ -0,0 +1,19 @@ +package com.wei.picquest.core.network.di + +import com.wei.picquest.core.network.PqNetworkDataSource +import com.wei.picquest.core.network.retrofit.RetrofitPqNetwork +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +/** + * TODO Wei 移動至 build variants 下產出資料夾 + */ +@Module +@InstallIn(SingletonComponent::class) +interface FlavoredNetworkModule { + + @Binds + fun binds(implementation: RetrofitPqNetwork): PqNetworkDataSource +} diff --git a/core/network/src/main/java/com/wei/picquest/core/network/di/NetworkModule.kt b/core/network/src/main/java/com/wei/picquest/core/network/di/NetworkModule.kt new file mode 100644 index 0000000..57ec455 --- /dev/null +++ b/core/network/src/main/java/com/wei/picquest/core/network/di/NetworkModule.kt @@ -0,0 +1,36 @@ +package com.wei.picquest.core.network.di + +import com.wei.core.network.BuildConfig +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.serialization.json.Json +import okhttp3.Call +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object NetworkModule { + + @Provides + @Singleton + fun providesNetworkJson(): Json = Json { + ignoreUnknownKeys = true + } + + @Provides + @Singleton + fun okHttpCallFactory(): Call.Factory = OkHttpClient.Builder() + .addInterceptor( + HttpLoggingInterceptor() + .apply { + if (BuildConfig.DEBUG) { + setLevel(HttpLoggingInterceptor.Level.BODY) + } + }, + ) + .build() +} diff --git a/core/network/src/main/java/com/wei/picquest/core/network/model/NetworkSearchImages.kt b/core/network/src/main/java/com/wei/picquest/core/network/model/NetworkSearchImages.kt new file mode 100644 index 0000000..188d83a --- /dev/null +++ b/core/network/src/main/java/com/wei/picquest/core/network/model/NetworkSearchImages.kt @@ -0,0 +1,70 @@ +package com.wei.picquest.core.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Network representation of [SearchImages] when fetched from / + */ +@Serializable +data class NetworkSearchImages( + @SerialName("total") + val total: Int, + @SerialName("totalHits") + val totalHits: Int, + @SerialName("hits") + val hits: List +) + +@Serializable +data class NetworkImageDetail( + @SerialName("id") + val id: Int, + @SerialName("pageURL") + val pageURL: String, + @SerialName("type") + val type: String, + @SerialName("tags") + val tags: String, + @SerialName("previewURL") + val previewURL: String, + @SerialName("previewWidth") + val previewWidth: Int, + @SerialName("previewHeight") + val previewHeight: Int, + @SerialName("webformatURL") + val webformatURL: String, + @SerialName("webformatWidth") + val webformatWidth: Int, + @SerialName("webformatHeight") + val webformatHeight: Int, + @SerialName("largeImageURL") + val largeImageURL: String, + @SerialName("fullHDURL") + val fullHDURL: String, + @SerialName("imageURL") + val imageURL: String, + @SerialName("imageWidth") + val imageWidth: Int, + @SerialName("imageHeight") + val imageHeight: Int, + @SerialName("imageSize") + val imageSize: Long, + @SerialName("views") + val views: Int, + @SerialName("downloads") + val downloads: Int, + @SerialName("likes") + val likes: Int, + @SerialName("comments") + val comments: Int, + @SerialName("user_id") + val userId: Int, + @SerialName("user") + val user: String, + @SerialName("userImageURL") + val userImageURL: String + // Add vectorURL if your account has full API access + // @SerialName("vectorURL") + // val vectorURL: String? = null +) \ No newline at end of file diff --git a/core/network/src/main/java/com/wei/picquest/core/network/retrofit/RetrofitPqNetwork.kt b/core/network/src/main/java/com/wei/picquest/core/network/retrofit/RetrofitPqNetwork.kt new file mode 100644 index 0000000..4e6cf77 --- /dev/null +++ b/core/network/src/main/java/com/wei/picquest/core/network/retrofit/RetrofitPqNetwork.kt @@ -0,0 +1,56 @@ +package com.wei.picquest.core.network.retrofit + +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import com.wei.core.network.BuildConfig +import com.wei.picquest.core.network.PqNetworkDataSource +import com.wei.picquest.core.network.model.NetworkSearchImages +import kotlinx.serialization.json.Json +import okhttp3.Call +import okhttp3.MediaType.Companion.toMediaType +import retrofit2.Retrofit +import retrofit2.http.GET +import retrofit2.http.Query +import javax.inject.Inject +import javax.inject.Singleton + +private const val PIXABAY_BASE_URL = BuildConfig.BACKEND_URL +private const val API_KEY = BuildConfig.API_KEY + +/** + * Retrofit API declaration for Pixabay Network API + */ +interface RetrofitPixabayApi { + /** + * https://pixabay.com/api/?key=${api key}&q=yellow+flowers&image_type=photo + */ + @GET("") + suspend fun searchImages( + @Query("key") apiKey: String = API_KEY, + @Query("q") query: String, + @Query("image_type") imageType: String = "photo", + // Add more parameters as needed + ): NetworkSearchImages +} + +/** + * [Retrofit] backed [PqNetworkDataSource] + */ +@Singleton +class RetrofitPqNetwork @Inject constructor( + networkJson: Json, + okhttpCallFactory: Call.Factory, +) : PqNetworkDataSource { + + private val pixabayApi = Retrofit.Builder() + .baseUrl(PIXABAY_BASE_URL) + .callFactory(okhttpCallFactory) + .addConverterFactory( + networkJson.asConverterFactory("application/json".toMediaType()), + ) + .build() + .create(RetrofitPixabayApi::class.java) + + override suspend fun searchImages(query: String): NetworkSearchImages { + return pixabayApi.searchImages(query = query) + } +} diff --git a/secrets.defaults.properties b/secrets.defaults.properties index a7f254e..a8f4b44 100644 --- a/secrets.defaults.properties +++ b/secrets.defaults.properties @@ -1,4 +1,5 @@ ## This file provides default values to modules using the secrets-gradle-plugin. It is necessary # because the secrets properties file is not under source control so CI builds will fail without # default values. -BACKEND_URL="https://pixabay.com/api/" \ No newline at end of file +BACKEND_URL="https://pixabay.com/api/" +API_KEY="fake_api_key" \ No newline at end of file