Skip to content

Commit

Permalink
Sandwiched housekeeping (rxjava2, store-kotlin 3 beta, android 26, no…
Browse files Browse the repository at this point in the history
… firebase and whatnot) (#87)
  • Loading branch information
stoyicker authored Aug 30, 2017
1 parent 04f61ba commit aa4cac2
Show file tree
Hide file tree
Showing 48 changed files with 432 additions and 480 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,3 @@ build
captures
dependencyReport
staticAnalysisReport/
*.keystore
google-services.json
master-slave-clean-store-firebase-crashreporting-private-key.json
15 changes: 3 additions & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ android:
components:
- tools
- platform-tools
- android-25
- build-tools-25.0.3
- android-26
- build-tools-26.0.1
- extra-android-m2repository
- extra-google-m2repository
branches:
Expand All @@ -19,15 +19,8 @@ env:
- TASK="./gradlew :app:clean :app:build :app:check :app:dokka --stacktrace"
- TASK="./gradlew :domain:clean :domain:build :domain:check :domain:dokka --stacktrace"
- TASK="./gradlew :data:clean :data:build :data:check :data:dokka --stacktrace"
- TASK="./gradlew :util-android:build :util-android:check :util-android:dokka :util-android-test:build :util-android-test:check :util-android-test:dokka --stacktrace"
before_install:
- openssl aes-256-cbc -K $encrypted_90d766e4084d_key -iv $encrypted_90d766e4084d_iv
-in secrets.tar.enc -out secrets.tar -d
- tar xvf secrets.tar
- mv google-services-debug.json app/src/debug/google-services.json
- mv google-services-release.json app/src/release/google-services.json
- TASK="./gradlew :util-android:build :util-android:check :util-android:dokka :util-android-test:build :util-android-test:check :util-android-test:dokka --stacktrace"
before_script:
- printf "org.gradle.daemon=false\nFirebaseServiceAccountFilePath=" > gradle.properties
- export ARTIFACT_VERSION=$(git rev-list --count HEAD)
- |
if [ "$TRAVIS_PULL_REQUEST" != "false" ] && [ "$TRAVIS_BRANCH" = "master" ]; then
Expand All @@ -41,8 +34,6 @@ after_success:
if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_BRANCH" = "master" ] && [[ "$TRAVIS_JOB_NUMBER" == *.1 ]]; then
echo "CI on master succeded. Executing release tasks..."
./ci/release.sh
echo "Uploading mapping to Firebase..."
./gradlew :app:firebaseUploadReleaseProguardMapping
fi
notifications:
email:
Expand Down
24 changes: 11 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
# Setup for contributions

Once cloned, just setup the hooks:

```shell
$<project-dir>: ./hooks/setup
```

# Build instructions

* Make sure you're passing a property to gradle (like through `gradle.properties`) keyed
`FirebaseServiceAccountFilePath`. Its value is irrelevant.
* Place the Firebase service account file, named
`master-slave-clean-store-firebase-crashreporting-private-key.json`, under the project root.
* Put your `google-services.json` files under the `debug` and `release` folders of the `app` module.
`./gradlew assemble` (or something like `gradlew.bat assemble` on Windows I guess).
You can also get an APK from the [Releases](https://github.com/stoyicker/master-slave-clean-store/releases)
tab, courtesy of Travis.

# Architecture
This is a reactive app: it runs by reacting to user interactions. Here
Expand All @@ -38,3 +28,11 @@ code documentation generation tool for Kotlin, similar to what Javadoc is for Ja
Unit and integration tests are written using [Spek](https://spekframework.org), the specification
framework for Kotlin. Run them with the `test` Gradle task in each module.
Instrumentation tests are only present in the `app` module and can be run using the `cAT` task.

# Setup for contributions

Once cloned, just setup the hooks:

```shell
$<project-dir>: ./hooks/setup (or whatever equivalent if on Windows).
```
17 changes: 6 additions & 11 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@ apply plugin: 'kotlin-kapt'
apply plugin: 'org.jmailen.kotlinter'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'org.jetbrains.dokka-android'
apply plugin: 'com.google.firebase.firebase-crash'

android {
compileSdkVersion rootProject.ext.androidCompileSdkVersion
buildToolsVersion rootProject.ext.androidBuildToolsVersion
signingConfigs {
release {
storeFile new File("alias.keystore")
storePassword("keystorePwd")
keyAlias("alias")
keyPassword("keyPwd")
storeFile new File("dummy12.keystore")
storePassword "dummy12"
keyAlias "dummy12"
keyPassword "dummy12"
}
}
buildTypes {
debug {
applicationIdSuffix ".debug" // Do not change as Firebase depends on this
applicationIdSuffix ".debug"
}
release {
signingConfig signingConfigs.release
Expand Down Expand Up @@ -61,6 +60,7 @@ android {
}
repositories {
jcenter()
maven { url "https://maven.google.com" }
}
dependencies {
compile project(':data')
Expand All @@ -79,8 +79,3 @@ dependencies {
compile rootProject.ext.compileAppDependencies
testCompile rootProject.ext.testCompileDependencies
}

apply plugin: 'com.google.gms.google-services'

setProperty("FirebaseServiceAccountFilePath", rootProject.rootDir.absolutePath + "/" +
rootProject.ext.firebaseServiceAccountFileName)
20 changes: 5 additions & 15 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
-verbose
-dontobfuscate
-optimizations !code/allocation/variable
-keep class sun.misc.Unsafe { *; }
-dontwarn okhttp3.**
-dontnote okhttp3.**
-dontwarn okio.**
-dontnote okio.**
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
-dontwarn retrofit2.**
-keepattributes Signature
-keepattributes Exceptions
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
-dontnote rx.internal.util.PlatformDependent
-dontwarn org.junit.**
-dontwarn org.hamcrest.**
-dontwarn com.squareup.javawriter.**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import android.view.View
import app.common.PresentationPost
import app.detail.PostDetailActivity
import domain.entity.Post
import io.reactivex.observers.DisposableSingleObserver
import io.reactivex.subjects.ReplaySubject
import org.hamcrest.Matchers.allOf
import org.jorge.ms.app.R
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import rx.Subscriber
import rx.subjects.ReplaySubject
import util.android.test.BinaryIdlingResource
import util.android.test.matchers.withIndex
import java.net.UnknownHostException
Expand Down Expand Up @@ -66,7 +66,7 @@ internal class TopGamingActivityInstrumentation {
@Test
fun activityIsShown() {
SUBJECT = ReplaySubject.create()
SUBJECT.onCompleted()
SUBJECT.onComplete()
launchActivity()
onView(withId(android.R.id.content)).check { view, _ ->
assertEquals(View.VISIBLE, view.visibility, "Window visibility was not VISIBLE") }
Expand All @@ -75,7 +75,7 @@ internal class TopGamingActivityInstrumentation {
@Test
fun toolbarIsCompletelyShownOnOpening() {
SUBJECT = ReplaySubject.create()
SUBJECT.onCompleted()
SUBJECT.onComplete()
launchActivity()
val completelyDisplayedMatcher = matches(isCompletelyDisplayed())
onView(isAssignableFrom(Toolbar::class.java)).check(completelyDisplayedMatcher)
Expand All @@ -85,7 +85,7 @@ internal class TopGamingActivityInstrumentation {
@Test
fun goingBackPausesApp() {
SUBJECT = ReplaySubject.create()
SUBJECT.onCompleted()
SUBJECT.onComplete()
launchActivity()
expectedException.expect(NoActivityResumedException::class.java)
expectedException.expectMessage("Pressed back and killed the app")
Expand All @@ -95,8 +95,14 @@ internal class TopGamingActivityInstrumentation {
@Test
fun onLoadItemsAreShown() {
SUBJECT = ReplaySubject.create()
SUBJECT.onNext(Post("0", "Bananas title", "r/bananas", 879, "tb", "link"))
SUBJECT.onCompleted()
SUBJECT.onNext(setOf(Post(
"0",
"Bananas title",
"r/bananas",
879,
"tb",
"link")))
SUBJECT.onComplete()
launchActivity()
onView(withId(R.id.progress)).check { view, _ ->
assertEquals(View.GONE, view.visibility, "Progress visibility was not GONE") }
Expand All @@ -122,10 +128,16 @@ internal class TopGamingActivityInstrumentation {

@Test
fun onItemClickDetailIntentIsLaunched() {
val srcPost = Post("0", "Bananas title", "r/bananas", 879, "tb", "link")
val srcPost = Post(
"0",
"Bananas title",
"r/bananas",
879,
"tb",
"link")
SUBJECT = ReplaySubject.create()
SUBJECT.onNext(srcPost)
SUBJECT.onCompleted()
SUBJECT.onNext(setOf(srcPost))
SUBJECT.onComplete()
launchActivity()
Intents.init()
intending(anyIntent()).respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, null))
Expand All @@ -146,28 +158,23 @@ internal class TopGamingActivityInstrumentation {

companion object {
private lateinit var IDLING_RESOURCE: BinaryIdlingResource
internal lateinit var SUBJECT: ReplaySubject<Post>
internal val SUBSCRIBER_GENERATOR: (TopGamingAllTimePostsCoordinator) -> Subscriber<Post> =
internal lateinit var SUBJECT: ReplaySubject<Iterable<Post>>
internal val SUBSCRIBER_GENERATOR:
(TopGamingAllTimePostsCoordinator) -> DisposableSingleObserver<Iterable<Post>> =
{
object : Subscriber<Post>() {
private val realSubscriberDelegate = PageLoadSubscriber(it)

object : PageLoadSubscriber(it) {
override fun onStart() {
realSubscriberDelegate.onStart()
super.onStart()
IDLING_RESOURCE.setIdleState(false)
}

override fun onNext(post: Post) {
realSubscriberDelegate.onNext(post)
}

override fun onError(throwable: Throwable) {
realSubscriberDelegate.onError(throwable)
override fun onSuccess(payload: Iterable<Post>) {
super.onSuccess(payload)
IDLING_RESOURCE.setIdleState(true)
}

override fun onCompleted() {
realSubscriberDelegate.onCompleted()
override fun onError(throwable: Throwable) {
super.onError(throwable)
IDLING_RESOURCE.setIdleState(true)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import app.gaming.TopGamingActivityInstrumentation.Companion.SUBSCRIBER_GENERATO
import dagger.Component
import dagger.Module
import dagger.Provides
import domain.entity.Post
import domain.exec.PostExecutionThread
import domain.interactor.TopGamingAllTimePostsUseCase
import io.reactivex.Single
import javax.inject.Singleton

/**
Expand Down Expand Up @@ -60,7 +62,7 @@ internal class TopGamingAllTimePostsFeatureInstrumentationModule(
object : TopGamingAllTimePostsUseCase.Factory {
override fun newFetch(page: Int, postExecutionThread: PostExecutionThread) =
object : TopGamingAllTimePostsUseCase(page, UIPostExecutionThread) {
override fun buildUseCaseObservable() = SUBJECT
override fun buildUseCase(): Single<Iterable<Post>> = SUBJECT.singleOrError()
}

override fun newGet(page: Int, postExecutionThread: PostExecutionThread) =
Expand Down
Binary file removed app/src/debug/google-services.json.enc
Binary file not shown.
12 changes: 6 additions & 6 deletions app/src/main/kotlin/app/common/PresentationEntityMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ internal class PresentationEntityMapper {
* Maps a domain post to a presentation post.
*/
fun transform(post: Post) = PresentationPost(
post.id,
HtmlCompat.fromHtml(post.title).toString(),
post.subreddit,
post.score,
post.thumbnailLink,
post.url)
id = post.id,
title = HtmlCompat.fromHtml(post.title).toString(),
subreddit = post.subreddit,
score = post.score,
thumbnailLink = post.thumbnailLink,
url = post.url)
}
3 changes: 1 addition & 2 deletions app/src/main/kotlin/app/common/PresentationPost.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package app.common

import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import app.share.ShareFeature
Expand All @@ -14,7 +13,7 @@ internal data class PresentationPost(
val title: String,
val subreddit: String,
val score: Int,
val thumbnailLink: String,
val thumbnailLink: String?,
val url: String) : Parcelable, ShareFeature.Shareable {
override fun hashCode() = id.hashCode()

Expand Down
4 changes: 3 additions & 1 deletion app/src/main/kotlin/app/common/UIPostExecutionThread.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package app.common

import domain.exec.PostExecutionThread
import io.reactivex.Scheduler
import io.reactivex.android.schedulers.AndroidSchedulers

object UIPostExecutionThread : PostExecutionThread {
override fun provideScheduler(): rx.Scheduler = rx.android.schedulers.AndroidSchedulers.mainThread()
override fun scheduler(): Scheduler = AndroidSchedulers.mainThread()
}
Loading

0 comments on commit aa4cac2

Please sign in to comment.