diff --git a/app/build.gradle b/app/build.gradle index 22cc3e8a79..b64a69437f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -201,6 +201,8 @@ android { packagingOptions { exclude 'META-INF/atomicfu.kotlin_module' + exclude 'META-INF/AL2.0' + exclude 'META-INF/LGPL2.1' } testOptions { @@ -535,11 +537,11 @@ dependencies { implementation Deps.google_play_store // Required for in-app reviews androidTestImplementation Deps.uiautomator -// Removed pending AndroidX fixes androidTestImplementation "tools.fastlane:screengrab:2.0.0" // This Falcon version is added to maven central now required for Screengrab implementation 'com.jraska:falcon:2.2.0' -// androidTestImplementation "br.com.concretesolutions:kappuccino:1.2.1" + + androidTestImplementation Deps.androidx_compose_ui_test androidTestImplementation Deps.espresso_core, { exclude group: 'com.android.support', module: 'support-annotations' diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/assertions/AwesomeBarAssertion.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/assertions/AwesomeBarAssertion.kt deleted file mode 100644 index 9e30988d91..0000000000 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/assertions/AwesomeBarAssertion.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.mozilla.fenix.helpers.assertions - -import android.view.View -import androidx.test.espresso.ViewAssertion -import mozilla.components.browser.awesomebar.BrowserAwesomeBar - -class AwesomeBarAssertion { - companion object { - fun suggestionsAreGreaterThan(minimumSuggestions: Int): ViewAssertion { - return ViewAssertion { view, noViewFoundException -> - if (noViewFoundException != null) throw noViewFoundException - - val suggestionsCount = getSuggestionCountFromView(view) - - if (suggestionsCount <= minimumSuggestions) - throw AssertionError("The suggestion count is less than or equal to the minimum suggestions") - } - } - - fun suggestionsAreEqualTo(expectedItemCount: Int): ViewAssertion { - return ViewAssertion { view, noViewFoundException -> - if (noViewFoundException != null) throw noViewFoundException - - val suggestionsCount = getSuggestionCountFromView(view) - - if (suggestionsCount != expectedItemCount) - throw AssertionError("The expected item count is $expectedItemCount, and the suggestions count within the AwesomeBar is $suggestionsCount") - } - } - - private fun getSuggestionCountFromView(view: View): Int { - return (view as BrowserAwesomeBar).adapter?.itemCount - ?: throw AssertionError("This view is not of type BrowserAwesomeBar") - } - } -} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt index 06ac71c14b..9a19799578 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt @@ -4,6 +4,7 @@ package org.mozilla.fenix.ui +import androidx.compose.ui.test.junit4.AndroidComposeTestRule import org.junit.Ignore import org.junit.Rule import org.junit.Test @@ -23,7 +24,10 @@ import org.mozilla.fenix.ui.robots.homeScreen class SearchTest { /* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping. @get:Rule - val activityTestRule = HomeActivityTestRule() + val activityTestRule = AndroidComposeTestRule( + HomeActivityTestRule(), + { it.activity } + ) @Test fun searchScreenItemsTest() { @@ -59,10 +63,10 @@ class SearchTest { }.goBack { }.openSearch { // verifySearchWithText() - clickSearchEngineButton("DuckDuckGo") + clickSearchEngineButton(activityTestRule, "DuckDuckGo") typeSearch("mozilla") - verifySearchEngineResults("DuckDuckGo") - clickSearchEngineResult("DuckDuckGo") + verifySearchEngineResults(activityTestRule, "DuckDuckGo", 4) + clickSearchEngineResult(activityTestRule, "DuckDuckGo") verifySearchEngineURL("DuckDuckGo") } } @@ -77,8 +81,8 @@ class SearchTest { }.goBack { }.goBack { }.openSearch { - scrollToSearchEngineSettings() - clickSearchEngineSettings() + scrollToSearchEngineSettings(activityTestRule) + clickSearchEngineSettings(activityTestRule) verifySearchSettings() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt index 9bfaaa549f..8bd5907628 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -5,8 +5,10 @@ package org.mozilla.fenix.ui import android.view.View +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.onNodeWithText import androidx.core.net.toUri -import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.IdlingRegistry import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.ActivityTestRule @@ -65,7 +67,6 @@ class SmokeTest { private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) private lateinit var mockWebServer: MockWebServer private var awesomeBar: ViewVisibilityIdlingResource? = null - private var searchSuggestionsIdlingResource: RecyclerViewIdlingResource? = null private var addonsListIdlingResource: RecyclerViewIdlingResource? = null private var recentlyClosedTabsListIdlingResource: RecyclerViewIdlingResource? = null private var readerViewNotification: ViewVisibilityIdlingResource? = null @@ -84,10 +85,14 @@ class SmokeTest { return searchDialogFragment?.view?.findViewById(R.id.awesome_bar) } - @get:Rule - val activityTestRule = HomeActivityIntentTestRule() private lateinit var browserStore: BrowserStore + @get:Rule + val activityTestRule = AndroidComposeTestRule( + HomeActivityIntentTestRule(), + { it.activity } + ) + @get: Rule val intentReceiverActivityTestRule = ActivityTestRule( IntentReceiverActivity::class.java, true, false @@ -119,10 +124,6 @@ class SmokeTest { IdlingRegistry.getInstance().unregister(awesomeBar!!) } - if (searchSuggestionsIdlingResource != null) { - IdlingRegistry.getInstance().unregister(searchSuggestionsIdlingResource!!) - } - if (addonsListIdlingResource != null) { IdlingRegistry.getInstance().unregister(addonsListIdlingResource!!) } @@ -477,38 +478,43 @@ class SmokeTest { }.openSearch { verifyKeyboardVisibility() clickSearchEngineShortcutButton() - verifySearchEngineList() - changeDefaultSearchEngine("Amazon.com") + verifySearchEngineList(activityTestRule) + changeDefaultSearchEngine(activityTestRule, "Amazon.com") verifySearchEngineIcon("Amazon.com") }.goToSearchEngine { + mDevice.waitForIdle() }.enterURLAndEnterToBrowser(defaultWebPage.url) { }.openTabDrawer { }.openNewTab { clickSearchEngineShortcutButton() mDevice.waitForIdle() - changeDefaultSearchEngine("Bing") + changeDefaultSearchEngine(activityTestRule, "Bing") verifySearchEngineIcon("Bing") }.goToSearchEngine { + mDevice.waitForIdle() }.enterURLAndEnterToBrowser(defaultWebPage.url) { }.openTabDrawer { }.openNewTab { clickSearchEngineShortcutButton() mDevice.waitForIdle() - changeDefaultSearchEngine("DuckDuckGo") + changeDefaultSearchEngine(activityTestRule, "DuckDuckGo") verifySearchEngineIcon("DuckDuckGo") }.goToSearchEngine { + mDevice.waitForIdle() }.enterURLAndEnterToBrowser(defaultWebPage.url) { }.openTabDrawer { }.openNewTab { clickSearchEngineShortcutButton() - changeDefaultSearchEngine("Wikipedia") + changeDefaultSearchEngine(activityTestRule, "Wikipedia") verifySearchEngineIcon("Wikipedia") }.goToSearchEngine { + mDevice.waitForIdle() }.enterURLAndEnterToBrowser(defaultWebPage.url) { }.openTabDrawer { // Checking whether the next search will be with default or not }.openNewTab { }.goToSearchEngine { + mDevice.waitForIdle() }.enterURLAndEnterToBrowser(defaultWebPage.url) { }.openNavigationToolbar { }.clickUrlbar { @@ -532,7 +538,9 @@ class SmokeTest { }.openSearch { verifyKeyboardVisibility() clickSearchEngineShortcutButton() - verifyEnginesListShortcutContains("YouTube") + mDevice.waitForIdle() + activityTestRule.waitForIdle() + verifyEnginesListShortcutContains(activityTestRule, "YouTube") } } @@ -550,11 +558,13 @@ class SmokeTest { awesomeBar = ViewVisibilityIdlingResource(it, View.VISIBLE) } IdlingRegistry.getInstance().register(awesomeBar!!) - searchSuggestionsIdlingResource = - RecyclerViewIdlingResource(awesomeBarView as RecyclerView, 1) - IdlingRegistry.getInstance().register(searchSuggestionsIdlingResource!!) - verifySearchSuggestionsAreMoreThan(0) - IdlingRegistry.getInstance().unregister(searchSuggestionsIdlingResource!!) + + activityTestRule.waitForIdle() + + activityTestRule + .onNodeWithText("mozilla firefox") + .assertExists() + .assertIsDisplayed() }.goBack { }.openThreeDotMenu { }.openSettings { @@ -564,11 +574,12 @@ class SmokeTest { }.goBack { }.openNavigationToolbar { typeSearchTerm("mozilla") - searchSuggestionsIdlingResource = - RecyclerViewIdlingResource(getAwesomebarView() as RecyclerView) - IdlingRegistry.getInstance().register(searchSuggestionsIdlingResource!!) - verifySearchSuggestionsAreEqualTo(0) - IdlingRegistry.getInstance().unregister(searchSuggestionsIdlingResource!!) + + activityTestRule.waitForIdle() + + activityTestRule + .onNodeWithText("mozilla firefox") + .assertDoesNotExist() } } @@ -675,7 +686,7 @@ class SmokeTest { IdlingRegistry.getInstance().register(addonsListIdlingResource!!) clickInstallAddon(addonName) acceptInstallAddon() - verifyDownloadAddonPrompt(addonName, activityTestRule) + verifyDownloadAddonPrompt(addonName, activityTestRule.activityRule) IdlingRegistry.getInstance().unregister(addonsListIdlingResource!!) }.goBack { }.openNavigationToolbar { @@ -1407,7 +1418,7 @@ class SmokeTest { clickAlwaysStartOnHomeToggle() } - restartApp(activityTestRule) + restartApp(activityTestRule.activityRule) homeScreen { verifyHomeScreen() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt index cf13f754b6..4ce0b677ff 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt @@ -39,8 +39,6 @@ import org.mozilla.fenix.R import org.mozilla.fenix.helpers.SessionLoadedIdlingResource import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestHelper.packageName -import org.mozilla.fenix.helpers.assertions.AwesomeBarAssertion.Companion.suggestionsAreEqualTo -import org.mozilla.fenix.helpers.assertions.AwesomeBarAssertion.Companion.suggestionsAreGreaterThan import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull @@ -49,12 +47,6 @@ import org.mozilla.fenix.helpers.ext.waitNotNull */ class NavigationToolbarRobot { - fun verifySearchSuggestionsAreMoreThan(suggestionSize: Int) = - assertSuggestionsAreMoreThan(suggestionSize) - - fun verifySearchSuggestionsAreEqualTo(suggestionSize: Int) = - assertSuggestionsAreEqualTo(suggestionSize) - fun verifyNoHistoryBookmarks() = assertNoHistoryBookmarks() fun verifyTabButtonShortcutMenuItems() = assertTabButtonShortcutMenuItems() @@ -280,16 +272,6 @@ fun openEditURLView() { ) } -private fun assertSuggestionsAreEqualTo(suggestionSize: Int) { - mDevice.waitForIdle() - onView(withId(R.id.awesome_bar)).check(suggestionsAreEqualTo(suggestionSize)) -} - -private fun assertSuggestionsAreMoreThan(suggestionSize: Int) { - mDevice.waitForIdle() - onView(withId(R.id.awesome_bar)).check(suggestionsAreGreaterThan(suggestionSize)) -} - private fun assertNoHistoryBookmarks() { onView(withId(R.id.container)) .check(matches(not(hasDescendant(withText("Test_Page_1"))))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt index c81b235989..49f7eefcec 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt @@ -6,19 +6,25 @@ package org.mozilla.fenix.ui.robots -import androidx.recyclerview.widget.RecyclerView +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.assertCountEquals +import androidx.compose.ui.test.assertHasClickAction +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.ComposeTestRule +import androidx.compose.ui.test.onAllNodesWithText +import androidx.compose.ui.test.onFirst +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performScrollToIndex import androidx.test.espresso.Espresso.onView import androidx.test.espresso.ViewInteraction -import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.closeSoftKeyboard -import androidx.test.espresso.action.ViewActions.swipeDown import androidx.test.espresso.action.ViewActions.typeText import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.Visibility -import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId @@ -52,24 +58,24 @@ class SearchRobot { fun verifyScanButton() = assertScanButton() fun verifySearchEngineButton() = assertSearchEngineButton() fun verifySearchWithText() = assertSearchWithText() - fun verifySearchEngineResults(searchEngineName: String) = - assertSearchEngineResults(searchEngineName) + fun verifySearchEngineResults(rule: ComposeTestRule, searchEngineName: String, count: Int) = + assertSearchEngineResults(rule, searchEngineName, count) fun verifySearchEngineURL(searchEngineName: String) = assertSearchEngineURL(searchEngineName) fun verifySearchSettings() = assertSearchSettings() fun verifySearchBarEmpty() = assertSearchBarEmpty() fun verifyKeyboardVisibility() = assertKeyboardVisibility(isExpectedToBeVisible = true) - fun verifySearchEngineList() = assertSearchEngineList() + fun verifySearchEngineList(rule: ComposeTestRule) = rule.assertSearchEngineList() fun verifySearchEngineIcon(expectedText: String) { onView(withContentDescription(expectedText)) } fun verifyDefaultSearchEngine(expectedText: String) = assertDefaultSearchEngine(expectedText) - fun verifyEnginesListShortcutContains(searchEngineName: String) = assertEngineListShortcutContains(searchEngineName) + fun verifyEnginesListShortcutContains(rule: ComposeTestRule, searchEngineName: String) = rule.assertEngineListShortcutContains(searchEngineName) - fun changeDefaultSearchEngine(searchEngineName: String) = - selectDefaultSearchEngine(searchEngineName) + fun changeDefaultSearchEngine(rule: ComposeTestRule, searchEngineName: String) = + rule.selectDefaultSearchEngine(searchEngineName) fun clickSearchEngineShortcutButton() { val searchEnginesShortcutButton = mDevice.findObject( @@ -96,33 +102,45 @@ class SearchRobot { browserToolbarEditView().perform(typeText(searchTerm)) } - fun clickSearchEngineButton(searchEngineName: String) { - searchEngineButton(searchEngineName).perform(click()) + fun clickSearchEngineButton(rule: ComposeTestRule, searchEngineName: String) { + rule.onNodeWithText(searchEngineName) + .assertExists() + .assertHasClickAction() + .performClick() } - fun clickSearchEngineResult(searchEngineName: String) { + fun clickSearchEngineResult(rule: ComposeTestRule, searchEngineName: String) { mDevice.waitNotNull( Until.findObjects(By.text(searchEngineName)), TestAssetHelper.waitingTime ) - awesomeBar().perform( - RecyclerViewActions.actionOnItemAtPosition( - 0, - click() - ) - ) + + rule.onAllNodesWithText(searchEngineName) + .onFirst() + .assertIsDisplayed() + .assertHasClickAction() + .performClick() } - fun scrollToSearchEngineSettings() { + @OptIn(ExperimentalTestApi::class) + fun scrollToSearchEngineSettings(rule: ComposeTestRule) { // Soft keyboard is visible on screen on view access; hide it onView(allOf(withId(R.id.search_wrapper))).perform( closeSoftKeyboard() ) - onView(allOf(withId(R.id.awesome_bar))).perform(ViewActions.swipeUp()) + + mDevice.findObject(UiSelector().text("Google")) + .waitForExists(waitingTime) + + rule.onNodeWithTag("mozac.awesomebar.suggestions") + .performScrollToIndex(5) } - fun clickSearchEngineSettings() { - onView(withText("Search engine settings")).perform(click()) + fun clickSearchEngineSettings(rule: ComposeTestRule) { + rule.onNodeWithText("Search engine settings") + .assertIsDisplayed() + .assertHasClickAction() + .performClick() } fun clickClearButton() { @@ -187,16 +205,9 @@ class SearchRobot { } } -private fun awesomeBar() = onView(withId(R.id.awesome_bar)) - private fun browserToolbarEditView() = onView(Matchers.allOf(withId(R.id.mozac_browser_toolbar_edit_url_view))) -private fun searchEngineButton(searchEngineName: String): ViewInteraction { - mDevice.waitNotNull(Until.findObject(By.text(searchEngineName)), TestAssetHelper.waitingTime) - return onView(Matchers.allOf(withText(searchEngineName))) -} - private fun denyPermissionButton(): UiObject { mDevice.waitNotNull(Until.findObjects(By.text("Deny")), TestAssetHelper.waitingTime) return mDevice.findObject(UiSelector().text("Deny")) @@ -209,7 +220,7 @@ private fun allowPermissionButton(): UiObject { private fun scanButton(): ViewInteraction { mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/search_scan_button")), TestAssetHelper.waitingTime) - return onView(allOf(withId(R.id.search_scan_button))) + return onView(allOf(withId(R.id.qr_scan_button))) } private fun clearButton() = onView(withId(R.id.mozac_browser_toolbar_clear_view)) @@ -225,10 +236,9 @@ private fun assertSearchEngineURL(searchEngineName: String) { .check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) } -private fun assertSearchEngineResults(searchEngineName: String) { - val count = - mDevice.wait(Until.findObjects(By.text((searchEngineName))), TestAssetHelper.waitingTime) - assert(count.size > 1) +private fun assertSearchEngineResults(rule: ComposeTestRule, searchEngineName: String, count: Int) { + rule.onAllNodesWithText(searchEngineName) + .assertCountEquals(count) } private fun assertSearchView() { @@ -277,34 +287,54 @@ private fun assertKeyboardVisibility(isExpectedToBeVisible: Boolean) = { ) } -private fun assertSearchEngineList() { +private fun ComposeTestRule.assertSearchEngineList() { onView(withId(R.id.mozac_browser_toolbar_edit_icon)).click() - onView(withText("Google")) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - onView(withText("Amazon.com")) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - onView(withText("Bing")) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - onView(withText("DuckDuckGo")) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - onView(withText("Wikipedia")) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + + onNodeWithText("Google") + .assertExists() + .assertIsDisplayed() + + onNodeWithText("Amazon.com") + .assertExists() + .assertIsDisplayed() + + onNodeWithText("Bing") + .assertExists() + .assertIsDisplayed() + + onNodeWithText("DuckDuckGo") + .assertExists() + .assertIsDisplayed() + + onNodeWithText("Wikipedia") + .assertExists() + .assertIsDisplayed() } -private fun assertEngineListShortcutContains(searchEngineName: String) { +@OptIn(ExperimentalTestApi::class) +private fun ComposeTestRule.assertEngineListShortcutContains(searchEngineName: String) { mDevice.findObject(UiSelector().resourceId("$packageName:id/awesome_bar")) .waitForExists(waitingTime) - onView(withId(R.id.awesome_bar)) - .perform(swipeDown()) - .check(matches(hasDescendant(withText(searchEngineName)))) + mDevice.findObject(UiSelector().text("Google")) + .waitForExists(waitingTime) + + onNodeWithTag("mozac.awesomebar.suggestions") + .performScrollToIndex(5) + + onNodeWithText(searchEngineName) + .assertExists() + .assertIsDisplayed() + .assertHasClickAction() } -private fun selectDefaultSearchEngine(searchEngine: String) { +private fun ComposeTestRule.selectDefaultSearchEngine(searchEngine: String) { onView(withId(R.id.mozac_browser_toolbar_edit_icon)).click() - onView(withText(searchEngine)) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - .perform(click()) + + onNodeWithText(searchEngine) + .assertExists() + .assertIsDisplayed() + .performClick() } private fun assertDefaultSearchEngine(expectedText: String) { diff --git a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarWrapper.kt b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarWrapper.kt index 110845b956..a78f57e3a6 100644 --- a/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarWrapper.kt +++ b/app/src/main/java/org/mozilla/fenix/search/awesomebar/AwesomeBarWrapper.kt @@ -14,6 +14,7 @@ import mozilla.components.compose.browser.awesomebar.AwesomeBar import mozilla.components.compose.browser.awesomebar.AwesomeBarDefaults import mozilla.components.compose.browser.awesomebar.AwesomeBarOrientation import mozilla.components.concept.awesomebar.AwesomeBar +import mozilla.components.support.ktx.android.view.hideKeyboard import org.mozilla.fenix.R import org.mozilla.fenix.ext.settings import org.mozilla.fenix.theme.FirefoxTheme @@ -63,7 +64,8 @@ class AwesomeBarWrapper @JvmOverloads constructor( }, onAutoComplete = { suggestion -> onEditSuggestionListener?.invoke(suggestion.editSuggestion!!) - } + }, + onScroll = { hideKeyboard() } ) } }