Skip to content

Commit

Permalink
create: DI and Service
Browse files Browse the repository at this point in the history
  • Loading branch information
amirisback committed Jan 14, 2024
1 parent ead7d56 commit c528dbc
Show file tree
Hide file tree
Showing 28 changed files with 1,160 additions and 4 deletions.
36 changes: 35 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
id("kotlin-android")
id("kotlin-parcelize")
id("kotlin-kapt")
id("com.google.dagger.hilt.android")
}

android {
Expand Down Expand Up @@ -40,6 +41,7 @@ android {
}

buildFeatures {
buildConfig = true
viewBinding = true
}

Expand All @@ -56,13 +58,45 @@ dependencies {
implementation("androidx.fragment:fragment-ktx:1.6.2")

implementation("androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")

implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0")

implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")

implementation("androidx.room:room-runtime:${DepGradleVersion.room}")

// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:${DepGradleVersion.room}")

// optional - Kotlin Extensions and Coroutines support for Room
implementation("androidx.room:room-ktx:${DepGradleVersion.room}")

implementation("androidx.datastore:datastore-preferences:${DepGradleVersion.preferences_version}")

// Glide
implementation("com.github.bumptech.glide:glide:${DepGradleVersion.glide}")

implementation("com.google.code.gson:gson:2.10.1")
implementation("com.squareup.retrofit2:retrofit:${DepGradleVersion.retrofit}")
implementation("com.squareup.retrofit2:converter-gson:${DepGradleVersion.retrofit}")
implementation("com.squareup.okhttp3:logging-interceptor:${DepGradleVersion.logging_interceptor}")

implementation("com.google.dagger:hilt-android:${DepGradleVersion.dagger_hilt}")

kapt("com.google.dagger:hilt-android-compiler:${DepGradleVersion.dagger_hilt}")

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${DepGradleVersion.coroutine}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:${DepGradleVersion.coroutine}")


debugImplementation("com.github.chuckerteam.chucker:library:${DepGradleVersion.chucker}")
releaseImplementation("com.github.chuckerteam.chucker:library-no-op:${DepGradleVersion.chucker}")


kapt("androidx.lifecycle:lifecycle-compiler:2.7.0")
implementation("androidx.lifecycle:lifecycle-common-java8:2.7.0")
implementation("androidx.lifecycle:lifecycle-service:2.7.0")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.qomunal.opensource.androidresearch

import android.app.Application
import android.content.Context
import dagger.hilt.android.HiltAndroidApp

/**
* Created by faisalamircs on 13/01/2024
Expand All @@ -12,6 +14,25 @@ import android.app.Application
*/


@HiltAndroidApp
class QomunalApp : Application() {

init {
instance = this
}

companion object {
private var instance: QomunalApp? = null

fun applicationContext(): Context {
return instance!!.applicationContext
}


}

override fun onCreate() {
super.onCreate()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.qomunal.opensource.androidresearch.di

import android.content.Context
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.qomunal.opensource.androidresearch.BuildConfig
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent

import okhttp3.Cache
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type
import java.util.concurrent.TimeUnit

@Module
@InstallIn(SingletonComponent::class)
class NetworkModule {

@Provides
fun provideRetrofitLogging(): HttpLoggingInterceptor = if (BuildConfig.DEBUG) {
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
} else {
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.NONE)
}

@Provides
fun provideOkHTTPClient(
loggingInterceptor: HttpLoggingInterceptor,
cache: Cache,
@ApplicationContext context: Context
): OkHttpClient.Builder {

// Create the Interceptor
val chuckerInterceptor = ChuckerInterceptor.Builder(context)
.build()

return OkHttpClient.Builder()
.cache(cache)
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.addInterceptor(chuckerInterceptor)
}

@Provides
fun provideRetrofitFactory() : Converter.Factory {
return object : Converter.Factory() {
fun converterFactory() = this
override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit
) = object : Converter<ResponseBody, Any?> {
val nextResponseBodyConverter =
retrofit.nextResponseBodyConverter<Any?>(converterFactory(), type, annotations)
override fun convert(value: ResponseBody) =
if (value.contentLength() != 0L) nextResponseBodyConverter.convert(value) else null
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.qomunal.opensource.androidresearch.di

import com.qomunal.opensource.androidresearch.domain.meal.MealApiService
import com.qomunal.opensource.androidresearch.domain.news.NewsApiService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import retrofit2.Converter

/**
* Created by faisalamircs on 14/01/2024
* -----------------------------------------
* Name : Muhammad Faisal Amir
* E-mail : [email protected]
* Github : github.com/amirisback
* -----------------------------------------
*/

@Module(includes = [NetworkModule::class])
@InstallIn(SingletonComponent::class)
class ServiceModule {

@Provides
fun provideNewsApiService(
httpClient: OkHttpClient.Builder,
converterFactory: Converter.Factory
): NewsApiService {
return NewsApiService.Creator().createApi(httpClient, converterFactory)
}

@Provides
fun provideMealApiService(
httpClient: OkHttpClient.Builder,
converterFactory: Converter.Factory
): MealApiService {
return MealApiService.Creator().createApi(httpClient, converterFactory)
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package com.qomunal.opensource.androidresearch.domain.meal


import com.google.gson.GsonBuilder
import com.qomunal.opensource.androidresearch.domain.meal.response.*
import okhttp3.OkHttpClient
import retrofit2.Converter
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
import javax.inject.Inject

/**
* Created by Faisal Amir
* FrogoBox Inc License
* =========================================
* consumable-code-the-meal-db-api
* Copyright (C) 15/03/2020.
* All rights reserved
* -----------------------------------------
* Name : Muhammad Faisal Amir
* E-mail : [email protected]
* Github : github.com/amirisback
* LinkedIn : linkedin.com/in/faisalamircs
* -----------------------------------------
* FrogoBox Software Industries
* com.frogobox.frogomealsapi.data.source
*
*/
interface MealApiService {

// Search meal by name
@GET(MealUrl.URL_SEARCH_MEAL)
suspend fun searchMeal(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_NAME) nameMeal: String
): Response<MealsResponse<MealResponse>>

// List all meals by first letter
@GET(MealUrl.URL_SEARCH_MEAL)
suspend fun listAllMeal(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_FIRST_LETTER) firstLetter: String
): Response<MealsResponse<MealResponse>>

// Lookup full meal details by id
@GET(MealUrl.URL_LOOKUP_MEAL)
suspend fun lookupFullMeal(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_ID) idMeal: String
): Response<MealsResponse<MealResponse>>

// Lookup a single random meal
@GET(MealUrl.URL_RANDOM_MEAL)
suspend fun lookupRandomMeal(
@Path(MealConstant.PATH_API_KEY) apiKey: String
): Response<MealsResponse<MealResponse>>

// List all meal categories
@GET(MealUrl.URL_CATEGORIES)
suspend fun listMealCategories(
@Path(MealConstant.PATH_API_KEY) apiKey: String
): Response<CategoriesResponse>

// List all Categories
@GET(MealUrl.URL_LIST)
suspend fun listAllCateories(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_CATEGORY) query: String
): Response<MealsResponse<CategoryResponse>>

// List all Area
@GET(MealUrl.URL_LIST)
suspend fun listAllArea(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_AREA) query: String
): Response<MealsResponse<AreaResponse>>

// List all Ingredients
@GET(MealUrl.URL_LIST)
suspend fun listAllIngredients(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_INGREDIENT) query: String
): Response<MealsResponse<IngredientResponse>>

// Filter by main ingredient
@GET(MealUrl.URL_FILTER)
suspend fun filterByIngredient(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_INGREDIENT) ingredient: String
): Response<MealsResponse<MealFilterResponse>>

// Filter by Category
suspend fun filterByCategory(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_CATEGORY) category: String
): Response<MealsResponse<MealFilterResponse>>

// Filter by Area
suspend fun filterByArea(
@Path(MealConstant.PATH_API_KEY) apiKey: String,
@Query(MealConstant.QUERY_AREA) area: String
): Response<MealsResponse<MealFilterResponse>>

class Creator {
@Inject
fun createApi(httpClient: OkHttpClient.Builder, converterFactory: Converter.Factory): MealApiService {
val retrofit = Retrofit.Builder().baseUrl(MealUrl.BASE_URL)
.addConverterFactory(converterFactory)
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
.client(httpClient.build())
.build()

return retrofit.create(MealApiService::class.java)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.qomunal.opensource.androidresearch.domain.meal

/**
* Created by Faisal Amir
* =========================================
* Copyright (C) 15/03/2020.
* All rights reserved
* -----------------------------------------
* Name : Muhammad Faisal Amir
* E-mail : [email protected]
* Github : github.com/amirisback
* LinkedIn : linkedin.com/in/faisalamircs
* -----------------------------------------
*
*/

object MealConstant {

const val QUERY_NAME = "s"
const val QUERY_FIRST_LETTER = "f"
const val QUERY_ID = "i"
const val QUERY_CATEGORY = "c"
const val QUERY_AREA = "a"
const val QUERY_INGREDIENT = "i"

const val PATH_API_KEY = "api_key"

const val VALUE_LIST = "list"

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.qomunal.opensource.androidresearch.domain.meal

/*
* Created by faisalamir on 27/07/21
* Consumable
* -----------------------------------------
* Name : Muhammad Faisal Amir
* E-mail : [email protected]
* Github : github.com/amirisback
* -----------------------------------------
* Copyright (C) 2021 FrogoBox Inc.
* All rights reserved
*
*/
object MealUrl {

const val BASE_URL = "https://www.themealdb.com/"
const val BASE_PATH = "api/json/v1/"
const val PATH_API = "{api_key}/"
const val API_KEY = "1"

const val URL_SEARCH_MEAL = "$BASE_PATH$PATH_API" + "search.php"
const val URL_LOOKUP_MEAL = "$BASE_PATH$PATH_API" + "lookup.php"
const val URL_RANDOM_MEAL = "$BASE_PATH$PATH_API" + "random.php"
const val URL_CATEGORIES = "$BASE_PATH$PATH_API" + "categories.php"
const val URL_LIST = "$BASE_PATH$PATH_API" + "list.php"
const val URL_FILTER = "$BASE_PATH$PATH_API" + "filter.php"

}
Loading

0 comments on commit c528dbc

Please sign in to comment.