Separate adapter from rest of activity
This commit is contained in:
parent
b36e581480
commit
05f13df17a
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,830 @@
|
||||
package org.fdroid.fdroid.views;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.support.v4.widget.TextViewCompat;
|
||||
import android.support.v7.text.AllCapsTransformationMethod;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.Html;
|
||||
import android.text.Spannable;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.URLSpan;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.InstalledAppProvider;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.privileged.views.AppDiff;
|
||||
import org.fdroid.fdroid.privileged.views.AppSecurityPermissions;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
||||
|
||||
public class AppDetailsRecyclerViewAdapter
|
||||
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
public interface AppDetailsRecyclerViewAdapterCallbacks {
|
||||
boolean isAppDownloading();
|
||||
boolean isAppInstalled();
|
||||
void enableAndroidBeam();
|
||||
void disableAndroidBeam();
|
||||
void openUrl(String url);
|
||||
void installApk();
|
||||
void installApk(Apk apk);
|
||||
void upgradeApk();
|
||||
void uninstallApk();
|
||||
void installCancel();
|
||||
void launchApk();
|
||||
}
|
||||
|
||||
private final int VIEWTYPE_HEADER = 0;
|
||||
private final int VIEWTYPE_SCREENSHOTS = 1;
|
||||
private final int VIEWTYPE_WHATS_NEW = 2;
|
||||
private final int VIEWTYPE_DONATE = 3;
|
||||
private final int VIEWTYPE_LINKS = 4;
|
||||
private final int VIEWTYPE_PERMISSIONS = 5;
|
||||
private final int VIEWTYPE_VERSIONS = 6;
|
||||
private final int VIEWTYPE_VERSION = 7;
|
||||
|
||||
private final Context mContext;
|
||||
private App mApp;
|
||||
private final AppDetailsRecyclerViewAdapterCallbacks mCallbacks;
|
||||
private RecyclerView mRecyclerView;
|
||||
private ArrayList<Object> mItems;
|
||||
private ArrayList<Apk> mVersions;
|
||||
private boolean mShowVersions;
|
||||
|
||||
private HeaderViewHolder mHeaderView;
|
||||
|
||||
public AppDetailsRecyclerViewAdapter(Context context, App app, AppDetailsRecyclerViewAdapterCallbacks callbacks) {
|
||||
mContext = context;
|
||||
mCallbacks = callbacks;
|
||||
updateItems(app);
|
||||
}
|
||||
|
||||
public void updateItems(App app) {
|
||||
mApp = app;
|
||||
|
||||
// Get versions
|
||||
mVersions = new ArrayList<>();
|
||||
final List<Apk> apks = ApkProvider.Helper.findByPackageName(mContext, mApp.packageName);
|
||||
for (final Apk apk : apks) {
|
||||
if (apk.compatible || Preferences.get().showIncompatibleVersions()) {
|
||||
mVersions.add(apk);
|
||||
}
|
||||
}
|
||||
|
||||
if (mItems == null)
|
||||
mItems = new ArrayList<>();
|
||||
else
|
||||
mItems.clear();
|
||||
addItem(VIEWTYPE_HEADER);
|
||||
addItem(VIEWTYPE_SCREENSHOTS);
|
||||
addItem(VIEWTYPE_WHATS_NEW);
|
||||
addItem(VIEWTYPE_DONATE);
|
||||
addItem(VIEWTYPE_LINKS);
|
||||
addItem(VIEWTYPE_PERMISSIONS);
|
||||
addItem(VIEWTYPE_VERSIONS);
|
||||
}
|
||||
|
||||
private void setShowVersions(boolean showVersions) {
|
||||
mShowVersions = showVersions;
|
||||
mItems.removeAll(mVersions);
|
||||
if (showVersions) {
|
||||
mItems.addAll(mItems.indexOf(VIEWTYPE_VERSIONS) + 1, mVersions);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void addItem(int item) {
|
||||
// Gives us a chance to hide sections that are not used, e.g. the donate section when
|
||||
// we have no donation links.
|
||||
if (item == VIEWTYPE_DONATE) {
|
||||
if (!shouldShowDonate())
|
||||
return;
|
||||
} else if (item == VIEWTYPE_PERMISSIONS) {
|
||||
if (!shouldShowPermissions())
|
||||
return;
|
||||
}
|
||||
mItems.add(item);
|
||||
}
|
||||
|
||||
private boolean shouldShowPermissions() {
|
||||
// Figure out if we should show permissions section
|
||||
Apk curApk = null;
|
||||
for (int i = 0; i < mVersions.size(); i++) {
|
||||
final Apk apk = mVersions.get(i);
|
||||
if (apk.versionCode == mApp.suggestedVersionCode) {
|
||||
curApk = apk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
final boolean curApkCompatible = curApk != null && curApk.compatible;
|
||||
return mVersions.size() > 0 && (curApkCompatible || Preferences.get().showIncompatibleVersions());
|
||||
}
|
||||
|
||||
private boolean shouldShowDonate() {
|
||||
return uriIsSetAndCanBeOpened(mApp.donateURL) ||
|
||||
uriIsSetAndCanBeOpened(mApp.bitcoinAddr) ||
|
||||
uriIsSetAndCanBeOpened(mApp.litecoinAddr) ||
|
||||
uriIsSetAndCanBeOpened(mApp.flattrID);
|
||||
}
|
||||
|
||||
public HeaderViewHolder getHeaderView() {
|
||||
return mHeaderView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
if (viewType == VIEWTYPE_HEADER) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.app_details2_header, parent, false);
|
||||
return new HeaderViewHolder(view);
|
||||
} else if (viewType == VIEWTYPE_SCREENSHOTS) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.app_details2_screenshots, parent, false);
|
||||
return new ScreenShotsViewHolder(view);
|
||||
} else if (viewType == VIEWTYPE_WHATS_NEW) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.app_details2_whatsnew, parent, false);
|
||||
return new WhatsNewViewHolder(view);
|
||||
} else if (viewType == VIEWTYPE_DONATE) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.app_details2_donate, parent, false);
|
||||
return new DonateViewHolder(view);
|
||||
} else if (viewType == VIEWTYPE_LINKS) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.app_details2_links, parent, false);
|
||||
return new ExpandableLinearLayoutViewHolder(view);
|
||||
} else if (viewType == VIEWTYPE_PERMISSIONS) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.app_details2_links, parent, false);
|
||||
return new ExpandableLinearLayoutViewHolder(view);
|
||||
} else if (viewType == VIEWTYPE_VERSIONS) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.app_details2_links, parent, false);
|
||||
return new ExpandableLinearLayoutViewHolder(view);
|
||||
} else if (viewType == VIEWTYPE_VERSION) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.apklistitem, parent, false);
|
||||
return new VersionViewHolder(view);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
|
||||
int viewType = getItemViewType(position);
|
||||
if (viewType == VIEWTYPE_HEADER) {
|
||||
final HeaderViewHolder vh = (HeaderViewHolder) holder;
|
||||
mHeaderView = vh;
|
||||
ImageLoader.getInstance().displayImage(mApp.iconUrlLarge, vh.iconView, vh.displayImageOptions);
|
||||
vh.titleView.setText(mApp.name);
|
||||
if (!TextUtils.isEmpty(mApp.author)) {
|
||||
vh.authorView.setText(mContext.getString(R.string.by_author) + " " + mApp.author);
|
||||
vh.authorView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
vh.authorView.setVisibility(View.GONE);
|
||||
}
|
||||
vh.summaryView.setText(mApp.summary);
|
||||
final Spanned desc = Html.fromHtml(mApp.description, null, new Utils.HtmlTagHandler());
|
||||
vh.descriptionView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
vh.descriptionView.setText(trimNewlines(desc));
|
||||
if (vh.descriptionView.getText() instanceof Spannable) {
|
||||
Spannable spannable = (Spannable) vh.descriptionView.getText();
|
||||
URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
|
||||
for (URLSpan span : spans) {
|
||||
int start = spannable.getSpanStart(span);
|
||||
int end = spannable.getSpanEnd(span);
|
||||
int flags = spannable.getSpanFlags(span);
|
||||
spannable.removeSpan(span);
|
||||
// Create out own safe link span
|
||||
SafeURLSpan safeUrlSpan = new SafeURLSpan(span.getURL());
|
||||
spannable.setSpan(safeUrlSpan, start, end, flags);
|
||||
}
|
||||
}
|
||||
vh.descriptionView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (vh.descriptionView.getLineCount() < HeaderViewHolder.MAX_LINES) {
|
||||
vh.descriptionMoreView.setVisibility(View.GONE);
|
||||
} else {
|
||||
vh.descriptionMoreView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
vh.buttonSecondaryView.setText(R.string.menu_uninstall);
|
||||
vh.buttonSecondaryView.setVisibility(mCallbacks.isAppInstalled() ? View.VISIBLE : View.INVISIBLE);
|
||||
vh.buttonSecondaryView.setOnClickListener(mOnUnInstallClickListener);
|
||||
vh.buttonPrimaryView.setText(R.string.menu_install);
|
||||
vh.buttonPrimaryView.setVisibility(mVersions.size() > 0 ? View.VISIBLE : View.GONE);
|
||||
if (mCallbacks.isAppDownloading()) {
|
||||
vh.buttonPrimaryView.setText(R.string.downloading);
|
||||
vh.buttonPrimaryView.setEnabled(false);
|
||||
} else if (!mCallbacks.isAppInstalled() && mApp.suggestedVersionCode > 0 &&
|
||||
mVersions.size() > 0) {
|
||||
// Check count > 0 due to incompatible apps resulting in an empty list.
|
||||
// If App isn't installed
|
||||
//installed = false;
|
||||
//statusView.setText(R.string.details_notinstalled);
|
||||
mCallbacks.disableAndroidBeam();
|
||||
// Set Install button and hide second button
|
||||
vh.buttonPrimaryView.setText(R.string.menu_install);
|
||||
vh.buttonPrimaryView.setOnClickListener(mOnInstallClickListener);
|
||||
vh.buttonPrimaryView.setEnabled(true);
|
||||
} else if (mCallbacks.isAppInstalled()) {
|
||||
// If App is installed
|
||||
//installed = true;
|
||||
//statusView.setText(getString(R.string.details_installed, app.installedVersionName));
|
||||
mCallbacks.enableAndroidBeam();
|
||||
if (mApp.canAndWantToUpdate(mContext)) {
|
||||
//updateWanted = true;
|
||||
vh.buttonPrimaryView.setText(R.string.menu_upgrade);
|
||||
vh.buttonPrimaryView.setOnClickListener(mOnUpgradeClickListener);
|
||||
} else {
|
||||
//updateWanted = false;
|
||||
if (mContext.getPackageManager().getLaunchIntentForPackage(mApp.packageName) != null) {
|
||||
vh.buttonPrimaryView.setText(R.string.menu_launch);
|
||||
vh.buttonPrimaryView.setOnClickListener(mOnLaunchClickListener);
|
||||
} else {
|
||||
vh.buttonPrimaryView.setVisibility(View.GONE);
|
||||
//vh.buttonPrimaryView.setText(R.string.menu_uninstall);
|
||||
}
|
||||
}
|
||||
vh.buttonPrimaryView.setEnabled(true);
|
||||
}
|
||||
if (mCallbacks.isAppDownloading()) {
|
||||
vh.buttonLayout.setVisibility(View.GONE);
|
||||
vh.progressLayout.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
vh.buttonLayout.setVisibility(View.VISIBLE);
|
||||
vh.progressLayout.setVisibility(View.GONE);
|
||||
}
|
||||
vh.progressCancel.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallbacks.installCancel();
|
||||
}
|
||||
});
|
||||
|
||||
/*TextView currentVersion = (TextView) view.findViewById(R.id.current_version);
|
||||
if (!appDetails.getApks().isEmpty()) {
|
||||
currentVersion.setText(appDetails.getApks().getItem(0).versionName + " (" + app.license + ")");
|
||||
} else {
|
||||
currentVersion.setVisibility(View.GONE);
|
||||
btMain.setVisibility(View.GONE);
|
||||
}*/
|
||||
|
||||
} else if (viewType == VIEWTYPE_SCREENSHOTS) {
|
||||
ScreenShotsViewHolder vh = (ScreenShotsViewHolder) holder;
|
||||
LinearLayoutManager lm = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false);
|
||||
vh.recyclerView.setLayoutManager(lm);
|
||||
ScreenShotsRecyclerViewAdapter adapter = new ScreenShotsRecyclerViewAdapter(vh.itemView.getContext(), mApp);
|
||||
vh.recyclerView.setAdapter(adapter);
|
||||
vh.recyclerView.setHasFixedSize(true);
|
||||
vh.recyclerView.setNestedScrollingEnabled(false);
|
||||
if (vh.snapHelper != null)
|
||||
vh.snapHelper.attachToRecyclerView(null);
|
||||
vh.snapHelper = new LinearLayoutManagerSnapHelper(lm);
|
||||
vh.snapHelper.setLinearSnapHelperListener(adapter);
|
||||
vh.snapHelper.attachToRecyclerView(vh.recyclerView);
|
||||
} else if (viewType == VIEWTYPE_WHATS_NEW) {
|
||||
WhatsNewViewHolder vh = (WhatsNewViewHolder) holder;
|
||||
vh.textView.setText("WHATS NEW GOES HERE");
|
||||
} else if (viewType == VIEWTYPE_DONATE) {
|
||||
DonateViewHolder vh = (DonateViewHolder) holder;
|
||||
vh.contentView.removeAllViews();
|
||||
|
||||
// Donate button
|
||||
if (uriIsSetAndCanBeOpened(mApp.donateURL)) {
|
||||
addLinkItemView(vh.contentView, R.string.menu_donate, R.drawable.ic_donate, mApp.donateURL);
|
||||
}
|
||||
|
||||
// Bitcoin
|
||||
if (uriIsSetAndCanBeOpened(mApp.bitcoinAddr)) {
|
||||
addLinkItemView(vh.contentView, R.string.menu_bitcoin, R.drawable.ic_bitcoin, "bitcoin:" + mApp.bitcoinAddr);
|
||||
}
|
||||
|
||||
// Litecoin
|
||||
if (uriIsSetAndCanBeOpened(mApp.litecoinAddr)) {
|
||||
addLinkItemView(vh.contentView, R.string.menu_litecoin, R.drawable.ic_litecoin, "litecoin:" + mApp.litecoinAddr);
|
||||
}
|
||||
|
||||
// Flattr
|
||||
if (uriIsSetAndCanBeOpened(mApp.flattrID)) {
|
||||
addLinkItemView(vh.contentView, R.string.menu_flattr, R.drawable.ic_flattr, "https://flattr.com/thing/" + mApp.flattrID);
|
||||
}
|
||||
} else if (viewType == VIEWTYPE_LINKS) {
|
||||
final ExpandableLinearLayoutViewHolder vh = (ExpandableLinearLayoutViewHolder) holder;
|
||||
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean shouldBeVisible = (vh.contentView.getVisibility() != View.VISIBLE);
|
||||
vh.contentView.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE);
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(vh.headerView, R.drawable.ic_website, 0, shouldBeVisible ? R.drawable.ic_expand_less_grey600 : R.drawable.ic_expand_more_grey600, 0);
|
||||
}
|
||||
});
|
||||
vh.headerView.setText(R.string.links);
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(vh.headerView, R.drawable.ic_website, 0, R.drawable.ic_expand_more_grey600, 0);
|
||||
vh.contentView.removeAllViews();
|
||||
|
||||
// Source button
|
||||
if (uriIsSetAndCanBeOpened(mApp.sourceURL)) {
|
||||
addLinkItemView(vh.contentView, R.string.menu_source, R.drawable.ic_source_code, mApp.sourceURL);
|
||||
}
|
||||
|
||||
// Issues button
|
||||
if (uriIsSetAndCanBeOpened(mApp.trackerURL)) {
|
||||
addLinkItemView(vh.contentView, R.string.menu_issues, R.drawable.ic_issues, mApp.trackerURL);
|
||||
}
|
||||
|
||||
// Changelog button
|
||||
if (uriIsSetAndCanBeOpened(mApp.changelogURL)) {
|
||||
addLinkItemView(vh.contentView, R.string.menu_changelog, R.drawable.ic_changelog, mApp.changelogURL);
|
||||
}
|
||||
|
||||
// Website button
|
||||
if (uriIsSetAndCanBeOpened(mApp.webURL)) {
|
||||
addLinkItemView(vh.contentView, R.string.menu_website, R.drawable.ic_website, mApp.webURL);
|
||||
}
|
||||
|
||||
// Email button
|
||||
if (uriIsSetAndCanBeOpened(mApp.email)) {
|
||||
final String subject = Uri.encode(mContext.getString(R.string.app_details_subject, mApp.name));
|
||||
String url = "mailto:" + mApp.email + "?subject=" + subject;
|
||||
addLinkItemView(vh.contentView, R.string.menu_email, R.drawable.ic_email, url);
|
||||
}
|
||||
} else if (viewType == VIEWTYPE_PERMISSIONS) {
|
||||
final ExpandableLinearLayoutViewHolder vh = (ExpandableLinearLayoutViewHolder) holder;
|
||||
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean shouldBeVisible = (vh.contentView.getVisibility() != View.VISIBLE);
|
||||
vh.contentView.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE);
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(vh.headerView, R.drawable.ic_lock_24dp_grey600, 0, shouldBeVisible ? R.drawable.ic_expand_less_grey600 : R.drawable.ic_expand_more_grey600, 0);
|
||||
}
|
||||
});
|
||||
vh.headerView.setText(R.string.permissions);
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(vh.headerView, R.drawable.ic_lock_24dp_grey600, 0, R.drawable.ic_expand_more_grey600, 0);
|
||||
vh.contentView.removeAllViews();
|
||||
AppDiff appDiff = new AppDiff(mContext.getPackageManager(), mVersions.get(0));
|
||||
AppSecurityPermissions perms = new AppSecurityPermissions(mContext, appDiff.pkgInfo);
|
||||
vh.contentView.addView(perms.getPermissionsView(AppSecurityPermissions.WHICH_ALL));
|
||||
} else if (viewType == VIEWTYPE_VERSIONS) {
|
||||
final ExpandableLinearLayoutViewHolder vh = (ExpandableLinearLayoutViewHolder) holder;
|
||||
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setShowVersions(!mShowVersions);
|
||||
}
|
||||
});
|
||||
vh.headerView.setText(R.string.versions);
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(vh.headerView, R.drawable.ic_access_time_24dp_grey600, 0, mShowVersions ? R.drawable.ic_expand_less_grey600 : R.drawable.ic_expand_more_grey600, 0);
|
||||
} else if (viewType == VIEWTYPE_VERSION) {
|
||||
final VersionViewHolder vh = (VersionViewHolder) holder;
|
||||
java.text.DateFormat df = DateFormat.getDateFormat(mContext);
|
||||
final Apk apk = (Apk)mItems.get(position);
|
||||
|
||||
vh.version.setText(mContext.getString(R.string.version)
|
||||
+ " " + apk.versionName
|
||||
+ (apk.versionCode == mApp.suggestedVersionCode ? " ☆" : ""));
|
||||
|
||||
vh.status.setText(getInstalledStatus(apk));
|
||||
|
||||
vh.repository.setText(mContext.getString(R.string.repo_provider,
|
||||
RepoProvider.Helper.findById(mContext, apk.repo).getName()));
|
||||
|
||||
if (apk.size > 0) {
|
||||
vh.size.setText(Utils.getFriendlySize(apk.size));
|
||||
vh.size.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
vh.size.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (!Preferences.get().expertMode()) {
|
||||
vh.api.setVisibility(View.GONE);
|
||||
} else if (apk.minSdkVersion > 0 && apk.maxSdkVersion < Apk.SDK_VERSION_MAX_VALUE) {
|
||||
vh.api.setText(mContext.getString(R.string.minsdk_up_to_maxsdk,
|
||||
Utils.getAndroidVersionName(apk.minSdkVersion),
|
||||
Utils.getAndroidVersionName(apk.maxSdkVersion)));
|
||||
vh.api.setVisibility(View.VISIBLE);
|
||||
} else if (apk.minSdkVersion > 0) {
|
||||
vh.api.setText(mContext.getString(R.string.minsdk_or_later,
|
||||
Utils.getAndroidVersionName(apk.minSdkVersion)));
|
||||
vh.api.setVisibility(View.VISIBLE);
|
||||
} else if (apk.maxSdkVersion > 0) {
|
||||
vh.api.setText(mContext.getString(R.string.up_to_maxsdk,
|
||||
Utils.getAndroidVersionName(apk.maxSdkVersion)));
|
||||
vh.api.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (apk.srcname != null) {
|
||||
vh.buildtype.setText("source");
|
||||
} else {
|
||||
vh.buildtype.setText("bin");
|
||||
}
|
||||
|
||||
if (apk.added != null) {
|
||||
vh.added.setText(mContext.getString(R.string.added_on,
|
||||
df.format(apk.added)));
|
||||
vh.added.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
vh.added.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (Preferences.get().expertMode() && apk.nativecode != null) {
|
||||
vh.nativecode.setText(TextUtils.join(" ", apk.nativecode));
|
||||
vh.nativecode.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
vh.nativecode.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (apk.incompatibleReasons != null) {
|
||||
vh.incompatibleReasons.setText(
|
||||
mContext.getResources().getString(
|
||||
R.string.requires_features,
|
||||
TextUtils.join(", ", apk.incompatibleReasons)));
|
||||
vh.incompatibleReasons.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
vh.incompatibleReasons.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// Disable it all if it isn't compatible...
|
||||
final View[] views = {
|
||||
vh.itemView,
|
||||
vh.version,
|
||||
vh.status,
|
||||
vh.repository,
|
||||
vh.size,
|
||||
vh.api,
|
||||
vh.buildtype,
|
||||
vh.added,
|
||||
vh.nativecode,
|
||||
};
|
||||
for (final View v : views) {
|
||||
v.setEnabled(apk.compatible);
|
||||
}
|
||||
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallbacks.installApk(apk);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(RecyclerView.ViewHolder holder) {
|
||||
if (holder instanceof HeaderViewHolder) {
|
||||
mHeaderView = null;
|
||||
}
|
||||
super.onViewRecycled(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (mItems.get(position) instanceof Apk)
|
||||
return VIEWTYPE_VERSION;
|
||||
return (Integer)mItems.get(position);
|
||||
}
|
||||
|
||||
public class HeaderViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final int MAX_LINES = 5;
|
||||
|
||||
final ImageView iconView;
|
||||
final TextView titleView;
|
||||
final TextView authorView;
|
||||
final TextView summaryView;
|
||||
final TextView descriptionView;
|
||||
final TextView descriptionMoreView;
|
||||
final View buttonLayout;
|
||||
final Button buttonPrimaryView;
|
||||
final Button buttonSecondaryView;
|
||||
final View progressLayout;
|
||||
final ProgressBar progressBar;
|
||||
final TextView progressLabel;
|
||||
final TextView progressPercent;
|
||||
final View progressCancel;
|
||||
final DisplayImageOptions displayImageOptions;
|
||||
|
||||
HeaderViewHolder(View view) {
|
||||
super(view);
|
||||
iconView = (ImageView) view.findViewById(R.id.icon);
|
||||
titleView = (TextView) view.findViewById(R.id.title);
|
||||
authorView = (TextView) view.findViewById(R.id.author);
|
||||
summaryView = (TextView) view.findViewById(R.id.summary);
|
||||
descriptionView = (TextView) view.findViewById(R.id.description);
|
||||
descriptionMoreView = (TextView) view.findViewById(R.id.description_more);
|
||||
buttonLayout = view.findViewById(R.id.button_layout);
|
||||
buttonPrimaryView = (Button) view.findViewById(R.id.primaryButtonView);
|
||||
buttonSecondaryView = (Button) view.findViewById(R.id.secondaryButtonView);
|
||||
progressLayout = view.findViewById(R.id.progress_layout);
|
||||
progressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
|
||||
progressLabel = (TextView) view.findViewById(R.id.progress_label);
|
||||
progressPercent = (TextView) view.findViewById(R.id.progress_percent);
|
||||
progressCancel = view.findViewById(R.id.progress_cancel);
|
||||
displayImageOptions = new DisplayImageOptions.Builder()
|
||||
.cacheInMemory(true)
|
||||
.cacheOnDisk(true)
|
||||
.imageScaleType(ImageScaleType.NONE)
|
||||
.showImageOnLoading(R.drawable.ic_repo_app_default)
|
||||
.showImageForEmptyUri(R.drawable.ic_repo_app_default)
|
||||
.bitmapConfig(Bitmap.Config.RGB_565)
|
||||
.build();
|
||||
descriptionView.setMaxLines(MAX_LINES);
|
||||
descriptionView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
|
||||
descriptionMoreView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Remember current scroll position so that we can restore it
|
||||
LinearLayoutManager lm = (LinearLayoutManager)mRecyclerView.getLayoutManager();
|
||||
int pos = lm.findFirstVisibleItemPosition();
|
||||
int posOffset = 0;
|
||||
if (pos != NO_POSITION) {
|
||||
View firstChild = mRecyclerView.getChildAt(0);
|
||||
posOffset = (firstChild == null) ? 0 : (firstChild.getTop()); // - mRecyclerView.getPaddingTop());
|
||||
}
|
||||
if (TextViewCompat.getMaxLines(descriptionView) != MAX_LINES) {
|
||||
descriptionView.setMaxLines(MAX_LINES);
|
||||
descriptionMoreView.setText(R.string.more);
|
||||
} else {
|
||||
descriptionView.setMaxLines(Integer.MAX_VALUE);
|
||||
descriptionMoreView.setText(R.string.less);
|
||||
}
|
||||
if (pos != NO_POSITION) {
|
||||
// Restore scroll position
|
||||
lm.scrollToPositionWithOffset(pos, posOffset);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Set ALL caps (in a way compatible with SDK 10)
|
||||
AllCapsTransformationMethod allCapsTransformation = new AllCapsTransformationMethod(view.getContext());
|
||||
buttonPrimaryView.setTransformationMethod(allCapsTransformation);
|
||||
buttonSecondaryView.setTransformationMethod(allCapsTransformation);
|
||||
descriptionMoreView.setTransformationMethod(allCapsTransformation);
|
||||
}
|
||||
|
||||
public void setProgress(int bytesDownloaded, int totalBytes, int resIdString) {
|
||||
if (bytesDownloaded == 0 && totalBytes == 0) {
|
||||
// Remove progress bar
|
||||
progressLayout.setVisibility(View.GONE);
|
||||
buttonLayout.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
progressBar.setMax(totalBytes);
|
||||
progressBar.setProgress(bytesDownloaded);
|
||||
progressBar.setIndeterminate(totalBytes == -1);
|
||||
if (resIdString != 0) {
|
||||
progressLabel.setText(resIdString);
|
||||
progressPercent.setText("");
|
||||
} else if (totalBytes > 0 && bytesDownloaded >= 0) {
|
||||
float percent = bytesDownloaded * 100 / totalBytes;
|
||||
progressLabel.setText(Utils.getFriendlySize(bytesDownloaded) + " / " + Utils.getFriendlySize(totalBytes));
|
||||
NumberFormat format = NumberFormat.getPercentInstance();
|
||||
format.setMaximumFractionDigits(0);
|
||||
progressPercent.setText(format.format(percent / 100));
|
||||
} else if (bytesDownloaded >= 0) {
|
||||
progressLabel.setText(Utils.getFriendlySize(bytesDownloaded));
|
||||
progressPercent.setText("");
|
||||
}
|
||||
|
||||
// Make sure it's visible
|
||||
if (progressLayout.getVisibility() != View.VISIBLE) {
|
||||
progressLayout.setVisibility(View.VISIBLE);
|
||||
buttonLayout.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView);
|
||||
mRecyclerView = recyclerView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
|
||||
mRecyclerView = null;
|
||||
super.onDetachedFromRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
private class ScreenShotsViewHolder extends RecyclerView.ViewHolder {
|
||||
final RecyclerView recyclerView;
|
||||
LinearLayoutManagerSnapHelper snapHelper;
|
||||
|
||||
ScreenShotsViewHolder(View view) {
|
||||
super(view);
|
||||
recyclerView = (RecyclerView) view.findViewById(R.id.screenshots);
|
||||
}
|
||||
}
|
||||
|
||||
private class WhatsNewViewHolder extends RecyclerView.ViewHolder {
|
||||
final TextView textView;
|
||||
|
||||
WhatsNewViewHolder(View view) {
|
||||
super(view);
|
||||
textView = (TextView) view.findViewById(R.id.text);
|
||||
}
|
||||
}
|
||||
|
||||
private class DonateViewHolder extends RecyclerView.ViewHolder {
|
||||
final TextView textView;
|
||||
final LinearLayout contentView;
|
||||
|
||||
DonateViewHolder(View view) {
|
||||
super(view);
|
||||
textView = (TextView) view.findViewById(R.id.text);
|
||||
contentView = (LinearLayout) view.findViewById(R.id.ll_information);
|
||||
}
|
||||
}
|
||||
|
||||
private class ExpandableLinearLayoutViewHolder extends RecyclerView.ViewHolder {
|
||||
final TextView headerView;
|
||||
final LinearLayout contentView;
|
||||
|
||||
ExpandableLinearLayoutViewHolder(View view) {
|
||||
super(view);
|
||||
headerView = (TextView) view.findViewById(R.id.information);
|
||||
contentView = (LinearLayout) view.findViewById(R.id.ll_content);
|
||||
}
|
||||
}
|
||||
|
||||
private class VersionViewHolder extends RecyclerView.ViewHolder {
|
||||
final TextView version;
|
||||
final TextView status;
|
||||
final TextView repository;
|
||||
final TextView size;
|
||||
final TextView api;
|
||||
final TextView incompatibleReasons;
|
||||
final TextView buildtype;
|
||||
final TextView added;
|
||||
final TextView nativecode;
|
||||
|
||||
VersionViewHolder(View view) {
|
||||
super(view);
|
||||
version = (TextView) view.findViewById(R.id.version);
|
||||
status = (TextView) view.findViewById(R.id.status);
|
||||
repository = (TextView) view.findViewById(R.id.repository);
|
||||
size = (TextView) view.findViewById(R.id.size);
|
||||
api = (TextView) view.findViewById(R.id.api);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void addLinkItemView(ViewGroup parent, int resIdText, int resIdDrawable, String url) {
|
||||
TextView view = (TextView) LayoutInflater.from(parent.getContext()).inflate(R.layout.app_details2_link_item, parent, false);
|
||||
view.setTag(url);
|
||||
view.setText(resIdText);
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(view, resIdDrawable, 0, 0, 0);
|
||||
parent.addView(view);
|
||||
view.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onLinkClicked((String) v.getTag());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String getInstalledStatus(final Apk apk) {
|
||||
// Definitely not installed.
|
||||
if (apk.versionCode != mApp.installedVersionCode) {
|
||||
return mContext.getString(R.string.app_not_installed);
|
||||
}
|
||||
// Definitely installed this version.
|
||||
if (apk.sig != null && apk.sig.equals(mApp.installedSig)) {
|
||||
return mContext.getString(R.string.app_installed);
|
||||
}
|
||||
// Installed the same version, but from someplace else.
|
||||
final String installerPkgName;
|
||||
try {
|
||||
installerPkgName = mContext.getPackageManager().getInstallerPackageName(mApp.packageName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w("AppDetailsAdapter", "Application " + mApp.packageName + " is not installed anymore");
|
||||
return mContext.getString(R.string.app_not_installed);
|
||||
}
|
||||
if (TextUtils.isEmpty(installerPkgName)) {
|
||||
return mContext.getString(R.string.app_inst_unknown_source);
|
||||
}
|
||||
final String installerLabel = InstalledAppProvider
|
||||
.getApplicationLabel(mContext, installerPkgName);
|
||||
return mContext.getString(R.string.app_inst_known_source, installerLabel);
|
||||
}
|
||||
|
||||
private void onLinkClicked(String url) {
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
mCallbacks.openUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
private View.OnClickListener mOnInstallClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallbacks.installApk();
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener mOnUnInstallClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallbacks.uninstallApk();
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener mOnUpgradeClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallbacks.upgradeApk();
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener mOnLaunchClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallbacks.launchApk();
|
||||
}
|
||||
};
|
||||
|
||||
private boolean uriIsSetAndCanBeOpened(String s) {
|
||||
if (TextUtils.isEmpty(s))
|
||||
return false;
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(s));
|
||||
return (intent.resolveActivity(mContext.getPackageManager()) != null);
|
||||
}
|
||||
|
||||
// The HTML formatter adds "\n\n" at the end of every paragraph. This
|
||||
// is desired between paragraphs, but not at the end of the whole
|
||||
// string as it adds unwanted spacing at the end of the TextView.
|
||||
// Remove all trailing newlines.
|
||||
// Use this function instead of a trim() as that would require
|
||||
// converting to String and thus losing formatting (e.g. bold).
|
||||
private static CharSequence trimNewlines(CharSequence s) {
|
||||
if (s == null || s.length() < 1) {
|
||||
return s;
|
||||
}
|
||||
int i;
|
||||
for (i = s.length() - 1; i >= 0; i--) {
|
||||
if (s.charAt(i) != '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == s.length() - 1) {
|
||||
return s;
|
||||
}
|
||||
return s.subSequence(0, i + 1);
|
||||
}
|
||||
|
||||
@SuppressLint("ParcelCreator")
|
||||
private static final class SafeURLSpan extends URLSpan {
|
||||
SafeURLSpan(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View widget) {
|
||||
try {
|
||||
super.onClick(widget);
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
Toast.makeText(widget.getContext(),
|
||||
widget.getContext().getString(R.string.no_handler_app, getURL()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,14 +6,13 @@
|
||||
app:cardElevation="3dp"
|
||||
app:cardBackgroundColor="#ffffff"
|
||||
android:padding="10dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
>
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:adjustViewBounds="true"
|
||||
android:minWidth="@dimen/details_screenshot_width"
|
||||
android:scaleType="fitCenter"
|
||||
/>
|
||||
</android.support.v7.widget.CardView>
|
@ -3,5 +3,5 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/screenshots"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp">
|
||||
android:layout_height="@dimen/details_screenshot_height">
|
||||
</android.support.v7.widget.RecyclerView>
|
@ -5,6 +5,9 @@
|
||||
<dimen name="material_listitem_height">48dp</dimen>
|
||||
<dimen name="app_bar_height">180dp</dimen>
|
||||
<dimen name="details_activity_padding">8dp</dimen>
|
||||
|
||||
<dimen name="details_screenshot_height">200dp</dimen>
|
||||
<dimen name="details_screenshot_width">200dp</dimen>
|
||||
<!-- "Not selected" items are inset by this value, while the selected one is not -->
|
||||
<dimen name="details_screenshot_margin">8dp</dimen>
|
||||
<!-- The selected item stands out from the background by this elevation -->
|
||||
|
Loading…
x
Reference in New Issue
Block a user