diff --git a/app/src/main/java/org/fdroid/fdroid/AppDetails2.java b/app/src/main/java/org/fdroid/fdroid/AppDetails2.java index cf242b497..40f17cb55 100644 --- a/app/src/main/java/org/fdroid/fdroid/AppDetails2.java +++ b/app/src/main/java/org/fdroid/fdroid/AppDetails2.java @@ -369,6 +369,11 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog return; } initiateInstall(apk); + + // Scroll back to the header, so that the user can see the progress beginning. This can be + // removed once https://gitlab.com/fdroid/fdroidclient/issues/903 is implemented. However + // for now it adds valuable feedback to the user about the download they just initiated. + ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(0, 0); } private void initiateInstall(Apk apk) { diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index f869db5c0..236b3f9af 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -432,8 +432,12 @@ public class App extends ValueObject implements Comparable, Parcelable { Set locales, String key) { try { for (String locale : locales) { - if (localized.containsKey(locale)) { - return locale + "/" + localized.get(locale).get(key); + Map entry = localized.get(locale); + if (entry != null) { + Object value = entry.get(key); + if (value != null && value.toString().length() > 0) { + return locale + "/" + value; + } } } } catch (ClassCastException e) { diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/FeatureImage.java b/app/src/main/java/org/fdroid/fdroid/views/apps/FeatureImage.java index 7b728e3b4..bc0d820c3 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/apps/FeatureImage.java +++ b/app/src/main/java/org/fdroid/fdroid/views/apps/FeatureImage.java @@ -14,6 +14,7 @@ import android.os.Build; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; import android.support.v7.graphics.Palette; import android.support.v7.widget.AppCompatImageView; import android.text.TextUtils; @@ -25,6 +26,8 @@ import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; +import org.fdroid.fdroid.R; + import java.util.Random; /** @@ -58,23 +61,34 @@ public class FeatureImage extends AppCompatImageView { @Nullable private Paint[] trianglePaints; - private static final Paint WHITE_PAINT = new Paint(); - - static { - WHITE_PAINT.setColor(Color.WHITE); - WHITE_PAINT.setStyle(Paint.Style.FILL); - } + /** + * F-Droid blue is shown behind the animation which eases in the feature graphics. This is + * preferable to showing white behind, which can be a bit harsh. + */ + @ColorInt + private int baseColour; public FeatureImage(Context context) { super(context); + init(context); } public FeatureImage(Context context, @Nullable AttributeSet attrs) { super(context, attrs); + init(context); } public FeatureImage(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + float[] hsv = new float[3]; + Color.colorToHSV(ContextCompat.getColor(context, R.color.fdroid_blue), hsv); + hsv[1] *= 0.5f; + hsv[2] *= 0.7f; + baseColour = Color.HSVToColor(hsv); } /** @@ -118,7 +132,10 @@ public class FeatureImage extends AppCompatImageView { for (int i = 0; i < trianglePaints.length; i++) { trianglePaints[i] = random.nextBoolean() ? paintOne : paintTwo; } + } + public void setColorAndAnimateChange(@ColorInt int colour) { + setColour(colour); animateColourChange(); } @@ -210,6 +227,7 @@ public class FeatureImage extends AppCompatImageView { paint.setAlpha(currentAlpha); } + canvas.drawColor(baseColour); for (int i = 0; i < triangles.length; i++) { canvas.drawPath(triangles[i], trianglePaints[i]); } @@ -236,6 +254,7 @@ public class FeatureImage extends AppCompatImageView { } public void loadImageAndDisplay(@NonNull ImageLoader loader, @NonNull DisplayImageOptions imageOptions, @Nullable String featureImageToShow, @Nullable String fallbackImageToExtractColours) { + setColour(ContextCompat.getColor(getContext(), R.color.fdroid_blue)); if (!TextUtils.isEmpty(featureImageToShow)) { loadImageAndDisplay(loader, imageOptions, featureImageToShow); } else if (!TextUtils.isEmpty(fallbackImageToExtractColours)) { @@ -252,7 +271,7 @@ public class FeatureImage extends AppCompatImageView { @Override public void onGenerated(Palette palette) { if (palette != null) { - setColour(palette.getDominantColor(Color.LTGRAY)); + setColorAndAnimateChange(palette.getDominantColor(Color.LTGRAY)); } } }); diff --git a/app/src/main/java/org/fdroid/fdroid/views/categories/AppCardController.java b/app/src/main/java/org/fdroid/fdroid/views/categories/AppCardController.java index 1c327c76c..6436e9f0e 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/categories/AppCardController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/categories/AppCardController.java @@ -10,6 +10,7 @@ import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.content.ContextCompat; import android.support.v4.util.Pair; import android.support.v7.graphics.Palette; import android.support.v7.widget.RecyclerView; @@ -120,7 +121,7 @@ public class AppCardController extends RecyclerView.ViewHolder implements ImageL ImageLoader.getInstance().displayImage(app.iconUrl, icon, displayImageOptions, this); if (featuredImage != null) { - featuredImage.setColour(0); + featuredImage.setColour(ContextCompat.getColor(activity, R.color.fdroid_blue)); featuredImage.setImageDrawable(null); // Note: We could call the convenience function loadImageAndDisplay(ImageLoader, DisplayImageOptions, String, String) @@ -183,7 +184,7 @@ public class AppCardController extends RecyclerView.ViewHolder implements ImageL new Palette.Builder(loadedImage).generate(new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { - featuredImage.setColour(palette.getDominantColor(Color.LTGRAY)); + featuredImage.setColorAndAnimateChange(palette.getDominantColor(Color.LTGRAY)); } }); } diff --git a/app/src/main/java/org/fdroid/fdroid/views/categories/CategoryController.java b/app/src/main/java/org/fdroid/fdroid/views/categories/CategoryController.java index 10e99162a..50d02e3ee 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/categories/CategoryController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/categories/CategoryController.java @@ -94,7 +94,7 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade image.setColour(backgroundColour); image.setImageDrawable(null); } else { - image.setColour(0); + image.setColour(ContextCompat.getColor(activity, R.color.fdroid_blue)); ImageLoader.getInstance().displayImage("drawable://" + categoryImageId, image, displayImageOptions); } } diff --git a/app/src/main/java/org/fdroid/fdroid/views/installed/InstalledAppsActivity.java b/app/src/main/java/org/fdroid/fdroid/views/installed/InstalledAppsActivity.java index 6f051dd6d..c459bbffc 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/installed/InstalledAppsActivity.java +++ b/app/src/main/java/org/fdroid/fdroid/views/installed/InstalledAppsActivity.java @@ -32,6 +32,7 @@ import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; @@ -43,6 +44,8 @@ import org.fdroid.fdroid.views.apps.AppListItemController; public class InstalledAppsActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks { private InstalledAppListAdapter adapter; + private RecyclerView appList; + private TextView emptyState; @Override protected void onCreate(Bundle savedInstanceState) { @@ -59,10 +62,12 @@ public class InstalledAppsActivity extends AppCompatActivity implements LoaderMa adapter = new InstalledAppListAdapter(this); - RecyclerView appList = (RecyclerView) findViewById(R.id.app_list); + appList = (RecyclerView) findViewById(R.id.app_list); appList.setHasFixedSize(true); appList.setLayoutManager(new LinearLayoutManager(this)); appList.setAdapter(adapter); + + emptyState = (TextView) findViewById(R.id.empty_state); } @Override @@ -85,6 +90,14 @@ public class InstalledAppsActivity extends AppCompatActivity implements LoaderMa @Override public void onLoadFinished(Loader loader, Cursor cursor) { adapter.setApps(cursor); + + if (adapter.getItemCount() == 0) { + appList.setVisibility(View.GONE); + emptyState.setVisibility(View.VISIBLE); + } else { + appList.setVisibility(View.VISIBLE); + emptyState.setVisibility(View.GONE); + } } @Override diff --git a/app/src/main/java/org/fdroid/fdroid/views/updates/UpdatesViewBinder.java b/app/src/main/java/org/fdroid/fdroid/views/updates/UpdatesViewBinder.java index 50d287bfe..6b5a8bc24 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/updates/UpdatesViewBinder.java +++ b/app/src/main/java/org/fdroid/fdroid/views/updates/UpdatesViewBinder.java @@ -5,22 +5,28 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.FrameLayout; +import android.widget.TextView; import org.fdroid.fdroid.R; public class UpdatesViewBinder { private final UpdatesAdapter adapter; + private final RecyclerView list; + private final TextView emptyState; public UpdatesViewBinder(AppCompatActivity activity, FrameLayout parent) { View view = activity.getLayoutInflater().inflate(R.layout.main_tab_updates, parent, true); adapter = new UpdatesAdapter(activity); + adapter.registerAdapterDataObserver(adapterChangeListener); - RecyclerView list = (RecyclerView) view.findViewById(R.id.list); + list = (RecyclerView) view.findViewById(R.id.list); list.setHasFixedSize(true); list.setLayoutManager(new LinearLayoutManager(activity)); list.setAdapter(adapter); + + emptyState = (TextView) view.findViewById(R.id.empty_state); } public void bind() { @@ -30,4 +36,32 @@ public class UpdatesViewBinder { public void unbind() { adapter.stopListeningForStatusUpdates(); } + + private void updateEmptyState() { + if (adapter.getItemCount() == 0) { + list.setVisibility(View.GONE); + emptyState.setVisibility(View.VISIBLE); + } else { + list.setVisibility(View.VISIBLE); + emptyState.setVisibility(View.GONE); + } + } + + @SuppressWarnings("FieldCanBeLocal") + private final RecyclerView.AdapterDataObserver adapterChangeListener = new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + updateEmptyState(); + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + updateEmptyState(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + updateEmptyState(); + } + }; } diff --git a/app/src/main/res/layout/apklistitem.xml b/app/src/main/res/layout/apklistitem.xml index 6989b9286..57ac5405a 100644 --- a/app/src/main/res/layout/apklistitem.xml +++ b/app/src/main/res/layout/apklistitem.xml @@ -9,6 +9,7 @@ android:paddingBottom="5dp" android:paddingLeft="10dp" android:paddingRight="10dp" + android:background="?attr/selectableItemBackground" > + + + +