Show empty state feedback for latest + categories
The text is more comprehensive on the main screen than on categories, because this is the view that all users will see when they first open F-Droid. Fixes #879.
This commit is contained in:
parent
510ec5f7c7
commit
ab5ea39f7c
app/src/main
java/org/fdroid/fdroid/views/main
res
@ -12,6 +12,7 @@ import android.support.v7.widget.LinearLayoutManager;
|
|||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.data.CategoryProvider;
|
import org.fdroid.fdroid.data.CategoryProvider;
|
||||||
@ -30,6 +31,8 @@ class CategoriesViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
|
|||||||
|
|
||||||
private final CategoryAdapter categoryAdapter;
|
private final CategoryAdapter categoryAdapter;
|
||||||
private final AppCompatActivity activity;
|
private final AppCompatActivity activity;
|
||||||
|
private final TextView emptyState;
|
||||||
|
private final RecyclerView categoriesList;
|
||||||
|
|
||||||
CategoriesViewBinder(final AppCompatActivity activity, FrameLayout parent) {
|
CategoriesViewBinder(final AppCompatActivity activity, FrameLayout parent) {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
@ -38,7 +41,9 @@ class CategoriesViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
|
|||||||
|
|
||||||
categoryAdapter = new CategoryAdapter(activity, activity.getSupportLoaderManager());
|
categoryAdapter = new CategoryAdapter(activity, activity.getSupportLoaderManager());
|
||||||
|
|
||||||
RecyclerView categoriesList = (RecyclerView) categoriesView.findViewById(R.id.category_list);
|
emptyState = (TextView) categoriesView.findViewById(R.id.empty_state);
|
||||||
|
|
||||||
|
categoriesList = (RecyclerView) categoriesView.findViewById(R.id.category_list);
|
||||||
categoriesList.setHasFixedSize(true);
|
categoriesList.setHasFixedSize(true);
|
||||||
categoriesList.setLayoutManager(new LinearLayoutManager(activity));
|
categoriesList.setLayoutManager(new LinearLayoutManager(activity));
|
||||||
categoriesList.setAdapter(categoryAdapter);
|
categoriesList.setAdapter(categoryAdapter);
|
||||||
@ -77,6 +82,14 @@ class CategoriesViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
categoryAdapter.setCategoriesCursor(cursor);
|
categoryAdapter.setCategoriesCursor(cursor);
|
||||||
|
|
||||||
|
if (categoryAdapter.getItemCount() == 0) {
|
||||||
|
emptyState.setVisibility(View.VISIBLE);
|
||||||
|
categoriesList.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
emptyState.setVisibility(View.GONE);
|
||||||
|
categoriesList.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -13,14 +13,20 @@ import android.support.v7.widget.GridLayoutManager;
|
|||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.UpdateService;
|
import org.fdroid.fdroid.UpdateService;
|
||||||
import org.fdroid.fdroid.data.AppProvider;
|
import org.fdroid.fdroid.data.AppProvider;
|
||||||
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
import org.fdroid.fdroid.data.Schema;
|
import org.fdroid.fdroid.data.Schema;
|
||||||
import org.fdroid.fdroid.views.apps.AppListActivity;
|
import org.fdroid.fdroid.views.apps.AppListActivity;
|
||||||
import org.fdroid.fdroid.views.whatsnew.WhatsNewAdapter;
|
import org.fdroid.fdroid.views.whatsnew.WhatsNewAdapter;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a list of newly added or recently updated apps and displays them to the user.
|
* Loads a list of newly added or recently updated apps and displays them to the user.
|
||||||
*/
|
*/
|
||||||
@ -30,6 +36,8 @@ class WhatsNewViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
|
|||||||
|
|
||||||
private final WhatsNewAdapter whatsNewAdapter;
|
private final WhatsNewAdapter whatsNewAdapter;
|
||||||
private final AppCompatActivity activity;
|
private final AppCompatActivity activity;
|
||||||
|
private final TextView emptyState;
|
||||||
|
private final RecyclerView appList;
|
||||||
|
|
||||||
WhatsNewViewBinder(final AppCompatActivity activity, FrameLayout parent) {
|
WhatsNewViewBinder(final AppCompatActivity activity, FrameLayout parent) {
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
@ -41,7 +49,9 @@ class WhatsNewViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
|
|||||||
GridLayoutManager layoutManager = new GridLayoutManager(activity, 2);
|
GridLayoutManager layoutManager = new GridLayoutManager(activity, 2);
|
||||||
layoutManager.setSpanSizeLookup(new WhatsNewAdapter.SpanSizeLookup());
|
layoutManager.setSpanSizeLookup(new WhatsNewAdapter.SpanSizeLookup());
|
||||||
|
|
||||||
RecyclerView appList = (RecyclerView) whatsNewView.findViewById(R.id.app_list);
|
emptyState = (TextView) whatsNewView.findViewById(R.id.empty_state);
|
||||||
|
|
||||||
|
appList = (RecyclerView) whatsNewView.findViewById(R.id.app_list);
|
||||||
appList.setHasFixedSize(true);
|
appList.setHasFixedSize(true);
|
||||||
appList.setLayoutManager(layoutManager);
|
appList.setLayoutManager(layoutManager);
|
||||||
appList.setAdapter(whatsNewAdapter);
|
appList.setAdapter(whatsNewAdapter);
|
||||||
@ -89,6 +99,37 @@ class WhatsNewViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
whatsNewAdapter.setAppsCursor(cursor);
|
whatsNewAdapter.setAppsCursor(cursor);
|
||||||
|
|
||||||
|
if (whatsNewAdapter.getItemCount() == 0) {
|
||||||
|
emptyState.setVisibility(View.VISIBLE);
|
||||||
|
appList.setVisibility(View.GONE);
|
||||||
|
explainEmptyStateToUser();
|
||||||
|
} else {
|
||||||
|
emptyState.setVisibility(View.GONE);
|
||||||
|
appList.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void explainEmptyStateToUser() {
|
||||||
|
StringBuilder emptyStateText = new StringBuilder();
|
||||||
|
emptyStateText.append(activity.getString(R.string.latest__empty_state__no_recent_apps));
|
||||||
|
emptyStateText.append("\n\n");
|
||||||
|
|
||||||
|
int repoCount = RepoProvider.Helper.countEnabledRepos(activity);
|
||||||
|
if (repoCount == 0) {
|
||||||
|
emptyStateText.append(activity.getString(R.string.latest__empty_state__no_enabled_repos));
|
||||||
|
} else {
|
||||||
|
Date lastUpdate = RepoProvider.Helper.lastUpdate(activity);
|
||||||
|
if (lastUpdate == null) {
|
||||||
|
emptyStateText.append(activity.getString(R.string.latest__empty_state__never_updated));
|
||||||
|
} else {
|
||||||
|
long msDiff = Calendar.getInstance().getTimeInMillis() - lastUpdate.getTime();
|
||||||
|
int daysDiff = (int) TimeUnit.MILLISECONDS.toDays(msDiff);
|
||||||
|
emptyStateText.append(activity.getResources().getQuantityString(R.plurals.details_last_update_days, daysDiff, daysDiff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyState.setText(emptyStateText.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,6 +16,18 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:layout_editor_absoluteX="8dp" />
|
tools:layout_editor_absoluteX="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/empty_state"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
style="@style/AppListEmptyText"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/categories__empty_state__no_categories" />
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/category_list"
|
android:id="@+id/category_list"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -21,6 +21,14 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/empty_state"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
style="@style/AppListEmptyText"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="@string/latest__empty_state__no_recent_apps"/>
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/app_list"
|
android:id="@+id/app_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -159,6 +159,12 @@
|
|||||||
<string name="main_menu__categories">Categories</string>
|
<string name="main_menu__categories">Categories</string>
|
||||||
<string name="main_menu__swap_nearby">Nearby</string>
|
<string name="main_menu__swap_nearby">Nearby</string>
|
||||||
|
|
||||||
|
<string name="latest__empty_state__no_recent_apps">No recent apps found</string>
|
||||||
|
<string name="latest__empty_state__never_updated">Once your list of apps has been updated, the latest apps should show here</string>
|
||||||
|
<string name="latest__empty_state__no_enabled_repos">Once you enable a repository and let it update, the latest apps should show here</string>
|
||||||
|
|
||||||
|
<string name="categories__empty_state__no_categories">No categories to display</string>
|
||||||
|
|
||||||
<string name="preference_category__my_apps">My Apps</string>
|
<string name="preference_category__my_apps">My Apps</string>
|
||||||
<string name="preference_manage_installed_apps">Manage Installed Apps</string>
|
<string name="preference_manage_installed_apps">Manage Installed Apps</string>
|
||||||
|
|
||||||
|
@ -93,6 +93,13 @@
|
|||||||
</style>
|
</style>
|
||||||
<style name="BodyText" parent="BodyTextBase" />
|
<style name="BodyText" parent="BodyTextBase" />
|
||||||
|
|
||||||
|
<style name="AppListEmptyText">
|
||||||
|
<item name="android:id">@android:id/empty</item>
|
||||||
|
<item name="android:gravity">center</item>
|
||||||
|
<item name="android:padding">20dp</item>
|
||||||
|
<item name="android:textSize">20sp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="SwapTheme.Wizard" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="SwapTheme.Wizard" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
<item name="colorButtonNormal">@color/swap_bright_blue</item>
|
<item name="colorButtonNormal">@color/swap_bright_blue</item>
|
||||||
<item name="actionButtonStyle">@style/SwapTheme.Wizard.ActionButton</item>
|
<item name="actionButtonStyle">@style/SwapTheme.Wizard.ActionButton</item>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user