Skip to content

Commit 06499de

Browse files
author
Patrick Jackson
committed
tweaks to speech. working on iOS
1 parent 6ae0cd4 commit 06499de

File tree

15 files changed

+134
-98
lines changed

15 files changed

+134
-98
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class AndroidNavigator : Navigator, Application.ActivityLifecycleCallbacks {
2929
when (screen) {
3030
Screen.QUESTION -> navController.navigate(R.id.action_startScreen_to_questionScreen)
3131
Screen.GAME_COMPLETE -> navController.navigate(R.id.action_questionScreen_to_resultsFragment)
32-
// Screen.START -> navController.navigate(R.id.startScreen)
33-
Screen.START -> navController.navigate(R.id.action_resultsFragment_to_startScreen)
32+
Screen.START -> navController.navigate(R.id.startScreen)
33+
// Screen.START -> navController.navigate(R.id.action_resultsFragment_to_startScreen)
3434
Screen.SETTINGS -> {
3535
val dialog = SettingsDialogFragment.newInstance()
3636
dialog.show(currentActivity!!.supportFragmentManager, "SettingsFragment")

android/src/main/java/com/willowtreeapps/namegame/MainActivity.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ class MainActivity : AppCompatActivity() {
3434
override fun onSupportNavigateUp(): Boolean = Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp()
3535

3636
override fun onBackPressed() {
37-
// val navHostFragment =
38-
// this.supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
39-
// val currentFragment = navHostFragment?.childFragmentManager?.fragments?.get(0)
40-
// if (currentFragment is IOnBackPressed)
41-
// (currentFragment as IOnBackPressed).onBackPressed()
37+
val navHostFragment =
38+
this.supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
39+
val currentFragment = navHostFragment?.childFragmentManager?.fragments?.get(0)
40+
if (currentFragment is IOnBackPressed)
41+
(currentFragment as IOnBackPressed).onBackPressed()
4242
super.onBackPressed()
4343
}
4444

android/src/main/java/com/willowtreeapps/namegame/Utils.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import android.animation.Animator
44
import android.animation.AnimatorListenerAdapter
55
import android.animation.AnimatorSet
66
import android.content.res.Resources
7-
import android.graphics.drawable.Drawable
87
import com.bumptech.glide.load.DataSource
98
import com.bumptech.glide.load.engine.GlideException
109
import com.bumptech.glide.request.RequestListener
1110
import com.bumptech.glide.request.target.Target
11+
import com.willowtreeapps.common.util.TimeUtil
12+
import kotlin.math.abs
13+
import kotlin.random.Random
1214

1315
val Int.dp: Int
1416
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
@@ -40,4 +42,7 @@ fun <T: Any> GlideRequest<T>.onComplete(after: () -> Unit): GlideRequest<T> {
4042
}
4143

4244
})
43-
}
45+
}
46+
47+
48+

android/src/main/java/com/willowtreeapps/namegame/store/QuestionFragment.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class QuestionFragment : BaseNameGameViewFragment<QuestionPresenter>(), Question
6666
}
6767

6868
override fun onError(error: Int) {
69+
Logger.d("Error with speech recognizer: code =$error")
6970
}
7071

7172
override fun onResults(results: Bundle) {

common/src/commonMain/kotlin/com/willowtreeapps/common/AppState.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ data class AppState(val isLoadingItems: Boolean = false,
3030
else
3131
null
3232

33-
fun getItem(id: ItemId?) = items.find { it.id == id }
34-
3533
fun currentQuestionItem() = currentQuestion!!.choices.find { it.id == currentQuestion!!.itemId }!!
3634

3735
fun isGameComplete(): Boolean = currentQuestionIndex >= questions.size || (currentQuestionIndex == questions.size - 1 && questions[currentQuestionIndex].status != Question.Status.UNANSWERED)

common/src/commonMain/kotlin/com/willowtreeapps/common/GameEngine.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ class GameEngine(navigator: Navigator,
3737
}
3838

3939
init {
40-
appStore.dispatch(Actions.LoadAllSettingsAction())
40+
CoroutineScope(uiContext).launch {
41+
appStore.dispatch(Actions.LoadAllSettingsAction())
42+
}
4143
}
4244

4345
fun dispatch(action: Any) {

common/src/commonMain/kotlin/com/willowtreeapps/common/NetworkThunks.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import kotlin.coroutines.CoroutineContext
1010
* actions. This allows dispatching a loading, success, and failure state.
1111
*/
1212
class NetworkThunks(private val networkContext: CoroutineContext,
13-
val store: Store<AppState>) : CoroutineScope {
13+
val engine: GameEngine) : CoroutineScope {
1414
private val job = Job()
1515
override val coroutineContext: CoroutineContext
1616
get() = networkContext + job
@@ -26,14 +26,14 @@ class NetworkThunks(private val networkContext: CoroutineContext,
2626
val repo = repoForCategory(categoryId)
2727
Logger.d("Fetching StoreInfo and Feed")
2828
launch {
29-
store.dispatch(Actions.FetchingItemsStartedAction())
30-
val result = repo.fetchItems()
29+
engine.dispatch(Actions.FetchingItemsStartedAction())
30+
val result = repo.fetchItems(state.settings.numQuestions)
3131
if (result.isSuccessful) {
3232
Logger.d("Success")
33-
store.dispatch(Actions.FetchingItemsSuccessAction(result.response!!))
33+
engine.dispatch(Actions.FetchingItemsSuccessAction(result.response!!))
3434
} else {
3535
Logger.d("Failure")
36-
store.dispatch(Actions.FetchingItemsFailedAction(result.message!!))
36+
engine.dispatch(Actions.FetchingItemsFailedAction(result.message!!))
3737
}
3838
}
3939
}

common/src/commonMain/kotlin/com/willowtreeapps/common/Reducers.kt

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@ package com.willowtreeapps.common
22

33
import com.willowtreeapps.common.Actions.*
44
import com.willowtreeapps.common.util.NO_MATCH
5-
import com.willowtreeapps.common.util.TimeUtil
65
import com.willowtreeapps.common.util.match
7-
import kotlin.math.abs
8-
import kotlin.random.Random
9-
import kotlin.reflect.KProperty0
10-
import kotlin.reflect.KProperty1
116

127
/**
138
* Reducers and functions used by reducers are in this file. Functions must be pure functions without
@@ -17,11 +12,10 @@ fun reducer(state: AppState, action: Any): AppState =
1712
when (action) {
1813
is FetchingItemsStartedAction -> state.copy(isLoadingItems = true)
1914
is FetchingItemsSuccessAction -> {
20-
val questions = generateQuestions(action.itemsHolder.items, state.settings.numQuestions)
2115
state.copy(isLoadingItems = false,
2216
items = action.itemsHolder.items,
2317
questionTitle = action.itemsHolder.questionTitle,
24-
questions = questions)
18+
questions = action.itemsHolder.questions)
2519
}
2620
is FetchingItemsFailedAction -> state.copy(isLoadingItems = false, errorLoadingItems = true, errorMsg = action.message)
2721
is NamePickedAction -> {
@@ -74,43 +68,3 @@ fun reducer(state: AppState, action: Any): AppState =
7468
else -> throw AssertionError("Action ${action::class.simpleName} not handled")
7569
}
7670

77-
fun generateQuestions(items: List<Item>, n: Int): List<Question> =
78-
items.filter { it.imageUrl != "" }
79-
.takeRandomDistinct(n)
80-
.map { item ->
81-
val choiceList = items.takeRandomDistinct(3).toMutableList()
82-
choiceList.add(abs(random.nextInt() % 4), item)
83-
84-
Question(itemId = item.id, choices = choiceList
85-
.map { it })
86-
}
87-
88-
private val random = Random(TimeUtil.systemTimeMs())
89-
90-
/**
91-
* Take N distict elements from the list. Distinct is determined by a comparision of objects in the
92-
* list.
93-
* @throws IllegalStateException when n > number of distinct elements.
94-
* @return New immutable list containing N random elements from the given List.
95-
*/
96-
fun <T> List<T>.takeRandomDistinct(n: Int): List<T> {
97-
val newList = mutableListOf<T>()
98-
val uniqueItems = this.distinctBy { it }
99-
if (uniqueItems.size < n) {
100-
throw IllegalStateException("Unable to get $n unique random elements from given list.")
101-
}
102-
while (newList.size < n) {
103-
val randomIndex = abs(random.nextInt() % uniqueItems.size)
104-
val next = uniqueItems[randomIndex]
105-
if (newList.contains(next)) {
106-
continue
107-
} else {
108-
newList.add(next)
109-
}
110-
}
111-
return newList.toList()
112-
}
113-
114-
115-
fun <T> List<T>.takeRandom(): T =
116-
this[random.nextInt(this.size - 1)]

common/src/commonMain/kotlin/com/willowtreeapps/common/repo/ItemRepository.kt

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,39 @@
11
package com.willowtreeapps.common.repo
22

3-
import com.willowtreeapps.common.Item
4-
import com.willowtreeapps.common.PlatformDispatcher
5-
import com.willowtreeapps.common.ItemId
6-
import com.willowtreeapps.common.takeRandom
3+
import com.willowtreeapps.common.*
4+
import com.willowtreeapps.common.util.random
5+
import com.willowtreeapps.common.util.takeRandom
6+
import com.willowtreeapps.common.util.takeRandomDistinct
7+
import kotlin.math.abs
78

89
/**
910
* interface for providing list of items for the game. Items are generic representation.
1011
* This may be used for any data source to generate questions.
1112
*/
1213
interface ItemRepository {
13-
suspend fun fetchItems(): GatewayResponse<ItemsHolder, GenericError>
14+
suspend fun fetchItems(numQuestions: Int): GatewayResponse<ItemsHolder, GenericError>
1415
}
1516

1617
data class ItemsHolder(val questionTitle: String,
1718
val items: List<Item>,
19+
val questions: List<Question>,
1820
val gameResultResponses: GameResultResponses = GameResultResponses())
1921

2022
class ProfileItemRepository(val repo: ProfilesRepository = KtorProfilesRepository()) : ItemRepository {
21-
override suspend fun fetchItems(): GatewayResponse<ItemsHolder, GenericError> {
23+
24+
override suspend fun fetchItems(numQuestions: Int): GatewayResponse<ItemsHolder, GenericError> {
2225
val results = repo.profiles()
2326
return if (results.isSuccessful) {
27+
val items = results.response?.map {
28+
Item(id = ItemId(it.id),
29+
firstName = it.firstName,
30+
lastName = it.lastName,
31+
imageUrl = "https:${it.headshot.url}")
32+
}!!
33+
2434
val itemHolder = ItemsHolder(questionTitle = "Who is this?",
25-
items = results.response?.map { Item(id = ItemId(it.id), firstName = it.firstName, lastName = it.lastName, imageUrl = "https:${it.headshot.url}") }!!)
35+
items = items,
36+
questions = generateQuestions(items, numQuestions))
2637
GatewayResponse.createSuccess(itemHolder, 200, "")
2738
} else {
2839
GatewayResponse.createError(GenericError("Error"), 500, "")
@@ -32,15 +43,24 @@ class ProfileItemRepository(val repo: ProfilesRepository = KtorProfilesRepositor
3243
}
3344

3445
class DogItemRepository(val repo: KtorDogsRepository = KtorDogsRepository(PlatformDispatcher)) : ItemRepository {
35-
override suspend fun fetchItems(): GatewayResponse<ItemsHolder, GenericError> {
46+
47+
override suspend fun fetchItems(numQuestions: Int): GatewayResponse<ItemsHolder, GenericError> {
3648
val results = repo.dogs()
3749
return if (results.isSuccessful) {
50+
val items = results.response?.map {
51+
if (it.subBreed != null && it.subBreed.isNotEmpty()) {
52+
Item(id = ItemId(it.breed + "_" + it.subBreed),
53+
firstName = it.subBreed, lastName = it.breed,
54+
imageUrl = it.imageUrl)
55+
} else {
56+
Item(id = ItemId(it.breed + "_" + it.subBreed),
57+
firstName = it.breed, lastName = it.subBreed ?: "",
58+
imageUrl = it.imageUrl)
59+
}
60+
}!!
3861
val itemsHolder = ItemsHolder(questionTitle = "Name the breed",
39-
items = results.response?.map {
40-
Item(id = ItemId(it.breed + "_" + it.subBreed),
41-
firstName = it.breed, lastName = it.subBreed ?: "",
42-
imageUrl = it.imageUrl)
43-
}!!)
62+
items = items,
63+
questions = generateQuestions(items, numQuestions))
4464
GatewayResponse.createSuccess(itemsHolder, 200, "")
4565
} else {
4666
GatewayResponse.createError(GenericError("Error"), 500, "")
@@ -50,14 +70,17 @@ class DogItemRepository(val repo: KtorDogsRepository = KtorDogsRepository(Platfo
5070
}
5171

5272
class CatItemRepository(val repo: KtorCatsRepository = KtorCatsRepository(PlatformDispatcher)) : ItemRepository {
53-
override suspend fun fetchItems(): GatewayResponse<ItemsHolder, GenericError> {
73+
74+
override suspend fun fetchItems(numQuestions: Int): GatewayResponse<ItemsHolder, GenericError> {
5475
val results = repo.allBreeds()
76+
val items = results.response?.map {
77+
Item(id = ItemId(it.id),
78+
firstName = it.breed, lastName = "",
79+
imageUrl = it.imageUrl)
80+
}!!
5581
val itemsHolder = ItemsHolder(questionTitle = "Name the breed",
56-
items = results.response?.map {
57-
Item(id = ItemId(it.id),
58-
firstName = it.breed, lastName = "",
59-
imageUrl = it.imageUrl)
60-
}!!)
82+
items = items,
83+
questions = generateQuestions(items, numQuestions))
6184
return if (results.isSuccessful) {
6285
GatewayResponse.createSuccess(itemsHolder, 200, "")
6386
} else {
@@ -102,3 +125,15 @@ val zeroScoreResponses = listOf(
102125
"Did you even try??",
103126
"Not even one correct?? \nWow...want to try again?",
104127
"Even my cat gets a few right....")
128+
129+
fun generateQuestions(items: List<Item>, n: Int): List<Question> =
130+
items.filter { it.imageUrl != "" }
131+
.takeRandomDistinct(n)
132+
.map { item ->
133+
val choiceList = items.takeRandomDistinct(3).toMutableList()
134+
choiceList.add(abs(random.nextInt() % 4), item)
135+
136+
Question(itemId = item.id, choices = choiceList
137+
.map { it })
138+
}
139+

common/src/commonMain/kotlin/com/willowtreeapps/common/ui/PresenterFactory.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import kotlin.coroutines.CoroutineContext
1313
internal class PresenterFactory(private val gameEngine: GameEngine, networkContext: CoroutineContext) : StoreSubscriber<AppState> {
1414

1515
private val timerThunks = TimerThunks(networkContext, gameEngine)
16-
private val networkThunks = NetworkThunks(networkContext, gameEngine.appStore)
16+
private val networkThunks = NetworkThunks(networkContext, gameEngine)
1717
// private val presenters = mutableSetOf<Presenter>()
1818
private var subscription: StoreSubscription? = null
1919

0 commit comments

Comments
 (0)