Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull request for android Job - Pedro Henrique Freitas #40

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx

.idea/
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
62 changes: 62 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 29

defaultConfig {
applicationId "com.challenge.nexaas"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
kotlinOptions {
jvmTarget = "1.8"
}
}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
//navigation component
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
//koin
implementation "org.koin:koin-android:$koin_version"
implementation "org.koin:koin-android-viewmodel:$koin_version"
// Retrofit
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
//coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutine_version"
//room
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.google.android.material:material:1.1.0'
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
testImplementation "androidx.arch.core:core-testing:$arch_testing_version"
testImplementation "com.google.truth:truth:$truth_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.challenge.nexaas

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.challenge.nexaas", appContext.packageName)
}
}
24 changes: 24 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.challenge.nexaas">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".NexaasApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
36 changes: 36 additions & 0 deletions app/src/main/java/com/challenge/nexaas/AppDatabase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.challenge.nexaas

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.challenge.nexaas.data.Product
import com.challenge.nexaas.data.ProductDAO

@Database(
version = 1,
entities = [Product::class],
exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
abstract fun productDao(): ProductDAO

companion object {
private const val DATABASE_NAME = "nexaas.db"

@Volatile
private var instance: AppDatabase? = null

fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
}

private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
.fallbackToDestructiveMigration()
.build()
}
}
}
28 changes: 28 additions & 0 deletions app/src/main/java/com/challenge/nexaas/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.challenge.nexaas

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.content_main.*

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
configActionBar()
}

private fun configActionBar() {
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(navController.graph)
toolbar.setupWithNavController(navController, appBarConfiguration)
}

override fun onSupportNavigateUp() =
NavHostFragment.findNavController(nav_host_fragment).navigateUp()
}
20 changes: 20 additions & 0 deletions app/src/main/java/com/challenge/nexaas/NexaasApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.challenge.nexaas

import android.app.Application
import com.challenge.nexaas.di.apiModule
import com.challenge.nexaas.di.daoModule
import com.challenge.nexaas.di.repositoryModule
import com.challenge.nexaas.di.viewModelModule
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin

class NexaasApplication : Application() {

override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@NexaasApplication)
modules(listOf(apiModule, daoModule, repositoryModule, viewModelModule))
}
}
}
22 changes: 22 additions & 0 deletions app/src/main/java/com/challenge/nexaas/data/Product.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.challenge.nexaas.data

import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize

@Entity
@Parcelize
data class Product(
@PrimaryKey
val name: String,
val description: String,
@SerializedName("image_url")
val imageUrl: String,
val price: Int,
val quantity: Int,
val shipping: Int,
val stock: Int,
val tax: Int
) : Parcelable
17 changes: 17 additions & 0 deletions app/src/main/java/com/challenge/nexaas/data/ProductDAO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.challenge.nexaas.data

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

@Dao
interface ProductDAO {

@Query("SELECT * FROM Product")
fun getAll(): List<Product>

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveAll(products: List<Product>)

}
16 changes: 16 additions & 0 deletions app/src/main/java/com/challenge/nexaas/data/ProductRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.challenge.nexaas.data

interface ProductRepository : ProductService

class ProductRepositoryImpl(private val service: ProductService, private val dao: ProductDAO) :
ProductRepository {
override suspend fun getProducts(): List<Product> {
return try {
val product = service.getProducts()
dao.saveAll(product)
dao.getAll()
} catch (e: Exception) {
dao.getAll()
}
}
}
9 changes: 9 additions & 0 deletions app/src/main/java/com/challenge/nexaas/data/ProductService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.challenge.nexaas.data

import retrofit2.http.GET

interface ProductService {

@GET("data.json")
suspend fun getProducts(): List<Product>
}
33 changes: 33 additions & 0 deletions app/src/main/java/com/challenge/nexaas/di/ApiViewModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.challenge.nexaas.di

import com.challenge.nexaas.data.ProductService
import okhttp3.OkHttpClient
import org.koin.dsl.module
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

val apiModule = module {
single { provideDefaultOkhttpClient() }
single { provideRetrofit(get()) }
}

private const val URL =
"https://raw.githubusercontent.com/myfreecomm/desafio-mobile-android/master/api/"

fun provideDefaultOkhttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request()
chain.proceed(request)
}
.build()
}

fun provideRetrofit(client: OkHttpClient): ProductService {
return Retrofit.Builder()
.baseUrl(URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ProductService::class.java)
}
9 changes: 9 additions & 0 deletions app/src/main/java/com/challenge/nexaas/di/DaoModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.challenge.nexaas.di

import com.challenge.nexaas.AppDatabase
import org.koin.dsl.module

val daoModule = module {
single { AppDatabase.getInstance(get()) }
single { get<AppDatabase>().productDao() }
}
9 changes: 9 additions & 0 deletions app/src/main/java/com/challenge/nexaas/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.challenge.nexaas.di

import com.challenge.nexaas.data.ProductRepository
import com.challenge.nexaas.data.ProductRepositoryImpl
import org.koin.dsl.module

val repositoryModule = module {
single<ProductRepository> { ProductRepositoryImpl(get(), get()) }
}
9 changes: 9 additions & 0 deletions app/src/main/java/com/challenge/nexaas/di/ViewModelModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.challenge.nexaas.di

import com.challenge.nexaas.ui.ProdutcListViewModel
import org.koin.android.viewmodel.dsl.viewModel
import org.koin.dsl.module

val viewModelModule = module {
viewModel { ProdutcListViewModel(get()) }
}
Loading