App version list overhaul
This commit is contained in:
parent
acefc4ca59
commit
3b711ea571
@ -427,6 +427,7 @@ public class AppDetails2 extends AppCompatActivity
|
|||||||
case Downloading:
|
case Downloading:
|
||||||
if (newStatus.progressMax == 0) {
|
if (newStatus.progressMax == 0) {
|
||||||
// The first progress notification we get telling us our status is "Downloading"
|
// The first progress notification we get telling us our status is "Downloading"
|
||||||
|
adapter.notifyAboutDownloadedApk(newStatus.apk);
|
||||||
adapter.setIndeterminateProgress(R.string.download_pending);
|
adapter.setIndeterminateProgress(R.string.download_pending);
|
||||||
} else {
|
} else {
|
||||||
adapter.setProgress(newStatus.progressCurrent, newStatus.progressMax);
|
adapter.setProgress(newStatus.progressCurrent, newStatus.progressMax);
|
||||||
|
@ -18,6 +18,7 @@ import android.support.v4.widget.TextViewCompat;
|
|||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.GridLayout;
|
import android.support.v7.widget.GridLayout;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.LinearSmoothScroller;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
@ -26,11 +27,12 @@ import android.text.TextUtils;
|
|||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.text.style.URLSpan;
|
import android.text.style.URLSpan;
|
||||||
import android.util.Log;
|
import android.util.DisplayMetrics;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@ -45,7 +47,7 @@ import org.fdroid.fdroid.Utils;
|
|||||||
import org.fdroid.fdroid.data.Apk;
|
import org.fdroid.fdroid.data.Apk;
|
||||||
import org.fdroid.fdroid.data.ApkProvider;
|
import org.fdroid.fdroid.data.ApkProvider;
|
||||||
import org.fdroid.fdroid.data.App;
|
import org.fdroid.fdroid.data.App;
|
||||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
import org.fdroid.fdroid.data.Repo;
|
||||||
import org.fdroid.fdroid.data.RepoProvider;
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
import org.fdroid.fdroid.installer.Installer;
|
import org.fdroid.fdroid.installer.Installer;
|
||||||
import org.fdroid.fdroid.privileged.views.AppDiff;
|
import org.fdroid.fdroid.privileged.views.AppDiff;
|
||||||
@ -54,6 +56,7 @@ import org.fdroid.fdroid.views.main.MainActivity;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@ -103,6 +106,9 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
|
|
||||||
private HeaderViewHolder headerView;
|
private HeaderViewHolder headerView;
|
||||||
|
|
||||||
|
private Apk downloadedApk;
|
||||||
|
private final HashMap<Integer, Boolean> versionsExpandTracker = new HashMap<>();
|
||||||
|
|
||||||
public AppDetailsRecyclerViewAdapter(Context context, @NonNull App app, AppDetailsRecyclerViewAdapterCallbacks callbacks) {
|
public AppDetailsRecyclerViewAdapter(Context context, @NonNull App app, AppDetailsRecyclerViewAdapterCallbacks callbacks) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.callbacks = callbacks;
|
this.callbacks = callbacks;
|
||||||
@ -125,6 +131,9 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
compatibleVersionsDifferentSig.add(apk);
|
compatibleVersionsDifferentSig.add(apk);
|
||||||
if (allowBySig) {
|
if (allowBySig) {
|
||||||
versions.add(apk);
|
versions.add(apk);
|
||||||
|
if (!versionsExpandTracker.containsKey(apk.versionCode)) {
|
||||||
|
versionsExpandTracker.put(apk.versionCode, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,11 +151,18 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
addItem(VIEWTYPE_LINKS);
|
addItem(VIEWTYPE_LINKS);
|
||||||
addItem(VIEWTYPE_PERMISSIONS);
|
addItem(VIEWTYPE_PERMISSIONS);
|
||||||
addItem(VIEWTYPE_VERSIONS);
|
addItem(VIEWTYPE_VERSIONS);
|
||||||
|
if (showVersions) {
|
||||||
|
setShowVersions(true);
|
||||||
|
}
|
||||||
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setShowVersions(boolean showVersions) {
|
void setShowVersions(boolean showVersions) {
|
||||||
|
setShowVersions(showVersions, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setShowVersions(boolean showVersions, boolean scrollTo) {
|
||||||
this.showVersions = showVersions;
|
this.showVersions = showVersions;
|
||||||
boolean itemsWereRemoved = items.removeAll(versions);
|
boolean itemsWereRemoved = items.removeAll(versions);
|
||||||
int startIndex = items.indexOf(VIEWTYPE_VERSIONS) + 1;
|
int startIndex = items.indexOf(VIEWTYPE_VERSIONS) + 1;
|
||||||
@ -158,11 +174,26 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
if (showVersions) {
|
if (showVersions) {
|
||||||
items.addAll(startIndex, versions);
|
items.addAll(startIndex, versions);
|
||||||
notifyItemRangeInserted(startIndex, versions.size());
|
notifyItemRangeInserted(startIndex, versions.size());
|
||||||
if (recyclerView != null) {
|
if (recyclerView != null && scrollTo) {
|
||||||
((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(startIndex - 1, 0);
|
final LinearSmoothScroller smoothScroller = new LinearSmoothScroller(context) {
|
||||||
|
@Override
|
||||||
|
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
|
||||||
|
// The default speed of smooth scrolling doesn't look good
|
||||||
|
// and it's too fast when it happens while inserting
|
||||||
|
// multiple recycler view items
|
||||||
|
return 75f / displayMetrics.densityDpi;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Expanding the version list reveals up to 5 items by default
|
||||||
|
int visibleVersionLimit = Math.min(versions.size(), 5);
|
||||||
|
smoothScroller.setTargetPosition(startIndex + visibleVersionLimit - 1);
|
||||||
|
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
|
||||||
}
|
}
|
||||||
} else if (itemsWereRemoved) {
|
} else if (itemsWereRemoved) {
|
||||||
notifyItemRangeRemoved(startIndex, versions.size());
|
notifyItemRangeRemoved(startIndex, versions.size());
|
||||||
|
if (recyclerView != null && scrollTo) {
|
||||||
|
recyclerView.smoothScrollToPosition(startIndex - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,10 +236,24 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
uriIsSetAndCanBeOpened(app.getLiberapayUri());
|
uriIsSetAndCanBeOpened(app.getLiberapayUri());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void notifyVersionViewsChanged() {
|
||||||
|
int startIndex = items.indexOf(VIEWTYPE_VERSIONS) + 1;
|
||||||
|
notifyItemRangeChanged(startIndex, versions.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyAboutDownloadedApk(final Apk apk) {
|
||||||
|
downloadedApk = apk;
|
||||||
|
notifyVersionViewsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
public void clearProgress() {
|
public void clearProgress() {
|
||||||
if (headerView != null) {
|
if (headerView != null) {
|
||||||
headerView.clearProgress();
|
headerView.clearProgress();
|
||||||
}
|
}
|
||||||
|
if (downloadedApk != null) {
|
||||||
|
notifyVersionViewsChanged();
|
||||||
|
downloadedApk = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIndeterminateProgress(int resIdString) {
|
public void setIndeterminateProgress(int resIdString) {
|
||||||
@ -757,7 +802,7 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
itemView.setOnClickListener(new View.OnClickListener() {
|
itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
setShowVersions(!showVersions);
|
setShowVersions(!showVersions, true);
|
||||||
updateExpandableItem(showVersions);
|
updateExpandableItem(showVersions);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -945,129 +990,174 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
|
|
||||||
private class VersionViewHolder extends RecyclerView.ViewHolder {
|
private class VersionViewHolder extends RecyclerView.ViewHolder {
|
||||||
final TextView version;
|
final TextView version;
|
||||||
final TextView status;
|
final TextView statusInstalled;
|
||||||
|
final TextView statusSuggested;
|
||||||
|
final TextView statusIncompatible;
|
||||||
|
final TextView added;
|
||||||
|
final ImageView expandArrow;
|
||||||
|
final View expandedLayout;
|
||||||
final TextView repository;
|
final TextView repository;
|
||||||
final TextView size;
|
final TextView size;
|
||||||
final TextView api;
|
final TextView api;
|
||||||
|
final Button buttonInstallUpgrade;
|
||||||
|
final Button buttonDowngrade;
|
||||||
|
Button buttonAction;
|
||||||
|
final View busyIndicator;
|
||||||
final TextView incompatibleReasons;
|
final TextView incompatibleReasons;
|
||||||
final TextView buildtype;
|
|
||||||
final TextView added;
|
private Apk apk;
|
||||||
final TextView nativecode;
|
|
||||||
|
|
||||||
VersionViewHolder(View view) {
|
VersionViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
version = (TextView) view.findViewById(R.id.version);
|
version = (TextView) view.findViewById(R.id.version);
|
||||||
status = (TextView) view.findViewById(R.id.status);
|
statusInstalled = (TextView) view.findViewById(R.id.status_installed);
|
||||||
|
statusSuggested = (TextView) view.findViewById(R.id.status_suggested);
|
||||||
|
statusIncompatible = (TextView) view.findViewById(R.id.status_incompatible);
|
||||||
|
added = (TextView) view.findViewById(R.id.added);
|
||||||
|
expandArrow = (ImageView) view.findViewById(R.id.expand_arrow);
|
||||||
|
expandedLayout = (View) view.findViewById(R.id.expanded_layout);
|
||||||
repository = (TextView) view.findViewById(R.id.repository);
|
repository = (TextView) view.findViewById(R.id.repository);
|
||||||
size = (TextView) view.findViewById(R.id.size);
|
size = (TextView) view.findViewById(R.id.size);
|
||||||
api = (TextView) view.findViewById(R.id.api);
|
api = (TextView) view.findViewById(R.id.api);
|
||||||
|
buttonInstallUpgrade = (Button) view.findViewById(R.id.button_install_upgrade);
|
||||||
|
buttonDowngrade = (Button) view.findViewById(R.id.button_downgrade);
|
||||||
|
busyIndicator = (View) view.findViewById(R.id.busy_indicator);
|
||||||
incompatibleReasons = (TextView) view.findViewById(R.id.incompatible_reasons);
|
incompatibleReasons = (TextView) view.findViewById(R.id.incompatible_reasons);
|
||||||
buildtype = (TextView) view.findViewById(R.id.buildtype);
|
|
||||||
added = (TextView) view.findViewById(R.id.added);
|
|
||||||
nativecode = (TextView) view.findViewById(R.id.nativecode);
|
|
||||||
|
|
||||||
int margin = context.getResources().getDimensionPixelSize(R.dimen.layout_horizontal_margin);
|
int margin = context.getResources().getDimensionPixelSize(R.dimen.layout_horizontal_margin);
|
||||||
int padding = context.getResources().getDimensionPixelSize(R.dimen.details_activity_padding);
|
int padding = context.getResources().getDimensionPixelSize(R.dimen.details_activity_padding);
|
||||||
ViewCompat.setPaddingRelative(view, margin + padding + ViewCompat.getPaddingStart(view), view.getPaddingTop(), margin + padding + ViewCompat.getPaddingEnd(view), view.getPaddingBottom());
|
ViewCompat.setPaddingRelative(view, margin + padding + ViewCompat.getPaddingStart(view), view.getPaddingTop(), margin + ViewCompat.getPaddingEnd(view), view.getPaddingBottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindModel(final Apk apk) {
|
public void bindModel(final Apk apk) {
|
||||||
java.text.DateFormat df = DateFormat.getDateFormat(context);
|
this.apk = apk;
|
||||||
|
|
||||||
boolean isSuggested = apk.versionCode == app.suggestedVersionCode &&
|
boolean isAppInstalled = app.isInstalled(context);
|
||||||
|
boolean isApkInstalled = apk.versionCode == app.installedVersionCode;
|
||||||
|
boolean isApkSuggested = apk.versionCode == app.suggestedVersionCode &&
|
||||||
TextUtils.equals(apk.sig, app.getMostAppropriateSignature());
|
TextUtils.equals(apk.sig, app.getMostAppropriateSignature());
|
||||||
|
boolean isApkDownloading = callbacks.isAppDownloading() && downloadedApk != null &&
|
||||||
|
downloadedApk.compareTo(apk) == 0;
|
||||||
|
|
||||||
version.setText(context.getString(R.string.version)
|
// Version name and statuses
|
||||||
+ " " + apk.versionName
|
version.setText(apk.versionName);
|
||||||
+ (isSuggested ? " ☆" : ""));
|
statusSuggested.setVisibility(isApkSuggested && apk.compatible ? View.VISIBLE : View.GONE);
|
||||||
|
statusInstalled.setVisibility(isApkInstalled ? View.VISIBLE : View.GONE);
|
||||||
|
statusIncompatible.setVisibility(!apk.compatible ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
String statusText = getInstalledStatus(apk);
|
// Version name width correction in case it's
|
||||||
status.setText(statusText);
|
// too long to prevent truncating the statuses
|
||||||
|
if (statusSuggested.getVisibility() == View.VISIBLE ||
|
||||||
if ("Installed".equals(statusText)) {
|
statusInstalled.getVisibility() == View.VISIBLE ||
|
||||||
version.setTextColor(ContextCompat.getColor(context, R.color.fdroid_blue));
|
statusIncompatible.getVisibility() == View.VISIBLE) {
|
||||||
}
|
int maxWidth = (int) (Resources.getSystem().getDisplayMetrics().widthPixels * 0.4);
|
||||||
|
version.setMaxWidth(maxWidth);
|
||||||
repository.setText(context.getString(R.string.repo_provider,
|
|
||||||
RepoProvider.Helper.findById(context, apk.repoId).getName()));
|
|
||||||
|
|
||||||
if (apk.size > 0) {
|
|
||||||
size.setText(Utils.getFriendlySize(apk.size));
|
|
||||||
size.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
} else {
|
||||||
size.setVisibility(View.GONE);
|
version.setMaxWidth(Integer.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Preferences.get().expertMode()) {
|
// Added date
|
||||||
api.setVisibility(View.GONE);
|
java.text.DateFormat df = DateFormat.getDateFormat(context);
|
||||||
} else if (apk.minSdkVersion > 0 && apk.maxSdkVersion < Apk.SDK_VERSION_MAX_VALUE) {
|
added.setText(context.getString(R.string.added_on, df.format(apk.added)));
|
||||||
api.setText(context.getString(R.string.minsdk_up_to_maxsdk,
|
|
||||||
Utils.getAndroidVersionName(apk.minSdkVersion),
|
|
||||||
Utils.getAndroidVersionName(apk.maxSdkVersion)));
|
|
||||||
api.setVisibility(View.VISIBLE);
|
|
||||||
} else if (apk.minSdkVersion > 0) {
|
|
||||||
api.setText(context.getString(R.string.minsdk_or_later,
|
|
||||||
Utils.getAndroidVersionName(apk.minSdkVersion)));
|
|
||||||
api.setVisibility(View.VISIBLE);
|
|
||||||
} else if (apk.maxSdkVersion > 0) {
|
|
||||||
api.setText(context.getString(R.string.up_to_maxsdk,
|
|
||||||
Utils.getAndroidVersionName(apk.maxSdkVersion)));
|
|
||||||
api.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apk.srcname != null) {
|
// Repository name, APK size and required Android version
|
||||||
buildtype.setText("source");
|
Repo repo = RepoProvider.Helper.findById(context, apk.repoId);
|
||||||
|
repository.setText(repo != null ? repo.getName() : context.getString(R.string.unknown));
|
||||||
|
size.setText(context.getString(R.string.app_size, Utils.getFriendlySize(apk.size)));
|
||||||
|
api.setText(getApiText(apk));
|
||||||
|
|
||||||
|
// Figuring out whether to show Install/Upgrade button or Downgrade button
|
||||||
|
buttonDowngrade.setVisibility(View.GONE);
|
||||||
|
buttonInstallUpgrade.setVisibility(View.GONE);
|
||||||
|
buttonInstallUpgrade.setText(context.getString(R.string.menu_install));
|
||||||
|
showActionButton(buttonInstallUpgrade, isApkInstalled, isApkDownloading);
|
||||||
|
if (isAppInstalled && !isApkInstalled) {
|
||||||
|
if (apk.versionCode > app.installedVersionCode) {
|
||||||
|
// Change the label to indicate that pressing this
|
||||||
|
// button will result in upgrading the installed app
|
||||||
|
buttonInstallUpgrade.setText(R.string.menu_upgrade);
|
||||||
} else {
|
} else {
|
||||||
buildtype.setText("bin");
|
// The Downgrade button should be shown in this case
|
||||||
|
buttonInstallUpgrade.setVisibility(View.GONE);
|
||||||
|
showActionButton(buttonDowngrade, false, isApkDownloading);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apk.added != null) {
|
// Show busy indicator when the APK is being downloaded
|
||||||
added.setText(context.getString(R.string.added_on,
|
busyIndicator.setVisibility(isApkDownloading ? View.VISIBLE : View.GONE);
|
||||||
df.format(apk.added)));
|
|
||||||
added.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
added.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Preferences.get().expertMode() && apk.nativecode != null) {
|
// Display incompatible reasons when the app
|
||||||
nativecode.setText(TextUtils.join(" ", apk.nativecode));
|
// isn't compatible and the expert mode is enabled
|
||||||
nativecode.setVisibility(View.VISIBLE);
|
if (Preferences.get().expertMode() && !apk.compatible) {
|
||||||
} else {
|
String incompatibleReasonsText = getIncompatibleReasonsText(apk);
|
||||||
nativecode.setVisibility(View.GONE);
|
if (incompatibleReasonsText != null) {
|
||||||
}
|
|
||||||
|
|
||||||
boolean mismatchedSig = app.installedSig != null && !TextUtils.equals(app.installedSig, apk.sig);
|
|
||||||
|
|
||||||
if (apk.incompatibleReasons != null) {
|
|
||||||
incompatibleReasons.setText(
|
|
||||||
context.getResources().getString(
|
|
||||||
R.string.requires_features,
|
|
||||||
TextUtils.join(", ", apk.incompatibleReasons)));
|
|
||||||
incompatibleReasons.setVisibility(View.VISIBLE);
|
|
||||||
} else if (mismatchedSig) {
|
|
||||||
incompatibleReasons.setText(
|
|
||||||
context.getString(R.string.app_details__incompatible_mismatched_signature));
|
|
||||||
incompatibleReasons.setVisibility(View.VISIBLE);
|
incompatibleReasons.setVisibility(View.VISIBLE);
|
||||||
|
incompatibleReasons.setText(incompatibleReasonsText);
|
||||||
|
} else {
|
||||||
|
incompatibleReasons.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
incompatibleReasons.setVisibility(View.GONE);
|
incompatibleReasons.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable it all if it isn't compatible...
|
// Expand the view if it was previously expanded or when downloading
|
||||||
final View[] views = {
|
expand(versionsExpandTracker.get(apk.versionCode) || isApkDownloading);
|
||||||
itemView,
|
|
||||||
version,
|
// Toggle expanded view when clicking the whole version item
|
||||||
status,
|
|
||||||
repository,
|
|
||||||
size,
|
|
||||||
api,
|
|
||||||
buildtype,
|
|
||||||
added,
|
|
||||||
nativecode,
|
|
||||||
};
|
|
||||||
for (final View v : views) {
|
|
||||||
v.setEnabled(apk.compatible && !mismatchedSig);
|
|
||||||
}
|
|
||||||
itemView.setOnClickListener(new View.OnClickListener() {
|
itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
toggleExpanded();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getApiText(final Apk apk) {
|
||||||
|
String apiText = "Android ";
|
||||||
|
if (apk.minSdkVersion > 0 && apk.maxSdkVersion < Apk.SDK_VERSION_MAX_VALUE) {
|
||||||
|
apiText += context.getString(R.string.minsdk_up_to_maxsdk,
|
||||||
|
Utils.getAndroidVersionName(apk.minSdkVersion),
|
||||||
|
Utils.getAndroidVersionName(apk.maxSdkVersion));
|
||||||
|
} else if (apk.minSdkVersion > 0) {
|
||||||
|
apiText += context.getString(R.string.minsdk_or_later,
|
||||||
|
Utils.getAndroidVersionName(apk.minSdkVersion));
|
||||||
|
} else if (apk.maxSdkVersion > 0) {
|
||||||
|
apiText += context.getString(R.string.up_to_maxsdk,
|
||||||
|
Utils.getAndroidVersionName(apk.maxSdkVersion));
|
||||||
|
}
|
||||||
|
return apiText;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getIncompatibleReasonsText(final Apk apk) {
|
||||||
|
if (apk.incompatibleReasons != null) {
|
||||||
|
return context.getResources().getString(R.string.requires_features,
|
||||||
|
TextUtils.join(", ", apk.incompatibleReasons));
|
||||||
|
} else {
|
||||||
|
boolean mismatchedSig = app.installedSig != null
|
||||||
|
&& !TextUtils.equals(app.installedSig, apk.sig);
|
||||||
|
if (mismatchedSig) {
|
||||||
|
return context.getString(R.string.app_details__incompatible_mismatched_signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showActionButton(Button button, boolean isApkInstalled, boolean isApkDownloading) {
|
||||||
|
buttonAction = button;
|
||||||
|
if (isApkDownloading) {
|
||||||
|
// Don't show the button in this case
|
||||||
|
// as the busy indicator will take its place
|
||||||
|
buttonAction.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
// The button should be shown but it should be also disabled
|
||||||
|
// if either the APK isn't compatible or it's already installed
|
||||||
|
// or also when some other APK is currently being downloaded
|
||||||
|
buttonAction.setVisibility(View.VISIBLE);
|
||||||
|
boolean buttonActionDisabled = !apk.compatible || isApkInstalled ||
|
||||||
|
callbacks.isAppDownloading();
|
||||||
|
buttonAction.setEnabled(!buttonActionDisabled);
|
||||||
|
buttonAction.setAlpha(buttonActionDisabled ? 0.15f : 1f);
|
||||||
|
buttonAction.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
callbacks.installApk(apk);
|
callbacks.installApk(apk);
|
||||||
@ -1076,6 +1166,51 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expand(boolean expand) {
|
||||||
|
versionsExpandTracker.put(apk.versionCode, expand);
|
||||||
|
expandedLayout.setVisibility(expand ? View.VISIBLE : View.GONE);
|
||||||
|
expandArrow.setImageDrawable(ContextCompat.getDrawable(context, expand ?
|
||||||
|
R.drawable.ic_expand_less_grey600 : R.drawable.ic_expand_more_grey600));
|
||||||
|
|
||||||
|
// This is required to make these labels
|
||||||
|
// auto-scrollable when they are too long
|
||||||
|
version.setSelected(expand);
|
||||||
|
repository.setSelected(expand);
|
||||||
|
size.setSelected(expand);
|
||||||
|
api.setSelected(expand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleExpanded() {
|
||||||
|
if (busyIndicator.getVisibility() == View.VISIBLE) {
|
||||||
|
// Don't allow collapsing the view when the busy indicator
|
||||||
|
// is shown because the APK is being downloaded and it's quite important
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean expand = !versionsExpandTracker.get(apk.versionCode);
|
||||||
|
expand(expand);
|
||||||
|
|
||||||
|
if (expand) {
|
||||||
|
// Scroll the versions view to a correct position so it can show the whole item
|
||||||
|
final LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
|
||||||
|
final int currentPosition = getAdapterPosition();
|
||||||
|
if (currentPosition >= lm.findLastCompletelyVisibleItemPosition()) {
|
||||||
|
// Do it only if the item is near the bottom of current viewport
|
||||||
|
recyclerView.getViewTreeObserver()
|
||||||
|
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
// Expanded item dimensions should be already calculated at this moment
|
||||||
|
// so it's possible to correctly scroll to a given position
|
||||||
|
recyclerView.smoothScrollToPosition(currentPosition);
|
||||||
|
recyclerView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addLinkItemView(ViewGroup parent, int resIdText, int resIdDrawable, final String url) {
|
private void addLinkItemView(ViewGroup parent, int resIdText, int resIdDrawable, final String url) {
|
||||||
addLinkItemView(parent, resIdText, resIdDrawable, url, null);
|
addLinkItemView(parent, resIdText, resIdDrawable, url, null);
|
||||||
}
|
}
|
||||||
@ -1098,31 +1233,6 @@ public class AppDetailsRecyclerViewAdapter
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getInstalledStatus(final Apk apk) {
|
|
||||||
// Definitely not installed.
|
|
||||||
if (apk.versionCode != app.installedVersionCode) {
|
|
||||||
return context.getString(R.string.app_not_installed);
|
|
||||||
}
|
|
||||||
// Definitely installed this version.
|
|
||||||
if (apk.sig != null && apk.sig.equals(app.installedSig)) {
|
|
||||||
return context.getString(R.string.app_installed);
|
|
||||||
}
|
|
||||||
// Installed the same version, but from someplace else.
|
|
||||||
final String installerPkgName;
|
|
||||||
try {
|
|
||||||
installerPkgName = context.getPackageManager().getInstallerPackageName(app.packageName);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
Log.w("AppDetailsAdapter", "Application " + app.packageName + " is not installed anymore");
|
|
||||||
return context.getString(R.string.app_not_installed);
|
|
||||||
}
|
|
||||||
if (TextUtils.isEmpty(installerPkgName)) {
|
|
||||||
return context.getString(R.string.app_inst_unknown_source);
|
|
||||||
}
|
|
||||||
final String installerLabel = InstalledAppProvider
|
|
||||||
.getApplicationLabel(context, installerPkgName);
|
|
||||||
return context.getString(R.string.app_inst_known_source, installerLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onLinkClicked(String url) {
|
private void onLinkClicked(String url) {
|
||||||
if (!TextUtils.isEmpty(url)) {
|
if (!TextUtils.isEmpty(url)) {
|
||||||
callbacks.openUrl(url);
|
callbacks.openUrl(url);
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="24dp" />
|
||||||
|
<solid android:color="#b87032" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="24dp" />
|
||||||
|
<solid android:color="#22ffffff" />
|
||||||
|
<stroke android:color="#b87032" android:width="2dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="24dp" />
|
||||||
|
<solid android:color="@color/fdroid_blue" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="24dp" />
|
||||||
|
<solid android:color="#22ffffff" />
|
||||||
|
<stroke android:color="@color/fdroid_blue" android:width="2dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||||
|
<stroke android:width="1dp" android:color="#d86758" />
|
||||||
|
<corners android:radius="2dp" />
|
||||||
|
</shape>
|
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||||
|
<stroke android:width="1dp" android:color="#19c878" />
|
||||||
|
<corners android:radius="2dp" />
|
||||||
|
</shape>
|
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||||
|
<stroke android:width="1dp" android:color="#429fff" />
|
||||||
|
<corners android:radius="2dp" />
|
||||||
|
</shape>
|
@ -1,112 +1,171 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:layout_marginBottom="4dp"
|
||||||
android:paddingTop="5dp"
|
android:paddingTop="5dp"
|
||||||
android:paddingBottom="5dp"
|
android:paddingBottom="5dp"
|
||||||
android:paddingLeft="10dp"
|
android:paddingLeft="10dp"
|
||||||
android:paddingRight="10dp"
|
android:paddingRight="4dp"
|
||||||
android:background="?attr/selectableItemBackground">
|
android:background="?attr/selectableItemBackground">
|
||||||
|
|
||||||
<TextView android:id="@+id/version"
|
<LinearLayout android:id="@+id/basic_layout"
|
||||||
android:textStyle="bold"
|
android:layout_width="match_parent"
|
||||||
android:maxLines="2"
|
android:layout_height="wrap_content">
|
||||||
android:ellipsize="end"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textSize="18sp"
|
|
||||||
tools:text="Version 1.0 (as if!)"/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/status"
|
|
||||||
android:textSize="13sp"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:layout_below="@id/version"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
tools:text="Installed" />
|
|
||||||
|
|
||||||
<TextView android:id="@+id/repository"
|
|
||||||
android:textSize="13sp"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:layout_below="@id/status"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
tools:text="Provided By F-Droid archive" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/container_added_nativecode"
|
android:orientation="vertical"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_below="@id/repository"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<TextView android:id="@+id/added"
|
|
||||||
android:textSize="13sp"
|
|
||||||
android:layout_weight="0"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:gravity="start"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
tools:text="Added on 1/1/2050" />
|
|
||||||
|
|
||||||
<TextView android:id="@+id/nativecode"
|
|
||||||
android:textSize="13sp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:ellipsize="end"
|
android:layout_height="wrap_content">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:gravity="end"
|
|
||||||
android:textAlignment="viewEnd"
|
|
||||||
tools:text=""
|
|
||||||
tools:visibility="gone" />
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView android:id="@+id/version"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="18sp"
|
||||||
|
tools:text="1.2.3"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingTop="3dp">
|
||||||
|
|
||||||
|
<TextView android:id="@+id/status_suggested"
|
||||||
|
style="@style/AppVersionStatus"
|
||||||
|
android:background="@drawable/app_version_item_status_suggested"
|
||||||
|
android:textColor="#429fff"
|
||||||
|
android:text="@string/app_suggested" />
|
||||||
|
|
||||||
|
<TextView android:id="@+id/status_installed"
|
||||||
|
style="@style/AppVersionStatus"
|
||||||
|
android:background="@drawable/app_version_item_status_installed"
|
||||||
|
android:textColor="#19c878"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:text="@string/app_installed" />
|
||||||
|
|
||||||
|
<TextView android:id="@+id/status_incompatible"
|
||||||
|
style="@style/AppVersionStatus"
|
||||||
|
android:background="@drawable/app_version_item_status_incompatible"
|
||||||
|
android:textColor="#d86758"
|
||||||
|
android:text="@string/app_incompatible" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView android:id="@+id/buildtype"
|
<TextView android:id="@+id/added"
|
||||||
android:textSize="13sp"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginBottom="4sp"
|
android:singleLine="true"
|
||||||
tools:text="source" />
|
android:ellipsize="end"
|
||||||
|
android:textSize="13sp"
|
||||||
|
tools:text="Added on 31/12/2050" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView android:id="@+id/expand_arrow"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:src="@drawable/ic_expand_more_grey600" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout android:id="@+id/expanded_layout"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_below="@id/basic_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginEnd="8dp">
|
||||||
|
|
||||||
|
<TextView android:id="@+id/repository"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:textColor="?attr/lightGrayTextColor"
|
||||||
|
android:textSize="12sp"
|
||||||
|
tools:text="F-Droid" />
|
||||||
|
|
||||||
<TextView android:id="@+id/size"
|
<TextView android:id="@+id/size"
|
||||||
android:textSize="13sp"
|
|
||||||
android:layout_below="@id/buildtype"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginBottom="4sp"
|
android:singleLine="true"
|
||||||
tools:text="12mb" />
|
android:ellipsize="marquee"
|
||||||
|
android:textColor="?attr/lightGrayTextColor"
|
||||||
|
android:textSize="12sp"
|
||||||
|
tools:text="Size: 4.8 MiB" />
|
||||||
|
|
||||||
<TextView android:id="@+id/api"
|
<TextView android:id="@+id/api"
|
||||||
android:textSize="13sp"
|
|
||||||
android:layout_below="@id/buildtype"
|
|
||||||
android:layout_toLeftOf="@id/size"
|
|
||||||
android:layout_toStartOf="@id/size"
|
|
||||||
android:layout_marginRight="16sp"
|
|
||||||
android:layout_marginEnd="16sp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
tools:text=""
|
android:singleLine="true"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:textColor="?attr/lightGrayTextColor"
|
||||||
|
android:textSize="12sp"
|
||||||
|
tools:text="Android 4.1 or later" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<android.support.v7.widget.AppCompatButton android:id="@+id/button_install_upgrade"
|
||||||
|
style="@style/DetailsButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
app:textAllCaps="true"
|
||||||
|
tools:text="@string/menu_install"
|
||||||
|
android:textColor="@color/fdroid_blue"
|
||||||
|
android:background="@drawable/app_version_button_bg_selector_install_upgrade" />
|
||||||
|
|
||||||
|
<android.support.v7.widget.AppCompatButton android:id="@+id/button_downgrade"
|
||||||
|
style="@style/DetailsButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginRight="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
app:textAllCaps="true"
|
||||||
|
android:text="@string/menu_downgrade"
|
||||||
|
android:textColor="#b87032"
|
||||||
|
android:background="@drawable/app_version_button_bg_selector_downgrade"
|
||||||
tools:visibility="gone" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<ProgressBar android:id="@+id/busy_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView android:id="@+id/incompatible_reasons"
|
<TextView android:id="@+id/incompatible_reasons"
|
||||||
android:textSize="13sp"
|
|
||||||
android:layout_below="@id/container_added_nativecode"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
tools:text=""
|
android:layout_height="wrap_content"
|
||||||
tools:visibility="gone" />
|
android:textColor="#d86758"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
tools:text="Requires: armeabi-v7a" />
|
||||||
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
@ -87,6 +87,7 @@ This often occurs with apps installed via Google Play or other sources, if they
|
|||||||
<string name="about_source">Source code</string>
|
<string name="about_source">Source code</string>
|
||||||
<string name="about_license">License</string>
|
<string name="about_license">License</string>
|
||||||
|
|
||||||
|
<string name="app_suggested">Suggested</string>
|
||||||
<string name="app_incompatible">Incompatible</string>
|
<string name="app_incompatible">Incompatible</string>
|
||||||
<string name="app_installed">Installed</string>
|
<string name="app_installed">Installed</string>
|
||||||
<string name="app_not_installed">Not Installed</string>
|
<string name="app_not_installed">Not Installed</string>
|
||||||
@ -101,6 +102,7 @@ This often occurs with apps installed via Google Play or other sources, if they
|
|||||||
<string name="app__install_downloaded_update">Update</string>
|
<string name="app__install_downloaded_update">Update</string>
|
||||||
<string name="app_installed_media">File installed to %s</string>
|
<string name="app_installed_media">File installed to %s</string>
|
||||||
<string name="app_permission_storage">F-Droid needs the storage permission to install this to storage. Please allow it on the next screen to proceed with installation.</string>
|
<string name="app_permission_storage">F-Droid needs the storage permission to install this to storage. Please allow it on the next screen to proceed with installation.</string>
|
||||||
|
<string name="app_size">Size: %1$s</string>
|
||||||
|
|
||||||
<string name="app_list__name__downloading_in_progress">Downloading %1$s</string>
|
<string name="app_list__name__downloading_in_progress">Downloading %1$s</string>
|
||||||
<string name="app_list__name__successfully_installed">%1$s installed</string>
|
<string name="app_list__name__successfully_installed">%1$s installed</string>
|
||||||
@ -187,6 +189,7 @@ This often occurs with apps installed via Google Play or other sources, if they
|
|||||||
<string name="menu_license">License: %s</string>
|
<string name="menu_license">License: %s</string>
|
||||||
<string name="menu_source">Source Code</string>
|
<string name="menu_source">Source Code</string>
|
||||||
<string name="menu_upgrade">Upgrade</string>
|
<string name="menu_upgrade">Upgrade</string>
|
||||||
|
<string name="menu_downgrade">Downgrade</string>
|
||||||
<string name="menu_donate">Donate</string>
|
<string name="menu_donate">Donate</string>
|
||||||
<string name="menu_bitcoin">Bitcoin</string>
|
<string name="menu_bitcoin">Bitcoin</string>
|
||||||
<string name="menu_litecoin">Litecoin</string>
|
<string name="menu_litecoin">Litecoin</string>
|
||||||
|
@ -170,6 +170,18 @@
|
|||||||
<item name="android:drawablePadding">12dp</item>
|
<item name="android:drawablePadding">12dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="AppVersionStatus">
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:layout_marginTop">1dp</item>
|
||||||
|
<item name="android:layout_marginLeft">6dp</item>
|
||||||
|
<item name="android:paddingLeft">4dp</item>
|
||||||
|
<item name="android:paddingRight">4dp</item>
|
||||||
|
<item name="android:paddingBottom">1dp</item>
|
||||||
|
<item name="android:maxLines">1</item>
|
||||||
|
<item name="android:textSize">12sp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="AppDetailsSubheaderText" parent="AppDetailsSubheaderTextBase"/>
|
<style name="AppDetailsSubheaderText" parent="AppDetailsSubheaderTextBase"/>
|
||||||
|
|
||||||
<style name="AppThemeTransparent" parent="@android:style/Theme.NoDisplay"/>
|
<style name="AppThemeTransparent" parent="@android:style/Theme.NoDisplay"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user