Skip to content

[stable-3.32] Nmc/1980 Empty state #345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: stable-3.32
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions app/src/androidTest/java/com/nmc/android/ui/EmptyStateViewIT.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package com.nmc.android.ui

import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import com.nextcloud.test.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.lib.resources.notifications.models.Notification
import com.owncloud.android.ui.activity.FolderPickerActivity
import com.owncloud.android.ui.activity.NotificationsActivity
import com.owncloud.android.ui.activity.ReceiveExternalFilesActivity
import com.owncloud.android.ui.activity.UploadListActivity
import com.owncloud.android.ui.fragment.GalleryFragment
import com.owncloud.android.ui.fragment.OCFileListFragment
import com.owncloud.android.ui.fragment.SearchType
import com.owncloud.android.ui.trashbin.TrashbinActivity
import org.junit.Rule
import org.junit.Test

/**
* test to validate empty state on different screens
*/
class EmptyStateViewIT : AbstractIT() {

@get:Rule
val testActivityRule = ActivityScenarioRule(TestActivity::class.java)

@Test
fun validate_emptyState_NoSearch() {
loadOCFileListFragmentWithSearchType(SearchType.NO_SEARCH)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No files here")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Upload some content or sync with your devices.")))
}

@Test
fun validate_emptyState_FileSearch() {
loadOCFileListFragmentWithSearchType(SearchType.FILE_SEARCH)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No results")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Search for a file (at least 2 characters)")))
}

@Test
fun validate_emptyState_FavoriteSearch() {
loadOCFileListFragmentWithSearchType(SearchType.FAVORITE_SEARCH)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("Nothing favorited yet")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Files and folders you mark as favorites will show up here.")))
}

@Test
fun validate_emptyState_RecentSearch() {
loadOCFileListFragmentWithSearchType(SearchType.RECENTLY_MODIFIED_SEARCH)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No results")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Found no files modified within the last 7 days")))
}

@Test
fun validate_emptyState_SharedSearch() {
loadOCFileListFragmentWithSearchType(SearchType.SHARED_FILTER)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("Nothing shared yet")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Files and folders you share will show up here.")))
}

@Test
fun validate_emptyState_GallerySearch() {
loadGalleryFragment()
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No files here")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("No photos or videos uploaded yet")))
}

@Test
fun validate_emptyState_Notification() {
val activityScenario = ActivityScenario.launch(NotificationsActivity::class.java)
waitForIdleSync()
activityScenario.onActivity {
it.runOnUiThread { it.populateList(ArrayList<Notification>()) }
}

onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No notifications")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Please check back later.")))
}

@Test
fun validate_errorState_Trashbin() {
ActivityScenario.launch(TrashbinActivity::class.java)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("Error")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Loading trash bin failed!")))
}

@Test
fun validate_emptyState_Trashbin() {
val activityScenario = ActivityScenario.launch(TrashbinActivity::class.java)
activityScenario.onActivity {
it.showTrashbinFolder(emptyList())
}
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No deleted files")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("You will be able to recover deleted files from here.")))
}

@Test
fun validate_emptyState_FolderPicker() {
ActivityScenario.launch(FolderPickerActivity::class.java)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No files here")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Upload some content or sync with your devices.")))
}

@Test
fun validate_emptyState_ReceivedExternalFiles() {
ActivityScenario.launch(ReceiveExternalFilesActivity::class.java)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No files here")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("")))
}

@Test
fun validate_emptyState_UploadList() {
ActivityScenario.launch(UploadListActivity::class.java)
onView(withId(R.id.empty_list_icon)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_headline)).check(matches(withText("No uploads available")))
onView(withId(R.id.empty_list_view_text)).check(matches(isCompletelyDisplayed()))
onView(withId(R.id.empty_list_view_text)).check(matches(withText("Upload some content or activate auto upload.")))
}

private fun loadOCFileListFragmentWithSearchType(searchType: SearchType) {
testActivityRule.scenario.onActivity {
it.addFragment(OCFileListFragment())
}

waitForIdleSync()

testActivityRule.scenario.onActivity {
val fragment = (it.fragment as OCFileListFragment)
fragment.setEmptyListMessage(searchType)
}
}

private fun loadGalleryFragment() {
testActivityRule.scenario.onActivity {
it.addFragment(GalleryFragment())
}

waitForIdleSync()

testActivityRule.scenario.onActivity {
val fragment = (it.fragment as GalleryFragment)
fragment.setEmptyListMessage(SearchType.GALLERY_SEARCH)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ open class FolderPickerActivity :
it.setMessageForEmptyList(
R.string.folder_list_empty_headline,
R.string.file_list_empty_moving,
R.drawable.ic_list_empty_create_folder,
R.drawable.ic_list_empty_folder,
true
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ class NotificationsActivity : AppCompatActivity(), NotificationsContract.View, I
* sets up the UI elements and loads all notification items.
*/
private fun setupContent() {
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_notification)
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_list_empty_notification)
setLoadingMessageEmpty()
val layoutManager = LinearLayoutManager(this)
binding.list.layoutManager = layoutManager
Expand Down Expand Up @@ -336,7 +336,7 @@ class NotificationsActivity : AppCompatActivity(), NotificationsContract.View, I
binding.emptyList.emptyListView.visibility = View.VISIBLE
binding.emptyList.emptyListViewHeadline.text = headline
binding.emptyList.emptyListViewText.text = message
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_notification)
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_list_empty_notification)
binding.emptyList.emptyListViewText.visibility = View.VISIBLE
binding.emptyList.emptyListIcon.visibility = View.VISIBLE
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ private void populateDirectoryList(OCFile file) {

if (files.isEmpty()) {
setMessageForEmptyList(R.string.file_list_empty_headline, R.string.empty,
R.drawable.uploads);
R.drawable.ic_list_empty_uploads);
mEmptyListContainer.setVisibility(View.VISIBLE);
binding.list.setVisibility(View.GONE);
} else {
Expand Down Expand Up @@ -827,7 +827,7 @@ public void setMessageForEmptyList(@StringRes final int headline, @StringRes fin
if (mEmptyListContainer != null && mEmptyListMessage != null) {
mEmptyListHeadline.setText(headline);
mEmptyListMessage.setText(message);
mEmptyListIcon.setImageDrawable(viewThemeUtils.platform.tintPrimaryDrawable(this, icon));
mEmptyListIcon.setImageResource(icon);
mEmptyListIcon.setVisibility(View.VISIBLE);
mEmptyListMessage.setVisibility(View.VISIBLE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ class SyncedFoldersActivity :
binding.list.layoutManager = lm
binding.list.adapter = adapter
load(getItemsDisplayedPerFolder(), false)
//NMC customization
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_list_empty_synced_folders)
}

private fun showHiddenItems() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,7 @@ private void handleUploadWorkerState() {
private void setupContent() {
binding.list.setEmptyView(binding.emptyList.getRoot());
binding.emptyList.getRoot().setVisibility(View.GONE);
binding.emptyList.emptyListIcon.setImageResource(R.drawable.uploads);
binding.emptyList.emptyListIcon.getDrawable().mutate();
binding.emptyList.emptyListIcon.setAlpha(0.5f);
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_list_empty_uploads);
binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
binding.emptyList.emptyListViewHeadline.setText(getString(R.string.upload_list_empty_headline));
binding.emptyList.emptyListViewText.setText(getString(R.string.upload_list_empty_text_auto_upload));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,14 +585,8 @@ open class ExtendedListFragment :
mEmptyListHeadline?.setText(headline)
mEmptyListMessage?.setText(message)

if (tintIcon) {
context?.let {
val drawable = viewThemeUtils.platform.tintDrawable(it, icon, ColorRole.PRIMARY)
mEmptyListIcon?.setImageDrawable(drawable)
}
} else {
mEmptyListIcon?.setImageResource(icon)
}
// tinting is not required in NMC
mEmptyListIcon?.setImageResource(icon)

mEmptyListIcon?.setVisibility(View.VISIBLE)
mEmptyListMessage?.visibility = View.VISIBLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,8 @@ class UnifiedSearchFragment :
requireContext().getString(R.string.file_list_empty_headline_server_search)
binding.emptyList.emptyListViewText.text =
requireContext().getString(R.string.file_list_empty_unified_search_no_results)
binding.emptyList.emptyListIcon.setImageDrawable(
viewThemeUtils.platform.tintDrawable(requireContext(), R.drawable.ic_search_grey)
)
//NMC Customization
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_search_empty)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class TrashbinActivity :
recyclerView.setEmptyView(binding.emptyList.emptyListView)

binding.emptyList.emptyListView.visibility = View.GONE
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_delete)
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_list_empty_trashbin)
binding.emptyList.emptyListIcon.visibility = View.VISIBLE
binding.emptyList.emptyListViewHeadline.text = getString(R.string.trashbin_empty_headline)
binding.emptyList.emptyListViewText.text = getString(R.string.trashbin_empty_message)
Expand Down Expand Up @@ -310,7 +310,7 @@ class TrashbinActivity :
trashbinListAdapter?.setTrashbinFiles(trashbinFiles, true)
binding.swipeContainingList.isRefreshing = false
binding.loadingContent.visibility = View.GONE
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_delete)
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_list_empty_trashbin)
binding.emptyList.emptyListViewHeadline.text = getString(R.string.trashbin_empty_headline)
binding.emptyList.emptyListViewText.text = getString(R.string.trashbin_empty_message)
binding.list.visibility = View.VISIBLE
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/res/drawable-night/ic_list_empty_error.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/empty_list_icon_color_dark"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,1C5.9249,1 1,5.9249 1,12C1,18.0751 5.9249,23 12,23C18.0751,23 23,18.0751 23,12C23,9.0826 21.8411,6.2847 19.7782,4.2218C17.7153,2.1589 14.9174,1 12,1ZM11,6.75L13,6.75L13,13.25L11,13.25L11,6.75ZM12,17.25C11.3096,17.25 10.75,16.6904 10.75,16C10.75,15.3096 11.3096,14.75 12,14.75C12.6904,14.75 13.25,15.3096 13.25,16C13.25,16.6904 12.6904,17.25 12,17.25L12,17.25Z"
android:strokeWidth="1"
android:fillColor="#262626"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>
13 changes: 13 additions & 0 deletions app/src/main/res/drawable-night/ic_list_empty_media.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/empty_list_icon_color_dark"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#191919"
android:fillType="evenOdd"
android:pathData="M5.355,11.5C5.61,12.03 5.915,12.535 6.265,13L6.265,13L2,13L2,19.145C2,19.34 2.16,19.5 2.355,19.5L2.355,19.5L10.17,19.5L12,21.33L12,16.4C12.41,16.46 12.825,16.5 13.255,16.505C13.34,16.505 13.42,16.49 13.505,16.49L13.505,16.49L13.505,22.34C13.505,22.995 12.97,23.425 12.415,23.425C12.145,23.425 11.875,23.325 11.655,23.105L11.655,23.105L9.55,21L2.355,21C1.33,21 0.5,20.17 0.5,19.145L0.5,19.145L0.5,11.5ZM19.5,10.06L23.5,12.405L23.5,14.235L20.99,13.6L20.99,13.6L20.99,19.855C20.99,21.955 19.4,22.275 18.53,22.205C17.185,22.095 16.105,21.15 16.12,20.05C16.14,18.95 17.24,18.13 18.59,18.22C18.91,18.245 19.22,18.32 19.5,18.43L19.5,18.43L19.5,10.06ZM13.25,0.5C17.255,0.5 20.5,3.745 20.5,7.75C20.5,8.125 20.46,8.495 20.405,8.855L20.405,8.855L18.985,8.02C18.99,7.93 19,7.84 19,7.75C19,4.58 16.42,2 13.25,2C10.08,2 7.5,4.58 7.5,7.75C7.5,10.92 10.08,13.5 13.25,13.5C15.22,13.5 16.965,12.5 18,10.985L18,10.985L18,13.22C16.725,14.325 15.07,15 13.25,15C9.245,15 6,11.755 6,7.75C6,3.745 9.245,0.5 13.25,0.5ZM11.5,5.17L16.115,7.835L11.5,10.5L11.5,5.17Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
13 changes: 13 additions & 0 deletions app/src/main/res/drawable-night/ic_list_empty_notification.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/empty_list_icon_color_dark"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#262626"
android:fillType="evenOdd"
android:pathData="M22,16.95C19.65,14.6 19.3,12.3 19.2,11.15L19,9.4C18.75,6.25 16.45,3.8 13.5,3.15C13.5,3.1 13.5,3.05 13.5,3C13.5,2.15 12.85,1.5 12,1.5C11.15,1.5 10.5,2.15 10.5,3C10.5,3.05 10.5,3.1 10.5,3.15C7.55,3.8 5.25,6.25 5,9.4L4.85,11.15C4.7,12.25 4.35,14.55 2,16.95L2,20.5L9.05,20.5C9.3,21.9 10.5,23 12,23C13.5,23 14.7,21.9 14.95,20.5L22,20.5L22,16.95ZM20.5,19L3.5,19L3.5,17.55C5.1,15.85 6.1,13.65 6.3,11.3L6.45,9.55C6.75,6.65 9.1,4.5 12,4.5C14.9,4.5 17.25,6.65 17.5,9.55L17.65,11.3C17.85,13.65 18.85,15.85 20.45,17.55L20.45,19L20.5,19Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
Loading