Skip to content

Commit 51dbb88

Browse files
committed
refactor presenters and add Timer. iOS still WIP
1 parent 4d2a0f4 commit 51dbb88

File tree

31 files changed

+523
-201
lines changed

31 files changed

+523
-201
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class NameGameApp : Application() {
1212
super.onCreate()
1313
instance = this
1414
val navigator = AndroidNavigator()
15-
gameEngine = GameEngine(navigator, this, Dispatchers.IO)
15+
gameEngine = GameEngine(navigator, this, Dispatchers.IO, Dispatchers.Main)
1616

1717
registerActivityLifecycleCallbacks(navigator)
1818
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class GameResultsFragment : Fragment(), CoroutineScope, GameResultsView, MainAct
3333

3434
private fun initViews() {
3535
btn_start_over.setOnClickListener {
36-
NameGameApp.gameEngine().detachView(presenter!!)
36+
NameGameApp.gameEngine().detachView(this)
3737
presenter?.startOverTapped()
3838
}
3939
}
@@ -45,7 +45,7 @@ class GameResultsFragment : Fragment(), CoroutineScope, GameResultsView, MainAct
4545

4646
override fun onPause() {
4747
super.onPause()
48-
NameGameApp.gameEngine().detachView(presenter!!)
48+
NameGameApp.gameEngine().detachView(this)
4949
}
5050

5151
override fun showResults(viewState: GameResultsViewState) {

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

Lines changed: 87 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
1515
import com.willowtreeapps.common.QuestionViewState
1616
import com.willowtreeapps.common.ui.QuestionView
1717
import kotlinx.android.synthetic.main.fragment_question.*
18-
import kotlinx.coroutines.CoroutineScope
19-
import kotlinx.coroutines.Dispatchers
2018
import nl.dionsegijn.konfetti.models.Shape
2119
import nl.dionsegijn.konfetti.models.Size
22-
import java.lang.IllegalStateException
2320
import kotlin.coroutines.CoroutineContext
2421
import android.widget.Button
2522
import androidx.annotation.ColorRes
23+
import androidx.core.content.res.ResourcesCompat
24+
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
2625
import com.willowtreeapps.common.ui.QuestionPresenter
2726
import com.willowtreeapps.namegame.*
27+
import kotlinx.coroutines.*
2828

2929

3030
class QuestionFragment : Fragment(), CoroutineScope, QuestionView, MainActivity.IOnBackPressed {
3131

32-
private var presenter: QuestionPresenter? = null
32+
private lateinit var presenter: QuestionPresenter
3333

3434
override val coroutineContext: CoroutineContext
3535
get() = Dispatchers.Main
@@ -51,26 +51,26 @@ class QuestionFragment : Fragment(), CoroutineScope, QuestionView, MainActivity.
5151

5252
override fun onPause() {
5353
super.onPause()
54-
NameGameApp.gameEngine().detachView(presenter!!)
54+
NameGameApp.gameEngine().detachView(this)
5555
}
5656

5757
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
5858
initViews()
5959
}
6060

6161
private fun initViews() {
62-
button1.setOnClickListener { presenter?.namePicked(button1.text.toString()) }
63-
button2.setOnClickListener { presenter?.namePicked(button2.text.toString()) }
64-
button3.setOnClickListener { presenter?.namePicked(button3.text.toString()) }
65-
button4.setOnClickListener { presenter?.namePicked(button4.text.toString()) }
66-
btn_next.setOnClickListener { presenter?.nextTapped() }
67-
btn_end_game.setOnClickListener { presenter?.endGameTapped() }
62+
button1.setOnClickListener { presenter.namePicked(button1.text.toString()) }
63+
button2.setOnClickListener { presenter.namePicked(button2.text.toString()) }
64+
button3.setOnClickListener { presenter.namePicked(button3.text.toString()) }
65+
button4.setOnClickListener { presenter.namePicked(button4.text.toString()) }
66+
btn_next.setOnClickListener { presenter.nextTapped() }
67+
btn_end_game.setOnClickListener { presenter.endGameTapped() }
6868
}
6969

7070

7171
override fun onBackPressed(): Boolean {
72-
NameGameApp.gameEngine().detachView(presenter!!)
73-
presenter?.onBackPressed()
72+
NameGameApp.gameEngine().detachView(this)
73+
presenter.onBackPressed()
7474
return false
7575
}
7676

@@ -82,25 +82,16 @@ class QuestionFragment : Fragment(), CoroutineScope, QuestionView, MainActivity.
8282
setProfileAndFadeIn(viewState)
8383
}
8484
}
85-
}
86-
87-
88-
override fun showCorrectAnswer(viewState: QuestionViewState) {
89-
hideButtonsShowNext(viewState, false)
90-
celebrate()
91-
}
9285

93-
override fun showWrongAnswer(viewState: QuestionViewState) {
94-
wrongShakeAnimation(viewState) { hideButtonsShowNext(viewState, false) }
9586
}
9687

97-
override fun showCorrectAnswerEndGame(viewState: QuestionViewState) {
98-
hideButtonsShowNext(viewState, true)
88+
override fun showCorrectAnswer(viewState: QuestionViewState, isEndGame: Boolean) {
89+
hideButtonsShowNext(viewState, isEndGame)
9990
celebrate()
10091
}
10192

102-
override fun showWrongAnswerEndGame(viewState: QuestionViewState) {
103-
wrongShakeAnimation(viewState) { hideButtonsShowNext(viewState, true) }
93+
override fun showWrongAnswer(viewState: QuestionViewState, isEndGame: Boolean) {
94+
wrongShakeAnimation(viewState) { hideButtonsShowNext(viewState, isEndGame) }
10495
}
10596

10697
private val showButtonsAnimatorSet by lazy {
@@ -115,19 +106,23 @@ class QuestionFragment : Fragment(), CoroutineScope, QuestionView, MainActivity.
115106

116107
private fun wrongShakeAnimation(viewState: QuestionViewState, after: () -> Unit) {
117108
val selectedBtn = getBtnByNum(viewState.selectedBtnNum)
118-
selectedBtn.isSelected = true
119-
val animScaleX = ObjectAnimator.ofFloat(selectedBtn, View.SCALE_X, 3F, 0.5F, 1F)
120-
val animScaleY = ObjectAnimator.ofFloat(selectedBtn, View.SCALE_Y, 3F, 0.5F, 1F)
121-
val upSet = AnimatorSet()
122-
upSet.playTogether(animScaleX, animScaleY)
123-
upSet.interpolator = BounceInterpolator()
124-
upSet.duration = 500
125-
upSet.addListener(object : AnimatorListenerAdapter() {
126-
override fun onAnimationEnd(animation: Animator?) {
127-
after()
128-
}
129-
})
130-
upSet.start()
109+
if (selectedBtn != null) {
110+
selectedBtn.isSelected = true
111+
val animScaleX = ObjectAnimator.ofFloat(selectedBtn, View.SCALE_X, 3F, 0.5F, 1F)
112+
val animScaleY = ObjectAnimator.ofFloat(selectedBtn, View.SCALE_Y, 3F, 0.5F, 1F)
113+
val upSet = AnimatorSet()
114+
upSet.playTogether(animScaleX, animScaleY)
115+
upSet.interpolator = BounceInterpolator()
116+
upSet.duration = 500
117+
upSet.addListener(object : AnimatorListenerAdapter() {
118+
override fun onAnimationEnd(animation: Animator?) {
119+
after()
120+
}
121+
})
122+
upSet.start()
123+
} else {
124+
after()
125+
}
131126
}
132127

133128
/**
@@ -157,8 +152,8 @@ class QuestionFragment : Fragment(), CoroutineScope, QuestionView, MainActivity.
157152
set
158153
}
159154
}
160-
restoreX = correctBtn.x
161-
restoreY = correctBtn.y
155+
restoreX = correctBtn?.x
156+
restoreY = correctBtn?.y
162157
lastCorrectBtn = correctBtn
163158
lastSelectedBtn = selectedBtn
164159

@@ -170,15 +165,15 @@ class QuestionFragment : Fragment(), CoroutineScope, QuestionView, MainActivity.
170165
val set = AnimatorSet()
171166
set.playTogether(anim1, anim2, anim3, anim4)
172167
set.onComplete {
173-
val btn = if (isEndGame) {
174-
btn_end_game
175-
} else {
176-
btn_next
177-
}
178-
btn.visibility = View.VISIBLE
179-
btn.alpha = 0F
180-
btn.animate().alpha(1f)
168+
val btn = if (isEndGame) {
169+
btn_end_game
170+
} else {
171+
btn_next
181172
}
173+
btn.visibility = View.VISIBLE
174+
btn.alpha = 0F
175+
btn.animate().alpha(1f)
176+
}
182177
set.start()
183178
}
184179

@@ -217,6 +212,47 @@ class QuestionFragment : Fragment(), CoroutineScope, QuestionView, MainActivity.
217212
}
218213
}
219214

215+
override fun setTimerText(viewState: QuestionViewState) {
216+
activity?.runOnUiThread {
217+
txt_timer.scaleX = 0f
218+
txt_timer.scaleY = 0f
219+
txt_timer.alpha = 1f
220+
txt_timer.text = viewState.questionTime.toString()
221+
txt_timer.animate()
222+
.scaleX(1f)
223+
.scaleY(1f)
224+
.setInterpolator(FastOutSlowInInterpolator())
225+
.setDuration(500)
226+
.withEndAction {
227+
if (txt_timer != null) {
228+
txt_timer.animate()
229+
.scaleX(0f)
230+
.scaleY(0f)
231+
.duration = 500
232+
}
233+
}
234+
}
235+
}
236+
237+
override fun showTimesUp(viewState: QuestionViewState, isEndGame: Boolean) {
238+
activity?.runOnUiThread {
239+
txt_timer.scaleX = 0f
240+
txt_timer.scaleY = 0f
241+
txt_timer.text = "TIMES UP!!"
242+
txt_timer.setTextColor(ResourcesCompat.getColor(context?.resources!!, R.color.red, null))
243+
txt_timer.animate()
244+
.scaleX(1f)
245+
.scaleY(1f)
246+
.setInterpolator(FastOutSlowInInterpolator())
247+
.setDuration(500)
248+
.withEndAction {
249+
showWrongAnswer(viewState, isEndGame)
250+
txt_timer.animate().alpha(0f)
251+
}
252+
253+
}
254+
}
255+
220256
private fun celebrate() {
221257
view_konfetti.build()
222258
.addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA)
@@ -230,12 +266,12 @@ class QuestionFragment : Fragment(), CoroutineScope, QuestionView, MainActivity.
230266
.burst(200)
231267
}
232268

233-
private fun getBtnByNum(num: Int): Button = when (num) {
269+
private fun getBtnByNum(num: Int): Button? = when (num) {
234270
1 -> button1
235271
2 -> button2
236272
3 -> button3
237273
4 -> button4
238-
else -> throw IllegalStateException("Invalid correct button index")
274+
else -> null//throw IllegalStateException("Invalid button index")
239275
}
240276

241277

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class StartFragment : Fragment(), CoroutineScope, StartView {
1818
override val coroutineContext: CoroutineContext
1919
get() = Dispatchers.Main
2020

21-
var presenter: StartPresenter? = null
21+
private var presenter: StartPresenter? = null
2222

2323
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
2424
return inflater.inflate(R.layout.fragment_start, container, false)
@@ -39,7 +39,7 @@ class StartFragment : Fragment(), CoroutineScope, StartView {
3939

4040
override fun onPause() {
4141
super.onPause()
42-
NameGameApp.gameEngine().detachView(presenter!!)
42+
NameGameApp.gameEngine().detachView(this)
4343
}
4444

4545
override fun hideLoading() {

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

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,56 +34,56 @@
3434
tools:srcCompat="@tools:sample/avatars" />
3535

3636
<Button
37-
style="@style/ChoiceButton"
3837
android:id="@+id/button3"
38+
style="@style/ChoiceButton"
3939
android:layout_width="193dp"
4040
android:layout_height="wrap_content"
4141
android:layout_marginStart="8dp"
4242
android:layout_marginBottom="32dp"
43-
android:text="Button"
4443
android:alpha="0"
44+
android:text="Button"
4545
app:layout_constraintBottom_toBottomOf="parent"
4646
app:layout_constraintEnd_toStartOf="@+id/button4"
4747
app:layout_constraintHorizontal_bias="0.5"
4848
app:layout_constraintStart_toStartOf="parent" />
4949

5050
<Button
51-
style="@style/ChoiceButton"
5251
android:id="@+id/button4"
52+
style="@style/ChoiceButton"
5353
android:layout_width="194dp"
5454
android:layout_height="wrap_content"
5555
android:layout_marginEnd="8dp"
5656
android:layout_marginBottom="32dp"
57-
android:text="Button"
5857
android:alpha="0"
58+
android:text="Button"
5959
app:layout_constraintBottom_toBottomOf="parent"
6060
app:layout_constraintEnd_toEndOf="parent"
6161
app:layout_constraintHorizontal_bias="0.5"
6262
app:layout_constraintStart_toEndOf="@+id/button3" />
6363

6464
<Button
65-
style="@style/ChoiceButton"
6665
android:id="@+id/button1"
66+
style="@style/ChoiceButton"
6767
android:layout_width="193dp"
6868
android:layout_height="wrap_content"
6969
android:layout_marginStart="8dp"
7070
android:layout_marginBottom="8dp"
71-
android:text="Button"
7271
android:alpha="0"
72+
android:text="Button"
7373
app:layout_constraintBottom_toTopOf="@+id/button3"
7474
app:layout_constraintEnd_toStartOf="@+id/button2"
7575
app:layout_constraintHorizontal_bias="0.5"
7676
app:layout_constraintStart_toStartOf="parent" />
7777

7878
<Button
79-
style="@style/ChoiceButton"
8079
android:id="@+id/button2"
80+
style="@style/ChoiceButton"
8181
android:layout_width="194dp"
8282
android:layout_height="wrap_content"
8383
android:layout_marginEnd="8dp"
8484
android:layout_marginBottom="8dp"
85-
android:text="Button"
8685
android:alpha="0"
86+
android:text="Button"
8787
app:layout_constraintBottom_toTopOf="@+id/button4"
8888
app:layout_constraintEnd_toEndOf="parent"
8989
app:layout_constraintHorizontal_bias="0.5"
@@ -107,6 +107,7 @@
107107
app:layout_constraintEnd_toStartOf="@+id/button2"
108108
app:layout_constraintHorizontal_bias="0.5"
109109
app:layout_constraintStart_toEndOf="@+id/button1" />
110+
110111
<Button
111112
android:id="@+id/btn_end_game"
112113
android:layout_width="wrap_content"
@@ -123,6 +124,20 @@
123124
<nl.dionsegijn.konfetti.KonfettiView
124125
android:id="@+id/view_konfetti"
125126
android:layout_width="match_parent"
126-
android:layout_height="match_parent" />
127+
android:layout_height="match_parent"
128+
tools:layout_editor_absoluteX="0dp"
129+
tools:layout_editor_absoluteY="0dp" />
130+
131+
<TextView
132+
android:id="@+id/txt_timer"
133+
style="@style/TimerText"
134+
android:layout_width="wrap_content"
135+
android:layout_height="wrap_content"
136+
android:layout_marginTop="22dp"
137+
android:text="5"
138+
app:layout_constraintEnd_toEndOf="parent"
139+
app:layout_constraintHorizontal_bias="0.5"
140+
app:layout_constraintStart_toStartOf="parent"
141+
app:layout_constraintTop_toBottomOf="@+id/imageView" />
127142

128143
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/values/dimens.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
<dimen name="nav_header_height">176dp</dimen>
77
<dimen name="txt_title_size">34sp</dimen>
88
<dimen name="txt_subtitle_size">24sp</dimen>
9+
<dimen name="txt_timer_size">62sp</dimen>
910

1011
</resources>

app/src/main/res/values/styles.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
<item name="android:textSize">@dimen/txt_subtitle_size</item>
4242
</style>
4343

44+
<style name="TimerText">
45+
<item name="android:textColor">?attr/colorPrimary</item>
46+
<item name="android:textSize">@dimen/txt_timer_size</item>
47+
</style>
48+
4449
<style name="ChoiceButton" parent="Widget.MaterialComponents.Button.TextButton">
4550
<item name="android:textSize">18sp</item>
4651
<item name="android:textColor">@drawable/button_color_selector</item>

common/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ kotlin {
3939

4040
// Change to `presets.iosArm64` to deploy the app to iPhone
4141
// Change to `presets.iosX64` to deploy the app to iPhone
42-
// fromPreset(presets.iosX64, 'ios') {
43-
fromPreset(presets.iosArm64, 'ios') {
42+
fromPreset(presets.iosX64, 'ios') {
43+
// fromPreset(presets.iosArm64, 'ios') {
4444
compilations.main.outputKinds('FRAMEWORK')
4545
}
4646
}

0 commit comments

Comments
 (0)