Merge branch 'feature/app-details-minor-refresh' into 'master'

Refresh layout of AppDetails screen

This change primarily affects the AppDetails links section to make them easier to click. It also strips down the UI a bit to provide a cleaner interface as well as some modest Material Design tweaks.

Fixes #389.

Also fixes an unreported issue where the permissions list would be blank if the app only requested the root permission on devices which no longer support this.

The most significant change is arguably removing the expand/collapse functionality around the links and permissions UI elements. I think personally this kind of UI behavior is a bit of an anti-pattern as it clutters up the UI visually and doesn't provide much if any real utility to the user. Also, given the background and context of the app, I would argue that the links (especially to the source code and website) should have high visual priority as well as the permissions the application requests. I know I personally very commonly click on these before deciding to install any given app.

It's not perfect, and I would like to do more eventually, but I tried to refrain from making too many or too drastic of changes to the existing design for now.

| **before** | **after** |
| -------- | -------- |
| ![before] | ![after] |

**link touch target**

![touch_target]

[before]: https://gitlab.com/zaventh/fdroidclient/uploads/c45d27a19777ea345820d8753d3e290b/before_480.png
[after]: https://gitlab.com/zaventh/fdroidclient/uploads/b1f517c9de9e74c63b6957fed68b3dd3/after_480.png
[touch_target]: https://gitlab.com/zaventh/fdroidclient/uploads/6e7a38610bc792f11a76fe837fb9f28a/touch_target.png

See merge request !153
This commit is contained in:
Daniel Martí 2015-10-05 21:08:52 +00:00
commit 7875d8622e
11 changed files with 298 additions and 296 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -22,8 +22,10 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingLeft="@dimen/layout_horizontal_margin"
android:paddingStart="@dimen/layout_horizontal_margin"
android:paddingRight="@dimen/layout_horizontal_margin"
android:paddingEnd="@dimen/layout_horizontal_margin"
android:paddingTop="4dp">
<TextView
@ -91,142 +93,111 @@ Android is open in the sense that you are free to install apks from anywhere you
Changelog" />
<ImageView
<TextView
android:id="@+id/view_more_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:contentDescription="@string/content_description_view_more"
android:src="@drawable/ic_expand_more_grey600"
tools:src="@drawable/ic_expand_more_grey600" />
android:layout_gravity="bottom|center_horizontal"
android:text="@string/more"
android:textAllCaps="true"
android:textSize="14sp"
android:layout_marginTop="8dp"
android:textColor="?android:textColorSecondary"
tools:ignore="UnusedAttribute" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2px"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="?android:attr/listDivider"
tools:ignore="PxUsage" />
<LinearLayout
android:id="@+id/ll_information"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:orientation="vertical">
android:orientation="vertical"
tools:ignore="UnusedAttribute">
<TextView
android:id="@+id/information"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8sp"
android:drawableRight="@drawable/ic_expand_more_grey600"
android:drawablePadding="4dp"
android:drawableEnd="@drawable/ic_expand_more_grey600"
android:singleLine="true"
style="@style/AppDetailsSubheaderText"
android:text="@string/links"
android:textStyle="bold"
tools:text="@string/links"
tools:drawableRight="@drawable/ic_expand_more_grey600"/>
android:drawableRight="@drawable/ic_expand_more_grey600"
android:drawableEnd="@drawable/ic_expand_more_grey600"
android:drawableLeft="@drawable/ic_website"
android:drawableStart="@drawable/ic_website" />
<LinearLayout
android:id="@+id/ll_information_content"
android:layout_width="fill_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:orientation="vertical">
android:orientation="vertical"
android:layout_marginLeft="@dimen/layout_horizontal_margin"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:visibility="gone">
<TextView
android:id="@+id/source"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/AppDetailsLink"
android:drawableLeft="@drawable/ic_source_code"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_source_code"
android:gravity="center_vertical"
android:text="@string/menu_source"
tools:text="@string/menu_source" />
android:text="@string/menu_source" />
<TextView
android:id="@+id/issues"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/AppDetailsLink"
android:drawableLeft="@drawable/ic_issues"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_issues"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:text="@string/menu_issues"
tools:text="@string/menu_issues" />
android:text="@string/menu_issues" />
<TextView
android:id="@+id/changelog"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/AppDetailsLink"
android:drawableLeft="@drawable/ic_changelog"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_changelog"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:text="@string/menu_changelog"
tools:text="@string/menu_changelog" />
android:text="@string/menu_changelog" />
<TextView
android:id="@+id/website"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/AppDetailsLink"
android:drawableLeft="@drawable/ic_website"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_website"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:text="@string/menu_website"
tools:text="@string/menu_website" />
android:text="@string/menu_website" />
<TextView
android:id="@+id/donate"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/AppDetailsLink"
android:drawableLeft="@drawable/ic_donate"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_donate"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:text="@string/menu_donate"
tools:text="@string/menu_donate" />
android:text="@string/menu_donate" />
<TextView
android:id="@+id/bitcoin"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/AppDetailsLink"
android:drawableLeft="@drawable/ic_bitcoin"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_bitcoin"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:text="@string/menu_bitcoin"
tools:text="@string/menu_bitcoin" />
android:text="@string/menu_bitcoin" />
<TextView
android:id="@+id/litecoin"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/AppDetailsLink"
android:drawableLeft="@drawable/ic_litecoin"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_litecoin"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:text="@string/menu_litecoin"
tools:text="@string/menu_litecoin" />
android:text="@string/menu_litecoin" />
<TextView
android:id="@+id/flattr"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/AppDetailsLink"
android:drawableLeft="@drawable/ic_flattr"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_flattr"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:text="@string/menu_flattr"
tools:text="@string/menu_flattr" />
android:text="@string/menu_flattr" />
</LinearLayout>
</LinearLayout>
<LinearLayout
@ -234,27 +205,29 @@ Changelog" />
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:orientation="vertical">
android:orientation="vertical"
android:layout_marginBottom="8dp"
tools:ignore="UnusedAttribute">
<TextView
android:id="@+id/permissions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8sp"
android:drawablePadding="4dp"
android:drawableEnd="@drawable/ic_expand_more_grey600"
style="@style/AppDetailsSubheaderText"
android:text="@string/permissions"
android:drawableLeft="@drawable/ic_lock_24dp_grey600"
android:drawableStart="@drawable/ic_lock_24dp_grey600"
android:drawableRight="@drawable/ic_expand_more_grey600"
android:singleLine="true"
android:textStyle="bold"
tools:text="Permissions for version 1.0"
tools:drawableRight="@drawable/ic_expand_more_grey600"/>
android:drawableEnd="@drawable/ic_expand_more_grey600" />
<TextView
android:id="@+id/permissions_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="false"
android:textSize="13sp"
android:fontFamily="sans-serif-light"
android:textSize="14sp"
android:visibility="gone"
android:layout_marginLeft="@dimen/layout_horizontal_margin"
android:layout_marginStart="@dimen/layout_horizontal_margin"
tools:text=" * Full network access
* View network connections
* View Wi-Fi connections

View File

@ -15,4 +15,8 @@
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
</style>
<style name="AppDetailsLink" parent="AppDetailsLinkBase">
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
</resources>

View File

@ -4,4 +4,6 @@
<dimen name="applist_icon_normal_size">48dp</dimen>
<dimen name="applist_icon_compact_size">32dp</dimen>
<dimen name="layout_horizontal_margin">16dp</dimen>
<dimen name="material_listitem_height">48dp</dimen>
</resources>

View File

@ -64,6 +64,8 @@
<string name="repo_add_add">Add</string>
<string name="links">Links</string>
<string name="content_description_view_more">View more</string>
<string name="more">More</string>
<string name="less">Less</string>
<string name="back">Back</string>
<string name="cancel">Cancel</string>
@ -189,6 +191,7 @@
<string name="global_error_updating_repos">Error during update: %s</string>
<string name="no_permissions">No permissions are used.</string>
<string name="permissions_for_long">Permissions for version %s</string>
<string name="permissions">Permissions</string>
<string name="no_handler_app">You don\'t have any available app that can handle %s.</string>
<string name="compactlayout">Compact Layout</string>
<string name="compactlayout_on">Show icons at a smaller size</string>

View File

@ -178,4 +178,24 @@
<item name="android:textStyle">italic</item>
</style>
<style name="AppDetailsLinkBase">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">@dimen/material_listitem_height</item>
<item name="android:drawablePadding">12dp</item>
<item name="android:gravity">center_vertical</item>
</style>
<style name="AppDetailsLink" parent="AppDetailsLinkBase" />
<style name="AppDetailsSubheaderTextBase">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">@dimen/material_listitem_height</item>
<item name="android:textSize">16sp</item>
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:singleLine">true</item>
<item name="android:gravity">center_vertical</item>
<item name="android:drawablePadding">12dp</item>
</style>
<style name="AppDetailsSubheaderText" parent="AppDetailsSubheaderTextBase" />
</resources>

View File

@ -43,6 +43,7 @@ import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.support.v4.app.NavUtils;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog;
@ -1056,11 +1057,24 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
private AppDetailsData data;
private static final int MAX_LINES = 5;
private static boolean view_all_description;
private static boolean view_all_information;
private static boolean view_all_permissions;
private static LinearLayout ll_view_more_description;
private static LinearLayout ll_view_more_information;
private static LinearLayout ll_view_more_permissions;
private final View.OnClickListener expander_permissions = new View.OnClickListener() {
@Override
public void onClick(View v) {
final TextView permissionListView = (TextView) ll_view_more_permissions.findViewById(R.id.permissions_list);
final TextView permissionHeader = (TextView) ll_view_more_permissions.findViewById(R.id.permissions);
if (permissionListView.getVisibility() == View.GONE) {
permissionListView.setVisibility(View.VISIBLE);
permissionHeader.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getActivity(), R.drawable.ic_lock_24dp_grey600), null, ContextCompat.getDrawable(getActivity(), R.drawable.ic_expand_less_grey600), null);
} else {
permissionListView.setVisibility(View.GONE);
permissionHeader.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getActivity(), R.drawable.ic_lock_24dp_grey600), null, ContextCompat.getDrawable(getActivity(), R.drawable.ic_expand_more_grey600), null);
}
}
};
private ViewGroup layout_links;
public AppDetailsSummaryFragment() {
prefs = Preferences.get();
@ -1116,168 +1130,22 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
return s.subSequence(0, i);
}
private void setupView(final View view) {
// Expandable description
final TextView description = (TextView) view.findViewById(R.id.description);
final Spanned desc = Html.fromHtml(getApp().description, null, new Utils.HtmlTagHandler());
description.setMovementMethod(SafeLinkMovementMethod.getInstance(getActivity()));
description.setText(trimNewlines(desc));
final ImageView view_more_description = (ImageView) view.findViewById(R.id.view_more_description);
description.post(new Runnable() {
@Override
public void run() {
// If description has more than five lines
if (description.getLineCount() > MAX_LINES) {
description.setMaxLines(MAX_LINES);
description.setOnClickListener(expander_description);
view_all_description = true;
private ViewGroup layout_links_content;
private View.OnClickListener expander_links = new View.OnClickListener() {
@Override
public void onClick(View v) {
ll_view_more_description = (LinearLayout) view.findViewById(R.id.ll_description);
ll_view_more_description.setOnClickListener(expander_description);
TextView linksHeader = (TextView) layout_links.findViewById(R.id.information);
view_more_description.setImageResource(R.drawable.ic_expand_more_grey600);
view_more_description.setOnClickListener(expander_description);
} else {
view_more_description.setVisibility(View.GONE);
}
}
});
// App ID
final TextView appIdView = (TextView) view.findViewById(R.id.appid);
if (prefs.expertMode())
appIdView.setText(getApp().id);
else
appIdView.setVisibility(View.GONE);
// Expandable information
ll_view_more_information = (LinearLayout) view.findViewById(R.id.ll_information);
final TextView information = (TextView) view.findViewById(R.id.information);
final LinearLayout ll_view_more_information_content = (LinearLayout) view.findViewById(R.id.ll_information_content);
ll_view_more_information_content.setVisibility(View.GONE);
view_all_information = true;
information.setCompoundDrawablesWithIntrinsicBounds(null, null, getActivity().getResources().getDrawable(R.drawable.ic_expand_more_grey600), null);
ll_view_more_information.setOnClickListener(expander_information);
information.setOnClickListener(expander_information);
// Summary
final TextView summaryView = (TextView) view.findViewById(R.id.summary);
summaryView.setText(getApp().summary);
// Website button
TextView tv = (TextView) view.findViewById(R.id.website);
if (!TextUtils.isEmpty(getApp().webURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Source button
tv = (TextView) view.findViewById(R.id.source);
if (!TextUtils.isEmpty(getApp().sourceURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Issues button
tv = (TextView) view.findViewById(R.id.issues);
if (!TextUtils.isEmpty(getApp().trackerURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Changelog button
tv = (TextView) view.findViewById(R.id.changelog);
if (!TextUtils.isEmpty(getApp().changelogURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Donate button
tv = (TextView) view.findViewById(R.id.donate);
if (!TextUtils.isEmpty(getApp().donateURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Bitcoin
tv = (TextView) view.findViewById(R.id.bitcoin);
if (!TextUtils.isEmpty(getApp().bitcoinAddr))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Litecoin
tv = (TextView) view.findViewById(R.id.litecoin);
if (!TextUtils.isEmpty(getApp().litecoinAddr))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Flattr
tv = (TextView) view.findViewById(R.id.flattr);
if (!TextUtils.isEmpty(getApp().flattrID))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Categories TextView
final TextView categories = (TextView) view.findViewById(R.id.categories);
if (prefs.expertMode() && getApp().categories != null)
categories.setText(getApp().categories.toString().replaceAll(",", ", "));
else
categories.setVisibility(View.GONE);
Apk curApk = null;
for (int i = 0; i < getApks().getCount(); i++) {
final Apk apk = getApks().getItem(i);
if (apk.vercode == getApp().suggestedVercode) {
curApk = apk;
break;
}
}
// Expandable permissions
ll_view_more_permissions = (LinearLayout) view.findViewById(R.id.ll_permissions);
final TextView permissionHeader = (TextView) view.findViewById(R.id.permissions);
final TextView permissionListView = (TextView) view.findViewById(R.id.permissions_list);
permissionListView.setVisibility(View.GONE);
view_all_permissions = true;
final boolean curApkCompatible = curApk != null && curApk.compatible;
if (!getApks().isEmpty() && (curApkCompatible || prefs.showIncompatibleVersions())) {
permissionHeader.setText(getString(R.string.permissions_for_long, getApks().getItem(0).version));
permissionHeader.setCompoundDrawablesWithIntrinsicBounds(null, null, getActivity().getResources().getDrawable(R.drawable.ic_expand_more_grey600), null);
ll_view_more_permissions.setOnClickListener(expander_permissions);
permissionHeader.setOnClickListener(expander_permissions);
} else {
permissionHeader.setVisibility(View.GONE);
permissionHeader.setCompoundDrawables(null, null, null, null);
}
// Anti features
final TextView antiFeaturesView = (TextView) view.findViewById(R.id.antifeatures);
if (getApp().antiFeatures != null) {
StringBuilder sb = new StringBuilder();
for (final String af : getApp().antiFeatures) {
final String afdesc = descAntiFeature(af);
if (afdesc != null) {
sb.append("\t• ").append(afdesc).append('\n');
}
}
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
antiFeaturesView.setText(sb.toString());
if (layout_links_content.getVisibility() == View.GONE) {
layout_links_content.setVisibility(View.VISIBLE);
linksHeader.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getActivity(), R.drawable.ic_website), null, ContextCompat.getDrawable(getActivity(), R.drawable.ic_expand_less_grey600), null);
} else {
antiFeaturesView.setVisibility(View.GONE);
layout_links_content.setVisibility(View.GONE);
linksHeader.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getActivity(), R.drawable.ic_website), null, ContextCompat.getDrawable(getActivity(), R.drawable.ic_expand_more_grey600), null);
}
} else {
antiFeaturesView.setVisibility(View.GONE);
}
updateViews(view);
}
};
private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
public void onClick(View v) {
@ -1317,68 +1185,200 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
private final View.OnClickListener expander_description = new View.OnClickListener() {
public void onClick(View v) {
final TextView description = (TextView) ll_view_more_description.findViewById(R.id.description);
final ImageView view_more_permissions = (ImageView) ll_view_more_description.findViewById(R.id.view_more_description);
final TextView view_more_permissions = (TextView)ll_view_more_description.findViewById(R.id.view_more_description);
if (view_all_description) {
description.setMaxLines(Integer.MAX_VALUE);
view_more_permissions.setImageResource(R.drawable.ic_expand_less_grey600);
view_more_permissions.setText(getString(R.string.less));
} else {
description.setMaxLines(MAX_LINES);
view_more_permissions.setImageResource(R.drawable.ic_expand_more_grey600);
description.setEllipsize(TextUtils.TruncateAt.MARQUEE);
view_more_permissions.setText(R.string.more);
}
view_all_description ^= true;
}
};
private final View.OnClickListener expander_information = new View.OnClickListener() {
public void onClick(View v) {
final TextView informationHeader = (TextView) ll_view_more_information.findViewById(R.id.information);
final LinearLayout information_content = (LinearLayout) ll_view_more_information.findViewById(R.id.ll_information_content);
if (!view_all_information) {
information_content.setVisibility(View.GONE);
informationHeader.setCompoundDrawablesWithIntrinsicBounds(null, null, getActivity().getResources().getDrawable(R.drawable.ic_expand_more_grey600), null);
} else {
information_content.setVisibility(View.VISIBLE);
informationHeader.setCompoundDrawablesWithIntrinsicBounds(null, null, getActivity().getResources().getDrawable(R.drawable.ic_expand_less_grey600), null);
}
view_all_information ^= true;
}
};
private void setupView(final View view) {
// Expandable description
final TextView description = (TextView) view.findViewById(R.id.description);
final Spanned desc = Html.fromHtml(getApp().description, null, new Utils.HtmlTagHandler());
description.setMovementMethod(SafeLinkMovementMethod.getInstance(getActivity()));
description.setText(trimNewlines(desc));
final View view_more_description = view.findViewById(R.id.view_more_description);
description.post(new Runnable() {
@Override
public void run() {
// If description has more than five lines
if (description.getLineCount() > MAX_LINES) {
description.setMaxLines(MAX_LINES);
description.setEllipsize(TextUtils.TruncateAt.MARQUEE);
description.setOnClickListener(expander_description);
view_all_description = true;
private final View.OnClickListener expander_permissions = new View.OnClickListener() {
public void onClick(View v) {
final TextView permissionHeader = (TextView) ll_view_more_permissions.findViewById(R.id.permissions);
final TextView permissionListView = (TextView) ll_view_more_permissions.findViewById(R.id.permissions_list);
if (!view_all_permissions) {
permissionListView.setVisibility(View.GONE);
permissionHeader.setCompoundDrawablesWithIntrinsicBounds(null, null, getActivity().getResources().getDrawable(R.drawable.ic_expand_more_grey600), null);
} else {
CommaSeparatedList permsList = getApks().getItem(0).permissions;
if (permsList == null) {
permissionListView.setText(R.string.no_permissions);
ll_view_more_description = (LinearLayout) view.findViewById(R.id.ll_description);
ll_view_more_description.setOnClickListener(expander_description);
view_more_description.setOnClickListener(expander_description);
} else {
Iterator<String> permissions = permsList.iterator();
StringBuilder sb = new StringBuilder();
while (permissions.hasNext()) {
final String permissionName = permissions.next();
try {
final Permission permission = new Permission(getActivity(), permissionName);
// TODO: Make this list RTL friendly
sb.append("\t• ").append(permission.getName()).append('\n');
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Permission not yet available: " + permissionName);
}
}
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
}
permissionListView.setText(sb.toString());
view_more_description.setVisibility(View.GONE);
}
permissionListView.setVisibility(View.VISIBLE);
permissionHeader.setCompoundDrawablesWithIntrinsicBounds(null, null, getActivity().getResources().getDrawable(R.drawable.ic_expand_less_grey600), null);
}
view_all_permissions ^= true;
});
// App ID
final TextView appIdView = (TextView) view.findViewById(R.id.appid);
if (prefs.expertMode())
appIdView.setText(getApp().id);
else
appIdView.setVisibility(View.GONE);
// Summary
final TextView summaryView = (TextView) view.findViewById(R.id.summary);
summaryView.setText(getApp().summary);
layout_links = (ViewGroup) view.findViewById(R.id.ll_information);
layout_links_content = (ViewGroup) layout_links.findViewById(R.id.ll_information_content);
final TextView linksHeader = (TextView) view.findViewById(R.id.information);
linksHeader.setOnClickListener(expander_links);
// Website button
View tv = view.findViewById(R.id.website);
if (!TextUtils.isEmpty(getApp().webURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Source button
tv = view.findViewById(R.id.source);
if (!TextUtils.isEmpty(getApp().sourceURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Issues button
tv = view.findViewById(R.id.issues);
if (!TextUtils.isEmpty(getApp().trackerURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Changelog button
tv = view.findViewById(R.id.changelog);
if (!TextUtils.isEmpty(getApp().changelogURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Donate button
tv = view.findViewById(R.id.donate);
if (!TextUtils.isEmpty(getApp().donateURL))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Bitcoin
tv = view.findViewById(R.id.bitcoin);
if (!TextUtils.isEmpty(getApp().bitcoinAddr))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Litecoin
tv = view.findViewById(R.id.litecoin);
if (!TextUtils.isEmpty(getApp().litecoinAddr))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Flattr
tv = view.findViewById(R.id.flattr);
if (!TextUtils.isEmpty(getApp().flattrID))
tv.setOnClickListener(mOnClickListener);
else
tv.setVisibility(View.GONE);
// Categories TextView
final TextView categories = (TextView) view.findViewById(R.id.categories);
if (prefs.expertMode() && getApp().categories != null)
categories.setText(getApp().categories.toString().replaceAll(",", ", "));
else
categories.setVisibility(View.GONE);
Apk curApk = null;
for (int i = 0; i < getApks().getCount(); i++) {
final Apk apk = getApks().getItem(i);
if (apk.vercode == getApp().suggestedVercode) {
curApk = apk;
break;
}
}
};
// Expandable permissions
ll_view_more_permissions = (LinearLayout) view.findViewById(R.id.ll_permissions);
final TextView permissionHeader = (TextView) view.findViewById(R.id.permissions);
final boolean curApkCompatible = curApk != null && curApk.compatible;
if (!getApks().isEmpty() && (curApkCompatible || prefs.showIncompatibleVersions())) {
// build and set the string once
buildPermissionInfo();
permissionHeader.setOnClickListener(expander_permissions);
} else {
permissionHeader.setVisibility(View.GONE);
}
// Anti features
final TextView antiFeaturesView = (TextView) view.findViewById(R.id.antifeatures);
if (getApp().antiFeatures != null) {
StringBuilder sb = new StringBuilder();
for (final String af : getApp().antiFeatures) {
final String afdesc = descAntiFeature(af);
if (afdesc != null) {
sb.append("\t• ").append(afdesc).append('\n');
}
}
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
antiFeaturesView.setText(sb.toString());
} else {
antiFeaturesView.setVisibility(View.GONE);
}
} else {
antiFeaturesView.setVisibility(View.GONE);
}
updateViews(view);
}
private void buildPermissionInfo() {
final TextView permissionListView = (TextView) ll_view_more_permissions.findViewById(R.id.permissions_list);
CommaSeparatedList permsList = getApks().getItem(0).permissions;
if (permsList == null) {
permissionListView.setText(R.string.no_permissions);
} else {
Iterator<String> permissions = permsList.iterator();
StringBuilder sb = new StringBuilder();
while (permissions.hasNext()) {
final String permissionName = permissions.next();
try {
final Permission permission = new Permission(getActivity(), permissionName);
// TODO: Make this list RTL friendly
sb.append("\t• ").append(permission.getName()).append('\n');
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Permission not yet available: " + permissionName);
}
}
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
permissionListView.setText(sb.toString());
} else {
permissionListView.setText(R.string.no_permissions);
}
}
}
private String descAntiFeature(String af) {
switch (af) {