Merge branch 'even-more-ui-fixes' into 'master'

Even more ui fixes

Closes #931

See merge request !471
This commit is contained in:
Hans-Christoph Steiner 2017-04-11 21:07:02 +00:00
commit 46adf47fdf
11 changed files with 111 additions and 15 deletions

View File

@ -369,6 +369,11 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
return; return;
} }
initiateInstall(apk); 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) { private void initiateInstall(Apk apk) {

View File

@ -432,8 +432,12 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
Set<String> locales, String key) { Set<String> locales, String key) {
try { try {
for (String locale : locales) { for (String locale : locales) {
if (localized.containsKey(locale)) { Map<String, Object> entry = localized.get(locale);
return locale + "/" + localized.get(locale).get(key); if (entry != null) {
Object value = entry.get(key);
if (value != null && value.toString().length() > 0) {
return locale + "/" + value;
}
} }
} }
} catch (ClassCastException e) { } catch (ClassCastException e) {

View File

@ -14,6 +14,7 @@ import android.os.Build;
import android.support.annotation.ColorInt; import android.support.annotation.ColorInt;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.graphics.Palette; import android.support.v7.graphics.Palette;
import android.support.v7.widget.AppCompatImageView; import android.support.v7.widget.AppCompatImageView;
import android.text.TextUtils; 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.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.fdroid.fdroid.R;
import java.util.Random; import java.util.Random;
/** /**
@ -58,23 +61,34 @@ public class FeatureImage extends AppCompatImageView {
@Nullable @Nullable
private Paint[] trianglePaints; private Paint[] trianglePaints;
private static final Paint WHITE_PAINT = new Paint(); /**
* F-Droid blue is shown behind the animation which eases in the feature graphics. This is
static { * preferable to showing white behind, which can be a bit harsh.
WHITE_PAINT.setColor(Color.WHITE); */
WHITE_PAINT.setStyle(Paint.Style.FILL); @ColorInt
} private int baseColour;
public FeatureImage(Context context) { public FeatureImage(Context context) {
super(context); super(context);
init(context);
} }
public FeatureImage(Context context, @Nullable AttributeSet attrs) { public FeatureImage(Context context, @Nullable AttributeSet attrs) {
super(context, attrs); super(context, attrs);
init(context);
} }
public FeatureImage(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { public FeatureImage(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, 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++) { for (int i = 0; i < trianglePaints.length; i++) {
trianglePaints[i] = random.nextBoolean() ? paintOne : paintTwo; trianglePaints[i] = random.nextBoolean() ? paintOne : paintTwo;
} }
}
public void setColorAndAnimateChange(@ColorInt int colour) {
setColour(colour);
animateColourChange(); animateColourChange();
} }
@ -210,6 +227,7 @@ public class FeatureImage extends AppCompatImageView {
paint.setAlpha(currentAlpha); paint.setAlpha(currentAlpha);
} }
canvas.drawColor(baseColour);
for (int i = 0; i < triangles.length; i++) { for (int i = 0; i < triangles.length; i++) {
canvas.drawPath(triangles[i], trianglePaints[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) { 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)) { if (!TextUtils.isEmpty(featureImageToShow)) {
loadImageAndDisplay(loader, imageOptions, featureImageToShow); loadImageAndDisplay(loader, imageOptions, featureImageToShow);
} else if (!TextUtils.isEmpty(fallbackImageToExtractColours)) { } else if (!TextUtils.isEmpty(fallbackImageToExtractColours)) {
@ -252,7 +271,7 @@ public class FeatureImage extends AppCompatImageView {
@Override @Override
public void onGenerated(Palette palette) { public void onGenerated(Palette palette) {
if (palette != null) { if (palette != null) {
setColour(palette.getDominantColor(Color.LTGRAY)); setColorAndAnimateChange(palette.getDominantColor(Color.LTGRAY));
} }
} }
}); });

View File

@ -10,6 +10,7 @@ import android.support.annotation.IdRes;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.ActivityOptionsCompat; import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.util.Pair; import android.support.v4.util.Pair;
import android.support.v7.graphics.Palette; import android.support.v7.graphics.Palette;
import android.support.v7.widget.RecyclerView; 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); ImageLoader.getInstance().displayImage(app.iconUrl, icon, displayImageOptions, this);
if (featuredImage != null) { if (featuredImage != null) {
featuredImage.setColour(0); featuredImage.setColour(ContextCompat.getColor(activity, R.color.fdroid_blue));
featuredImage.setImageDrawable(null); featuredImage.setImageDrawable(null);
// Note: We could call the convenience function loadImageAndDisplay(ImageLoader, DisplayImageOptions, String, String) // 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() { new Palette.Builder(loadedImage).generate(new Palette.PaletteAsyncListener() {
@Override @Override
public void onGenerated(Palette palette) { public void onGenerated(Palette palette) {
featuredImage.setColour(palette.getDominantColor(Color.LTGRAY)); featuredImage.setColorAndAnimateChange(palette.getDominantColor(Color.LTGRAY));
} }
}); });
} }

View File

@ -94,7 +94,7 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade
image.setColour(backgroundColour); image.setColour(backgroundColour);
image.setImageDrawable(null); image.setImageDrawable(null);
} else { } else {
image.setColour(0); image.setColour(ContextCompat.getColor(activity, R.color.fdroid_blue));
ImageLoader.getInstance().displayImage("drawable://" + categoryImageId, image, displayImageOptions); ImageLoader.getInstance().displayImage("drawable://" + categoryImageId, image, displayImageOptions);
} }
} }

View File

@ -32,6 +32,7 @@ import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
@ -43,6 +44,8 @@ import org.fdroid.fdroid.views.apps.AppListItemController;
public class InstalledAppsActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> { public class InstalledAppsActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private InstalledAppListAdapter adapter; private InstalledAppListAdapter adapter;
private RecyclerView appList;
private TextView emptyState;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -59,10 +62,12 @@ public class InstalledAppsActivity extends AppCompatActivity implements LoaderMa
adapter = new InstalledAppListAdapter(this); adapter = new InstalledAppListAdapter(this);
RecyclerView appList = (RecyclerView) findViewById(R.id.app_list); appList = (RecyclerView) findViewById(R.id.app_list);
appList.setHasFixedSize(true); appList.setHasFixedSize(true);
appList.setLayoutManager(new LinearLayoutManager(this)); appList.setLayoutManager(new LinearLayoutManager(this));
appList.setAdapter(adapter); appList.setAdapter(adapter);
emptyState = (TextView) findViewById(R.id.empty_state);
} }
@Override @Override
@ -85,6 +90,14 @@ public class InstalledAppsActivity extends AppCompatActivity implements LoaderMa
@Override @Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.setApps(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 @Override

View File

@ -5,22 +5,28 @@ 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;
public class UpdatesViewBinder { public class UpdatesViewBinder {
private final UpdatesAdapter adapter; private final UpdatesAdapter adapter;
private final RecyclerView list;
private final TextView emptyState;
public UpdatesViewBinder(AppCompatActivity activity, FrameLayout parent) { public UpdatesViewBinder(AppCompatActivity activity, FrameLayout parent) {
View view = activity.getLayoutInflater().inflate(R.layout.main_tab_updates, parent, true); View view = activity.getLayoutInflater().inflate(R.layout.main_tab_updates, parent, true);
adapter = new UpdatesAdapter(activity); 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.setHasFixedSize(true);
list.setLayoutManager(new LinearLayoutManager(activity)); list.setLayoutManager(new LinearLayoutManager(activity));
list.setAdapter(adapter); list.setAdapter(adapter);
emptyState = (TextView) view.findViewById(R.id.empty_state);
} }
public void bind() { public void bind() {
@ -30,4 +36,32 @@ public class UpdatesViewBinder {
public void unbind() { public void unbind() {
adapter.stopListeningForStatusUpdates(); 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();
}
};
} }

View File

@ -9,6 +9,7 @@
android:paddingBottom="5dp" android:paddingBottom="5dp"
android:paddingLeft="10dp" android:paddingLeft="10dp"
android:paddingRight="10dp" android:paddingRight="10dp"
android:background="?attr/selectableItemBackground"
> >
<TextView android:id="@+id/version" <TextView android:id="@+id/version"

View File

@ -36,7 +36,6 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/header_height" app:layout_constraintTop_toTopOf="@+id/header_height"
android:foreground="?attr/selectableItemBackground" android:foreground="?attr/selectableItemBackground"
android:clickable="true"
> >
<android.support.constraint.ConstraintLayout <android.support.constraint.ConstraintLayout

View File

@ -16,6 +16,18 @@
app:theme="?attr/actionBarTheme" app:theme="?attr/actionBarTheme"
app:popupTheme="?attr/actionBarPopupTheme" /> app:popupTheme="?attr/actionBarPopupTheme" />
<TextView
android:id="@+id/empty_state"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
style="@style/AppListEmptyText"
android:visibility="gone"
android:text="@string/empty_installed_app_list" />
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/app_list" android:id="@+id/app_list"
android:layout_width="0dp" android:layout_width="0dp"

View File

@ -5,6 +5,14 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView
android:id="@+id/empty_state"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="@style/AppListEmptyText"
android:visibility="gone"
android:text="@string/empty_can_update_app_list" />
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/list" android:id="@+id/list"
tools:listitem="@layout/app_list_item" tools:listitem="@layout/app_list_item"