Skip to content

Commit d9e2130

Browse files
authored
Merge pull request #16 from patjackson52/feature/settings
settings screen with local persistance
2 parents b72b830 + 18c9051 commit d9e2130

File tree

41 files changed

+2268
-97
lines changed

Some content is hidden

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

41 files changed

+2268
-97
lines changed

app/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ android {
2323
minifyEnabled false
2424
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
2525
}
26+
debug {
27+
// MPP libraries don't currently get this resolution automatically
28+
matchingFallbacks = ['release']
29+
}
2630
}
2731
packagingOptions {
2832
exclude 'META-INF/*.kotlin_module'
@@ -55,6 +59,7 @@ dependencies {
5559
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
5660
implementation project(':common')
5761
implementation 'nl.dionsegijn:konfetti:1.1.2'
62+
implementation "com.russhwolf:multiplatform-settings:$multiplatformSettingsVersion"
5863

5964
kapt 'com.github.bumptech.glide:compiler:4.8.0'
6065
testImplementation 'junit:junit:4.12'

app/src/main/java/com/willowtreeapps/namegame/AndroidNavigator.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package com.willowtreeapps.namegame
33
import android.app.Activity
44
import android.app.Application
55
import android.os.Bundle
6+
import androidx.appcompat.app.AppCompatActivity
67
import androidx.navigation.findNavController
78
import com.willowtreeapps.common.middleware.Navigator
89
import com.willowtreeapps.common.middleware.Screen
10+
import com.willowtreeapps.namegame.store.SettingsDialogFragment
911

1012
/**
1113
* Android implementation of Navigator interface. This will load the appropriate Activity or Fragment
@@ -15,7 +17,7 @@ import com.willowtreeapps.common.middleware.Screen
1517
class AndroidNavigator : Navigator, Application.ActivityLifecycleCallbacks {
1618

1719

18-
private var currentActivity: Activity? = null
20+
private var currentActivity: AppCompatActivity? = null
1921

2022
//TODO consider using current screen & destination screen to determine routing & animation
2123
override fun goto(screen: Screen) {
@@ -25,6 +27,10 @@ class AndroidNavigator : Navigator, Application.ActivityLifecycleCallbacks {
2527
Screen.GAME_COMPLETE -> navController.navigate(R.id.action_questionScreen_to_resultsFragment)
2628
// Screen.START -> navController.navigate(R.id.startScreen)
2729
Screen.START -> navController.navigate(R.id.action_resultsFragment_to_startScreen)
30+
Screen.SETTINGS -> {
31+
val dialog = SettingsDialogFragment.newInstance()
32+
dialog.show(currentActivity!!.supportFragmentManager, "SettingsFragment")
33+
}
2834
else -> throw IllegalArgumentException("Screen $screen is not handled in AndroidNavigator")
2935
}
3036
}
@@ -36,7 +42,7 @@ class AndroidNavigator : Navigator, Application.ActivityLifecycleCallbacks {
3642
}
3743

3844
override fun onActivityStarted(activity: Activity?) {
39-
currentActivity = activity
45+
currentActivity = activity as AppCompatActivity?
4046
}
4147

4248
override fun onActivityDestroyed(activity: Activity?) {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.willowtreeapps.namegame.store
2+
3+
import android.app.Dialog
4+
import android.os.Bundle
5+
import android.view.LayoutInflater
6+
import android.view.View
7+
import android.view.ViewGroup
8+
import androidx.fragment.app.DialogFragment
9+
import com.willowtreeapps.common.SettingsViewState
10+
import com.willowtreeapps.common.ui.SettingsPresenter
11+
import com.willowtreeapps.common.ui.SettingsView
12+
import com.willowtreeapps.namegame.NameGameApp
13+
import com.willowtreeapps.namegame.R
14+
import kotlinx.android.synthetic.main.fragment_settings.*
15+
16+
class SettingsDialogFragment: DialogFragment(), SettingsView {
17+
18+
var presenter: SettingsPresenter? = null
19+
20+
companion object {
21+
fun newInstance(): SettingsDialogFragment {
22+
val f = SettingsDialogFragment()
23+
return f
24+
}
25+
}
26+
27+
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
28+
val dialog = super.onCreateDialog(savedInstanceState)
29+
return dialog
30+
}
31+
32+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
33+
return inflater.inflate(R.layout.fragment_settings, container, false)
34+
}
35+
36+
37+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
38+
super.onViewCreated(view, savedInstanceState)
39+
numberPicker.minValue = 1
40+
numberPicker.maxValue = 20
41+
numberPicker.setOnValueChangedListener { _, _, newVal ->
42+
presenter?.numQuestionsChanged(newVal)
43+
}
44+
btn_ok.setOnClickListener { dismiss() }
45+
}
46+
47+
override fun onResume() {
48+
super.onResume()
49+
presenter = NameGameApp.gameEngine().attachView(this) as SettingsPresenter
50+
}
51+
52+
override fun onPause() {
53+
super.onPause()
54+
NameGameApp.gameEngine().detachView(this)
55+
}
56+
57+
override fun showSettings(viewState: SettingsViewState) {
58+
numberPicker.value = viewState.numQuestions
59+
}
60+
}

app/src/main/java/com/willowtreeapps/namegame/store/StartFragment.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ class StartFragment : Fragment(), CoroutineScope, StartView {
3030
presenter?.startGame()
3131
}
3232
}
33+
btn_settings.setOnClickListener {
34+
activity?.runOnUiThread {
35+
presenter?.settingsTapped()
36+
}
37+
}
3338
}
3439

3540
override fun onResume() {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:layout_width="300dp"
6+
android:layout_height="400dp"
7+
android:minWidth="300dp"
8+
android:minHeight="400dp"
9+
>
10+
11+
<Button
12+
android:id="@+id/btn_ok"
13+
android:layout_width="wrap_content"
14+
android:layout_height="wrap_content"
15+
android:layout_marginBottom="16dp"
16+
android:text="Ok"
17+
app:layout_constraintBottom_toBottomOf="parent"
18+
app:layout_constraintEnd_toEndOf="parent"
19+
app:layout_constraintHorizontal_bias="0.5"
20+
app:layout_constraintStart_toStartOf="parent"
21+
app:layout_constraintTop_toBottomOf="@+id/txt_num_questions" />
22+
23+
<NumberPicker
24+
android:id="@+id/numberPicker"
25+
android:layout_width="wrap_content"
26+
android:layout_height="wrap_content"
27+
android:layout_marginStart="8dp"
28+
android:layout_marginTop="24dp"
29+
android:layout_marginEnd="8dp"
30+
app:layout_constraintEnd_toEndOf="parent"
31+
app:layout_constraintHorizontal_bias="0.5"
32+
app:layout_constraintStart_toStartOf="parent"
33+
app:layout_constraintTop_toTopOf="parent" />
34+
35+
<TextView
36+
android:id="@+id/txt_num_questions"
37+
android:layout_width="wrap_content"
38+
android:layout_height="wrap_content"
39+
android:layout_marginTop="8dp"
40+
android:text="Number of Questions"
41+
app:layout_constraintEnd_toEndOf="@+id/numberPicker"
42+
app:layout_constraintStart_toStartOf="@+id/numberPicker"
43+
app:layout_constraintTop_toBottomOf="@+id/numberPicker" />
44+
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/layout/fragment_start.xml

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@
2424
app:layout_constraintHorizontal_bias="0.5"
2525
app:layout_constraintStart_toStartOf="parent" />
2626

27+
<Button
28+
android:id="@+id/btn_settings"
29+
android:layout_width="wrap_content"
30+
android:layout_height="wrap_content"
31+
android:layout_marginStart="8dp"
32+
android:layout_marginTop="16dp"
33+
android:layout_marginEnd="8dp"
34+
android:layout_marginBottom="80dp"
35+
android:text="Settings"
36+
app:layout_constraintBottom_toBottomOf="parent"
37+
app:layout_constraintEnd_toEndOf="parent"
38+
app:layout_constraintHorizontal_bias="0.501"
39+
app:layout_constraintStart_toStartOf="parent"
40+
app:layout_constraintTop_toBottomOf="@+id/btn_start" />
41+
2742
<ImageView
2843
android:id="@+id/imageView2"
2944
android:layout_width="wrap_content"
@@ -57,18 +72,17 @@
5772
app:layout_constraintEnd_toEndOf="parent"
5873
app:layout_constraintHorizontal_bias="0.5"
5974
app:layout_constraintStart_toStartOf="parent"
60-
app:layout_constraintTop_toTopOf="parent"
61-
app:layout_constraintVertical_bias="0.9" />
75+
app:layout_constraintTop_toBottomOf="@+id/btn_settings"
76+
app:layout_constraintVertical_bias="0.39" />
6277

6378
<TextView
6479
android:id="@+id/txt_error"
6580
android:layout_width="wrap_content"
6681
android:layout_height="wrap_content"
67-
android:layout_marginTop="24dp"
82+
android:layout_marginTop="20dp"
6883
android:text="TextView"
6984
app:layout_constraintEnd_toEndOf="parent"
70-
app:layout_constraintHorizontal_bias="0.5"
7185
app:layout_constraintStart_toStartOf="parent"
72-
app:layout_constraintTop_toBottomOf="@+id/btn_start" />
86+
app:layout_constraintTop_toBottomOf="@+id/btn_settings" />
7387

7488
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/test/java/com/willowtreeapps/namegame/ReducersTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,16 @@ class ReducersTest {
125125
assertEquals(10, final.questionClock)
126126
}
127127

128+
@Test
129+
fun `ChangeNumQuestionsAction should update AppState`() {
130+
val initial = generateInitialTestState()
131+
132+
val final = reducer(initial, Actions.ChangeNumQuestionsSettingsAction(10))
133+
134+
assertEquals(10, final.settings.numQuestions)
135+
136+
}
137+
128138
private fun generateInitialTestState(): AppState {
129139
val initialState = reducer(AppState(), Actions.FetchingProfilesSuccessAction(MockRepositoryFactory.getValidResponse()))
130140
return initialState

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ allprojects {
2525
mavenCentral()
2626
maven { url "https://jitpack.io" }
2727
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
28+
maven { url "https://dl.bintray.com/russhwolf/multiplatform-settings" }
2829
maven { url "https://kotlin.bintray.com/kotlinx" }
2930
maven { url "https://dl.bintray.com/kotlin/ktor" }
3031
maven { url "https://dl.bintray.com/soywiz/soywiz" }
@@ -47,6 +48,7 @@ ext {
4748
ktorVersion = '1.1.3'
4849
serializationVersion = '0.10.0'
4950
klockVersion = '1.3.1'
51+
multiplatformSettingsVersion = '0.2'
5052

5153
networkDependencies = [
5254
retrofit : "com.squareup.retrofit2:retrofit:${retrofitVersion}",

common/build.gradle

Lines changed: 26 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,38 @@
1-
//plugins {
2-
// id("org.jetbrains.kotlin.native.cocoapods")
3-
//}
41
repositories {
52
maven { url "https://dl.bintray.com/soywiz/soywiz" }
63
}
74

8-
apply plugin: 'kotlin-multiplatform'
95
apply plugin: 'com.android.library'
6+
apply plugin: 'kotlin-multiplatform'
107
apply plugin: 'kotlinx-serialization'
118

12-
13-
14-
15-
169
kotlin {
17-
18-
android {
19-
compilations.all {
20-
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) { task ->
21-
kotlinOptions {
22-
freeCompilerArgs = ['-Xuse-experimental=kotlin.Experimental']
23-
}
10+
targets {
11+
// fromPreset(presets.jvm, 'jvm')
12+
fromPreset(presets.android, 'android')
13+
final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
14+
? presets.iosArm64 : presets.iosX64
15+
16+
fromPreset(iOSTarget, 'ios') {
17+
binaries {
18+
framework('common')
2419
}
2520
}
26-
publishLibraryVariants("release")
27-
}
28-
29-
// iosArm64("ios")
30-
// iosX64("iosSim")
31-
//
32-
// targets.all { target ->
33-
// if (target.name == 'android') return // Android handles this differently
34-
// compilations.all { compilation ->
35-
// tasks[compileKotlinTaskName].kotlinOptions {
36-
// freeCompilerArgs = ['-Xuse-experimental=kotlin.Experimental']
21+
// fromPreset(presets.iosArm64, 'ios') {
22+
// binaries {
23+
// framework('common')
3724
// }
3825
// }
39-
// }
40-
//
41-
targets {
42-
fromPreset(presets.jvm, 'jvm')
4326

44-
// fromPreset(presets.android, 'androidMain')
45-
46-
// Change to `presets.iosArm64` to deploy the app to iPhone
47-
// Change to `presets.iosX64` to deploy the app to iPhone
48-
fromPreset(presets.iosX64, 'ios') {
49-
// fromPreset(presets.iosArm64, 'ios') {
50-
compilations.main.outputKinds('FRAMEWORK')
51-
}
5227
}
5328
sourceSets {
5429
commonMain {
5530
dependencies {
56-
implementation 'org.jetbrains.kotlin:kotlin-stdlib'
31+
api 'org.jetbrains.kotlin:kotlin-stdlib'
5732
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutinesVersion"
5833
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serializationVersion"
5934
implementation "io.ktor:ktor-client-logging:$ktorVersion"
35+
implementation "com.russhwolf:multiplatform-settings:$multiplatformSettingsVersion"
6036

6137

6238
implementation "io.ktor:ktor-client-core:$ktorVersion"
@@ -72,7 +48,7 @@ kotlin {
7248
}
7349
androidMain {
7450
dependencies {
75-
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
51+
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
7652
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
7753

7854
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion"
@@ -112,18 +88,20 @@ kotlin {
11288
implementation "io.ktor:ktor-client-json-native:$ktorVersion"
11389
}
11490
}
115-
116-
iosSimMain.dependsOn iosMain
117-
iosSimTest.dependsOn iosTest
11891
}
11992
}
12093

12194
android {
122-
compileSdkVersion 27
95+
compileSdkVersion 28
12396
defaultConfig {
12497
minSdkVersion 15
12598
}
12699
buildTypes {
100+
//This is for MultiplatformSettings
101+
debug {
102+
// MPP libraries don't currently get this resolution automatically
103+
matchingFallbacks = ['release']
104+
}
127105
release {
128106
minifyEnabled true
129107
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
@@ -135,16 +113,16 @@ android {
135113
// Don't run this task directly,
136114
// Xcode runs this task itself during its build process when we configure it.
137115
// make sure all Gradle infrastructure exists (gradle.wrapper, gradlew)
138-
//and gradlw is in executable mode (chmod +x gradlew)
139-
116+
//and gradlew is in executable mode (chmod +x gradlew)
140117
task packForXCode(type: Sync) {
141118
final File frameworkDir = new File(buildDir, "xcode-frameworks")
142119
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
120+
final def framework = kotlin.targets.ios.binaries.getFramework("common", mode)
143121

144122
inputs.property "mode", mode
145-
dependsOn kotlin.targets.ios.compilations.main.linkTaskName("FRAMEWORK", mode)
123+
dependsOn framework.linkTask
146124

147-
from { kotlin.targets.ios.compilations.main.getBinary("FRAMEWORK", mode).parentFile }
125+
from { framework.outputFile.parentFile }
148126
into frameworkDir
149127

150128
doLast {

0 commit comments

Comments
 (0)