Skip to content

Commit 324493f

Browse files
Rory KellyRoryKelly
Rory Kelly
authored andcommitted
adding github actions
tidying up example adding error checking removing code required to complete test basic test
1 parent 01b9889 commit 324493f

File tree

84 files changed

+1694
-1820
lines changed

Some content is hidden

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

84 files changed

+1694
-1820
lines changed

.github/workflows/android-feature.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Android Feature
2+
3+
on:
4+
push:
5+
branches:
6+
- '*'
7+
- '!master'
8+
- '!release*'
9+
10+
jobs:
11+
12+
test:
13+
name: Unit Tests
14+
runs-on: ubuntu-18.04
15+
16+
steps:
17+
- uses: actions/checkout@v1
18+
- name: set up JDK 1.8
19+
uses: actions/setup-java@v1
20+
with:
21+
java-version: 1.8
22+
- name: Unit tests
23+
run: bash ./gradlew test --stacktrace

.github/workflows/android-master.yml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Android Master
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- 'master'
7+
push:
8+
branches:
9+
- 'master'
10+
11+
jobs:
12+
13+
test:
14+
name: Unit Tests
15+
runs-on: ubuntu-18.04
16+
17+
steps:
18+
- uses: actions/checkout@v1
19+
- name: Set up JDK 1.8
20+
uses: actions/setup-java@v1
21+
with:
22+
java-version: 1.8
23+
- name: Run Unit tests
24+
run: bash ./gradlew test --stacktrace
25+
apk:
26+
name: upload
27+
runs-on: ubuntu-18.04
28+
29+
steps:
30+
- uses: actions/checkout@v1
31+
- name: Set up JDK 1.8
32+
uses: actions/setup-java@v1
33+
with:
34+
java-version: 1.8

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
# splash

app/build.gradle

+48-8
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ apply plugin: 'kotlin-android-extensions'
66

77
android {
88
compileSdkVersion 29
9-
buildToolsVersion "29.0.2"
9+
buildToolsVersion "29.0.3"
1010
defaultConfig {
11-
applicationId "com.puddlealley.splash"
11+
applicationId "com.rockspin.flux"
1212
minSdkVersion 23
1313
targetSdkVersion 29
1414
versionCode 1
@@ -21,18 +21,58 @@ android {
2121
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
2222
}
2323
}
24+
compileOptions {
25+
sourceCompatibility = 1.8
26+
targetCompatibility = 1.8
27+
}
28+
kotlinOptions {
29+
jvmTarget = "1.8"
30+
}
2431
}
2532

2633
dependencies {
2734
implementation fileTree(dir: 'libs', include: ['*.jar'])
28-
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
35+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
2936
implementation 'androidx.appcompat:appcompat:1.1.0'
30-
implementation 'androidx.core:core-ktx:1.1.0'
31-
implementation 'com.google.android.material:material:1.0.0'
32-
implementation 'androidx.annotation:annotation:1.1.0'
37+
implementation 'androidx.core:core-ktx:1.2.0'
3338
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
34-
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
39+
40+
// dependant projects
41+
implementation project(":splash")
42+
43+
// Koin for Kotlin-android
44+
implementation 'org.koin:koin-android:2.0.1'
45+
// Koin View Model
46+
implementation 'org.koin:koin-android-viewmodel:2.0.1'
47+
48+
// RxJava
49+
def rxJavaVersion = '2.2.12'
50+
def rxKotlinVersion = '2.4.0'
51+
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
52+
implementation "io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion"
53+
implementation 'com.jakewharton.rx2:replaying-share-kotlin:2.2.0'
54+
implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0'
55+
56+
// Auto dispose
57+
def autoDisposeVersion = "1.4.0"
58+
implementation "com.uber.autodispose:autodispose:$autoDisposeVersion"
59+
implementation "com.uber.autodispose:autodispose-android:$autoDisposeVersion"
60+
implementation "com.uber.autodispose:autodispose-android-archcomponents:$autoDisposeVersion"
61+
62+
// Timber
63+
implementation 'com.jakewharton.timber:timber:4.7.1'
64+
65+
// navigation
66+
implementation 'androidx.navigation:navigation-fragment:2.2.1'
67+
implementation 'androidx.navigation:navigation-ui:2.2.1'
68+
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
69+
implementation 'androidx.navigation:navigation-ui-ktx:2.2.1'
70+
71+
implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.1'
72+
3573
testImplementation 'junit:junit:4.12'
36-
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
74+
androidTestImplementation 'androidx.test:runner:1.2.0'
3775
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
76+
implementation 'com.google.android.material:material:1.1.0'
77+
3878
}

app/src/androidTest/java/com/puddlealley/splash/ExampleInstrumentedTest.kt renamed to app/src/androidTest/java/com/puddlealley/flux/ExampleInstrumentedTest.kt

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
package com.puddlealley.splash
1+
package com.puddlealley.flux
22

3-
import androidx.test.platform.app.InstrumentationRegistry
4-
import androidx.test.ext.junit.runners.AndroidJUnit4
3+
import androidx.test.InstrumentationRegistry
4+
import androidx.test.runner.AndroidJUnit4
55

66
import org.junit.Test
77
import org.junit.runner.RunWith
@@ -18,7 +18,7 @@ class ExampleInstrumentedTest {
1818
@Test
1919
fun useAppContext() {
2020
// Context of the app under test.
21-
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22-
assertEquals("com.puddlealley.splash", appContext.packageName)
21+
val appContext = InstrumentationRegistry.getTargetContext()
22+
assertEquals("com.rockspin.flux", appContext.packageName)
2323
}
2424
}

app/src/main/AndroidManifest.xml

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
package="com.puddlealley.splash">
3+
package="com.puddlealley.flux">
44

55
<application
6+
android:name="com.puddlealley.flux.App"
67
android:allowBackup="true"
78
android:icon="@mipmap/ic_launcher"
89
android:label="@string/app_name"
910
android:roundIcon="@mipmap/ic_launcher_round"
1011
android:supportsRtl="true"
1112
android:theme="@style/AppTheme">
12-
<activity
13-
android:name=".ui.login.LoginActivity"
14-
android:label="@string/app_name">
13+
<activity android:name="com.puddlealley.flux.ui.SecretCaveActivity" >
1514
<intent-filter>
1615
<action android:name="android.intent.action.MAIN" />
17-
1816
<category android:name="android.intent.category.LAUNCHER" />
1917
</intent-filter>
2018
</activity>
19+
<activity android:name="com.puddlealley.flux.ui.LoginActivity">
20+
21+
</activity>
2122
</application>
2223

2324
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.puddlealley.flux
2+
3+
import android.app.Application
4+
import com.puddlealley.flux.store.AppStore
5+
import com.puddlealley.splash.android.connect
6+
import org.koin.android.ext.android.inject
7+
import timber.log.Timber
8+
9+
class App : Application() {
10+
11+
val appStore: AppStore by inject()
12+
13+
override fun onCreate() {
14+
super.onCreate()
15+
createKoin(this)
16+
17+
Timber.plant(Timber.DebugTree())
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.puddlealley.flux
2+
3+
import android.content.Context
4+
import com.puddlealley.flux.service.Server
5+
import com.puddlealley.flux.service.ApiRequests
6+
import com.puddlealley.flux.store.AppStore
7+
import org.koin.android.ext.koin.androidContext
8+
import org.koin.core.context.startKoin
9+
import org.koin.dsl.module
10+
11+
/**
12+
* Create the di dependency tree for this app using koin
13+
*/
14+
fun createKoin(context: Context) = startKoin {
15+
modules(
16+
module {
17+
androidContext(context)
18+
single { AppStore(get()) }
19+
single { Server() }
20+
factory { ApiRequests(get()) }
21+
}
22+
)
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.puddlealley.flux.service
2+
3+
import com.puddlealley.splash.core.Result
4+
import io.reactivex.Observable
5+
import timber.log.Timber
6+
7+
sealed class LoginResult : Result {
8+
object Loading : LoginResult()
9+
data class Error(val error: String) : LoginResult()
10+
data class Success(val user: User) : LoginResult()
11+
}
12+
13+
sealed class CodeVerificationResult : Result {
14+
object Loading : CodeVerificationResult()
15+
data class Error(val error: String) : CodeVerificationResult()
16+
data class Success(val correct: Boolean) : CodeVerificationResult()
17+
}
18+
19+
class ApiRequests(private val server: Server) {
20+
21+
fun login(email :String, password: String): Observable<LoginResult> =
22+
server.login(email, password)
23+
.map<LoginResult> {
24+
LoginResult.Success(it)
25+
}.onErrorReturn {
26+
Timber.e(it,"error loading User")
27+
LoginResult.Error(it.message.orEmpty())
28+
}
29+
.toObservable()
30+
.startWith(LoginResult.Loading)
31+
32+
/**
33+
* Verifies the secret code.
34+
*/
35+
fun codeVerification(secretCode: String) : Observable<CodeVerificationResult> =
36+
server.validateSecretCode(secretCode)
37+
.map<CodeVerificationResult> {
38+
CodeVerificationResult.Success(it)
39+
}.onErrorReturn {
40+
Timber.e(it,"error verifying code")
41+
CodeVerificationResult.Error(it.message.orEmpty())
42+
}
43+
.toObservable()
44+
.startWith(CodeVerificationResult.Loading)
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.puddlealley.flux.service
2+
3+
import io.reactivex.Single
4+
import java.util.*
5+
import java.util.concurrent.TimeUnit
6+
7+
8+
/**
9+
* Represents basic calls to the server i.e a Retrofit service.
10+
*/
11+
class Server {
12+
13+
/**
14+
* Mock call that loads a user
15+
*/
16+
fun loadUser(userId: String): Single<User> {
17+
return Single.just(User(id = userId, name = "Rory")).delay(3, TimeUnit.SECONDS)
18+
}
19+
20+
fun login(email: String, password: String): Single<User> {
21+
return Single.just(User(id = "userId", name = "Rory")).delay(3, TimeUnit.SECONDS)
22+
}
23+
24+
/**
25+
* Mock call that validates a secret code
26+
*/
27+
fun validateSecretCode(secretCode: String) : Single<Boolean> =
28+
Single.just(secretCode.toLowerCase(Locale.ROOT) == "abbabba").delay(3, TimeUnit.SECONDS)
29+
30+
}
31+
32+
data class User(val id: String, val name: String)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.puddlealley.flux.store
2+
3+
import com.puddlealley.flux.service.ApiRequests
4+
import com.puddlealley.flux.store.device.SecretCaveState
5+
import com.puddlealley.flux.store.device.secretCarvEpic
6+
import com.puddlealley.flux.store.device.secretCaveReducer
7+
import com.puddlealley.flux.store.login.LoginState
8+
import com.puddlealley.flux.store.login.loginEpics
9+
import com.puddlealley.flux.store.login.loginReducer
10+
import com.puddlealley.splash.core.*
11+
12+
/**
13+
* A store that holds and updates the application state.
14+
*/
15+
class AppStore(apiRequests: ApiRequests) : DiStore<AppState>(
16+
appReducer,
17+
combineEpics(
18+
loginEpics(apiRequests),
19+
secretCarvEpic(apiRequests)
20+
).toMiddleware(),
21+
AppState()
22+
)
23+
24+
/**
25+
* The state that represents all data in the application.
26+
*/
27+
data class AppState(
28+
val loginState: LoginState = LoginState(),
29+
val secretCaveState: SecretCaveState = SecretCaveState()
30+
) : State
31+
32+
/**
33+
* An app reducer updates the app state based on dispatched actions.
34+
*/
35+
val appReducer = createReducer<AppState> { action ->
36+
copy(
37+
loginState = loginReducer(loginState, action),
38+
secretCaveState = secretCaveReducer(secretCaveState, action)
39+
)
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.puddlealley.flux.store.device
2+
3+
import com.puddlealley.flux.service.ApiRequests
4+
import com.puddlealley.flux.store.AppState
5+
import com.puddlealley.splash.core.createEpic
6+
import io.reactivex.Observable
7+
import io.reactivex.rxkotlin.ofType
8+
9+
fun secretCarvEpic(apiRequests: ApiRequests) =
10+
createEpic<AppState> { (actions) ->
11+
// this is a clue.
12+
val codeEntered = actions.ofType<SecretCaveEvents.CodeEntered>()
13+
14+
Observable.empty()
15+
}

0 commit comments

Comments
 (0)