Skip to content

Commit 66a3b8c

Browse files
authored
Allow onboarding to be relaunched
1 parent 2bd36a5 commit 66a3b8c

28 files changed

+351
-117
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright (c) 2018 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.app.launch
18+
19+
import android.arch.core.executor.testing.InstantTaskExecutorRule
20+
import android.arch.lifecycle.Observer
21+
import com.duckduckgo.app.launch.LaunchViewModel.Command.*
22+
import com.duckduckgo.app.onboarding.store.OnboardingStore
23+
import com.nhaarman.mockito_kotlin.mock
24+
import com.nhaarman.mockito_kotlin.verify
25+
import com.nhaarman.mockito_kotlin.whenever
26+
import org.junit.After
27+
import org.junit.Before
28+
import org.junit.Rule
29+
import org.junit.Test
30+
import org.mockito.Mockito.any
31+
32+
33+
class LaunchViewModelTest {
34+
35+
@get:Rule
36+
@Suppress("unused")
37+
var instantTaskExecutorRule = InstantTaskExecutorRule()
38+
39+
private var onboardingStore: OnboardingStore = mock()
40+
private var mockCommandObserver: Observer<LaunchViewModel.Command> = mock()
41+
42+
private val testee: LaunchViewModel by lazy {
43+
LaunchViewModel(onboardingStore)
44+
}
45+
46+
@After
47+
fun after() {
48+
testee.command.removeObserver(mockCommandObserver)
49+
}
50+
51+
@Test
52+
fun whenOnboardingShouldShowThenCommandIsOnboarding() {
53+
whenever(onboardingStore.shouldShow).thenReturn(true)
54+
testee.command.observeForever(mockCommandObserver)
55+
verify(mockCommandObserver).onChanged(any(Onboarding::class.java))
56+
}
57+
58+
@Test
59+
fun whenOnboardingShouldNotShowThenCommandIsHome() {
60+
whenever(onboardingStore.shouldShow).thenReturn(false)
61+
testee.command.observeForever(mockCommandObserver)
62+
verify(mockCommandObserver).onChanged(any(Home::class.java))
63+
}
64+
65+
@Test
66+
fun whenOnboardingDoneThenCommandIsHome() {
67+
whenever(onboardingStore.shouldShow).thenReturn(true)
68+
testee.command.observeForever(mockCommandObserver)
69+
verify(mockCommandObserver).onChanged(any(Onboarding::class.java))
70+
71+
testee.onOnboardingDone()
72+
verify(mockCommandObserver).onChanged(any(Home::class.java))
73+
}
74+
75+
}

app/src/androidTest/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModelTest.kt

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@
1717
package com.duckduckgo.app.onboarding.ui
1818

1919
import android.arch.core.executor.testing.InstantTaskExecutorRule
20-
import android.arch.lifecycle.Observer
2120
import com.duckduckgo.app.onboarding.store.OnboardingStore
2221
import com.nhaarman.mockito_kotlin.mock
22+
import com.nhaarman.mockito_kotlin.never
2323
import com.nhaarman.mockito_kotlin.verify
24-
import com.nhaarman.mockito_kotlin.whenever
25-
import org.junit.Assert.assertFalse
26-
import org.junit.Assert.assertTrue
2724
import org.junit.Rule
2825
import org.junit.Test
2926

@@ -35,37 +32,16 @@ class OnboardingViewModelTest {
3532
var instantTaskExecutorRule = InstantTaskExecutorRule()
3633

3734
private var onboardingStore: OnboardingStore = mock()
38-
private var viewStateObserver: Observer<OnboardingViewModel.ViewState> = mock()
3935

4036
private val testee: OnboardingViewModel by lazy {
41-
val model = OnboardingViewModel(onboardingStore)
42-
model.viewState.observeForever(viewStateObserver)
43-
model
37+
OnboardingViewModel(onboardingStore)
4438
}
4539

4640
@Test
47-
fun whenStartedThenStoreNotifiedThatOnboardingShown() {
48-
testee
49-
verify(onboardingStore).onboardingShown()
50-
}
51-
52-
@Test
53-
fun whenOnboardingShouldShowThenShowHomeIsFalse() {
54-
whenever(onboardingStore.shouldShow).thenReturn(true)
55-
assertFalse(testee.viewState.value!!.showHome)
56-
}
57-
58-
@Test
59-
fun whenOnboardingShouldNotShowThenShowHomeIsTrue() {
60-
whenever(onboardingStore.shouldShow).thenReturn(false)
61-
assertTrue(testee.viewState.value!!.showHome)
62-
}
63-
64-
@Test
65-
fun whenOnboardingDoneThenShowHomeIsTrue() {
66-
whenever(onboardingStore.shouldShow).thenReturn(true)
41+
fun whenOnboardingDoneThenStoreNotifiedThatOnboardingShown() {
42+
verify(onboardingStore, never()).onboardingShown()
6743
testee.onOnboardingDone()
68-
assertTrue(testee.viewState.value!!.showHome)
44+
verify(onboardingStore).onboardingShown()
6945
}
7046

7147
}

app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,20 @@
2121
android:value="true" />
2222

2323
<activity
24-
android:name="com.duckduckgo.app.onboarding.ui.OnboardingActivity"
24+
android:name="com.duckduckgo.app.launch.LaunchActivity"
2525
android:label="@string/appName">
26+
2627
<intent-filter>
2728
<action android:name="android.intent.action.MAIN" />
28-
2929
<category android:name="android.intent.category.LAUNCHER" />
3030
</intent-filter>
31+
3132
</activity>
33+
34+
<activity
35+
android:name="com.duckduckgo.app.onboarding.ui.OnboardingActivity"
36+
android:label="@string/appName" />
37+
3238
<activity
3339
android:name="com.duckduckgo.app.home.HomeActivity"
3440
android:label="@string/appName"
@@ -37,7 +43,6 @@
3743
<!-- Allows app to become default browser -->
3844
<intent-filter>
3945
<action android:name="android.intent.action.VIEW" />
40-
4146
<category android:name="android.intent.category.BROWSABLE" />
4247
<category android:name="android.intent.category.DEFAULT" />
4348

@@ -48,9 +53,7 @@
4853
<!-- Allows apps to consume links and text shared from other apps e.g chrome -->
4954
<intent-filter>
5055
<action android:name="android.intent.action.SEND" />
51-
5256
<category android:name="android.intent.category.DEFAULT" />
53-
5457
<data android:mimeType="text/plain" />
5558
</intent-filter>
5659

@@ -61,10 +64,12 @@
6164
</intent-filter>
6265

6366
</activity>
67+
6468
<activity
6569
android:name=".BrowserActivity"
6670
android:configChanges="keyboardHidden|orientation|screenSize"
6771
android:parentActivityName="com.duckduckgo.app.home.HomeActivity" />
72+
6873
<activity
6974
android:name="com.duckduckgo.app.privacymonitor.ui.PrivacyDashboardActivity"
7075
android:label="@string/privacyDashboardActivityTitle"
@@ -83,7 +88,7 @@
8388
android:parentActivityName="com.duckduckgo.app.privacymonitor.ui.PrivacyDashboardActivity" />
8489
<activity
8590
android:name="com.duckduckgo.app.settings.SettingsActivity"
86-
android:label="@string/settingsActivityTitle"/>
91+
android:label="@string/settingsActivityTitle" />
8792

8893
<activity
8994
android:name="com.duckduckgo.app.about.AboutDuckDuckGoActivity"
@@ -107,6 +112,7 @@
107112
android:name="android.appwidget.provider"
108113
android:resource="@xml/search_widget_info" />
109114
</receiver>
115+
110116
</application>
111117

112118
</manifest>

app/src/main/java/com/duckduckgo/app/di/AndroidBindingModule.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.duckduckgo.app.bookmarks.ui.BookmarksActivity
2020
import com.duckduckgo.app.browser.BrowserActivity
2121
import com.duckduckgo.app.home.HomeActivity
2222
import com.duckduckgo.app.job.AppConfigurationJobService
23+
import com.duckduckgo.app.launch.LaunchActivity
2324
import com.duckduckgo.app.onboarding.ui.OnboardingActivity
2425
import com.duckduckgo.app.privacymonitor.ui.PrivacyDashboardActivity
2526
import com.duckduckgo.app.privacymonitor.ui.PrivacyPracticesActivity
@@ -35,6 +36,10 @@ abstract class AndroidBindingModule {
3536

3637
/* Activities */
3738

39+
@ActivityScoped
40+
@ContributesAndroidInjector
41+
abstract fun launchActivity(): LaunchActivity
42+
3843
@ActivityScoped
3944
@ContributesAndroidInjector
4045
abstract fun onboardingActivity(): OnboardingActivity

app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.duckduckgo.app.browser.BrowserViewModel
2525
import com.duckduckgo.app.browser.DuckDuckGoUrlDetector
2626
import com.duckduckgo.app.browser.LongPressHandler
2727
import com.duckduckgo.app.browser.omnibar.QueryUrlConverter
28+
import com.duckduckgo.app.launch.LaunchViewModel
2829
import com.duckduckgo.app.onboarding.store.OnboardingStore
2930
import com.duckduckgo.app.onboarding.ui.OnboardingViewModel
3031
import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardDao
@@ -63,6 +64,7 @@ class ViewModelFactory @Inject constructor(
6364
override fun <T : ViewModel> create(modelClass: Class<T>) =
6465
with(modelClass) {
6566
when {
67+
isAssignableFrom(LaunchViewModel::class.java) -> LaunchViewModel(onboaringStore)
6668
isAssignableFrom(OnboardingViewModel::class.java) -> OnboardingViewModel(onboaringStore)
6769
isAssignableFrom(BrowserViewModel::class.java) -> browserViewModel()
6870
isAssignableFrom(PrivacyDashboardViewModel::class.java) -> PrivacyDashboardViewModel(privacySettingsStore, networkLeaderboardDao)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2018 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.app.launch
18+
19+
import android.arch.lifecycle.Observer
20+
import android.arch.lifecycle.ViewModelProviders
21+
import android.content.Intent
22+
import android.os.Bundle
23+
import com.duckduckgo.app.browser.R
24+
import com.duckduckgo.app.global.DuckDuckGoActivity
25+
import com.duckduckgo.app.global.ViewModelFactory
26+
import com.duckduckgo.app.home.HomeActivity
27+
import com.duckduckgo.app.onboarding.ui.OnboardingActivity
28+
import javax.inject.Inject
29+
30+
31+
class LaunchActivity : DuckDuckGoActivity() {
32+
33+
@Inject
34+
lateinit var viewModelFactory: ViewModelFactory
35+
36+
private val viewModel: LaunchViewModel by lazy {
37+
ViewModelProviders.of(this, viewModelFactory).get(LaunchViewModel::class.java)
38+
}
39+
40+
override fun onCreate(savedInstanceState: Bundle?) {
41+
super.onCreate(savedInstanceState)
42+
setContentView(R.layout.activity_launch)
43+
configureObservers()
44+
}
45+
46+
private fun configureObservers() {
47+
viewModel.command.observe(this, Observer {
48+
processCommand(it)
49+
})
50+
}
51+
52+
private fun processCommand(it: LaunchViewModel.Command?) {
53+
when (it) {
54+
LaunchViewModel.Command.Onboarding -> showOnboarding()
55+
LaunchViewModel.Command.Home -> showHome()
56+
}
57+
}
58+
59+
private fun showOnboarding() {
60+
startActivityForResult(OnboardingActivity.intent(this), ONBOARDING_REQUEST_CODE)
61+
}
62+
63+
private fun showHome() {
64+
startActivity(HomeActivity.intent(this))
65+
finish()
66+
}
67+
68+
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
69+
if (requestCode == ONBOARDING_REQUEST_CODE) {
70+
viewModel.onOnboardingDone()
71+
}
72+
}
73+
74+
companion object {
75+
private const val ONBOARDING_REQUEST_CODE = 100
76+
}
77+
78+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2018 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.app.launch
18+
19+
import android.arch.lifecycle.ViewModel
20+
import com.duckduckgo.app.global.SingleLiveEvent
21+
import com.duckduckgo.app.onboarding.store.OnboardingStore
22+
23+
class LaunchViewModel(onboardingStore: OnboardingStore) : ViewModel() {
24+
25+
val command: SingleLiveEvent<Command> = SingleLiveEvent()
26+
27+
sealed class Command {
28+
object Onboarding : Command()
29+
object Home : Command()
30+
}
31+
32+
init {
33+
if (onboardingStore.shouldShow) {
34+
command.value = Command.Onboarding
35+
} else {
36+
command.value = Command.Home
37+
}
38+
}
39+
40+
fun onOnboardingDone() {
41+
command.value = Command.Home
42+
}
43+
44+
}

0 commit comments

Comments
 (0)