Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4851fbf
hilt library
fedeturazzini Apr 22, 2022
fb0413d
hilt base imple
fedeturazzini Apr 22, 2022
660df80
strings for hilt
fedeturazzini Apr 22, 2022
17e9a9e
adding hilt activity for example
fedeturazzini Apr 22, 2022
006ab63
koin folder
fedeturazzini Apr 22, 2022
e948079
imple recipe part 1
fedeturazzini Apr 25, 2022
09bc105
Cleaning code
fedeturazzini Apr 25, 2022
73a3e21
cleaning
fedeturazzini Apr 25, 2022
f4839ff
clean
fedeturazzini Apr 25, 2022
7738e25
bye kapt verbose
fedeturazzini Apr 25, 2022
927c10c
cleaning imports
fedeturazzini Apr 25, 2022
f1581d2
code smell
fedeturazzini Apr 25, 2022
adfca45
code smell
fedeturazzini Apr 25, 2022
dd9983f
code smell :)
fedeturazzini Apr 25, 2022
8953937
+ smell code fixes
fedeturazzini Apr 25, 2022
76dcbac
code rev Juli
fedeturazzini Apr 25, 2022
59234a2
code rev juli
fedeturazzini Apr 25, 2022
e727425
code rev tomi
fedeturazzini Apr 25, 2022
7f4bca2
code rev tomi
fedeturazzini Apr 25, 2022
3204004
code rev tomi
fedeturazzini Apr 25, 2022
21226ce
ordered in lexicographic order
fedeturazzini Apr 25, 2022
189be0d
clean
fedeturazzini Apr 25, 2022
5eb0a74
code rev tomi
fedeturazzini Apr 25, 2022
25036ae
code rev tomi
fedeturazzini Apr 25, 2022
86dfc0d
code rev tomi
fedeturazzini Apr 25, 2022
dfea7cc
code rev juan
fedeturazzini Apr 25, 2022
0ab2c14
cod rev
fedeturazzini Apr 26, 2022
b2852a4
clean spaces
fedeturazzini Apr 26, 2022
37586d5
changes
fedeturazzini Apr 26, 2022
7087878
version compose
fedeturazzini Apr 29, 2022
99e399a
Ui compose imple
fedeturazzini Apr 29, 2022
1a6c48a
fix imports
fedeturazzini Apr 29, 2022
19048fa
fixes
fedeturazzini Apr 29, 2022
0dfa982
clean
fedeturazzini Apr 29, 2022
8d64607
fix imports
fedeturazzini Apr 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ apply from: 'jacoco.gradle'
apply from: 'lint.gradle'
apply from: 'build-scripts.gradle'

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'

repositories {
mavenCentral()
maven { url 'https://maven.google.com' }
Expand Down Expand Up @@ -171,12 +174,15 @@ ext {
lottie_version = "4.2.0"
core_version = "1.6.0"
desugar_jdk_version = "1.1.5"
hilt_version = "2.38.1"
glide_version = "4.13.0"
compose_ui_tool = "1.1.1"

// Compose
activity_compose_version = "1.3.1"
activity_compose_version = '1.4.0'
constraintlayout_compose_version = "1.0.0-rc01"
viewmodel_compose_version = "1.0.0-alpha07"
}

jacoco {
toolVersion = "0.8.7"
}
Expand Down Expand Up @@ -208,6 +214,8 @@ dependencies {
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"

implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"

// Http Logging Interceptor
implementation "com.squareup.okhttp3:okhttp:$ok_http_version"
implementation "com.squareup.okhttp3:logging-interceptor:$ok_http_version"
Expand Down Expand Up @@ -291,6 +299,17 @@ dependencies {
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$viewmodel_compose_version"
implementation "com.google.android.material:compose-theme-adapter:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_tool"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_tool"


// Hilt: Official Google Dependency Injection Library
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"

// Glide: Image loading framework
implementation "com.github.bumptech.glide:glide:$glide_version"
annotationProcessor "com.github.bumptech.glide:compiler:$glide_version"

// Test
// Unit testing framework
Expand Down
11 changes: 7 additions & 4 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AndroidBase.Main">

android:theme="@style/Theme.AndroidBase.Main" >
<activity
android:name=".ui.HiltActivity"
android:exported="false" />
<!-- Animation Widget -->
<receiver android:name=".widgets.AnimationWidget"
android:exported="false">
<receiver
android:name=".widgets.AnimationWidget"
android:exported="false" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.rocketinsights.android

import android.app.Application
import com.rocketinsights.android.di.initKoin
import androidx.viewbinding.BuildConfig
import com.rocketinsights.android.di.koin.initKoin
import com.rocketinsights.android.work.messages.MessagesUpdateScheduler
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import timber.log.Timber

@HiltAndroidApp
class RocketApplication : Application() {

private val applicationScope = CoroutineScope(Dispatchers.Default)
Expand Down
19 changes: 19 additions & 0 deletions app/src/main/java/com/rocketinsights/android/di/hilt/AppModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.rocketinsights.android.di.hilt

import android.content.Context
import com.rocketinsights.android.RocketApplication
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Singleton
@Provides
fun provideApplication(@ApplicationContext app: Context): RocketApplication =
app as RocketApplication
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.rocketinsights.android.di.hilt

import com.google.gson.GsonBuilder
import com.rocketinsights.android.models.recipe_hilt.RecipeDtoMapper
import com.rocketinsights.android.network.hiltexample.RecipeService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object HiltNetworkModule {

private var okHttpClient: OkHttpClient? = null

@Singleton
@Provides
fun providesRecipeMapper(): RecipeDtoMapper = RecipeDtoMapper()

@Singleton
@Provides
fun provideRecipeService(): RecipeService {
return Retrofit.Builder()
.baseUrl("https://food2fork.ca/api/recipe/")
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
.client(buildClientHttp())
.build()
.create(RecipeService::class.java)
}

private fun buildClientHttp(): OkHttpClient? {
okHttpClient = OkHttpClient.Builder()
.addInterceptor(buildInterceptor())
.build()

return okHttpClient
}

private fun buildInterceptor() = Interceptor { chain ->
var request = chain.request()

request = request.newBuilder()
.addHeader(
"Authorization",
"Token 9c8b06d329136da358c2d00e76946b0111ce2c48"
)
.build()

chain.proceed(request = request)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.rocketinsights.android.di.hilt

import com.rocketinsights.android.models.recipe_hilt.RecipeDtoMapper
import com.rocketinsights.android.network.hiltexample.RecipeService
import com.rocketinsights.android.repos.RecipeRepository
import com.rocketinsights.android.repos.RecipeRepositoryImplementation
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {

@Singleton
@Provides
fun provideRecipeRepository(
recipeService: RecipeService,
recipeMapper: RecipeDtoMapper,
): RecipeRepository {
return RecipeRepositoryImplementation(
recipeService = recipeService,
mapper = recipeMapper
)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.rocketinsights.android.di
package com.rocketinsights.android.di.koin

import android.app.Application
import android.app.NotificationManager
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.rocketinsights.android.models.recipe_hilt

data class Recipe(
val id: Int,
val title: String?,
val publisher: String,
val featuredImage: String?,
val rating: Int = 0,
val sourceUrl: String,
val ingredients: List<String>,
val dateAdded: String,
val dateUpdated: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.rocketinsights.android.models.recipe_hilt

import com.google.gson.annotations.SerializedName

data class RecipeDto(
var pk: Int,
var title: String,
var publisher: String,
@SerializedName("featured_image")
var featuredImage: String,
var rating: Int = 0,
@SerializedName("source_url")
var sourceUrl: String,
var ingredients: List<String> = emptyList(),
@SerializedName("date_added")
var dateAdded: String,
@SerializedName("date_updated")
var dateUpdated: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.rocketinsights.android.models.recipe_hilt

class RecipeDtoMapper {
fun mapToDomainModel(model: RecipeDto): Recipe {
return Recipe(
id = model.pk,
title = model.title,
featuredImage = model.featuredImage,
rating = model.rating,
publisher = model.publisher,
sourceUrl = model.sourceUrl,
ingredients = model.ingredients,
dateAdded = model.dateAdded,
dateUpdated = model.dateUpdated,
)
}

fun toDomainList(initial: List<RecipeDto>): List<Recipe> = initial.map { mapToDomainModel(it) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.rocketinsights.android.network.hiltexample

import com.rocketinsights.android.models.recipe_hilt.RecipeDto

data class RecipeSearchResponse(
val count: Int,
val results: List<RecipeDto>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.rocketinsights.android.network.hiltexample

import retrofit2.http.GET
import retrofit2.http.Query

interface RecipeService {

@GET("search")
suspend fun searchRecipe(
@Query("page") page: Int,
@Query("query") query: String
): RecipeSearchResponse
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.rocketinsights.android.repos

import com.rocketinsights.android.models.recipe_hilt.Recipe

interface RecipeRepository {
suspend fun search(page: Int, query: String): List<Recipe>?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.rocketinsights.android.repos

import com.rocketinsights.android.models.recipe_hilt.Recipe
import com.rocketinsights.android.models.recipe_hilt.RecipeDtoMapper
import com.rocketinsights.android.network.hiltexample.RecipeService

class RecipeRepositoryImplementation(
private val recipeService: RecipeService,
private val mapper: RecipeDtoMapper,
) : RecipeRepository {

override suspend fun search(page: Int, query: String): List<Recipe> =
mapper.toDomainList(recipeService.searchRecipe(page = page, query = query).results)
}
93 changes: 93 additions & 0 deletions app/src/main/java/com/rocketinsights/android/ui/HiltActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.rocketinsights.android.ui

import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import com.rocketinsights.android.ui.compose.CircularProgressBar
import com.rocketinsights.android.ui.compose.RecipeCard
import com.rocketinsights.android.viewmodels.HiltListViewModel
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class HiltActivity : AppCompatActivity() {

private val viewModel: HiltListViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContent {
val recipes = viewModel.recipes.value
val searchQuery = viewModel.searchQuery.value
val loading = viewModel.loading.value
val focusManager = LocalFocusManager.current

Column() {
TextField(
value = searchQuery,
onValueChange = { newValue ->
viewModel.onSearchQueryChanged(newValue)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
label = {
Text(text = "Search")
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Search
),
leadingIcon = {
Icon(
imageVector = Icons.Filled.Search,
contentDescription = "icon"
)
},
keyboardActions = KeyboardActions(
onSearch = {
viewModel.newSearch(searchQuery)
focusManager.clearFocus()
}
)
)
Box(
modifier = Modifier.fillMaxSize()
) {
LazyColumn(content = {
itemsIndexed(
items = recipes
) { index, recipe ->
RecipeCard(
recipe = recipe,
onCardClick = {}
)
}
})

CircularProgressBar(isDisplayed = loading)
}
}
}
}
}
Loading