Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions .idea/checkstyle-idea.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 5 additions & 17 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ plugins {
id 'org.jetbrains.kotlin.android'
id 'androidx.navigation.safeargs'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
id 'org.jetbrains.kotlin.plugin.serialization' version '1.6.10'
}

Expand All @@ -12,7 +11,7 @@ android {

defaultConfig {
applicationId "com.ilein.thecocktailapp"
minSdk 21
minSdk 26
targetSdk 32
versionCode 1
versionName "1.0"
Expand Down Expand Up @@ -54,7 +53,7 @@ dependencies {

implementation 'androidx.legacy:legacy-support-v4:1.0.0'
def nav_version = "2.4.2"
def ktor_version = "1.6.8"
def ktor_version = "2.0.3"
def room_version = "2.4.2"
def koin_version = "3.2.0"

Expand All @@ -74,16 +73,6 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

// hilt
implementation "com.google.dagger:hilt-android:2.40.5"
kapt "com.google.dagger:hilt-compiler:2.40.5"

// retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'

// gson
implementation 'com.google.code.gson:gson:2.9.0'

Expand All @@ -98,12 +87,12 @@ dependencies {
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("ch.qos.logback:logback-classic:1.2.5")
implementation("io.ktor:ktor-client-logging:$ktor_version")
implementation("io.ktor:ktor-client-serialization:$ktor_version")
implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
implementation("io.ktor:ktor-client-cio:$ktor_version")

// Room
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-rxjava3:$room_version"
implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"

// Koin
Expand All @@ -116,7 +105,6 @@ dependencies {

// map
implementation "org.osmdroid:osmdroid-android:6.1.13"

implementation 'com.google.android.gms:play-services-location:17.1.0'

}
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.TheCocktailApp">
<activity
android:name=".MainActivity"
android:name=".presentation.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
11 changes: 5 additions & 6 deletions app/src/main/java/com/ilein/thecocktailapp/App.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package com.ilein.thecocktailapp

import android.app.Application
import com.ilein.thecocktailapp.koin.databaseModule
import com.ilein.thecocktailapp.koin.networkModule
import com.ilein.thecocktailapp.koin.vmModule
import dagger.hilt.android.HiltAndroidApp
import com.ilein.thecocktailapp.di.databaseModule
import com.ilein.thecocktailapp.di.networkModule
import com.ilein.thecocktailapp.di.useCaseModule
import com.ilein.thecocktailapp.di.vmModule
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin

@HiltAndroidApp
class App: Application() {

override fun onCreate() {
Expand All @@ -18,7 +17,7 @@ class App: Application() {
startKoin(){
androidLogger()
androidContext(this@App)
modules(databaseModule, networkModule, vmModule)
modules(databaseModule, networkModule, useCaseModule, vmModule)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.ilein.thecocktailapp.data

import com.ilein.thecocktailapp.data.db.LocalDataSource
import com.ilein.thecocktailapp.data.network.RemoteDataSource
import com.ilein.thecocktailapp.domain.Drink
import com.ilein.thecocktailapp.domain.FavoriteDrink
import com.ilein.thecocktailapp.domain.DrinkRepository
import kotlinx.coroutines.flow.Flow

class DrinkRepositoryImpl(
private val localDataSource: LocalDataSource,
private val remoteDataSource: RemoteDataSource
): DrinkRepository {
override suspend fun insertDrinkFavorites(drink: FavoriteDrink) =
localDataSource.insertDrinkFavorites(drink.toEntity())

override suspend fun getDrinkFavorites(): List<FavoriteDrink> =
localDataSource.getDrinkFavorites().map { it.toDomain() }

override suspend fun getDrinkFavoritesDesc(): List<FavoriteDrink> =
localDataSource.getDrinkFavoritesDesc().map { it.toDomain() }

override suspend fun getFavoriteDrink(drinkId: Int): FavoriteDrink? =
localDataSource.getDrink(drinkId)?.toDomain()

override suspend fun deleteFavoriteDrink(drinkId: Int) =
localDataSource.deleteDrink(drinkId)

override suspend fun getDrink(drinkId: Int): Flow<Drink> =
remoteDataSource.getDrink(drinkId)

override suspend fun getOneDrink(drinkId: Int): Drink =
remoteDataSource.getOneDrink(drinkId)

override suspend fun searchDrinks(query: String): Flow<List<Drink>> =
remoteDataSource.searchDrinks(query)
}
31 changes: 31 additions & 0 deletions app/src/main/java/com/ilein/thecocktailapp/data/MapperExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.ilein.thecocktailapp.data

import com.ilein.thecocktailapp.data.db.DrinkEntity
import com.ilein.thecocktailapp.data.network.model.DrinkModel
import com.ilein.thecocktailapp.data.network.model.DrinksModel
import com.ilein.thecocktailapp.domain.Drink
import com.ilein.thecocktailapp.domain.FavoriteDrink

fun FavoriteDrink.toEntity() = DrinkEntity(
id = this.id,
name = this.name,
image = this.image,
createDate = this.createDate,
note = this.note
)

fun DrinkEntity.toDomain() = FavoriteDrink(
id = this.id,
name = this.name,
image = this.image,
createDate = this.createDate,
note = this.note
)

fun DrinkModel.toDomain() = Drink(
id = this.idDrink,
name = this.strDrink,
image = this.strDrinkThumb,
ingredients = this.getIngredientsText(),
instruction = this.strInstructions
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ilein.thecocktailapp.db
package com.ilein.thecocktailapp.data.db

import android.os.Build
import androidx.annotation.RequiresApi
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.ilein.thecocktailapp.db
package com.ilein.thecocktailapp.data.db

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.time.LocalDateTime

@Entity(tableName = DrinkLikeDb.DRINK_LIKE_TABLE)
data class DrinkLikeEntity (
@Entity(tableName = DrinkFavoriteDb.DRINK_LIKE_TABLE)
data class DrinkEntity (
@PrimaryKey
@ColumnInfo(name = COLUMN_ID)
val id: Int,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.ilein.thecocktailapp.data.db

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query

@Dao
abstract class DrinkFavoriteDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract suspend fun insertDrink(drinkFavorite: DrinkEntity)

@Query("SELECT * FROM drink_like")
abstract suspend fun getDrinkFavorites(): List<DrinkEntity>

@Query("SELECT * FROM drink_like order by update_date desc")
abstract suspend fun getDrinkFavoritesDesc(): List<DrinkEntity>

@Query("SELECT * FROM drink_like WHERE id = :drinkId")
abstract suspend fun getDrink(drinkId: Int): DrinkEntity?

@Query("DELETE FROM drink_like WHERE id = :drinkId")
abstract suspend fun deleteDrink(drinkId: Int)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ilein.thecocktailapp.db
package com.ilein.thecocktailapp.data.db

import android.content.Context
import androidx.room.Database
Expand All @@ -10,27 +10,27 @@ import androidx.room.TypeConverters
version = 1,
exportSchema = false,
entities = [
DrinkLikeEntity::class
DrinkEntity::class
]
)

@TypeConverters(Converters::class)
abstract class DrinkLikeDb: RoomDatabase() {
abstract class DrinkFavoriteDb: RoomDatabase() {
companion object {

private const val databaseName = "drink_database"
const val DRINK_LIKE_TABLE = "drink_like"

fun createDatabaseInstance(context: Context): DrinkLikeDb {
fun createDatabaseInstance(context: Context): DrinkFavoriteDb {
return Room
.databaseBuilder(
context,
DrinkLikeDb::class.java,
DrinkFavoriteDb::class.java,
databaseName
)
.build()
}
}

abstract fun drinkLikeDao(): DrinkLikeDao
abstract fun drinkFavoriteDao(): DrinkFavoriteDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.ilein.thecocktailapp.data.db

interface LocalDataSource {
suspend fun insertDrinkFavorites(drinkLike: DrinkEntity)
suspend fun getDrinkFavorites(): List<DrinkEntity>
suspend fun getDrinkFavoritesDesc(): List<DrinkEntity>
suspend fun getDrink(drinkId: Int): DrinkEntity?
suspend fun deleteDrink(drinkId: Int)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.ilein.thecocktailapp.data.db

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext

class LocalDataSourceImpl(
private val dao: DrinkFavoriteDao,
private val ioDispatcher: CoroutineDispatcher
): LocalDataSource {
override suspend fun insertDrinkFavorites(drinkLike: DrinkEntity) =
withContext(ioDispatcher) { dao.insertDrink(drinkLike) }

override suspend fun getDrinkFavorites(): List<DrinkEntity> =
withContext(ioDispatcher) { dao.getDrinkFavorites()}

override suspend fun getDrinkFavoritesDesc(): List<DrinkEntity> =
withContext(ioDispatcher) { dao.getDrinkFavoritesDesc() }

override suspend fun getDrink(drinkId: Int): DrinkEntity? =
withContext(ioDispatcher) { dao.getDrink(drinkId) }

override suspend fun deleteDrink(drinkId: Int) =
withContext(ioDispatcher) { dao.deleteDrink(drinkId) }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.ilein.thecocktailapp.data.network

import com.ilein.thecocktailapp.BuildConfig
import com.ilein.thecocktailapp.data.network.model.DrinksModel
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.cache.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json

class ClientProvider {
private val baseUrl = BuildConfig.API_BASE_URL
private val drinks = "api/json/${BuildConfig.API_VERSION}/${BuildConfig.API_KEY}/search.php"
private val drink = "api/json/${BuildConfig.API_VERSION}/${BuildConfig.API_KEY}/lookup.php"


private val ktorClient = HttpClient() {
install(Logging) {
level = LogLevel.ALL
}

install(ContentNegotiation) {
json(Json{ ignoreUnknownKeys = true
prettyPrint = true
isLenient = true})
}
install(HttpCache)
}

suspend fun getDrink(drinkId: Int): DrinksModel = ktorClient.use {
it.get { host = baseUrl
url(port = 8080, path = buildPath(drink, mapOf(Pair("i", drinkId)))) }.body()
}

suspend fun searchDrinks(searchText: String): DrinksModel = ktorClient.use {
it.get { host = baseUrl
url(port = 8080, path = buildPath(drinks, mapOf(Pair("s", searchText)))) }.body()
}

private fun buildPath(
endpoint: String,
query: Map<String, Any?> = emptyMap(),
): String =
buildString {
append("$endpoint?")
append(
query.entries.joinToString(
separator = "&"
) { (key, value) ->
"$key=$value"
}
)
}
}
Loading