Initial work on details view
This commit is contained in:
parent
f355232bd5
commit
34450569b3
@ -404,6 +404,17 @@
|
|||||||
android:value=".FDroid" />
|
android:value=".FDroid" />
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".AppDetails2"
|
||||||
|
android:label="@string/app_details"
|
||||||
|
android:exported="true"
|
||||||
|
android:parentActivityName=".FDroid"
|
||||||
|
android:theme="@style/AppThemeLight.NoActionBar"
|
||||||
|
android:configChanges="layoutDirection|locale" >
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value=".FDroid" />
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:label="@string/menu_settings"
|
android:label="@string/menu_settings"
|
||||||
android:name=".PreferencesActivity"
|
android:name=".PreferencesActivity"
|
||||||
|
500
app/src/main/java/org/fdroid/fdroid/AppDetails2.java
Normal file
500
app/src/main/java/org/fdroid/fdroid/AppDetails2.java
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.view.ViewCompat;
|
||||||
|
import android.support.v4.widget.TextViewCompat;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.text.AllCapsTransformationMethod;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.Selection;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.text.style.ClickableSpan;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
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.data.App;
|
||||||
|
import org.fdroid.fdroid.data.AppProvider;
|
||||||
|
import org.fdroid.fdroid.views.LinearLayoutManagerSnapHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
||||||
|
|
||||||
|
public class AppDetails2 extends AppCompatActivity {
|
||||||
|
|
||||||
|
private static final String TAG = "AppDetails2";
|
||||||
|
|
||||||
|
private App mApp;
|
||||||
|
private RecyclerView mRecyclerView;
|
||||||
|
private AppDetailsRecyclerViewAdapter mAdapter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_app_details2);
|
||||||
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
toolbar.setTitle(""); // Nice and clean toolbar
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
|
App app = null;
|
||||||
|
String packageName = getPackageNameFromIntent(getIntent());
|
||||||
|
if (!TextUtils.isEmpty(packageName)) {
|
||||||
|
app = AppProvider.Helper.findHighestPriorityMetadata(getContentResolver(), packageName);
|
||||||
|
}
|
||||||
|
setApp(app); // Will call finish if empty or unknown
|
||||||
|
|
||||||
|
mRecyclerView = (RecyclerView) findViewById(R.id.rvDetails);
|
||||||
|
mAdapter = new AppDetailsRecyclerViewAdapter(this);
|
||||||
|
LinearLayoutManager lm = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
|
||||||
|
lm.setStackFromEnd(false);
|
||||||
|
mRecyclerView.setLayoutManager(lm);
|
||||||
|
mRecyclerView.setAdapter(mAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPackageNameFromIntent(Intent intent) {
|
||||||
|
if (!intent.hasExtra(AppDetails.EXTRA_APPID)) {
|
||||||
|
Log.e(TAG, "No package name found in the intent!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return intent.getStringExtra(AppDetails.EXTRA_APPID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If passed null, this will show a message to the user ("Could not find app ..." or something
|
||||||
|
* like that) and then finish the activity.
|
||||||
|
*/
|
||||||
|
private void setApp(App newApp) {
|
||||||
|
if (newApp == null) {
|
||||||
|
Toast.makeText(this, R.string.no_such_app, Toast.LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mApp = newApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AppDetailsRecyclerViewAdapter
|
||||||
|
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
|
||||||
|
private final int VIEWTYPE_HEADER = 0;
|
||||||
|
private final int VIEWTYPE_SCREENSHOTS = 1;
|
||||||
|
private final int VIEWTYPE_WHATS_NEW = 2;
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private ArrayList<Integer> mItems;
|
||||||
|
|
||||||
|
public AppDetailsRecyclerViewAdapter(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
updateItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateItems() {
|
||||||
|
if (mItems == null)
|
||||||
|
mItems = new ArrayList<>();
|
||||||
|
else
|
||||||
|
mItems.clear();
|
||||||
|
mItems.add(Integer.valueOf(VIEWTYPE_HEADER));
|
||||||
|
mItems.add(Integer.valueOf(VIEWTYPE_SCREENSHOTS));
|
||||||
|
mItems.add(Integer.valueOf(VIEWTYPE_WHATS_NEW));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
|
||||||
|
int viewType = mItems.get(position);
|
||||||
|
if (viewType == VIEWTYPE_HEADER) {
|
||||||
|
final HeaderViewHolder vh = (HeaderViewHolder) holder;
|
||||||
|
ImageLoader.getInstance().displayImage(mApp.iconUrlLarge, vh.iconView, vh.displayImageOptions);
|
||||||
|
vh.titleView.setText(mApp.name);
|
||||||
|
if (!TextUtils.isEmpty(mApp.author)) {
|
||||||
|
vh.authorView.setText(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(AppDetails2.SafeLinkMovementMethod.getInstance(mContext));
|
||||||
|
vh.descriptionView.setText(trimNewlines(desc));
|
||||||
|
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(mApp.isInstalled() ? View.VISIBLE : View.INVISIBLE);
|
||||||
|
vh.buttonPrimaryView.setText(R.string.menu_install);
|
||||||
|
vh.buttonPrimaryView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
/* if (appDetails.activeDownloadUrlString != null) {
|
||||||
|
btMain.setText(R.string.downloading);
|
||||||
|
btMain.setEnabled(false);
|
||||||
|
} else if (!app.isInstalled() && app.suggestedVersionCode > 0 &&
|
||||||
|
appDetails.adapter.getCount() > 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);
|
||||||
|
NfcHelper.disableAndroidBeam(appDetails);
|
||||||
|
// Set Install button and hide second button
|
||||||
|
btMain.setText(R.string.menu_install);
|
||||||
|
btMain.setOnClickListener(mOnClickListener);
|
||||||
|
btMain.setEnabled(true);
|
||||||
|
} else if (app.isInstalled()) {
|
||||||
|
// If App is installed
|
||||||
|
installed = true;
|
||||||
|
statusView.setText(getString(R.string.details_installed, app.installedVersionName));
|
||||||
|
NfcHelper.setAndroidBeam(appDetails, app.packageName);
|
||||||
|
if (app.canAndWantToUpdate(appDetails)) {
|
||||||
|
updateWanted = true;
|
||||||
|
btMain.setText(R.string.menu_upgrade);
|
||||||
|
} else {
|
||||||
|
updateWanted = false;
|
||||||
|
if (appDetails.packageManager.getLaunchIntentForPackage(app.packageName) != null) {
|
||||||
|
btMain.setText(R.string.menu_launch);
|
||||||
|
} else {
|
||||||
|
btMain.setText(R.string.menu_uninstall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
btMain.setOnClickListener(mOnClickListener);
|
||||||
|
btMain.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(mApp);
|
||||||
|
vh.recyclerView.setAdapter(adapter);
|
||||||
|
vh.recyclerView.setHasFixedSize(true);
|
||||||
|
vh.recyclerView.setNestedScrollingEnabled(false);
|
||||||
|
LinearLayoutManagerSnapHelper helper = new LinearLayoutManagerSnapHelper(lm);
|
||||||
|
helper.setLinearSnapHelperListener(adapter);
|
||||||
|
helper.attachToRecyclerView(vh.recyclerView);
|
||||||
|
} else if (viewType == VIEWTYPE_WHATS_NEW) {
|
||||||
|
WhatsNewViewHolder vh = (WhatsNewViewHolder) holder;
|
||||||
|
vh.textView.setText("WHATS NEW GOES HERE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mItems.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return 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 Button buttonPrimaryView;
|
||||||
|
final Button buttonSecondaryView;
|
||||||
|
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);
|
||||||
|
buttonPrimaryView = (Button) view.findViewById(R.id.primaryButtonView);
|
||||||
|
buttonSecondaryView = (Button) view.findViewById(R.id.secondaryButtonView);
|
||||||
|
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 view = lm.findViewByPosition(pos);
|
||||||
|
if (view != null)
|
||||||
|
posOffset = lm.getDecoratedTop(view);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " '" + titleView.getText() + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScreenShotsViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
final RecyclerView recyclerView;
|
||||||
|
|
||||||
|
ScreenShotsViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
recyclerView = (RecyclerView) view.findViewById(R.id.screenshots);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " screenshots";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WhatsNewViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
final TextView textView;
|
||||||
|
|
||||||
|
WhatsNewViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
textView = (TextView) view.findViewById(R.id.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " " + textView.getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScreenShotsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements LinearLayoutManagerSnapHelper.LinearSnapHelperListener {
|
||||||
|
private final App app;
|
||||||
|
private final DisplayImageOptions displayImageOptions;
|
||||||
|
private View selectedView;
|
||||||
|
private int selectedPosition;
|
||||||
|
private int selectedItemElevation;
|
||||||
|
private int unselectedItemMargin;
|
||||||
|
|
||||||
|
public ScreenShotsRecyclerViewAdapter(App app) {
|
||||||
|
super();
|
||||||
|
this.app = app;
|
||||||
|
selectedPosition = 0;
|
||||||
|
selectedItemElevation = getResources().getDimensionPixelSize(R.dimen.details_screenshot_selected_elevation);
|
||||||
|
unselectedItemMargin = getResources().getDimensionPixelSize(R.dimen.details_screenshot_margin);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||||
|
ScreenShotViewHolder vh = (ScreenShotViewHolder) holder;
|
||||||
|
setViewSelected(vh.itemView, position == selectedPosition);
|
||||||
|
if (position == selectedPosition)
|
||||||
|
this.selectedView = vh.itemView;
|
||||||
|
ImageLoader.getInstance().displayImage(mApp.iconUrlLarge, vh.image, displayImageOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.app_details2_screenshot_item, parent, false);
|
||||||
|
return new ScreenShotViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSnappedToView(View view, int snappedPosition) {
|
||||||
|
setViewSelected(selectedView, false);
|
||||||
|
selectedView = view;
|
||||||
|
selectedPosition = snappedPosition;
|
||||||
|
setViewSelected(selectedView, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setViewSelected(View view, boolean selected) {
|
||||||
|
if (view != null) {
|
||||||
|
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)view.getLayoutParams();
|
||||||
|
if (selected)
|
||||||
|
lp.setMargins(0,selectedItemElevation,0,selectedItemElevation);
|
||||||
|
else
|
||||||
|
lp.setMargins(0,unselectedItemMargin,0,unselectedItemMargin);
|
||||||
|
ViewCompat.setElevation(view, selected ? selectedItemElevation : 0);
|
||||||
|
view.setLayoutParams(lp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScreenShotViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
final ImageView image;
|
||||||
|
|
||||||
|
ScreenShotViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
image = (ImageView) view.findViewById(R.id.image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " screenshot";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class SafeLinkMovementMethod extends LinkMovementMethod {
|
||||||
|
|
||||||
|
private static AppDetails2.SafeLinkMovementMethod instance;
|
||||||
|
|
||||||
|
private final Context ctx;
|
||||||
|
|
||||||
|
private SafeLinkMovementMethod(Context ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AppDetails2.SafeLinkMovementMethod getInstance(Context ctx) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new AppDetails2.SafeLinkMovementMethod(ctx);
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CharSequence getLink(TextView widget, Spannable buffer,
|
||||||
|
MotionEvent event) {
|
||||||
|
int x = (int) event.getX();
|
||||||
|
int y = (int) event.getY();
|
||||||
|
x -= widget.getTotalPaddingLeft();
|
||||||
|
y -= widget.getTotalPaddingTop();
|
||||||
|
x += widget.getScrollX();
|
||||||
|
y += widget.getScrollY();
|
||||||
|
|
||||||
|
Layout layout = widget.getLayout();
|
||||||
|
final int line = layout.getLineForVertical(y);
|
||||||
|
final int off = layout.getOffsetForHorizontal(line, x);
|
||||||
|
final ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);
|
||||||
|
|
||||||
|
if (links.length > 0) {
|
||||||
|
final ClickableSpan link = links[0];
|
||||||
|
final Spanned s = (Spanned) widget.getText();
|
||||||
|
return s.subSequence(s.getSpanStart(link), s.getSpanEnd(link));
|
||||||
|
}
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer,
|
||||||
|
@NonNull MotionEvent event) {
|
||||||
|
try {
|
||||||
|
return super.onTouchEvent(widget, buffer, event);
|
||||||
|
} catch (ActivityNotFoundException ex) {
|
||||||
|
Selection.removeSelection(buffer);
|
||||||
|
final CharSequence link = getLink(widget, buffer, event);
|
||||||
|
Toast.makeText(ctx,
|
||||||
|
ctx.getString(R.string.no_handler_app, link),
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@ package org.fdroid.fdroid;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -31,6 +32,7 @@ import android.text.Html;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||||
@ -596,4 +598,9 @@ public final class Utils {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int dpToPx(int dp, Context ctx)
|
||||||
|
{
|
||||||
|
Resources r = ctx.getResources();
|
||||||
|
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
package org.fdroid.fdroid.views;
|
||||||
|
|
||||||
|
import android.support.v4.view.ViewCompat;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.LinearSnapHelper;
|
||||||
|
import android.support.v7.widget.OrientationHelper;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
||||||
|
|
||||||
|
public class LinearLayoutManagerSnapHelper extends LinearSnapHelper {
|
||||||
|
|
||||||
|
public interface LinearSnapHelperListener {
|
||||||
|
/**
|
||||||
|
* Tells the listener that we have selected a view to snap to.
|
||||||
|
* @param view The selected view (may be null)
|
||||||
|
* @param position Adapter position of the snapped to view (or NO_POSITION if none)
|
||||||
|
*/
|
||||||
|
void onSnappedToView(View view, int position);
|
||||||
|
};
|
||||||
|
|
||||||
|
private LinearLayoutManager mLlm;
|
||||||
|
private OrientationHelper mOrientationHelper;
|
||||||
|
private LinearSnapHelperListener mListener;
|
||||||
|
|
||||||
|
public LinearLayoutManagerSnapHelper(LinearLayoutManager llm) {
|
||||||
|
this.mLlm = llm;
|
||||||
|
this.mOrientationHelper = OrientationHelper.createHorizontalHelper(mLlm);
|
||||||
|
};
|
||||||
|
|
||||||
|
public void setLinearSnapHelperListener(LinearSnapHelperListener listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View findSnapView(RecyclerView.LayoutManager layoutManager) {
|
||||||
|
View snappedView = super.findSnapView(layoutManager);
|
||||||
|
if (layoutManager.canScrollHorizontally()) {
|
||||||
|
if (layoutManager instanceof LinearLayoutManager) {
|
||||||
|
int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
|
||||||
|
int lastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
|
||||||
|
if (firstChild == 0) {
|
||||||
|
View child = layoutManager.findViewByPosition(firstChild);
|
||||||
|
if (mOrientationHelper.getDecoratedEnd(child) >= mOrientationHelper.getDecoratedMeasurement(child) / 2
|
||||||
|
&& mOrientationHelper.getDecoratedEnd(child) > 0) {
|
||||||
|
int dist1 = super.calculateDistanceToFinalSnap(layoutManager, snappedView)[0];
|
||||||
|
int dist2 = mOrientationHelper.getDecoratedStart(child);
|
||||||
|
if (Math.abs(dist1) > Math.abs(dist2)) {
|
||||||
|
snappedView = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (lastChild == (mLlm.getItemCount() - 1)) {
|
||||||
|
View child = layoutManager.findViewByPosition(lastChild);
|
||||||
|
if (mOrientationHelper.getDecoratedStart(child) < mOrientationHelper.getTotalSpace() - mOrientationHelper.getDecoratedMeasurement(child) / 2
|
||||||
|
&& mOrientationHelper.getDecoratedStart(child) < mOrientationHelper.getTotalSpace()) {
|
||||||
|
int dist1 = super.calculateDistanceToFinalSnap(layoutManager, snappedView)[0];
|
||||||
|
int dist2 = mOrientationHelper.getTotalSpace() - mOrientationHelper.getDecoratedEnd(child);
|
||||||
|
if (Math.abs(dist1) > Math.abs(dist2)) {
|
||||||
|
snappedView = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mListener != null) {
|
||||||
|
int snappedPosition = 0;
|
||||||
|
if (snappedView != null)
|
||||||
|
snappedPosition = mLlm.getPosition(snappedView);
|
||||||
|
mListener.onSnappedToView(snappedView, snappedPosition);
|
||||||
|
}
|
||||||
|
return snappedView;
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.fdroid.fdroid.AppDetails;
|
import org.fdroid.fdroid.AppDetails;
|
||||||
|
import org.fdroid.fdroid.AppDetails2;
|
||||||
import org.fdroid.fdroid.Preferences;
|
import org.fdroid.fdroid.Preferences;
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.UpdateService;
|
import org.fdroid.fdroid.UpdateService;
|
||||||
@ -30,6 +31,7 @@ import org.fdroid.fdroid.views.AppListAdapter;
|
|||||||
|
|
||||||
public abstract class AppListFragment extends ListFragment implements
|
public abstract class AppListFragment extends ListFragment implements
|
||||||
AdapterView.OnItemClickListener,
|
AdapterView.OnItemClickListener,
|
||||||
|
AdapterView.OnItemLongClickListener,
|
||||||
Preferences.ChangeListener,
|
Preferences.ChangeListener,
|
||||||
LoaderManager.LoaderCallbacks<Cursor> {
|
LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
|
|
||||||
@ -109,6 +111,7 @@ public abstract class AppListFragment extends ListFragment implements
|
|||||||
// returns the list view is "called between onCreate and
|
// returns the list view is "called between onCreate and
|
||||||
// onActivityCreated" according to the docs.
|
// onActivityCreated" according to the docs.
|
||||||
getListView().setOnItemClickListener(this);
|
getListView().setOnItemClickListener(this);
|
||||||
|
getListView().setOnItemLongClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -155,11 +158,21 @@ public abstract class AppListFragment extends ListFragment implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
showItemDetails(view, position, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
showItemDetails(view, position, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showItemDetails(View view, int position, boolean useNewDetailsActivity) {
|
||||||
// Cursor is null in the swap list when touching the first item.
|
// Cursor is null in the swap list when touching the first item.
|
||||||
Cursor cursor = (Cursor) getListView().getItemAtPosition(position);
|
Cursor cursor = (Cursor) getListView().getItemAtPosition(position);
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
final App app = new App(cursor);
|
final App app = new App(cursor);
|
||||||
Intent intent = getAppDetailsIntent();
|
Intent intent = getAppDetailsIntent(useNewDetailsActivity);
|
||||||
intent.putExtra(AppDetails.EXTRA_APPID, app.packageName);
|
intent.putExtra(AppDetails.EXTRA_APPID, app.packageName);
|
||||||
intent.putExtra(AppDetails.EXTRA_FROM, getFromTitle());
|
intent.putExtra(AppDetails.EXTRA_FROM, getFromTitle());
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
@ -176,8 +189,8 @@ public abstract class AppListFragment extends ListFragment implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent getAppDetailsIntent() {
|
private Intent getAppDetailsIntent(boolean useNewDetailsActivity) {
|
||||||
return new Intent(getActivity(), AppDetails.class);
|
return new Intent(getActivity(), useNewDetailsActivity ? AppDetails2.class : AppDetails.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
BIN
app/src/main/res/drawable-mdpi/feature_placeholder.png
Normal file
BIN
app/src/main/res/drawable-mdpi/feature_placeholder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 346 KiB |
@ -0,0 +1,27 @@
|
|||||||
|
<?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="3dp" />
|
||||||
|
<solid android:color="@color/fdroid_blue_dark" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:state_checked="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="3dp" />
|
||||||
|
<solid android:color="@color/fdroid_blue_dark" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:state_enabled="false">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="3dp" />
|
||||||
|
<solid android:color="@color/fdroid_blue_dark" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="3dp" />
|
||||||
|
<solid android:color="@color/fdroid_blue" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
@ -0,0 +1,28 @@
|
|||||||
|
<?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="3dp" />
|
||||||
|
<solid android:color="@color/fdroid_blue" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:state_checked="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="3dp" />
|
||||||
|
<solid android:color="@color/fdroid_blue" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:state_enabled="false">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="3dp" />
|
||||||
|
<solid android:color="@color/fdroid_blue" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="3dp" />
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
<stroke android:color="@color/fdroid_blue" android:width="2dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
46
app/src/main/res/layout/activity_app_details2.xml
Normal file
46
app/src/main/res/layout/activity_app_details2.xml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.design.widget.CoordinatorLayout 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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
tools:context="org.fdroid.fdroid.AppDetails2">
|
||||||
|
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:id="@+id/app_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/app_bar_height"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:theme="@style/AppThemeLight.AppBarOverlay">
|
||||||
|
|
||||||
|
<android.support.design.widget.CollapsingToolbarLayout
|
||||||
|
android:id="@+id/toolbar_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
app:contentScrim="?attr/colorPrimary"
|
||||||
|
app:layout_scrollFlags="scroll|exitUntilCollapsed">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/backdrop"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:src="@drawable/feature_placeholder"
|
||||||
|
app:layout_collapseMode="parallax" />
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:layout_collapseMode="pin"
|
||||||
|
app:popupTheme="@style/AppThemeLight.PopupOverlay" />
|
||||||
|
|
||||||
|
</android.support.design.widget.CollapsingToolbarLayout>
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
|
<include layout="@layout/content_app_details2" />
|
||||||
|
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
125
app/src/main/res/layout/app_details2_header.xml
Executable file
125
app/src/main/res/layout/app_details2_header.xml
Executable file
@ -0,0 +1,125 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<android.support.v7.widget.CardView 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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
app:cardBackgroundColor="#efefef"
|
||||||
|
app:cardCornerRadius="3dp"
|
||||||
|
app:cardElevation="3dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
|
>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="72dp"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
android:paddingRight="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:src="@drawable/ic_repo_app_default" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_toEndOf="@id/icon"
|
||||||
|
android:layout_toRightOf="@id/icon"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||||
|
tools:text="App Title" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/author"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignEnd="@id/title"
|
||||||
|
android:layout_alignLeft="@id/title"
|
||||||
|
android:layout_alignRight="@id/title"
|
||||||
|
android:layout_alignStart="@id/title"
|
||||||
|
android:layout_below="@id/title"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="Author" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/icon"
|
||||||
|
android:layout_toEndOf="@id/icon"
|
||||||
|
android:layout_toRightOf="@id/icon"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/secondaryButtonView"
|
||||||
|
style="@style/DetailsSecondaryButtonStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:text="THIS IS BUTTON 1" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/primaryButtonView"
|
||||||
|
style="@style/DetailsPrimaryButtonStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:text="THIS IS 2" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/summary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="This app is awezome"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:textStyle="bold"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="This is the app description of this awezome app. It can be several lines long, but will be truncated at just a few if it is. A 'read more' button will appear so that you can expand the view and view the full text, if you wish. Yes, it will be blue and beautiful."
|
||||||
|
android:scrollbars="none"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description_more"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
style="@style/DetailsMoreButtonStyle"
|
||||||
|
android:gravity="right|end"
|
||||||
|
android:text="@string/more"
|
||||||
|
tools:text="more" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</android.support.v7.widget.CardView>
|
19
app/src/main/res/layout/app_details2_screenshot_item.xml
Normal file
19
app/src/main/res/layout/app_details2_screenshot_item.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
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:scaleType="fitCenter"
|
||||||
|
/>
|
||||||
|
</android.support.v7.widget.CardView>
|
7
app/src/main/res/layout/app_details2_screenshots.xml
Normal file
7
app/src/main/res/layout/app_details2_screenshots.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/screenshots"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="150dp">
|
||||||
|
</android.support.v7.widget.RecyclerView>
|
8
app/src/main/res/layout/app_details2_whatsnew.xml
Executable file
8
app/src/main/res/layout/app_details2_whatsnew.xml
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
/>
|
14
app/src/main/res/layout/content_app_details2.xml
Normal file
14
app/src/main/res/layout/content_app_details2.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
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"
|
||||||
|
android:id="@+id/rvDetails"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
app:behavior_overlapTop="40dp"
|
||||||
|
app:layoutManager="LinearLayoutManager"
|
||||||
|
tools:context="org.fdroid.fdroid.AppDetails2"
|
||||||
|
tools:showIn="@layout/activity_app_details2">
|
||||||
|
</android.support.v7.widget.RecyclerView>
|
@ -18,4 +18,11 @@
|
|||||||
<item name="android:colorButtonNormal">#04b9e6</item>
|
<item name="android:colorButtonNormal">#04b9e6</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="AppThemeLight.NoActionBar">
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||||
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -3,5 +3,10 @@
|
|||||||
|
|
||||||
<dimen name="layout_horizontal_margin">16dp</dimen>
|
<dimen name="layout_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="material_listitem_height">48dp</dimen>
|
<dimen name="material_listitem_height">48dp</dimen>
|
||||||
|
<dimen name="app_bar_height">180dp</dimen>
|
||||||
|
<!-- "Not selected" items are inset by this value, while the selected one is not -->
|
||||||
|
<dimen name="details_screenshot_margin">16dp</dimen>
|
||||||
|
<!-- The selected item stands out from the background by this elevation -->
|
||||||
|
<dimen name="details_screenshot_selected_elevation">3dp</dimen>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -246,4 +246,13 @@
|
|||||||
<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" />
|
||||||
|
|
||||||
|
<style name="AppThemeLight.NoActionBar">
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppThemeLight.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||||
|
|
||||||
|
<style name="AppThemeLight.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||||
</resources>
|
</resources>
|
||||||
|
26
app/src/main/res/values/styles_detail.xml
Normal file
26
app/src/main/res/values/styles_detail.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="DetailsPrimaryButtonStyle">
|
||||||
|
<item name="android:padding">5dp</item>
|
||||||
|
<item name="android:textSize">12sp</item>
|
||||||
|
<item name="android:textStyle">normal</item>
|
||||||
|
<item name="android:textColor">#ffffff</item>
|
||||||
|
<item name="android:background">@drawable/button_primary_background_selector</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="DetailsSecondaryButtonStyle">
|
||||||
|
<item name="android:padding">5dp</item>
|
||||||
|
<item name="android:textSize">12sp</item>
|
||||||
|
<item name="android:textStyle">normal</item>
|
||||||
|
<item name="android:textColor">@color/fdroid_blue</item>
|
||||||
|
<item name="android:background">@drawable/button_secondary_background_selector</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="DetailsMoreButtonStyle">
|
||||||
|
<item name="android:padding">5dp</item>
|
||||||
|
<item name="android:textSize">15sp</item>
|
||||||
|
<item name="android:textStyle">normal</item>
|
||||||
|
<item name="android:textColor">@color/fdroid_blue</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user