diff --git a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
index f4ec35ba6..1ed1803c2 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
@@ -732,6 +732,7 @@ public class AppProvider extends FDroidProvider {
case TOP_FROM_CATEGORY:
selection = selection.add(queryCategory(pathSegments.get(2)));
limit = Integer.parseInt(pathSegments.get(1));
+ sortOrder = getTableName() + "." + Cols.LAST_UPDATED + " DESC";
includeSwap = false;
break;
diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/CategorySpan.java b/app/src/main/java/org/fdroid/fdroid/views/apps/CategorySpan.java
index 628c65325..4c47d02d5 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/apps/CategorySpan.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/apps/CategorySpan.java
@@ -97,6 +97,8 @@ public class CategorySpan extends ReplacementSpan {
RectF backgroundRect = new RectF(0, 0, iconBackgroundSize + textLeadingPadding
+ textWidth + textTrailingPadding, height);
+ int backgroundColour = CategoryController.getBackgroundColour(context, categoryName.toString());
+
// The shadow below the entire category chip.
canvas.save();
canvas.translate(0, DROP_SHADOW_HEIGHT * density);
@@ -108,7 +110,7 @@ public class CategorySpan extends ReplacementSpan {
// The background which goes behind the text.
Paint backgroundPaint = new Paint();
- backgroundPaint.setColor(CategoryController.getBackgroundColour(context, categoryName.toString()));
+ backgroundPaint.setColor(backgroundColour);
backgroundPaint.setAntiAlias(true);
canvas.drawRoundRect(backgroundRect, cornerRadius, cornerRadius, backgroundPaint);
@@ -124,9 +126,15 @@ public class CategorySpan extends ReplacementSpan {
icon.setBounds(iconPadding, iconPadding, iconPadding + iconSize, iconPadding + iconSize);
icon.draw(canvas);
+ // Choose white or black text based on the perceived brightness.
+ // Uses some arbitrary magic from https://stackoverflow.com/a/946734/2391921
+ double grey = Color.red(backgroundColour) * 0.299 +
+ Color.green(backgroundColour) * 0.587 +
+ Color.blue(backgroundColour) * 0.114;
+
// The category name drawn to the right of the category name.
Paint textPaint = new Paint(paint);
- textPaint.setColor(Color.WHITE);
+ textPaint.setColor(grey < 186 ? Color.WHITE : Color.BLACK);
canvas.drawText(categoryName.toString(), iconBackgroundSize + textLeadingPadding, bottom, textPaint);
canvas.restore();
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 67790cd47..fab763e4e 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -8,17 +8,17 @@
#CBEFEC
#E2D6BC
- #6D6862
- #F25050
- #DBDDC9
+ #F3B569
+ #F65A5A
+ #73EABC
#DDDDD0
#FF7F66
#94D6FD
#F3CFC0
#D6A07A
#F4F4EC
- #6D6862
- #72C7EA
+ #FFD15F
+ #ADCEDE
#D3DB77
#DEEFE9
#FF7043
diff --git a/app/src/test/java/org/fdroid/fdroid/data/CategoryProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/CategoryProviderTest.java
index 60779cf99..e35c968c2 100644
--- a/app/src/test/java/org/fdroid/fdroid/data/CategoryProviderTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/data/CategoryProviderTest.java
@@ -17,9 +17,11 @@ import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import static org.fdroid.fdroid.Assert.assertContainsOnly;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@Config(constants = BuildConfig.class, application = Application.class, sdk = 23)
@@ -164,29 +166,29 @@ public class CategoryProviderTest extends FDroidProviderTest {
@Test
public void topAppsFromCategory() {
- insertAppWithCategory("com.dog", "Dog", "Animal");
- insertAppWithCategory("com.cat", "Cat", "Animal");
- insertAppWithCategory("com.bird", "Bird", "Animal");
- insertAppWithCategory("com.snake", "Snake", "Animal");
- insertAppWithCategory("com.rat", "Rat", "Animal");
+ insertAppWithCategory("com.dog", "Dog", "Animal", new Date(2017, 2, 6));
+ insertAppWithCategory("com.cat", "Cat", "Animal", new Date(2017, 2, 5));
+ insertAppWithCategory("com.bird", "Bird", "Animal", new Date(2017, 2, 4));
+ insertAppWithCategory("com.snake", "Snake", "Animal", new Date(2017, 2, 3));
+ insertAppWithCategory("com.rat", "Rat", "Animal", new Date(2017, 2, 2));
- insertAppWithCategory("com.rock", "Rock", "Mineral");
- insertAppWithCategory("com.stone", "Stone", "Mineral");
- insertAppWithCategory("com.boulder", "Boulder", "Mineral");
+ insertAppWithCategory("com.rock", "Rock", "Mineral", new Date(2017, 1, 4));
+ insertAppWithCategory("com.stone", "Stone", "Mineral", new Date(2017, 1, 3));
+ insertAppWithCategory("com.boulder", "Boulder", "Mineral", new Date(2017, 1, 2));
- insertAppWithCategory("com.banana", "Banana", "Vegetable");
- insertAppWithCategory("com.tomato", "Tomato", "Vegetable");
+ insertAppWithCategory("com.banana", "Banana", "Vegetable", new Date(2015, 1, 1));
+ insertAppWithCategory("com.tomato", "Tomato", "Vegetable", new Date(2017, 4, 4));
- assertContainsOnly(topAppsFromCategory("Animal", 3), new String[]{"com.bird", "com.cat", "com.dog"});
- assertContainsOnly(topAppsFromCategory("Animal", 2), new String[]{"com.bird", "com.cat"});
- assertContainsOnly(topAppsFromCategory("Animal", 1), new String[]{"com.bird"});
+ assertArrayEquals(getTopAppsFromCategory("Animal", 3), new String[]{"com.dog", "com.cat", "com.bird"});
+ assertArrayEquals(getTopAppsFromCategory("Animal", 2), new String[]{"com.dog", "com.cat"});
+ assertArrayEquals(getTopAppsFromCategory("Animal", 1), new String[]{"com.dog"});
- assertContainsOnly(topAppsFromCategory("Mineral", 2), new String[]{"com.boulder", "com.rock"});
+ assertArrayEquals(getTopAppsFromCategory("Mineral", 2), new String[]{"com.rock", "com.stone"});
- assertContainsOnly(topAppsFromCategory("Vegetable", 10), new String[]{"com.banana", "com.tomato"});
+ assertArrayEquals(getTopAppsFromCategory("Vegetable", 10), new String[]{"com.tomato", "com.banana"});
}
- public String[] topAppsFromCategory(String category, int numToGet) {
+ public String[] getTopAppsFromCategory(String category, int numToGet) {
List apps = AppProvider.Helper.cursorToList(contentResolver
.query(AppProvider.getTopFromCategoryUri(category, numToGet), Cols.ALL, null, null, Cols.NAME));
String[] packageNames = new String[apps.size()];
@@ -260,12 +262,21 @@ public class CategoryProviderTest extends FDroidProviderTest {
}
private void insertAppWithCategory(String id, String name, String categories) {
- insertAppWithCategory(id, name, categories, 1);
+ insertAppWithCategory(id, name, categories, new Date(), 1);
+ }
+
+ private void insertAppWithCategory(String id, String name, String categories, Date lastUpdated) {
+ insertAppWithCategory(id, name, categories, lastUpdated, 1);
}
private void insertAppWithCategory(String id, String name, String categories, long repoId) {
- ContentValues values = new ContentValues(1);
+ insertAppWithCategory(id, name, categories, new Date(), repoId);
+ }
+
+ private void insertAppWithCategory(String id, String name, String categories, Date lastUpdated, long repoId) {
+ ContentValues values = new ContentValues(2);
values.put(Cols.ForWriting.Categories.CATEGORIES, categories);
+ values.put(Cols.LAST_UPDATED, lastUpdated.getTime() / 1000);
AppProviderTest.insertApp(contentResolver, context, id, name, values, repoId);
}