Merge branch 'app_details_749_more_work' into 'master'
App details 749 more work See merge request !451
This commit is contained in:
commit
836d16393d
@ -13,6 +13,7 @@ import android.graphics.Bitmap;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.AppBarLayout;
|
||||||
import android.support.design.widget.CoordinatorLayout;
|
import android.support.design.widget.CoordinatorLayout;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
@ -46,6 +47,7 @@ import org.fdroid.fdroid.installer.InstallerService;
|
|||||||
import org.fdroid.fdroid.net.Downloader;
|
import org.fdroid.fdroid.net.Downloader;
|
||||||
import org.fdroid.fdroid.net.DownloaderService;
|
import org.fdroid.fdroid.net.DownloaderService;
|
||||||
import org.fdroid.fdroid.views.AppDetailsRecyclerViewAdapter;
|
import org.fdroid.fdroid.views.AppDetailsRecyclerViewAdapter;
|
||||||
|
import org.fdroid.fdroid.views.OverscrollLinearLayoutManager;
|
||||||
import org.fdroid.fdroid.views.ShareChooserDialog;
|
import org.fdroid.fdroid.views.ShareChooserDialog;
|
||||||
import org.fdroid.fdroid.views.apps.FeatureImage;
|
import org.fdroid.fdroid.views.apps.FeatureImage;
|
||||||
|
|
||||||
@ -59,6 +61,8 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
|
|
||||||
private FDroidApp fdroidApp;
|
private FDroidApp fdroidApp;
|
||||||
private App app;
|
private App app;
|
||||||
|
private CoordinatorLayout coordinatorLayout;
|
||||||
|
private AppBarLayout appBarLayout;
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
private AppDetailsRecyclerViewAdapter adapter;
|
private AppDetailsRecyclerViewAdapter adapter;
|
||||||
private LocalBroadcastManager localBroadcastManager;
|
private LocalBroadcastManager localBroadcastManager;
|
||||||
@ -91,10 +95,42 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
|
|||||||
|
|
||||||
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
||||||
|
|
||||||
|
coordinatorLayout = (CoordinatorLayout) findViewById(R.id.rootCoordinator);
|
||||||
|
appBarLayout = (AppBarLayout) coordinatorLayout.findViewById(R.id.app_bar);
|
||||||
recyclerView = (RecyclerView) findViewById(R.id.rvDetails);
|
recyclerView = (RecyclerView) findViewById(R.id.rvDetails);
|
||||||
adapter = new AppDetailsRecyclerViewAdapter(this, app, this);
|
adapter = new AppDetailsRecyclerViewAdapter(this, app, this);
|
||||||
LinearLayoutManager lm = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
|
OverscrollLinearLayoutManager lm = new OverscrollLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
|
||||||
lm.setStackFromEnd(false);
|
lm.setStackFromEnd(false);
|
||||||
|
|
||||||
|
/** The recyclerView/AppBarLayout combo has a bug that prevents a "fling" from the bottom
|
||||||
|
* to continue all the way to the top by expanding the AppBarLayout. It will instead stop
|
||||||
|
* with the app bar in a collapsed state. See here: https://code.google.com/p/android/issues/detail?id=177729
|
||||||
|
* Not sure this is the exact issue, but it is true that while in a fling the RecyclerView will
|
||||||
|
* consume the scroll events quietly, without calling the nested scrolling mechanism.
|
||||||
|
* We fix this behavior by using an OverscrollLinearLayoutManager that will give us information
|
||||||
|
* of overscroll, i.e. when we have not consumed all of a scroll event, and use this information
|
||||||
|
* to send the scroll to the app bar layout so that it will expand itself.
|
||||||
|
*/
|
||||||
|
lm.setOnOverscrollListener(new OverscrollLinearLayoutManager.OnOverscrollListener() {
|
||||||
|
@Override
|
||||||
|
public int onOverscrollX(int overscroll) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onOverscrollY(int overscroll) {
|
||||||
|
int consumed = 0;
|
||||||
|
if (overscroll < 0) {
|
||||||
|
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
||||||
|
CoordinatorLayout.Behavior behavior = lp.getBehavior();
|
||||||
|
if (behavior != null && behavior instanceof AppBarLayout.Behavior) {
|
||||||
|
((AppBarLayout.Behavior) behavior).onNestedScroll(coordinatorLayout, appBarLayout, recyclerView, 0, 0, 0, overscroll);
|
||||||
|
consumed = overscroll; // Consume all of it!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
});
|
||||||
recyclerView.setLayoutManager(lm);
|
recyclerView.setLayoutManager(lm);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import android.os.Parcel;
|
|||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.fdroid.fdroid.BuildConfig;
|
||||||
import org.fdroid.fdroid.RepoXMLHandler;
|
import org.fdroid.fdroid.RepoXMLHandler;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
|
import org.fdroid.fdroid.data.Schema.ApkTable.Cols;
|
||||||
@ -74,6 +75,11 @@ public class Apk extends ValueObject implements Comparable<Apk>, Parcelable {
|
|||||||
public String repoAddress;
|
public String repoAddress;
|
||||||
public String[] incompatibleReasons;
|
public String[] incompatibleReasons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A descriptive text for what has changed in the latest version.
|
||||||
|
*/
|
||||||
|
public String whatsNew;
|
||||||
|
|
||||||
public String[] antiFeatures;
|
public String[] antiFeatures;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -211,6 +217,13 @@ public class Apk extends ValueObject implements Comparable<Apk>, Parcelable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For now, just populate "what's new" with placeholder (or leave blank)
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
if (Math.random() > 0.5) {
|
||||||
|
whatsNew = "This section will contain the 'what's new' information for the apk.\n\n\t• Bug fixes.";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkRepoAddress() {
|
private void checkRepoAddress() {
|
||||||
|
@ -50,7 +50,10 @@ import org.fdroid.fdroid.privileged.views.AppSecurityPermissions;
|
|||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class AppDetailsRecyclerViewAdapter
|
public class AppDetailsRecyclerViewAdapter
|
||||||
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
@ -81,12 +84,11 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
|
|
||||||
private static final int VIEWTYPE_HEADER = 0;
|
private static final int VIEWTYPE_HEADER = 0;
|
||||||
private static final int VIEWTYPE_SCREENSHOTS = 1;
|
private static final int VIEWTYPE_SCREENSHOTS = 1;
|
||||||
private static final int VIEWTYPE_WHATS_NEW = 2;
|
private static final int VIEWTYPE_DONATE = 2;
|
||||||
private static final int VIEWTYPE_DONATE = 3;
|
private static final int VIEWTYPE_LINKS = 3;
|
||||||
private static final int VIEWTYPE_LINKS = 4;
|
private static final int VIEWTYPE_PERMISSIONS = 4;
|
||||||
private static final int VIEWTYPE_PERMISSIONS = 5;
|
private static final int VIEWTYPE_VERSIONS = 5;
|
||||||
private static final int VIEWTYPE_VERSIONS = 6;
|
private static final int VIEWTYPE_VERSION = 6;
|
||||||
private static final int VIEWTYPE_VERSION = 7;
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -125,7 +127,6 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
}
|
}
|
||||||
addItem(VIEWTYPE_HEADER);
|
addItem(VIEWTYPE_HEADER);
|
||||||
addItem(VIEWTYPE_SCREENSHOTS);
|
addItem(VIEWTYPE_SCREENSHOTS);
|
||||||
addItem(VIEWTYPE_WHATS_NEW);
|
|
||||||
addItem(VIEWTYPE_DONATE);
|
addItem(VIEWTYPE_DONATE);
|
||||||
addItem(VIEWTYPE_LINKS);
|
addItem(VIEWTYPE_LINKS);
|
||||||
addItem(VIEWTYPE_PERMISSIONS);
|
addItem(VIEWTYPE_PERMISSIONS);
|
||||||
@ -167,6 +168,12 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
|
|
||||||
private boolean shouldShowPermissions() {
|
private boolean shouldShowPermissions() {
|
||||||
// Figure out if we should show permissions section
|
// Figure out if we should show permissions section
|
||||||
|
Apk curApk = getSuggestedApk();
|
||||||
|
final boolean curApkCompatible = curApk != null && curApk.compatible;
|
||||||
|
return versions.size() > 0 && (curApkCompatible || Preferences.get().showIncompatibleVersions());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Apk getSuggestedApk() {
|
||||||
Apk curApk = null;
|
Apk curApk = null;
|
||||||
for (int i = 0; i < versions.size(); i++) {
|
for (int i = 0; i < versions.size(); i++) {
|
||||||
final Apk apk = versions.get(i);
|
final Apk apk = versions.get(i);
|
||||||
@ -175,8 +182,7 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final boolean curApkCompatible = curApk != null && curApk.compatible;
|
return curApk;
|
||||||
return versions.size() > 0 && (curApkCompatible || Preferences.get().showIncompatibleVersions());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldShowDonate() {
|
private boolean shouldShowDonate() {
|
||||||
@ -206,9 +212,6 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
case VIEWTYPE_SCREENSHOTS:
|
case VIEWTYPE_SCREENSHOTS:
|
||||||
View screenshots = inflater.inflate(R.layout.app_details2_screenshots, parent, false);
|
View screenshots = inflater.inflate(R.layout.app_details2_screenshots, parent, false);
|
||||||
return new ScreenShotsViewHolder(screenshots);
|
return new ScreenShotsViewHolder(screenshots);
|
||||||
case VIEWTYPE_WHATS_NEW:
|
|
||||||
View whatsNew = inflater.inflate(R.layout.app_details2_whatsnew, parent, false);
|
|
||||||
return new WhatsNewViewHolder(whatsNew);
|
|
||||||
case VIEWTYPE_DONATE:
|
case VIEWTYPE_DONATE:
|
||||||
View donate = inflater.inflate(R.layout.app_details2_donate, parent, false);
|
View donate = inflater.inflate(R.layout.app_details2_donate, parent, false);
|
||||||
return new DonateViewHolder(donate);
|
return new DonateViewHolder(donate);
|
||||||
@ -240,9 +243,6 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
case VIEWTYPE_SCREENSHOTS:
|
case VIEWTYPE_SCREENSHOTS:
|
||||||
((ScreenShotsViewHolder) holder).bindModel();
|
((ScreenShotsViewHolder) holder).bindModel();
|
||||||
break;
|
break;
|
||||||
case VIEWTYPE_WHATS_NEW:
|
|
||||||
((WhatsNewViewHolder) holder).bindModel();
|
|
||||||
break;
|
|
||||||
case VIEWTYPE_DONATE:
|
case VIEWTYPE_DONATE:
|
||||||
((DonateViewHolder) holder).bindModel();
|
((DonateViewHolder) holder).bindModel();
|
||||||
break;
|
break;
|
||||||
@ -289,9 +289,13 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
final ImageView iconView;
|
final ImageView iconView;
|
||||||
final TextView titleView;
|
final TextView titleView;
|
||||||
final TextView authorView;
|
final TextView authorView;
|
||||||
final TextView summaryView;
|
final TextView lastUpdateView;
|
||||||
|
final TextView whatsNewView;
|
||||||
final TextView descriptionView;
|
final TextView descriptionView;
|
||||||
final TextView descriptionMoreView;
|
final TextView descriptionMoreView;
|
||||||
|
final TextView antiFeaturesLabelView;
|
||||||
|
final TextView antiFeaturesView;
|
||||||
|
final View antiFeaturesWarningView;
|
||||||
final View buttonLayout;
|
final View buttonLayout;
|
||||||
final Button buttonPrimaryView;
|
final Button buttonPrimaryView;
|
||||||
final Button buttonSecondaryView;
|
final Button buttonSecondaryView;
|
||||||
@ -301,15 +305,20 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
final TextView progressPercent;
|
final TextView progressPercent;
|
||||||
final View progressCancel;
|
final View progressCancel;
|
||||||
final DisplayImageOptions displayImageOptions;
|
final DisplayImageOptions displayImageOptions;
|
||||||
|
boolean descriptionIsExpanded;
|
||||||
|
|
||||||
HeaderViewHolder(View view) {
|
HeaderViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
iconView = (ImageView) view.findViewById(R.id.icon);
|
iconView = (ImageView) view.findViewById(R.id.icon);
|
||||||
titleView = (TextView) view.findViewById(R.id.title);
|
titleView = (TextView) view.findViewById(R.id.title);
|
||||||
authorView = (TextView) view.findViewById(R.id.author);
|
authorView = (TextView) view.findViewById(R.id.author);
|
||||||
summaryView = (TextView) view.findViewById(R.id.summary);
|
lastUpdateView = (TextView) view.findViewById(R.id.text_last_update);
|
||||||
|
whatsNewView = (TextView) view.findViewById(R.id.whats_new);
|
||||||
descriptionView = (TextView) view.findViewById(R.id.description);
|
descriptionView = (TextView) view.findViewById(R.id.description);
|
||||||
descriptionMoreView = (TextView) view.findViewById(R.id.description_more);
|
descriptionMoreView = (TextView) view.findViewById(R.id.description_more);
|
||||||
|
antiFeaturesLabelView = (TextView) view.findViewById(R.id.label_anti_features);
|
||||||
|
antiFeaturesView = (TextView) view.findViewById(R.id.text_anti_features);
|
||||||
|
antiFeaturesWarningView = view.findViewById(R.id.anti_features_warning);
|
||||||
buttonLayout = view.findViewById(R.id.button_layout);
|
buttonLayout = view.findViewById(R.id.button_layout);
|
||||||
buttonPrimaryView = (Button) view.findViewById(R.id.primaryButtonView);
|
buttonPrimaryView = (Button) view.findViewById(R.id.primaryButtonView);
|
||||||
buttonSecondaryView = (Button) view.findViewById(R.id.secondaryButtonView);
|
buttonSecondaryView = (Button) view.findViewById(R.id.secondaryButtonView);
|
||||||
@ -339,10 +348,13 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
if (TextViewCompat.getMaxLines(descriptionView) != MAX_LINES) {
|
if (TextViewCompat.getMaxLines(descriptionView) != MAX_LINES) {
|
||||||
descriptionView.setMaxLines(MAX_LINES);
|
descriptionView.setMaxLines(MAX_LINES);
|
||||||
descriptionMoreView.setText(R.string.more);
|
descriptionMoreView.setText(R.string.more);
|
||||||
|
descriptionIsExpanded = false;
|
||||||
} else {
|
} else {
|
||||||
descriptionView.setMaxLines(Integer.MAX_VALUE);
|
descriptionView.setMaxLines(Integer.MAX_VALUE);
|
||||||
descriptionMoreView.setText(R.string.less);
|
descriptionMoreView.setText(R.string.less);
|
||||||
|
descriptionIsExpanded = true;
|
||||||
}
|
}
|
||||||
|
updateAntiFeaturesWarning();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Set ALL caps (in a way compatible with SDK 10)
|
// Set ALL caps (in a way compatible with SDK 10)
|
||||||
@ -392,7 +404,28 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
} else {
|
} else {
|
||||||
authorView.setVisibility(View.GONE);
|
authorView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
summaryView.setText(app.summary);
|
if (app.lastUpdated != null) {
|
||||||
|
long msDiff = Calendar.getInstance().getTimeInMillis() - app.lastUpdated.getTime();
|
||||||
|
int daysDiff = (int) TimeUnit.MILLISECONDS.toDays(msDiff);
|
||||||
|
lastUpdateView.setText(lastUpdateView.getContext().getResources().getQuantityString(R.plurals.details_last_update_days, daysDiff, daysDiff));
|
||||||
|
lastUpdateView.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
lastUpdateView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
Apk suggestedApk = getSuggestedApk();
|
||||||
|
if (suggestedApk == null || TextUtils.isEmpty(suggestedApk.whatsNew)) {
|
||||||
|
whatsNewView.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
//noinspection deprecation Ignore deprecation because the suggested way is only available in API 24.
|
||||||
|
Locale locale = context.getResources().getConfiguration().locale;
|
||||||
|
|
||||||
|
StringBuilder sbWhatsNew = new StringBuilder();
|
||||||
|
sbWhatsNew.append(whatsNewView.getContext().getString(R.string.details_new_in_version, suggestedApk.versionName).toUpperCase(locale));
|
||||||
|
sbWhatsNew.append("\n\n");
|
||||||
|
sbWhatsNew.append(suggestedApk.whatsNew);
|
||||||
|
whatsNewView.setText(sbWhatsNew);
|
||||||
|
whatsNewView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
final Spanned desc = Html.fromHtml(app.description, null, new Utils.HtmlTagHandler());
|
final Spanned desc = Html.fromHtml(app.description, null, new Utils.HtmlTagHandler());
|
||||||
descriptionView.setMovementMethod(LinkMovementMethod.getInstance());
|
descriptionView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
descriptionView.setText(trimTrailingNewlines(desc));
|
descriptionView.setText(trimTrailingNewlines(desc));
|
||||||
@ -412,13 +445,27 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
descriptionView.post(new Runnable() {
|
descriptionView.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (descriptionView.getLineCount() <= HeaderViewHolder.MAX_LINES) {
|
if (descriptionView.getLineCount() <= HeaderViewHolder.MAX_LINES && app.antiFeatures == null) {
|
||||||
descriptionMoreView.setVisibility(View.GONE);
|
descriptionMoreView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
descriptionMoreView.setVisibility(View.VISIBLE);
|
descriptionMoreView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (app.antiFeatures != null) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (String af : app.antiFeatures) {
|
||||||
|
String afdesc = descAntiFeature(af);
|
||||||
|
sb.append("\t• ").append(afdesc).append('\n');
|
||||||
|
}
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.setLength(sb.length() - 1);
|
||||||
|
antiFeaturesView.setText(sb.toString());
|
||||||
|
} else {
|
||||||
|
antiFeaturesView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateAntiFeaturesWarning();
|
||||||
buttonSecondaryView.setText(R.string.menu_uninstall);
|
buttonSecondaryView.setText(R.string.menu_uninstall);
|
||||||
buttonSecondaryView.setVisibility(app.isInstalled() ? View.VISIBLE : View.INVISIBLE);
|
buttonSecondaryView.setVisibility(app.isInstalled() ? View.VISIBLE : View.INVISIBLE);
|
||||||
buttonSecondaryView.setOnClickListener(onUnInstallClickListener);
|
buttonSecondaryView.setOnClickListener(onUnInstallClickListener);
|
||||||
@ -464,6 +511,39 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateAntiFeaturesWarning() {
|
||||||
|
if (app.antiFeatures == null || TextUtils.isEmpty(antiFeaturesView.getText())) {
|
||||||
|
antiFeaturesLabelView.setVisibility(View.GONE);
|
||||||
|
antiFeaturesView.setVisibility(View.GONE);
|
||||||
|
antiFeaturesWarningView.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
antiFeaturesLabelView.setVisibility(descriptionIsExpanded ? View.VISIBLE : View.GONE);
|
||||||
|
antiFeaturesView.setVisibility(descriptionIsExpanded ? View.VISIBLE : View.GONE);
|
||||||
|
antiFeaturesWarningView.setVisibility(descriptionIsExpanded ? View.GONE : View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String descAntiFeature(String af) {
|
||||||
|
switch (af) {
|
||||||
|
case "Ads":
|
||||||
|
return itemView.getContext().getString(R.string.antiadslist);
|
||||||
|
case "Tracking":
|
||||||
|
return itemView.getContext().getString(R.string.antitracklist);
|
||||||
|
case "NonFreeNet":
|
||||||
|
return itemView.getContext().getString(R.string.antinonfreenetlist);
|
||||||
|
case "NonFreeAdd":
|
||||||
|
return itemView.getContext().getString(R.string.antinonfreeadlist);
|
||||||
|
case "NonFreeDep":
|
||||||
|
return itemView.getContext().getString(R.string.antinonfreedeplist);
|
||||||
|
case "UpstreamNonFree":
|
||||||
|
return itemView.getContext().getString(R.string.antiupstreamnonfreelist);
|
||||||
|
case "NonFreeAssets":
|
||||||
|
return itemView.getContext().getString(R.string.antinonfreeassetslist);
|
||||||
|
default:
|
||||||
|
return af;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -503,19 +583,6 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WhatsNewViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
final TextView textView;
|
|
||||||
|
|
||||||
WhatsNewViewHolder(View view) {
|
|
||||||
super(view);
|
|
||||||
textView = (TextView) view.findViewById(R.id.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bindModel() {
|
|
||||||
textView.setText("WHATS NEW GOES HERE");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DonateViewHolder extends RecyclerView.ViewHolder {
|
private class DonateViewHolder extends RecyclerView.ViewHolder {
|
||||||
final TextView donateHeading;
|
final TextView donateHeading;
|
||||||
final GridLayout donationOptionsLayout;
|
final GridLayout donationOptionsLayout;
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
package org.fdroid.fdroid.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is like a standard LinearLayoutManager but with an option to add an
|
||||||
|
* overscroll listener. This can be used to consume overscrolls, e.g. to draw custom
|
||||||
|
* "glows".
|
||||||
|
*/
|
||||||
|
public class OverscrollLinearLayoutManager extends LinearLayoutManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A listener interface to get overscroll infromation.
|
||||||
|
*/
|
||||||
|
public interface OnOverscrollListener {
|
||||||
|
/**
|
||||||
|
* Notifies the listener that an overscroll has happened in the x direction.
|
||||||
|
* @param overscroll If negative, the recycler view has been scrolled to the "start"
|
||||||
|
* position. If positive to the "end" position.
|
||||||
|
* @return Return the amount of overscroll consumed. Returning 0 will let the
|
||||||
|
* recycler view handle this in the default way. Return "overscroll" to consume the
|
||||||
|
* whole event.
|
||||||
|
*/
|
||||||
|
int onOverscrollX(int overscroll);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the listener that an overscroll has happened in the y direction.
|
||||||
|
* @param overscroll If negative, the recycler view has been scrolled to the "top"
|
||||||
|
* position. If positive to the "bottom" position.
|
||||||
|
* @return Return the amount of overscroll consumed. Returning 0 will let the
|
||||||
|
* recycler view handle this in the default way. Return "overscroll" to consume the
|
||||||
|
* whole event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int onOverscrollY(int overscroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OnOverscrollListener overscrollListener = null;
|
||||||
|
|
||||||
|
public OverscrollLinearLayoutManager(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverscrollLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
||||||
|
super(context, orientation, reverseLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverscrollLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link OverscrollLinearLayoutManager.OnOverscrollListener} to get information about
|
||||||
|
* when the parent recyclerview is overscrolled.
|
||||||
|
*
|
||||||
|
* @param listener Listener to add
|
||||||
|
* @see OverscrollLinearLayoutManager.OnOverscrollListener
|
||||||
|
*/
|
||||||
|
public void setOnOverscrollListener(OnOverscrollListener listener) {
|
||||||
|
overscrollListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||||
|
int consumed = super.scrollHorizontallyBy(dx, recycler, state);
|
||||||
|
int overscrollX = dx - consumed;
|
||||||
|
if (overscrollX != 0) {
|
||||||
|
if (overscrollListener != null) {
|
||||||
|
int consumedByListener = overscrollListener.onOverscrollX(overscrollX);
|
||||||
|
consumed += consumedByListener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||||
|
int consumed = super.scrollVerticallyBy(dy, recycler, state);
|
||||||
|
int overscrollY = dy - consumed;
|
||||||
|
if (overscrollY != 0) {
|
||||||
|
if (overscrollListener != null) {
|
||||||
|
int consumedByListener = overscrollListener.onOverscrollY(overscrollY);
|
||||||
|
consumed += consumedByListener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
}
|
9
app/src/main/res/drawable/ic_warning_black_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_warning_black_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
|
||||||
|
</vector>
|
@ -12,97 +12,111 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="8dp"
|
android:orientation="vertical"
|
||||||
android:orientation="vertical">
|
android:paddingBottom="8dp"
|
||||||
|
>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/icon"
|
android:id="@+id/icon"
|
||||||
android:layout_width="72dp"
|
android:layout_width="72dp"
|
||||||
android:layout_height="72dp"
|
android:layout_height="72dp"
|
||||||
android:paddingRight="8dp"
|
|
||||||
android:paddingBottom="8dp"
|
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:paddingRight="8dp"
|
||||||
android:src="@drawable/ic_repo_app_default" />
|
android:src="@drawable/ic_repo_app_default" />
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/title"
|
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:layout_toEndOf="@id/icon"
|
android:layout_toEndOf="@id/icon"
|
||||||
android:layout_toRightOf="@id/icon"
|
android:layout_toRightOf="@id/icon"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
android:orientation="vertical">
|
||||||
tools:text="App Title" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/author"
|
android:id="@+id/title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignEnd="@id/title"
|
android:textAppearance="@style/DetailsAppTitleStyle"
|
||||||
android:layout_alignLeft="@id/title"
|
tools:text="App Title" />
|
||||||
android:layout_alignRight="@id/title"
|
|
||||||
android:layout_alignStart="@id/title"
|
<TextView
|
||||||
android:layout_below="@id/title"
|
android:id="@+id/author"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:layout_width="match_parent"
|
||||||
tools:text="Author" />
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="Author" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_last_update"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/DetailsLastUpdatedStyle"
|
||||||
|
android:textColor="@android:color/darker_gray"
|
||||||
|
tools:text="Update released 12 days ago" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/progress_layout"
|
android:id="@+id/progress_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/icon"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignParentRight="true">
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_below="@id/icon">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/progress_cancel"
|
android:id="@+id/progress_cancel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:src="@android:drawable/ic_menu_close_clear_cancel"
|
android:layout_centerVertical="true"
|
||||||
/>
|
android:src="@android:drawable/ic_menu_close_clear_cancel" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/progress_label"
|
android:id="@+id/progress_label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
|
||||||
android:text="@string/downloading"
|
android:text="@string/downloading"
|
||||||
/>
|
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/progress_percent"
|
android:id="@+id/progress_percent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_toLeftOf="@id/progress_cancel"
|
android:layout_toLeftOf="@id/progress_cancel"
|
||||||
android:layout_toStartOf="@id/progress_cancel"
|
android:layout_toStartOf="@id/progress_cancel"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
|
||||||
android:text=""
|
android:text=""
|
||||||
/>
|
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progress_bar"
|
android:id="@+id/progress_bar"
|
||||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_toLeftOf="@id/progress_cancel"
|
|
||||||
android:layout_toStartOf="@id/progress_cancel"
|
|
||||||
android:layout_below="@id/progress_label"
|
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
/>
|
android:layout_below="@id/progress_label"
|
||||||
|
android:layout_toLeftOf="@id/progress_cancel"
|
||||||
|
android:layout_toStartOf="@id/progress_cancel" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -124,7 +138,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:maxLines="1"
|
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
tools:text="THIS IS BUTTON 1" />
|
tools:text="THIS IS BUTTON 1" />
|
||||||
@ -137,7 +150,6 @@
|
|||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:maxLines="1"
|
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
tools:text="THIS IS 2" />
|
tools:text="THIS IS 2" />
|
||||||
@ -146,35 +158,80 @@
|
|||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/summary"
|
android:id="@+id/whats_new"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
tools:text="This app is awezome"
|
android:paddingStart="8dp"
|
||||||
android:scrollbars="none"
|
android:paddingEnd="8dp"
|
||||||
android:textStyle="bold"
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="@color/details_panel_light"
|
||||||
|
tools:text="NEW IN VERSION 1.0.2233\n\nA lot has happened since the last build:\n\n\t• Improved UI\n\t• Bug fixes"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/description"
|
android:id="@+id/description"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
tools:text="This is the app description of this awezome app. It can be several lines long, but will be truncated at just a few if it is. A 'read more' button will appear so that you can expand the view and view the full text, if you wish. Yes, it will be blue and beautiful."
|
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
/>
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="This is the app description of this awezome app. It can be several lines long, but will be truncated at just a few if it is. A 'read more' button will appear so that you can expand the view and view the full text, if you wish. Yes, it will be blue and beautiful." />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_anti_features"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
android:text="@string/antifeatures" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_anti_features"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="\t• This app tracks and reports your activity." />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/description_more"
|
android:id="@+id/description_more"
|
||||||
|
style="@style/DetailsMoreButtonStyle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:layout_marginStart="8dp"
|
||||||
style="@style/DetailsMoreButtonStyle"
|
android:layout_marginEnd="8dp"
|
||||||
android:gravity="right|end"
|
android:gravity="right|end"
|
||||||
android:text="@string/more"
|
android:text="@string/more"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
tools:text="more" />
|
tools:text="more" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/anti_features_warning"
|
||||||
|
style="@style/DetailsAntiFeaturesWarningStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
android:drawableStart="@drawable/ic_warning_black_24dp"
|
||||||
|
android:drawableLeft="@drawable/ic_warning_black_24dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:text="@string/antifeatureswarning" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</android.support.v7.widget.CardView>
|
</android.support.v7.widget.CardView>
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/text"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="@dimen/details_activity_padding"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
/>
|
|
@ -169,7 +169,10 @@
|
|||||||
|
|
||||||
<string name="details_installed">Version %s installed</string>
|
<string name="details_installed">Version %s installed</string>
|
||||||
<string name="details_notinstalled">Not installed</string>
|
<string name="details_notinstalled">Not installed</string>
|
||||||
|
<string name="details_new_in_version">New in version %s</string>
|
||||||
|
|
||||||
|
<string name="antifeatureswarning">This app has features you may not like.</string>
|
||||||
|
<string name="antifeatures">Anti-features</string>
|
||||||
<string name="antiadslist">This app contains advertising</string>
|
<string name="antiadslist">This app contains advertising</string>
|
||||||
<string name="antitracklist">This app tracks and reports your activity</string>
|
<string name="antitracklist">This app tracks and reports your activity</string>
|
||||||
<string name="antinonfreeadlist">This app promotes non-free add-ons</string>
|
<string name="antinonfreeadlist">This app promotes non-free add-ons</string>
|
||||||
@ -473,4 +476,10 @@
|
|||||||
<item quantity="one">View the single one app in the %2$s category</item>
|
<item quantity="one">View the single one app in the %2$s category</item>
|
||||||
<item quantity="other">View all %1$d apps from the %2$s category</item>
|
<item quantity="other">View all %1$d apps from the %2$s category</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
<plurals name="details_last_update_days">
|
||||||
|
<item quantity="zero">Updated today</item>
|
||||||
|
<item quantity="one">Updated %1$s day ago</item>
|
||||||
|
<item quantity="other">Updated %1$s days ago</item>
|
||||||
|
</plurals>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -34,4 +34,15 @@
|
|||||||
<item name="android:textColor">@color/fdroid_blue</item>
|
<item name="android:textColor">@color/fdroid_blue</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="DetailsAppTitleStyle" parent="TextAppearance.AppCompat.Title">
|
||||||
|
<item name="android:textSize">18sp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="DetailsLastUpdatedStyle" parent="TextAppearance.AppCompat.Small">
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="DetailsAntiFeaturesWarningStyle" parent="TextAppearance.AppCompat.Body1">
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -47,7 +47,7 @@ public class AppDetailsAdapterTest extends FDroidProviderTest {
|
|||||||
AppDetailsRecyclerViewAdapter adapter = new AppDetailsRecyclerViewAdapter(context, app, dummyCallbacks);
|
AppDetailsRecyclerViewAdapter adapter = new AppDetailsRecyclerViewAdapter(context, app, dummyCallbacks);
|
||||||
populateViewHolders(adapter);
|
populateViewHolders(adapter);
|
||||||
|
|
||||||
assertEquals(5, adapter.getItemCount());
|
assertEquals(4, adapter.getItemCount());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user