Skip to content

Commit 7b12ba7

Browse files
authored
Feature/feedback disambiguation (#459)
* WIP feedback disambiguation redesign * WIP updates to feedback UI * WIP build feedback disambiguation screens * Further work to add feedback disambiguation * All copy in working order across the screens * Add broken site feedback flow * Tidy up of feedback fragment code * Simplify feedback list decorator * Fix tests * Add dark theme * Skip the positive landing screen if can't rate; add dark theme buttons * UI polish after design review * Tweaking layout * Add scroll hack to ensure submit button visible if possible Replace faces with PNGs as vector drawables were rendering poorly * Start integration with server for submitting feedback Also renamed old "feedback" classes to "broken site" naming * Send feedback and broken site reports, along with pixel for some cases * Consolidated broken site and feedback services * Add missing subreason for autocomplete * Remove experiment inline class usage * Adding tests for the navigation flow * Remove ATB variant from version param * Code tidy * Only submit reason "broken_site" for legacy broken site dialog * Add adjustResize param to allow submit button to appear above keyboard * Fix case of string * Cody tidy * Code tidy * code tidy * Remove dispatcher provider attempt (hard to reason about) * Upgrade to latest stable WorkManager * Remove empty string check to make inline with iOS * Code tidy * Code tidy * Fix memory leak * Update api call to include broken site reason * Update legacy broken site dialog to be only about broken sites * Code tidy from PR feedback * Remove unused assets * Move all survey-related classes to the survey package * Change from doOnPreDraw to doOnNextLayout to fix multi-window crash * Switch to if statement instead of a when with a single item in it * Add intent flag required to launch Play Store from non-activity context * Make cornflower blue the default accent color for the whole app * Fixing lint warnings * Dismiss keyboard when transitioning away from a keyboard-using fragment * Switch from postValue to set value to try fix flakey test * Ensure UI methods are called from the Main thread
1 parent c2e51cf commit 7b12ba7

File tree

126 files changed

+4184
-616
lines changed

Some content is hidden

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

126 files changed

+4184
-616
lines changed

app/build.gradle

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,15 @@ android {
7878

7979
ext {
8080
androidX = "1.0.2"
81-
materialDesign = "1.1.0-alpha02"
81+
materialDesign = "1.0.0"
8282
architectureComponents = "1.1.1"
8383
architectureComponentsExtensions = "1.1.1"
8484
androidKtx = "1.0.1"
85+
fragmentKtx = "1.0.0"
8586
constraintLayout = "2.0.0-alpha3"
8687
lifecycle = "2.0.0"
87-
room = "2.1.0-alpha04"
88-
workManager = "1.0.0-beta03"
88+
room = "2.1.0-alpha05"
89+
workManager = "2.0.0"
8990
legacySupport = "1.0.0"
9091
espressoCore = "3.1.1"
9192
coreTesting = "2.0.0"
@@ -101,7 +102,7 @@ ext {
101102
okHttp = "3.10.0"
102103
rxJava = "2.1.10"
103104
rxAndroid = "2.0.2"
104-
timber = "4.6.1"
105+
timber = "4.7.1"
105106
rxRelay = "2.0.0"
106107
leakCanary = "1.6.2"
107108
mockito = "2.18.3"
@@ -112,6 +113,8 @@ ext {
112113

113114
dependencies {
114115
implementation "androidx.legacy:legacy-support-v4:$legacySupport"
116+
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0-beta01'
117+
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0'
115118
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanary"
116119
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanary"
117120

@@ -124,6 +127,7 @@ dependencies {
124127
implementation "com.squareup.retrofit2:retrofit:$retrofit"
125128
implementation "com.squareup.retrofit2:converter-moshi:$retrofit"
126129
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit"
130+
implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
127131
implementation "io.reactivex.rxjava2:rxjava:$rxJava"
128132
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroid"
129133
implementation "com.jakewharton.timber:timber:$timber"
@@ -139,6 +143,7 @@ dependencies {
139143

140144
// Android KTX
141145
implementation "androidx.core:core-ktx:$androidKtx"
146+
implementation "androidx.fragment:fragment-ktx:$fragmentKtx"
142147

143148
// ViewModel and LiveData
144149
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle"
@@ -153,7 +158,7 @@ dependencies {
153158
androidTestImplementation "androidx.room:room-testing:$room"
154159

155160
// WorkManager
156-
implementation "android.arch.work:work-runtime-ktx:$workManager"
161+
implementation "androidx.work:work-runtime-ktx:$workManager"
157162

158163
// Dagger
159164
kapt "com.google.dagger:dagger-android-processor:$dagger"

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter
4040
import com.duckduckgo.app.browser.session.WebViewSessionStorage
4141
import com.duckduckgo.app.cta.db.DismissedCtaDao
4242
import com.duckduckgo.app.cta.ui.CtaViewModel
43-
import com.duckduckgo.app.feedback.db.SurveyDao
43+
import com.duckduckgo.app.survey.db.SurveyDao
4444
import com.duckduckgo.app.global.db.AppConfigurationDao
4545
import com.duckduckgo.app.global.db.AppConfigurationEntity
4646
import com.duckduckgo.app.global.db.AppDatabase

app/src/androidTest/java/com/duckduckgo/app/cta/ui/CtaViewModelTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ import com.duckduckgo.app.InstantSchedulersRule
2323
import com.duckduckgo.app.cta.db.DismissedCtaDao
2424
import com.duckduckgo.app.cta.model.CtaId
2525
import com.duckduckgo.app.cta.model.DismissedCta
26-
import com.duckduckgo.app.feedback.db.SurveyDao
27-
import com.duckduckgo.app.feedback.model.Survey
28-
import com.duckduckgo.app.feedback.model.Survey.Status.SCHEDULED
2926
import com.duckduckgo.app.global.db.AppDatabase
3027
import com.duckduckgo.app.global.install.AppInstallStore
3128
import com.duckduckgo.app.statistics.pixels.Pixel
3229
import com.duckduckgo.app.statistics.pixels.Pixel.PixelName.*
30+
import com.duckduckgo.app.survey.db.SurveyDao
31+
import com.duckduckgo.app.survey.model.Survey
32+
import com.duckduckgo.app.survey.model.Survey.Status.SCHEDULED
3333
import com.duckduckgo.app.widget.ui.WidgetCapabilities
3434
import com.nhaarman.mockitokotlin2.any
3535
import com.nhaarman.mockitokotlin2.eq
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package com.duckduckgo.app.feedback.ui
2+
3+
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
4+
import androidx.lifecycle.Observer
5+
import com.duckduckgo.app.InstantSchedulersRule
6+
import com.duckduckgo.app.brokensite.BrokenSiteViewModel
7+
import com.duckduckgo.app.brokensite.BrokenSiteViewModel.Command
8+
import com.duckduckgo.app.brokensite.api.BrokenSiteSender
9+
import com.nhaarman.mockitokotlin2.any
10+
import com.nhaarman.mockitokotlin2.never
11+
import com.nhaarman.mockitokotlin2.verify
12+
import org.junit.After
13+
import org.junit.Assert.assertFalse
14+
import org.junit.Assert.assertTrue
15+
import org.junit.Before
16+
import org.junit.Rule
17+
import org.junit.Test
18+
import org.mockito.Mock
19+
import org.mockito.MockitoAnnotations
20+
21+
class BrokenSiteViewModelTest {
22+
23+
@get:Rule
24+
@Suppress("unused")
25+
var instantTaskExecutorRule = InstantTaskExecutorRule()
26+
27+
@get:Rule
28+
@Suppress("unused")
29+
val schedulers = InstantSchedulersRule()
30+
31+
@Mock
32+
private lateinit var mockBrokenSiteSender: BrokenSiteSender
33+
34+
@Mock
35+
private lateinit var mockCommandObserver: Observer<BrokenSiteViewModel.Command>
36+
37+
private lateinit var testee: BrokenSiteViewModel
38+
39+
private val viewState: BrokenSiteViewModel.ViewState
40+
get() = testee.viewState.value!!
41+
42+
@Before
43+
fun before() {
44+
MockitoAnnotations.initMocks(this)
45+
testee = BrokenSiteViewModel(mockBrokenSiteSender)
46+
testee.command.observeForever(mockCommandObserver)
47+
}
48+
49+
@After
50+
fun after() {
51+
testee.command.removeObserver(mockCommandObserver)
52+
}
53+
54+
@Test
55+
fun whenInitializedThenCannotSubmit() {
56+
assertFalse(viewState.submitAllowed)
57+
}
58+
59+
@Test
60+
fun whenNoUrlProvidedThenUrlFocused() {
61+
testee.setInitialBrokenSite(null)
62+
verify(mockCommandObserver).onChanged(Command.FocusUrl)
63+
}
64+
65+
@Test
66+
fun whenUrlProvidedThenMessageFocused() {
67+
testee.setInitialBrokenSite(url)
68+
verify(mockCommandObserver).onChanged(Command.FocusMessage)
69+
}
70+
71+
@Test
72+
fun whenUrlAndMessageNotEmptyThenCanSubmit() {
73+
testee.onBrokenSiteUrlChanged(url)
74+
testee.onFeedbackMessageChanged(message)
75+
assertTrue(viewState.submitAllowed)
76+
}
77+
78+
@Test
79+
fun whenNullUrlThenCannotSubmit() {
80+
testee.onBrokenSiteUrlChanged(null)
81+
testee.onFeedbackMessageChanged(message)
82+
assertFalse(viewState.submitAllowed)
83+
}
84+
85+
@Test
86+
fun whenEmptyUrlThenCannotSubmit() {
87+
testee.onBrokenSiteUrlChanged(" ")
88+
testee.onFeedbackMessageChanged(message)
89+
assertFalse(viewState.submitAllowed)
90+
}
91+
92+
@Test
93+
fun whenNullMessageThenCannotSubmit() {
94+
testee.onBrokenSiteUrlChanged(url)
95+
testee.onFeedbackMessageChanged(null)
96+
assertFalse(viewState.submitAllowed)
97+
}
98+
99+
@Test
100+
fun whenEmptyMessageThenCannotSubmit() {
101+
testee.onBrokenSiteUrlChanged(url)
102+
testee.onFeedbackMessageChanged(" ")
103+
assertFalse(viewState.submitAllowed)
104+
}
105+
106+
@Test
107+
fun whenCanSubmitBrokenSiteAndSubmitPressedThenFeedbackSubmitted() {
108+
testee.onBrokenSiteUrlChanged(url)
109+
testee.onFeedbackMessageChanged(message)
110+
testee.onSubmitPressed()
111+
112+
verify(mockBrokenSiteSender).submitBrokenSiteFeedback(message, url)
113+
verify(mockCommandObserver).onChanged(Command.ConfirmAndFinish)
114+
}
115+
116+
@Test
117+
fun whenCannotSubmitBrokenSiteAndSubmitPressedThenFeedbackNotSubmitted() {
118+
testee.onSubmitPressed()
119+
verify(mockBrokenSiteSender, never()).submitBrokenSiteFeedback(any(), any())
120+
verify(mockCommandObserver, never()).onChanged(Command.ConfirmAndFinish)
121+
}
122+
123+
companion object Constants {
124+
private const val url = "http://example.com"
125+
private const val message = "Feedback message"
126+
}
127+
128+
}

app/src/androidTest/java/com/duckduckgo/app/feedback/ui/FeedbackViewModelTest.kt

Lines changed: 0 additions & 174 deletions
This file was deleted.

0 commit comments

Comments
 (0)