Skip to content

Commit 9dd0364

Browse files
authored
Merge pull request #1 from tapptitude/develop
Some polish + testing framework setup.
2 parents 563d7d7 + 6de9540 commit 9dd0364

File tree

22 files changed

+412
-94
lines changed

22 files changed

+412
-94
lines changed

app/build.gradle

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@ apply plugin: 'kotlin-android-extensions'
77
apply plugin: 'kotlin-kapt'
88

99
android {
10-
compileSdkVersion 27
10+
compileSdkVersion 28
11+
testOptions.unitTests.includeAndroidResources true
12+
1113
defaultConfig {
1214
applicationId "com.tapptitude.mvp_kotlin_sample_android"
1315
minSdkVersion 21
14-
targetSdkVersion 27
16+
targetSdkVersion 28
1517
versionCode 1
1618
versionName "1.0"
1719
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
1820
}
21+
1922
buildTypes {
2023
release {
2124
minifyEnabled false
@@ -24,36 +27,61 @@ android {
2427
}
2528
}
2629

27-
dependencies {
28-
implementation fileTree(dir: 'libs', include: ['*.jar'])
30+
ext {
31+
// Support
32+
supportVersion = '28.0.0'
33+
// End Support
2934

30-
def dependencies = rootProject.ext.dependencies
31-
def testDependencies = rootProject.ext.testDependencies
35+
androidSupportTestVersion = '1.0.2'
36+
retrofitVersion = '2.4.0'
37+
daggerVersion = '2.16'
38+
rxAndroidVersion = '2.0.2'
39+
rxBindingKotlinVersion = '2.1.1'
40+
loggingInterceptorVersion = '3.11.0'
41+
jUnitVersion = '4.12'
42+
mockitoKotlinVersion = '1.5.0'
43+
mockitoInlineVersion = '2.13.0'
44+
glideVersion = '4.8.0'
45+
robolectricVersion = '4.0'
46+
robolectricShadowsSupportVersion = '3.3.2'
47+
}
3248

33-
implementation dependencies.kotlin
49+
dependencies {
50+
implementation fileTree(dir: 'libs', include: ['*.jar'])
3451

3552
// Android Support
36-
implementation dependencies.supportAppCompat
37-
implementation dependencies.supportRecyclerView
38-
implementation dependencies.constraintLayout
53+
implementation "com.android.support:appcompat-v7:$supportVersion"
54+
implementation "com.android.support:support-v4:$supportVersion"
55+
implementation "com.android.support:recyclerview-v7:$supportVersion"
56+
implementation "com.android.support:cardview-v7:$supportVersion"
57+
implementation "com.android.support:design:$supportVersion"
3958

4059
// Reactive
41-
implementation dependencies.rxAndroid
42-
implementation dependencies.rxBinding
60+
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
61+
implementation "com.jakewharton.rxbinding2:rxbinding-kotlin:$rxBindingKotlinVersion"
4362

4463
// Networking
45-
implementation dependencies.retrofit
46-
implementation dependencies.retrofitGsonConverter
47-
implementation dependencies.retrofitRxJavaAdapter
48-
implementation dependencies.retrofitInterceptor
64+
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
65+
implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
66+
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
67+
implementation "com.squareup.okhttp3:logging-interceptor:$loggingInterceptorVersion"
68+
implementation "com.github.bumptech.glide:glide:$glideVersion"
69+
annotationProcessor "com.github.bumptech.glide:compiler:$glideVersion"
4970

5071
// Dependency Injection
51-
implementation dependencies.dagger
52-
implementation dependencies.daggerSupport
53-
kapt dependencies.daggerCompiler
54-
kapt dependencies.daggerProcessor
72+
implementation "com.google.dagger:dagger:$daggerVersion"
73+
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
74+
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
75+
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
5576

5677
// Tests
57-
testImplementation testDependencies.jUnit
58-
testImplementation testDependencies.mockito
78+
testImplementation "junit:junit:$jUnitVersion"
79+
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion"
80+
testImplementation "com.nhaarman:mockito-kotlin-kt1.1:$mockitoKotlinVersion"
81+
testImplementation "org.mockito:mockito-core:$mockitoInlineVersion"
82+
testImplementation "org.mockito:mockito-inline:$mockitoInlineVersion"
83+
androidTestImplementation "com.android.support.test:runner:$androidSupportTestVersion"
84+
androidTestImplementation "com.android.support.test:rules:$androidSupportTestVersion"
85+
testImplementation "org.robolectric:robolectric:$robolectricVersion"
86+
testImplementation "org.robolectric:shadows-support-v4:$robolectricShadowsSupportVersion"
5987
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.tapptitude.mvpsample.data.model
2+
3+
import com.google.gson.annotations.SerializedName
4+
5+
class User(
6+
@SerializedName("id")
7+
var id: String? = null
8+
)

app/src/main/java/com/tapptitude/mvpsample/data/persistence/datetime/DateTimeNetworkRepository.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package com.tapptitude.mvpsample.data.persistence.datetime
22

33
import com.tapptitude.mvpsample.data.network.DateTimeApi
44
import com.tapptitude.mvpsample.data.network.models.DateTime
5+
import com.tapptitude.mvpsample.providers.SchedulerProvider
56
import io.reactivex.Observable
6-
import io.reactivex.schedulers.Schedulers
77

8-
class DateTimeNetworkRepository(private val dateTimeApi: DateTimeApi) : DateTimeRepository {
8+
class DateTimeNetworkRepository(
9+
private val dateTimeApi: DateTimeApi,
10+
private val schedulerProvider: SchedulerProvider
11+
) : DateTimeRepository {
912

1013
override fun loadDateTime(): Observable<DateTime> {
1114
return dateTimeApi.getDateTime()
12-
.subscribeOn(Schedulers.io())
15+
.subscribeOn(schedulerProvider.io())
1316
}
1417
}

app/src/main/java/com/tapptitude/mvpsample/data/persistence/ip/IpNetworkRepository.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package com.tapptitude.mvpsample.data.persistence.ip
22

33
import com.tapptitude.mvpsample.data.network.IpApi
44
import com.tapptitude.mvpsample.data.network.models.IpAddress
5+
import com.tapptitude.mvpsample.providers.SchedulerProvider
56
import io.reactivex.Observable
6-
import io.reactivex.schedulers.Schedulers
77

8-
class IpNetworkRepository(private val ipApi: IpApi) : IpRepository {
8+
class IpNetworkRepository(
9+
private val ipApi: IpApi,
10+
private val schedulerProvider: SchedulerProvider
11+
) : IpRepository {
912

1013
override fun loadIpAddress(): Observable<IpAddress> {
1114
return ipApi.getIpAddress()
12-
.subscribeOn(Schedulers.io())
15+
.subscribeOn(schedulerProvider.io())
1316
}
1417
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package com.tapptitude.mvpsample.di.builders
22

33
import com.tapptitude.mvpsample.presentation.home.activities.HomeActivity
4-
import com.tapptitude.mvpsample.di.modules.AppModule
54
import dagger.Module
65
import dagger.android.ContributesAndroidInjector
76

87
@Module
98
abstract class ActivityBuilder {
109

11-
@ContributesAndroidInjector(modules = [(AppModule::class)])
10+
@ContributesAndroidInjector
1211
abstract fun bindMainActivity(): HomeActivity
1312
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package com.tapptitude.mvpsample.di.builders
22

3-
import com.tapptitude.mvpsample.di.modules.AppModule
43
import com.tapptitude.mvpsample.presentation.home.fragments.SampleFragment
54
import dagger.Module
65
import dagger.android.ContributesAndroidInjector
76

87
@Module
98
abstract class FragmentBuilder {
109

11-
@ContributesAndroidInjector(modules = [(AppModule::class)])
10+
@ContributesAndroidInjector
1211
abstract fun bindQuestionFragment(): SampleFragment
1312
}

app/src/main/java/com/tapptitude/mvpsample/di/modules/AppModule.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,42 @@ package com.tapptitude.mvpsample.di.modules
22

33
import android.app.Application
44
import android.content.Context
5+
import com.google.gson.Gson
6+
import com.tapptitude.mvpsample.preferance.UserSessionManager
7+
import com.tapptitude.mvpsample.providers.RuntimeSchedulerProvider
8+
import com.tapptitude.mvpsample.providers.SchedulerProvider
59
import dagger.Module
610
import dagger.Provides
711
import javax.inject.Singleton
812

13+
private const val USER_PREFS = "user_sh_preferences"
14+
915
@Module
1016
class AppModule {
1117

1218
@Provides
1319
@Singleton
1420
internal fun provideContext(application: Application): Context = application
21+
22+
@Provides
23+
@Singleton
24+
fun provideAppGson(): Gson {
25+
return Gson()
26+
}
27+
28+
@Provides
29+
@Singleton
30+
fun provideUserSessionManager(
31+
context: Context,
32+
gson: Gson
33+
): UserSessionManager {
34+
val sharedPrefs = context.applicationContext.getSharedPreferences(USER_PREFS, Context.MODE_PRIVATE)
35+
return UserSessionManager(gson, sharedPrefs)
36+
}
37+
38+
@Provides
39+
@Singleton
40+
fun provideSchedulerProvider(): SchedulerProvider {
41+
return RuntimeSchedulerProvider()
42+
}
1543
}

app/src/main/java/com/tapptitude/mvpsample/di/modules/NetworkModule.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import retrofit2.converter.gson.GsonConverterFactory
1616
import java.io.File
1717
import javax.inject.Singleton
1818

19+
private const val CACHE_MAX_SIZE = (10 * 1024 * 1024).toLong()
20+
1921
@Module
2022
class NetworkModule {
2123

@@ -39,10 +41,10 @@ class NetworkModule {
3941

4042
@Provides
4143
@Singleton
42-
fun provideRetrofit(client: OkHttpClient): Retrofit.Builder {
44+
fun provideRetrofit(client: OkHttpClient, gson: Gson): Retrofit.Builder {
4345
return Retrofit.Builder()
4446
.client(client)
45-
.addConverterFactory(GsonConverterFactory.create(Gson()))
47+
.addConverterFactory(GsonConverterFactory.create(gson))
4648
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
4749
}
4850

@@ -58,7 +60,7 @@ class NetworkModule {
5860
}
5961

6062
val cacheDir = File(application.cacheDir.absolutePath, application.packageName)
61-
okHttpBuilder.cache(okhttp3.Cache(cacheDir, (10 * 1024 * 1024).toLong()))
63+
okHttpBuilder.cache(okhttp3.Cache(cacheDir, CACHE_MAX_SIZE))
6264
return okHttpBuilder.build()
6365
}
6466

app/src/main/java/com/tapptitude/mvpsample/di/modules/RepositoryModule.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.tapptitude.mvpsample.data.persistence.datetime.DateTimeNetworkReposit
66
import com.tapptitude.mvpsample.data.persistence.datetime.DateTimeRepository
77
import com.tapptitude.mvpsample.data.persistence.ip.IpNetworkRepository
88
import com.tapptitude.mvpsample.data.persistence.ip.IpRepository
9+
import com.tapptitude.mvpsample.providers.SchedulerProvider
910
import dagger.Module
1011
import dagger.Provides
1112
import javax.inject.Singleton
@@ -15,13 +16,19 @@ class RepositoryModule {
1516

1617
@Provides
1718
@Singleton
18-
internal fun provideDateTimeRepository(dateTimeApi: DateTimeApi): DateTimeRepository {
19-
return DateTimeNetworkRepository(dateTimeApi)
19+
internal fun provideDateTimeRepository(
20+
dateTimeApi: DateTimeApi,
21+
schedulerProvider: SchedulerProvider
22+
): DateTimeRepository {
23+
return DateTimeNetworkRepository(dateTimeApi, schedulerProvider)
2024
}
2125

2226
@Provides
2327
@Singleton
24-
internal fun provideIpRepository(ipApi: IpApi): IpRepository {
25-
return IpNetworkRepository(ipApi)
28+
internal fun provideIpRepository(
29+
ipApi: IpApi,
30+
schedulerProvider: SchedulerProvider
31+
): IpRepository {
32+
return IpNetworkRepository(ipApi, schedulerProvider)
2633
}
2734
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.tapptitude.mvpsample.preferance
2+
3+
import android.content.SharedPreferences
4+
import android.text.TextUtils
5+
import com.google.gson.Gson
6+
import com.tapptitude.mvpsample.data.model.User
7+
import javax.inject.Inject
8+
9+
private const val USER_DATA_KEY = "USER_DATA_KEY"
10+
private const val SESSION_TOKEN_KEY = "SESSION_TOKEN_KEY"
11+
private const val IP_INFO_KEY = "IP_INFO_KEY"
12+
13+
class UserSessionManager @Inject constructor(
14+
private val gson: Gson,
15+
private val userPreference: SharedPreferences
16+
) {
17+
18+
fun getUser(): User? {
19+
val stringUserData = userPreference.getString(USER_DATA_KEY, "")
20+
21+
if (TextUtils.isEmpty(stringUserData)) {
22+
return null
23+
}
24+
25+
return gson.fromJson(stringUserData, User::class.java)
26+
}
27+
28+
fun saveUser(user: User) {
29+
val stringUserData = gson.toJson(user)
30+
31+
userPreference.edit()
32+
.putString(USER_DATA_KEY, stringUserData)
33+
.apply()
34+
}
35+
36+
fun saveIp(ip: String) {
37+
userPreference.edit().putString(IP_INFO_KEY, ip).apply()
38+
}
39+
40+
fun isUserLoggedIn(): Boolean {
41+
return getSessionToken() != null
42+
}
43+
44+
fun saveSessionToken(newSessionToken: String) {
45+
userPreference.edit().putString(SESSION_TOKEN_KEY, newSessionToken).apply()
46+
}
47+
48+
fun getSessionToken(): String? {
49+
return userPreference.getString(SESSION_TOKEN_KEY, null)
50+
}
51+
52+
fun clearSession() {
53+
userPreference.edit()
54+
.clear()
55+
.apply()
56+
}
57+
}

0 commit comments

Comments
 (0)