Skip to content

Commit

Permalink
Merge pull request #48 from fayaz07/dev
Browse files Browse the repository at this point in the history
good for mvp
  • Loading branch information
fayaz07 committed Jan 25, 2022
2 parents 7fd740e + 387d663 commit f38e8e1
Show file tree
Hide file tree
Showing 30 changed files with 291 additions and 93 deletions.
1 change: 0 additions & 1 deletion .idea/.name

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

## Screenshots

<img src="screenshots/Screenshot_1642326281.png" width="33%" height="33%"/> <img src="screenshots/Screenshot_1642326294.png" width="33%" height="33%"/> <img src="screenshots/Screenshot_1642327175.png" width="33%" height="33%"/> <img src="screenshots/Screenshot_1642327163.png" width="33%" height="33%"/> <img src="screenshots/Screenshot_1642327181.png" width="33%" height="33%"/> <img src="screenshots/Screenshot_1642327190.png" width="33%" height="33%"/> <img src="screenshots/Screenshot_1642327210.png" width="33%" height="33%"/> <img src="screenshots/Screenshot_1642327197.png" width="33%" height="33%"/>
<img src="screenshots/S1.png" width="33%" height="33%"/> <img src="screenshots/S2.png" width="33%" height="33%"/> <img src="screenshots/S3.png" width="33%" height="33%"/> <img src="screenshots/S4.png" width="33%" height="33%"/> <img src="screenshots/S5.png" width="33%" height="33%"/> <img src="screenshots/S6.png" width="33%" height="33%"/>

## Config

Expand Down
7 changes: 2 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ android {
compileSdk 31

defaultConfig {
applicationId "com.mohammadfayaz.news"
applicationId "in.mohammadfayaz.hn"
minSdk 21
targetSdk 31
versionCode 1
Expand Down Expand Up @@ -71,11 +71,8 @@ dependencies {
implementation(libs.bundles.mikepenz)
implementation(libs.bundles.androidxViews)
implementation(libs.bundles.androidxCache)
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'

kapt(libs.bundles.kapt)
kapt(libs.bundles.kapt)

testImplementation(libs.bundles.testDependencies)
kaptTest(libs.bundles.daggerTestsAnnotation)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.mohammadfayaz.hn.data.sources.local

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertWithMessage
import com.mohammadfayaz.hn.data.sources.local.source.IdsLocalSource
import com.mohammadfayaz.hn.di.DatabaseModule
import com.mohammadfayaz.hn.domain.models.StoryIdModel
import com.mohammadfayaz.hn.domain.models.StoryType
import com.mohammadfayaz.hn.utils.DbConstants.FAKE_DB
import com.mohammadfayaz.hn.utils.SourceConstants.FAKE_LOCAL_IDS
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.*
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import javax.inject.Inject
import javax.inject.Named

@HiltAndroidTest
@UninstallModules(DatabaseModule::class)
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class LocalIdsSourceTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)

@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()

@Inject
@Named(FAKE_DB)
lateinit var db: HackerNewsDB

@Inject
@Named(FAKE_LOCAL_IDS)
lateinit var idsLocalSource: IdsLocalSource

private val items = mutableListOf<StoryIdModel>()

@Before
fun init() {
hiltRule.inject()

items.add(StoryIdModel(1, StoryType.SHOW))
items.add(StoryIdModel(2, StoryType.ASK))
items.add(StoryIdModel(3, StoryType.TOP))
items.add(StoryIdModel(4, StoryType.SHOW))
items.add(StoryIdModel(5, StoryType.JOB))
}

private fun matchItemsCount(type: StoryType, count: Int) = runBlocking {
val items = idsLocalSource.getIdsByStoryType(type)
assertWithMessage("There should be exactly $count story ids of type ${type.string}")
.that(items.size)
.isEqualTo(count)
}

@Test
fun aThereShouldNotBeAnyItems() = runBlocking {
StoryType.values().asList().forEach {
matchItemsCount(it, 0)
}
}

@Test
fun bInsertFewStoryIds(): Unit = runBlocking {
idsLocalSource.putIds(items)

StoryType.values().asList().forEach { type ->
val selected = items.filter {
it.type == type
}
matchItemsCount(type, selected.count())
}
}

@After
fun tearDownDb() {
db.close()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.mohammadfayaz.hn.data.sources.local

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import com.mohammadfayaz.hn.data.sources.local.source.StoriesLocalSource
import com.mohammadfayaz.hn.di.DatabaseModule
import com.mohammadfayaz.hn.domain.models.StoryModel
import com.mohammadfayaz.hn.domain.models.StoryType
import com.mohammadfayaz.hn.utils.DbConstants
import com.mohammadfayaz.hn.utils.SourceConstants
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.*
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import javax.inject.Inject
import javax.inject.Named
import kotlin.random.Random

@HiltAndroidTest
@UninstallModules(DatabaseModule::class)
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class LocalStorySourceTest {

@get:Rule
var hiltRule = HiltAndroidRule(this)

@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()

@Inject
@Named(DbConstants.FAKE_DB)
lateinit var db: HackerNewsDB

@Inject
@Named(SourceConstants.FAKE_LOCAL_STORIES)
lateinit var storiesLocalSource: StoriesLocalSource

@Before
fun init() {
hiltRule.inject()
}

@Test
fun storiesTest() = runBlocking {
for (i in 0..6) {
val id = Random.nextInt(0, 100)
val randomTypeIndex = Random.nextInt(0, StoryType.values().size)
val type = StoryType.values()[randomTypeIndex]

storiesLocalSource.put(StoryModel(id, "story"), type)

val story = storiesLocalSource.getById(id)
assertThat(story).isNotEqualTo(null)
assertThat(story?.id).isEqualTo(id)
assertThat(story?.storyType).isEqualTo(type)
}
}

@After
fun tearDownDb() {
db.close()
}
}
68 changes: 0 additions & 68 deletions app/src/androidTest/java/com/mohammadfayaz/hn/db/DatabaseTest.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,44 @@ package com.mohammadfayaz.hn.di

import android.content.Context
import com.mohammadfayaz.hn.data.sources.local.HackerNewsDB
import com.mohammadfayaz.hn.data.sources.local.dao.CommentsDao
import com.mohammadfayaz.hn.data.sources.local.dao.FavouritesDao
import com.mohammadfayaz.hn.data.sources.local.dao.IdsDao
import com.mohammadfayaz.hn.data.sources.local.dao.StoryDao
import com.mohammadfayaz.hn.utils.DbConstants.FAKE_COMMENTS_DAO
import com.mohammadfayaz.hn.utils.DbConstants.FAKE_DB
import com.mohammadfayaz.hn.utils.DbConstants.FAKE_FAVOURITES_DAO
import com.mohammadfayaz.hn.utils.DbConstants.FAKE_IDS_DAO
import com.mohammadfayaz.hn.utils.DbConstants.FAKE_STORY_DAO
import dagger.Module
import dagger.Provides
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import javax.inject.Named
import javax.inject.Singleton

@Module
@TestInstallIn(components = [SingletonComponent::class], replaces = [DatabaseModule::class])
object FakeDatabaseModule {

@Provides
@Singleton
@Named("fake_db")
@Named(FAKE_DB)
fun provideDatabase(@ApplicationContext context: Context) =
HackerNewsDB.getInstance(context, true)

@Provides
@Named(FAKE_STORY_DAO)
fun provideStoryDao(@Named(FAKE_DB) db: HackerNewsDB): StoryDao = db.storyDao()

@Provides
@Named(FAKE_IDS_DAO)
fun provideIdsDao(@Named(FAKE_DB) db: HackerNewsDB): IdsDao = db.idsDao()

@Provides
@Named(FAKE_FAVOURITES_DAO)
fun provideFavouritesDao(@Named(FAKE_DB) db: HackerNewsDB): FavouritesDao = db.favouritesDao()

@Provides
@Named(FAKE_COMMENTS_DAO)
fun provideCommentsDao(@Named(FAKE_DB) db: HackerNewsDB): CommentsDao = db.commentsDao()
}
28 changes: 28 additions & 0 deletions app/src/androidTest/java/com/mohammadfayaz/hn/di/LocalSources.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.mohammadfayaz.hn.di

import com.mohammadfayaz.hn.data.sources.local.dao.IdsDao
import com.mohammadfayaz.hn.data.sources.local.dao.StoryDao
import com.mohammadfayaz.hn.data.sources.local.source.IdsLocalSource
import com.mohammadfayaz.hn.data.sources.local.source.StoriesLocalSource
import com.mohammadfayaz.hn.utils.DbConstants.FAKE_IDS_DAO
import com.mohammadfayaz.hn.utils.DbConstants.FAKE_STORY_DAO
import com.mohammadfayaz.hn.utils.SourceConstants.FAKE_LOCAL_IDS
import com.mohammadfayaz.hn.utils.SourceConstants.FAKE_LOCAL_STORIES
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Named

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

@Provides
@Named(FAKE_LOCAL_IDS)
fun provideIdsLocalSource(@Named(FAKE_IDS_DAO) idsDao: IdsDao) = IdsLocalSource(idsDao)

@Provides
@Named(FAKE_LOCAL_STORIES)
fun provideStoriesLocalSource(@Named(FAKE_STORY_DAO) dao: StoryDao) = StoriesLocalSource(dao)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.mohammadfayaz.hn.utils

object DbConstants {
const val FAKE_DB: String = "fake_db"
const val FAKE_STORY_DAO: String = "fake_story_dao"
const val FAKE_IDS_DAO: String = "fake_ids_dao"
const val FAKE_FAVOURITES_DAO: String = "fake_favourites_dao"
const val FAKE_COMMENTS_DAO: String = "fake_comments_dao"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.mohammadfayaz.hn.utils

object SourceConstants {
const val FAKE_LOCAL_IDS = "l_ids"
const val FAKE_LOCAL_STORIES = "l_stories"
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class CommentListAdapter :
binding.apply {
authorNameTextView.text = story.by
commentTextView.text = HtmlCompat.fromHtml(story.text, HtmlCompat.FROM_HTML_MODE_COMPACT)
timeTextView.text = AppDateTimeUtils.formatDate(story.time)
timeTextView.text = AppDateTimeUtils.whenDidThisHappen(story.time)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class StoryListAdapter constructor(private val listener: StoryItemClickListener)
scoreTextView.text = story.score.toString()
commentsTextView.text = story.kids?.size.toString()
storyTypeTextView.text = story.storyType.string.uppercase()
timeTextView.text = AppDateTimeUtils.formatDate(story.time)
timeTextView.text = AppDateTimeUtils.whenDidThisHappen(story.time)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class AskStoryDetailFragment : Fragment() {
} else {
descriptionTextView.gone()
}
timeTextView.text = AppDateTimeUtils.formatDate(storyItem.time)
timeTextView.text = AppDateTimeUtils.whenDidThisHappen(storyItem.time)
scoreTextView.text = storyItem.score.toString()
commentsTextView.text = storyItem.kids?.size.toString()

Expand Down
Loading

0 comments on commit f38e8e1

Please sign in to comment.