Skip to content

Commit 53f4966

Browse files
author
Patrick Jackson
committed
initial commit
0 parents  commit 53f4966

File tree

176 files changed

+8118
-0
lines changed

Some content is hidden

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

176 files changed

+8118
-0
lines changed

.circleci/config.yml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
version: 2.1
2+
3+
references:
4+
5+
android_dependencies: &android_dependencies
6+
run:
7+
name: Download Android Dependencies
8+
command: |
9+
./gradlew androidDependencies
10+
11+
workspace_root: &workspace_root
12+
/tmp/workspace
13+
14+
attach_builds: &attach_builds
15+
attach_workspace:
16+
at: *workspace_root
17+
18+
executors:
19+
android_executor:
20+
docker:
21+
- image: circleci/android:api-28
22+
environment:
23+
TERM: dumb
24+
_JAVA_OPTIONS: '-Xms1024m -Xmx2048m'
25+
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xms1024m -Xmx2048m -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.compiler.execution.strategy="in-process" -Dorg.gradle.daemon=false'
26+
ANDROID_HOME: /opt/android/sdk
27+
ADB_INSTALL_TIMEOUT: 10
28+
29+
30+
jobs:
31+
build_android:
32+
executor: android_executor
33+
steps:
34+
- checkout
35+
- *android_dependencies
36+
- *attach_builds
37+
- run:
38+
name: Build and Run JVM Unit Tests
39+
command: ./gradlew build
40+
- store_artifacts:
41+
path: android/build/outputs/reports/
42+
- store_test_results:
43+
path: android/build/test-results
44+
- run:
45+
name: Move APKs to workspace
46+
command: |
47+
mkdir -p /tmp/workspace/apk
48+
cp -r android/build/outputs/apk/* /tmp/workspace/apk/
49+
- persist_to_workspace:
50+
root: *workspace_root
51+
paths:
52+
- apk
53+
54+
build_ios:
55+
macos:
56+
xcode: "10.1"
57+
58+
steps:
59+
- checkout
60+
- *attach_builds
61+
- run:
62+
name: Build xcode-framework
63+
command: ./gradlew common:build
64+
- run:
65+
name: Move frameworks to workspace
66+
command: |
67+
mkdir -p /tmp/workspace/xcode-frameworks
68+
cp -r common/build/xcode-frameworks/* /tmp/workspace/xcode-frameworks
69+
- persist_to_workspace:
70+
root: *workspace_root
71+
paths:
72+
- xcode-frameworks
73+
74+
75+
76+
workflows:
77+
build_all_platforms:
78+
jobs:
79+
- build_android:
80+
filters:
81+
branches:
82+
only:
83+
- /^feature.*/
84+
- /^bugfix.*/
85+
- master
86+
# - build_ios:
87+
# requires:
88+
# - build_android

.gitignore

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea/libraries
5+
/.idea/modules.xml
6+
/.idea/workspace.xml
7+
/.idea
8+
/iOS/NameGame/.idea/
9+
.DS_Store
10+
/build
11+
/common/build
12+
/captures
13+
.externalNativeBuild
14+
15+
# Created by https://www.gitignore.io/api/swift,xcode
16+
17+
### Swift ###
18+
# Xcode
19+
#
20+
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
21+
22+
## Build generated
23+
build/
24+
DerivedData/
25+
26+
27+
## Various settings
28+
*.pbxuser
29+
!default.pbxuser
30+
*.mode1v3
31+
!default.mode1v3
32+
*.mode2v3
33+
!default.mode2v3
34+
*.perspectivev3
35+
!default.perspectivev3
36+
xcuserdata/
37+
38+
## Other
39+
*.moved-aside
40+
*.xccheckout
41+
*.xcscmblueprint
42+
43+
## Obj-C/Swift specific
44+
*.hmap
45+
*.ipa
46+
*.dSYM.zip
47+
*.dSYM
48+
49+
## Playgrounds
50+
timeline.xctimeline
51+
playground.xcworkspace
52+
53+
# Swift Package Manager
54+
#
55+
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
56+
# Packages/
57+
# Package.pins
58+
.build/
59+
60+
# CocoaPods - Refactored to standalone file
61+
62+
# Carthage - Refactored to standalone file
63+
64+
# fastlane
65+
#
66+
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
67+
# screenshots whenever they are needed.
68+
# For more information about the recommended setup visit:
69+
# https://docs.fastlane.tools/best-practices/source-control/#source-control
70+
71+
fastlane/report.xml
72+
fastlane/Preview.html
73+
fastlane/screenshots
74+
fastlane/test_output
75+
76+
### Xcode ###
77+
# Xcode
78+
#
79+
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
80+
81+
## Build generated
82+
83+
## Various settings
84+
85+
## Other
86+
87+
88+
# End of https://www.gitignore.io/api/swift,xcode

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Open Library
2+
3+
__Android Build & Tests__
4+
5+
6+
[![CircleCI](https://circleci.com/gh/patjackson52/NameGameKotlinMpp.svg?style=svg)](https://circleci.com/gh/patjackson52/NameGameKotlinMpp)
7+
8+
__iOS Build & Tests____
9+
10+
[![Bitrise](https://app.bitrise.io/app/3eaf4fa6c0750504/status.svg?token=N7jdGFn6dvfLcuKZaBMW1g)](https://app.bitrise.io/app/3eaf4fa6c0750504#/builds)
11+
12+
A Kotlin multiplatform (Android/iOS) Library. The app utilizes the following:
13+
* [Ktor](https://ktor.io/clients/http-client.html) for networking
14+
* [Kotlinx Serialization](https://github.com/Kotlin/kotlinx.serialization)
15+
* [Multiplatform Settings](https://github.com/russhwolf/multiplatform-settings)
16+
17+
18+
## Android
19+
Building and testing the Android App can be completed with:
20+
```./gradlew build```
21+
or install with:
22+
```./gradle androidInstall```
23+
or opened and ran in Android Studio
24+
25+
26+
## iOS
27+
The iOS workspace in `/iOS/NameGame` can be open and ran from xCode or AppCode. A run script has been added to the build phase that will compile the common code into a framework which can be used for the project.
28+
29+
30+
## Architecture
31+
32+
A `GameEngine` object holds the state of the app in a redux store and provides a methods for views (fragments/UIViewControllers) to "attach". The `GameEngine` is initialized in the Application class on Android, and the AppDelegate on iOS. Because this `GameEngine` and the store is created at the application scope, the application state survives between ViewControllers/Fragments and rotation. Each view must attach/detach from the GameEngine when it is visible. `GameEngine.attachView(view)` returns the appropriate presenter for the view.
33+
34+
`BaseNameGameViewFragment` & `BaseNameGameViewController` handle attaching/detaching the presenter at the appropriate lifecycle methods. Each Fragment/ViewController extends from these.
35+
36+
An MVP arch is used with a redux store as the 'Model'. This approach allows maximum reuse of code and a simple contract for the platforms to satisfy. Presenters send `ViewStates` (simple data classes with fields needed to render UI) to the View interface. The View implementation has a reference to the presenter, and calls methods on the presetner for user interaction. This creates a unidirectional dataflow:
37+
38+
User interaction -> Dispatch Action -> new state (reduce) -> view rendered by presenter
39+
40+
## "Dumb Views"
41+
Views in this arch are truely 'dumb' - they should contain nearly no logic. They are responsible for rendering the view based on the `ViewState` given to them by the presenter. They are implemented for each platform and utilize native UI SDKs and libs for each platform. Android uses Fragments and iOS uses UIViewControllers.
42+
43+
## Presenters
44+
45+
![](https://storage.googleapis.com/treestorage/ui_f_of_state.png)
46+
47+
48+
Presenters give a layer of control between subscribing to the new state and the View. Views subscribing directly to the store results in code and logic in the View which must be duplicated on each platform. Presenters are singleton objects that contain no state other than the previous AppState. This works while presenters are for an entire screen, which for this app is the case. Another approach will be needed if multiple instances of a given presenter are needed. The presenter is responsible for rendering the view given the AppState or the delta in AppState. The Reduks library has a port of Reselect, which allows calling code only when a property changes. Presenters pass `ViewState` to View methods. All transformations from Appstate -> ViewState are extension functions in `Transformations.kt`.
49+
50+
51+
52+
![arch diagram](https://storage.googleapis.com/treestorage/Kotlin%20MPP%20Demo%20Arch.png)
53+
54+
## Async Actions
55+
In redux world there are many ways to handle creation of async actions. `Thunks` have been used in this app. `NetworkThunks` both use coroutines to launch concurrent operations that dispatch actions.
56+
57+
## Navigation
58+
In this app, Navigation is considered a side effect of the AppState. The `NavigationMiddleware` handles changing screens based on dispatched actions. The `NavigationMiddleware` takes an implementation of `Navigator` which is implemeneted for each platform.
59+
60+

android/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

android/build.gradle

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
2+
apply plugin: 'com.android.application'
3+
4+
apply plugin: 'kotlin-android'
5+
6+
apply plugin: 'kotlin-android-extensions'
7+
8+
apply plugin: 'kotlinx-serialization'
9+
10+
apply plugin: 'kotlin-kapt'
11+
12+
13+
android {
14+
compileOptions {
15+
sourceCompatibility JavaVersion.VERSION_1_8
16+
targetCompatibility JavaVersion.VERSION_1_8
17+
}
18+
compileSdkVersion 28
19+
defaultConfig {
20+
applicationId "com.jackson.openlibrary"
21+
minSdkVersion 26
22+
targetSdkVersion 28
23+
versionCode 1
24+
versionName "1.0"
25+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
26+
}
27+
buildTypes {
28+
release {
29+
minifyEnabled false
30+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
31+
}
32+
debug {
33+
// MPP libraries don't currently get this resolution automatically
34+
matchingFallbacks = ['release']
35+
}
36+
}
37+
// signingConfigs {
38+
// debug {
39+
// storeFile file("./debug.keystore")
40+
// storePassword 'android'
41+
// keyAlias 'android'
42+
// keyPassword 'android'
43+
// }
44+
// }
45+
packagingOptions {
46+
exclude 'META-INF/*.kotlin_module'
47+
}
48+
tasks.lint.enabled = false
49+
}
50+
51+
52+
dependencies {
53+
implementation fileTree(dir: 'libs', include: ['*.jar'])
54+
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
55+
implementation 'androidx.appcompat:appcompat:1.0.2'
56+
implementation 'com.google.android.material:material:1.1.0-alpha07'
57+
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
58+
implementation "android.arch.navigation:navigation-fragment-ktx:$ktxVersion"
59+
implementation "android.arch.navigation:navigation-ui-ktx:$ktxVersion"
60+
61+
implementation "com.facebook.stetho:stetho:$stethoVersion"
62+
implementation "com.facebook.stetho:stetho-okhttp3:$stethoVersion"
63+
implementation "com.github.bumptech.glide:glide:$glideVersion"
64+
implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion"
65+
66+
67+
implementation "io.ktor:ktor-client-okhttp:$ktorVersion"
68+
implementation "io.ktor:ktor-client-json-jvm:$ktorVersion"
69+
implementation group: 'org.slf4j', name: 'slf4j-android', version: '1.7.26'
70+
71+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
72+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
73+
implementation project(':common')
74+
implementation 'nl.dionsegijn:konfetti:1.1.2'
75+
implementation "com.russhwolf:multiplatform-settings:$multiplatformSettingsVersion"
76+
77+
kapt 'com.github.bumptech.glide:compiler:4.8.0'
78+
testImplementation 'junit:junit:4.12'
79+
androidTestImplementation 'androidx.test:runner:1.1.1'
80+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
81+
82+
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
83+
implementation 'com.google.firebase:firebase-core:16.0.8'
84+
implementation 'com.google.firebase:firebase-auth:16.2.1'
85+
implementation 'com.firebaseui:firebase-ui-auth:4.3.2'
86+
debugImplementation 'com.willowtreeapps.hyperion:hyperion-core:0.9.27'
87+
releaseImplementation 'com.willowtreeapps.hyperion:hyperion-core-no-op:0.9.27'
88+
debugImplementation 'com.willowtreeapps.hyperion:hyperion-measurement:0.9.27'
89+
debugImplementation 'com.willowtreeapps.hyperion:hyperion-shared-preferences:0.9.27'
90+
debugImplementation 'com.willowtreeapps.hyperion:hyperion-geiger-counter:0.9.27'
91+
debugImplementation 'com.willowtreeapps.hyperion:hyperion-build-config:0.9.27'
92+
debugImplementation 'com.willowtreeapps.hyperion:hyperion-attr:0.9.27'
93+
}

android/debug.keystore

2.25 KB
Binary file not shown.

android/google-services.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"project_info": {
3+
"project_number": "1060360359056",
4+
"firebase_url": "https://namegamekotlin.firebaseio.com",
5+
"project_id": "namegamekotlin",
6+
"storage_bucket": "namegamekotlin.appspot.com"
7+
},
8+
"client": [
9+
{
10+
"client_info": {
11+
"mobilesdk_app_id": "1:1060360359056:android:e41adf9f4239973b",
12+
"android_client_info": {
13+
"package_name": "com.willowtreeapps.namegame"
14+
}
15+
},
16+
"oauth_client": [
17+
{
18+
"client_id": "1060360359056-jg12tcoe1i1pi66u90ed0fths0o6p54q.apps.googleusercontent.com",
19+
"client_type": 1,
20+
"android_info": {
21+
"package_name": "com.willowtreeapps.namegame",
22+
"certificate_hash": "d92149ce680e55fcc9c0c4e12732362dad84a718"
23+
}
24+
},
25+
{
26+
"client_id": "1060360359056-99i0vklp7js0vpahpetks2njas0srsfd.apps.googleusercontent.com",
27+
"client_type": 3
28+
}
29+
],
30+
"api_key": [
31+
{
32+
"current_key": "AIzaSyA--LTJY3hBLRCyvTDwnqmCTKssXDkl0jo"
33+
}
34+
],
35+
"services": {
36+
"appinvite_service": {
37+
"other_platform_oauth_client": [
38+
{
39+
"client_id": "1060360359056-99i0vklp7js0vpahpetks2njas0srsfd.apps.googleusercontent.com",
40+
"client_type": 3
41+
}
42+
]
43+
}
44+
}
45+
}
46+
],
47+
"configuration_version": "1"
48+
}

0 commit comments

Comments
 (0)