Skip to content

Commit b537f85

Browse files
committed
Merge branch 'develop'
Final version of offline first approach with MVP
2 parents a5551e7 + 5c998b7 commit b537f85

File tree

72 files changed

+1408
-332
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1408
-332
lines changed

app/build.gradle

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
apply plugin: 'com.android.application'
2-
32
apply plugin: 'kotlin-android'
4-
53
apply plugin: 'kotlin-android-extensions'
64

75
android {
@@ -29,22 +27,28 @@ kapt {
2927

3028
dependencies {
3129
implementation fileTree(dir: 'libs', include: ['*.jar'])
32-
androidTestImplementation ('com.android.support.test.espresso:espresso-core:2.2.2', {
33-
exclude group: 'com.android.support', module: 'support-annotations'
34-
})
3530
implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
3631

37-
compile 'com.squareup.retrofit2:retrofit:2.3.0'
38-
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
39-
compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
40-
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
41-
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
42-
compile 'com.github.bumptech.glide:glide:4.0.0-RC1'
43-
44-
kapt 'com.google.dagger:dagger-compiler:2.5'
45-
compile 'com.google.dagger:dagger:2.8'
46-
47-
implementation 'com.android.support:appcompat-v7:26.0.0-beta1'
48-
implementation 'com.android.support:recyclerview-v7:26.0.0-beta1'
32+
implementation 'com.google.dagger:dagger:2.11'
33+
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
34+
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
35+
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
36+
implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
37+
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
38+
implementation 'com.github.bumptech.glide:glide:4.0.0-RC1'
39+
implementation "android.arch.persistence.room:runtime:1.0.0-alpha5"
40+
implementation "android.arch.persistence.room:rxjava2:1.0.0-alpha5"
41+
implementation 'com.facebook.stetho:stetho:1.5.0'
42+
implementation 'com.android.support:appcompat-v7:26.0.0'
43+
implementation 'com.android.support:recyclerview-v7:26.0.0'
44+
45+
kapt "android.arch.persistence.room:compiler:1.0.0-alpha5"
46+
kapt 'com.google.dagger:dagger-compiler:2.11'
47+
48+
testImplementation 'org.mockito:mockito-core:2.8.47'
4949
testImplementation 'junit:junit:4.12'
50+
51+
androidTestImplementation ('com.android.support.test.espresso:espresso-core:2.2.2', {
52+
exclude group: 'com.android.support', module: 'support-annotations'
53+
})
5054
}

app/src/androidTest/java/com/example/tamaskozmer/kotlinrxexample/ExampleInstrumentedTest.kt

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.example.tamaskozmer.kotlinrxexample
2+
3+
import android.arch.persistence.room.Room
4+
import android.support.test.InstrumentationRegistry
5+
import android.support.test.runner.AndroidJUnit4
6+
import com.example.tamaskozmer.kotlinrxexample.model.entities.User
7+
import com.example.tamaskozmer.kotlinrxexample.model.persistence.AppDatabase
8+
import com.example.tamaskozmer.kotlinrxexample.model.persistence.daos.UserDao
9+
import org.junit.After
10+
import org.junit.Assert
11+
import org.junit.Before
12+
import org.junit.Test
13+
import org.junit.runner.RunWith
14+
15+
/**
16+
* Created by Tamas_Kozmer on 7/24/2017.
17+
*/
18+
@RunWith(AndroidJUnit4::class)
19+
class UserDaoTest {
20+
21+
lateinit var userDao: UserDao
22+
lateinit var database: AppDatabase
23+
24+
@Before
25+
fun setup() {
26+
val context = InstrumentationRegistry.getTargetContext()
27+
database = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java).build()
28+
userDao = database.userDao()
29+
}
30+
31+
@After
32+
fun tearDown() {
33+
database.close()
34+
}
35+
36+
@Test
37+
fun testInsertAndGet() {
38+
val users = listOf(User(1, "Name", 100, "url"), User())
39+
userDao.insertAll(users)
40+
41+
val allUsers = userDao.getUsers(1)
42+
Assert.assertEquals(users, allUsers)
43+
}
44+
45+
@Test
46+
fun testUsersOrderedByCorrectly() {
47+
val users = listOf(
48+
User(1, "Name", 100, "url"),
49+
User(2, "Name2", 500, "url"),
50+
User(3, "Name3", 300, "url"))
51+
userDao.insertAll(users)
52+
53+
val allUsers = userDao.getUsers(1)
54+
val expectedUsers = users.sortedByDescending { it.reputation }
55+
Assert.assertEquals(expectedUsers, allUsers)
56+
}
57+
58+
@Test
59+
fun testConflictingInserts() {
60+
val users = listOf(
61+
User(1, "Name", 100, "url"),
62+
User(2, "Name2", 500, "url"),
63+
User(3, "Name3", 300, "url"))
64+
65+
val users2 = listOf(
66+
User(1, "Name", 1000, "url"),
67+
User(2, "Name2", 700, "url"),
68+
User(4, "Name3", 5500, "url"))
69+
userDao.insertAll(users)
70+
userDao.insertAll(users2)
71+
72+
val allUsers = userDao.getUsers(1)
73+
val expectedUsers = listOf(
74+
User(4, "Name3", 5500, "url"),
75+
User(1, "Name", 1000, "url"),
76+
User(2, "Name2", 700, "url"),
77+
User(3, "Name3", 300, "url"))
78+
79+
Assert.assertEquals(expectedUsers, allUsers)
80+
}
81+
82+
@Test
83+
fun testLimitUsersPerPage_FirstPageOnly30Items() {
84+
val users = (1..40L).map { User(it, "Name $it", it *100, "url") }
85+
86+
userDao.insertAll(users)
87+
88+
val retrievedUsers = userDao.getUsers(1)
89+
Assert.assertEquals(30, retrievedUsers.size)
90+
}
91+
92+
@Test
93+
fun testRequestSecondPage_LimitUsersPerPage_showOnlyRemainingItems() {
94+
val users = (1..40L).map { User(it, "Name $it", it *100, "url") }
95+
96+
userDao.insertAll(users)
97+
98+
val retrievedUsers = userDao.getUsers(2)
99+
Assert.assertEquals(10, retrievedUsers.size)
100+
}
101+
}

app/src/main/AndroidManifest.xml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="com.example.tamaskozmer.kotlinrxexample">
44

5-
<uses-permission android:name="android.permission.INTERNET"/>
5+
<uses-permission android:name="android.permission.INTERNET" />
6+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
67

78
<application
89
android:name=".CustomApplication"
@@ -12,7 +13,9 @@
1213
android:roundIcon="@mipmap/ic_launcher_round"
1314
android:supportsRtl="true"
1415
android:theme="@style/AppTheme">
15-
<activity android:name=".view.activities.MainActivity">
16+
<activity
17+
android:name=".view.activities.MainActivity"
18+
android:configChanges="orientation|screenSize">
1619
<intent-filter>
1720
<action android:name="android.intent.action.MAIN" />
1821

app/src/main/java/com/example/tamaskozmer/kotlinrxexample/CustomApplication.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.app.Application
44
import com.example.tamaskozmer.kotlinrxexample.di.components.ApplicationComponent
55
import com.example.tamaskozmer.kotlinrxexample.di.components.DaggerApplicationComponent
66
import com.example.tamaskozmer.kotlinrxexample.di.modules.ApplicationModule
7+
import com.facebook.stetho.Stetho
78

89
/**
910
* Created by Tamas_Kozmer on 7/4/2017.
@@ -19,6 +20,7 @@ class CustomApplication : Application() {
1920

2021
override fun onCreate() {
2122
super.onCreate()
23+
Stetho.initializeWithDefaults(this);
2224
component.inject(this)
2325
}
2426
}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
package com.example.tamaskozmer.kotlinrxexample.di.components
22

33
import com.example.tamaskozmer.kotlinrxexample.di.modules.DetailFragmentModule
4-
import com.example.tamaskozmer.kotlinrxexample.presentation.DetailPresenter
5-
import com.example.tamaskozmer.kotlinrxexample.view.fragments.DetailsFragment
4+
import com.example.tamaskozmer.kotlinrxexample.presentation.presenters.DetailPresenter
65
import dagger.Subcomponent
7-
import javax.inject.Singleton
86

97
/**
108
* Created by Tamas_Kozmer on 7/5/2017.
119
*/
12-
@Singleton
1310
@Subcomponent(modules = arrayOf(DetailFragmentModule::class))
1411
interface DetailFragmentComponent {
15-
fun inject(fragment: DetailsFragment)
1612
fun presenter() : DetailPresenter
1713
}
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
package com.example.tamaskozmer.kotlinrxexample.di.components
22

33
import com.example.tamaskozmer.kotlinrxexample.di.modules.UserListFragmentModule
4-
import com.example.tamaskozmer.kotlinrxexample.presentation.UserListPresenter
5-
import com.example.tamaskozmer.kotlinrxexample.view.fragments.UserListFragment
4+
import com.example.tamaskozmer.kotlinrxexample.presentation.presenters.UserListPresenter
65
import dagger.Subcomponent
7-
import javax.inject.Singleton
86

97
/**
108
* Created by Tamas_Kozmer on 7/4/2017.
119
*/
12-
@Singleton
1310
@Subcomponent(modules = arrayOf(UserListFragmentModule::class))
1411
interface UserListFragmentComponent {
15-
fun inject(fragment: UserListFragment)
1612
fun presenter() : UserListPresenter
1713
}

app/src/main/java/com/example/tamaskozmer/kotlinrxexample/di/modules/ApplicationModule.kt

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
package com.example.tamaskozmer.kotlinrxexample.di.modules
22

3+
import android.arch.persistence.room.Room
4+
import android.content.Context
35
import com.example.tamaskozmer.kotlinrxexample.CustomApplication
4-
import com.example.tamaskozmer.kotlinrxexample.model.UserRepository
6+
import com.example.tamaskozmer.kotlinrxexample.model.persistence.AppDatabase
7+
import com.example.tamaskozmer.kotlinrxexample.model.repositories.DetailsRepository
8+
import com.example.tamaskozmer.kotlinrxexample.model.repositories.UserRepository
59
import com.example.tamaskozmer.kotlinrxexample.model.services.QuestionService
610
import com.example.tamaskozmer.kotlinrxexample.model.services.UserService
11+
import com.example.tamaskozmer.kotlinrxexample.util.CalendarWrapper
12+
import com.example.tamaskozmer.kotlinrxexample.util.ConnectionHelper
13+
import com.example.tamaskozmer.kotlinrxexample.util.PreferencesHelper
714
import com.google.gson.Gson
815
import dagger.Module
916
import dagger.Provides
@@ -18,6 +25,11 @@ import javax.inject.Singleton
1825
@Module
1926
class ApplicationModule(val application: CustomApplication) {
2027
private val BASE_URL = "https://api.stackexchange.com/2.2/"
28+
private val DATABASE_NAME = "db-name"
29+
30+
@Provides
31+
@Singleton
32+
fun provideAppContext() : Context = application
2133

2234
@Provides
2335
@Singleton
@@ -29,8 +41,45 @@ class ApplicationModule(val application: CustomApplication) {
2941

3042
@Provides
3143
@Singleton
32-
fun provideUserRepository(retrofit: Retrofit) =
33-
UserRepository(
34-
retrofit.create(UserService::class.java),
35-
retrofit.create(QuestionService::class.java))
44+
fun provideUserRepository(retrofit: Retrofit, database: AppDatabase, connectionHelper: ConnectionHelper,
45+
preferencesHelper: PreferencesHelper, calendarWrapper: CalendarWrapper): UserRepository {
46+
return UserRepository(
47+
retrofit.create(UserService::class.java),
48+
database.userDao(),
49+
connectionHelper,
50+
preferencesHelper,
51+
calendarWrapper)
52+
}
53+
54+
@Provides
55+
@Singleton
56+
fun provideDetailsRepository(retrofit: Retrofit, database: AppDatabase, connectionHelper: ConnectionHelper,
57+
preferencesHelper: PreferencesHelper, calendarWrapper: CalendarWrapper) : DetailsRepository {
58+
return DetailsRepository(
59+
retrofit.create(UserService::class.java),
60+
retrofit.create(QuestionService::class.java),
61+
database.questionDao(),
62+
database.answerDao(),
63+
database.favoritedByUserDao(),
64+
connectionHelper,
65+
preferencesHelper,
66+
calendarWrapper)
67+
}
68+
69+
@Provides
70+
@Singleton
71+
fun provideDatabase(context: Context)
72+
= Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME).build()
73+
74+
@Provides
75+
@Singleton
76+
fun provideConnectionHelper(context: Context) = ConnectionHelper(context)
77+
78+
@Provides
79+
@Singleton
80+
fun providePreferencesHelper(context: Context) = PreferencesHelper(context)
81+
82+
@Provides
83+
@Singleton
84+
fun provideCalendarWrapper() = CalendarWrapper()
3685
}
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
package com.example.tamaskozmer.kotlinrxexample.di.modules
22

3-
import com.example.tamaskozmer.kotlinrxexample.model.UserRepository
4-
import com.example.tamaskozmer.kotlinrxexample.presentation.DetailPresenter
5-
import com.example.tamaskozmer.kotlinrxexample.view.fragments.DetailsFragment
3+
import com.example.tamaskozmer.kotlinrxexample.domain.interactors.GetDetails
4+
import com.example.tamaskozmer.kotlinrxexample.model.repositories.DetailsRepository
5+
import com.example.tamaskozmer.kotlinrxexample.presentation.presenters.DetailPresenter
66
import dagger.Module
77
import dagger.Provides
8-
import javax.inject.Singleton
98

109
/**
1110
* Created by Tamas_Kozmer on 7/5/2017.
1211
*/
1312
@Module
14-
class DetailFragmentModule(val fragment: DetailsFragment) {
13+
class DetailFragmentModule() {
1514
@Provides
16-
@Singleton
17-
fun providePresenter(userRepository: UserRepository) = DetailPresenter(userRepository)
15+
fun provideGetDetails(detailsRepository: DetailsRepository) = GetDetails(detailsRepository)
16+
17+
@Provides
18+
fun providePresenter(getDetails: GetDetails) = DetailPresenter(getDetails)
1819
}
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
package com.example.tamaskozmer.kotlinrxexample.di.modules
22

3-
import com.example.tamaskozmer.kotlinrxexample.model.UserRepository
4-
import com.example.tamaskozmer.kotlinrxexample.presentation.UserListPresenter
5-
import com.example.tamaskozmer.kotlinrxexample.view.fragments.UserListFragment
3+
import com.example.tamaskozmer.kotlinrxexample.domain.interactors.GetUsers
4+
import com.example.tamaskozmer.kotlinrxexample.model.repositories.UserRepository
5+
import com.example.tamaskozmer.kotlinrxexample.presentation.presenters.UserListPresenter
66
import dagger.Module
77
import dagger.Provides
8-
import javax.inject.Singleton
98

109
/**
1110
* Created by Tamas_Kozmer on 7/4/2017.
1211
*/
1312
@Module
14-
class UserListFragmentModule(val fragment: UserListFragment) {
13+
class UserListFragmentModule() {
1514
@Provides
16-
@Singleton
17-
fun providePresenter(userRepository: UserRepository) = UserListPresenter(userRepository)
15+
fun provideGetUsers(userRepository: UserRepository) = GetUsers(userRepository)
16+
17+
@Provides
18+
fun providePresenter(getUsers: GetUsers) = UserListPresenter(getUsers)
1819
}

0 commit comments

Comments
 (0)