Add version items directly to RecyclerView

This commit is contained in:
mvp76 2016-11-21 10:48:51 +01:00
parent 0855c0affe
commit 4a25df8461
3 changed files with 170 additions and 248 deletions

View File

@ -28,6 +28,7 @@ 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;
@ -51,6 +52,8 @@ import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.InstalledAppProvider;
import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.data.Schema;
import org.fdroid.fdroid.installer.InstallManagerService;
import org.fdroid.fdroid.installer.Installer;
@ -60,12 +63,12 @@ import org.fdroid.fdroid.net.Downloader;
import org.fdroid.fdroid.net.DownloaderService;
import org.fdroid.fdroid.privileged.views.AppDiff;
import org.fdroid.fdroid.privileged.views.AppSecurityPermissions;
import org.fdroid.fdroid.views.ApkListAdapter;
import org.fdroid.fdroid.views.LinearLayoutManagerSnapHelper;
import org.fdroid.fdroid.views.ScreenShotsRecyclerViewAdapter;
import org.fdroid.fdroid.views.ShareChooserDialog;
import java.util.ArrayList;
import java.util.List;
import static android.support.v7.widget.RecyclerView.NO_POSITION;
@ -215,10 +218,12 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
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 ArrayList<Integer> mItems;
private ApkListAdapter mApkListAdapter;
private ArrayList<Object> mItems;
private ArrayList<Apk> mVersions;
private boolean mShowVersions;
public AppDetailsRecyclerViewAdapter(Context context) {
mContext = context;
@ -226,7 +231,16 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
}
public void updateItems() {
mApkListAdapter = new ApkListAdapter(mContext, mApp);
// 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
@ -240,6 +254,15 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
addItem(VIEWTYPE_VERSIONS);
}
public 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.
@ -256,15 +279,15 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
private boolean shouldShowPermissions() {
// Figure out if we should show permissions section
Apk curApk = null;
for (int i = 0; i < mApkListAdapter.getCount(); i++) {
final Apk apk = mApkListAdapter.getItem(i);
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;
if (!mApkListAdapter.isEmpty() && (curApkCompatible || Preferences.get().showIncompatibleVersions())) {
if (mVersions.size() > 0 && (curApkCompatible || Preferences.get().showIncompatibleVersions())) {
return true;
}
return false;
@ -307,13 +330,17 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
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 = mItems.get(position);
int viewType = getItemViewType(position);
if (viewType == VIEWTYPE_HEADER) {
final HeaderViewHolder vh = (HeaderViewHolder) holder;
ImageLoader.getInstance().displayImage(mApp.iconUrlLarge, vh.iconView, vh.displayImageOptions);
@ -355,12 +382,12 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
vh.buttonSecondaryView.setVisibility(isAppInstalled() ? View.VISIBLE : View.INVISIBLE);
vh.buttonSecondaryView.setOnClickListener(mOnUnInstallClickListener);
vh.buttonPrimaryView.setText(R.string.menu_install);
vh.buttonPrimaryView.setVisibility(mApkListAdapter.getCount() > 0 ? View.VISIBLE : View.GONE);
vh.buttonPrimaryView.setVisibility(mVersions.size() > 0 ? View.VISIBLE : View.GONE);
if (mActiveDownloadUrlString != null) {
vh.buttonPrimaryView.setText(R.string.downloading);
vh.buttonPrimaryView.setEnabled(false);
} else if (!isAppInstalled() && mApp.suggestedVersionCode > 0 &&
mApkListAdapter.getCount() > 0) {
mVersions.size() > 0) {
// Check count > 0 due to incompatible apps resulting in an empty list.
// If App isn't installed
//installed = false;
@ -492,7 +519,7 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
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(getPackageManager(), mApkListAdapter.getItem(0));
AppDiff appDiff = new AppDiff(getPackageManager(), mVersions.get(0));
AppSecurityPermissions perms = new AppSecurityPermissions(mContext, appDiff.pkgInfo);
vh.contentView.addView(perms.getPermissionsView(AppSecurityPermissions.WHICH_ALL));
} else if (viewType == VIEWTYPE_VERSIONS) {
@ -500,18 +527,94 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
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_access_time_24dp_grey600, 0, shouldBeVisible ? R.drawable.ic_expand_less_grey600 : R.drawable.ic_expand_more_grey600, 0);
vh.itemView.requestLayout();
setShowVersions(!mShowVersions);
}
});
vh.headerView.setText(R.string.versions);
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(vh.headerView, R.drawable.ic_access_time_24dp_grey600, 0, R.drawable.ic_expand_more_grey600, 0);
vh.contentView.removeAllViews();
for (int i = 0; i < mApkListAdapter.getCount(); i++) {
View view = mApkListAdapter.getView(i, null, vh.contentView);
vh.contentView.addView(view, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
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);
}
}
}
@ -523,7 +626,9 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
@Override
public int getItemViewType(int position) {
return mItems.get(position);
if (mItems.get(position) instanceof Apk)
return VIEWTYPE_VERSION;
return (Integer)mItems.get(position);
}
public class HeaderViewHolder extends RecyclerView.ViewHolder {
@ -632,14 +737,28 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
}
}
public class VersionsViewHolder extends RecyclerView.ViewHolder {
final TextView headerView;
final ListView contentView;
public 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;
VersionsViewHolder(View view) {
VersionViewHolder(View view) {
super(view);
headerView = (TextView) view.findViewById(R.id.information);
contentView = (ListView) view.findViewById(R.id.lv_content);
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);
}
}
@ -657,7 +776,30 @@ public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog
});
}
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(TAG, "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)) {

View File

@ -1,190 +0,0 @@
package org.fdroid.fdroid.views;
import android.content.Context;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
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 java.util.List;
public class ApkListAdapter extends ArrayAdapter<Apk> {
private static final String TAG = "ApkListAdapter";
private final LayoutInflater mInflater;
private final App mApp;
public ApkListAdapter(Context context, App app) {
super(context, 0);
mApp = app;
mInflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
final List<Apk> apks = ApkProvider.Helper.findByPackageName(context, app.packageName);
for (final Apk apk : apks) {
if (apk.compatible || Preferences.get().showIncompatibleVersions()) {
add(apk);
}
}
}
private String getInstalledStatus(final Apk apk) {
// Definitely not installed.
if (apk.versionCode != mApp.installedVersionCode) {
return getContext().getString(R.string.app_not_installed);
}
// Definitely installed this version.
if (apk.sig != null && apk.sig.equals(mApp.installedSig)) {
return getContext().getString(R.string.app_installed);
}
// Installed the same version, but from someplace else.
final String installerPkgName;
try {
installerPkgName = getContext().getPackageManager().getInstallerPackageName(mApp.packageName);
} catch (IllegalArgumentException e) {
Log.w(TAG, "Application " + mApp.packageName + " is not installed anymore");
return getContext().getString(R.string.app_not_installed);
}
if (TextUtils.isEmpty(installerPkgName)) {
return getContext().getString(R.string.app_inst_unknown_source);
}
final String installerLabel = InstalledAppProvider
.getApplicationLabel(getContext(), installerPkgName);
return getContext().getString(R.string.app_inst_known_source, installerLabel);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
java.text.DateFormat df = DateFormat.getDateFormat(getContext());
final Apk apk = getItem(position);
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.apklistitem, parent, false);
holder = new ViewHolder();
holder.version = (TextView) convertView.findViewById(R.id.version);
holder.status = (TextView) convertView.findViewById(R.id.status);
holder.repository = (TextView) convertView.findViewById(R.id.repository);
holder.size = (TextView) convertView.findViewById(R.id.size);
holder.api = (TextView) convertView.findViewById(R.id.api);
holder.incompatibleReasons = (TextView) convertView.findViewById(R.id.incompatible_reasons);
holder.buildtype = (TextView) convertView.findViewById(R.id.buildtype);
holder.added = (TextView) convertView.findViewById(R.id.added);
holder.nativecode = (TextView) convertView.findViewById(R.id.nativecode);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.version.setText(getContext().getString(R.string.version)
+ " " + apk.versionName
+ (apk.versionCode == mApp.suggestedVersionCode ? "" : ""));
holder.status.setText(getInstalledStatus(apk));
holder.repository.setText(getContext().getString(R.string.repo_provider,
RepoProvider.Helper.findById(getContext(), apk.repo).getName()));
if (apk.size > 0) {
holder.size.setText(Utils.getFriendlySize(apk.size));
holder.size.setVisibility(View.VISIBLE);
} else {
holder.size.setVisibility(View.GONE);
}
if (!Preferences.get().expertMode()) {
holder.api.setVisibility(View.GONE);
} else if (apk.minSdkVersion > 0 && apk.maxSdkVersion < Apk.SDK_VERSION_MAX_VALUE) {
holder.api.setText(getContext().getString(R.string.minsdk_up_to_maxsdk,
Utils.getAndroidVersionName(apk.minSdkVersion),
Utils.getAndroidVersionName(apk.maxSdkVersion)));
holder.api.setVisibility(View.VISIBLE);
} else if (apk.minSdkVersion > 0) {
holder.api.setText(getContext().getString(R.string.minsdk_or_later,
Utils.getAndroidVersionName(apk.minSdkVersion)));
holder.api.setVisibility(View.VISIBLE);
} else if (apk.maxSdkVersion > 0) {
holder.api.setText(getContext().getString(R.string.up_to_maxsdk,
Utils.getAndroidVersionName(apk.maxSdkVersion)));
holder.api.setVisibility(View.VISIBLE);
}
if (apk.srcname != null) {
holder.buildtype.setText("source");
} else {
holder.buildtype.setText("bin");
}
if (apk.added != null) {
holder.added.setText(getContext().getString(R.string.added_on,
df.format(apk.added)));
holder.added.setVisibility(View.VISIBLE);
} else {
holder.added.setVisibility(View.GONE);
}
if (Preferences.get().expertMode() && apk.nativecode != null) {
holder.nativecode.setText(TextUtils.join(" ", apk.nativecode));
holder.nativecode.setVisibility(View.VISIBLE);
} else {
holder.nativecode.setVisibility(View.GONE);
}
if (apk.incompatibleReasons != null) {
holder.incompatibleReasons.setText(
getContext().getResources().getString(
R.string.requires_features,
TextUtils.join(", ", apk.incompatibleReasons)));
holder.incompatibleReasons.setVisibility(View.VISIBLE);
} else {
holder.incompatibleReasons.setVisibility(View.GONE);
}
// Disable it all if it isn't compatible...
final View[] views = {
convertView,
holder.version,
holder.status,
holder.repository,
holder.size,
holder.api,
holder.buildtype,
holder.added,
holder.nativecode,
};
for (final View v : views) {
v.setEnabled(apk.compatible);
}
return convertView;
}
private static class ViewHolder {
TextView version;
TextView status;
TextView repository;
TextView size;
TextView api;
TextView incompatibleReasons;
TextView buildtype;
TextView added;
TextView nativecode;
}
}

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll_information"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/details_activity_padding"
android:clickable="true"
android:orientation="vertical"
tools:ignore="UnusedAttribute">
<TextView
android:id="@+id/information"
style="@style/AppDetailsSubheaderText"
android:text="@string/version"
android:drawableRight="@drawable/ic_expand_more_grey600"
android:drawableEnd="@drawable/ic_expand_more_grey600"
android:drawableLeft="@drawable/ic_website"
android:drawableStart="@drawable/ic_website" />
<ListView
android:id="@+id/lv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="@dimen/layout_horizontal_margin"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:visibility="gone">
</ListView>
</LinearLayout>