mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1293790 - Implement Paged TopSites View r=sebastian
This uses a ViewPager, with each page containing a grid managed by a separate RecyclerView. One main adapter splits the data into appropriately sized groups for each RecyclerView to handle. MozReview-Commit-ID: 9XGuw0NckD4 --HG-- rename : mobile/android/base/resources/layout/activity_stream_card_top_sites_item.xml => mobile/android/base/resources/layout/activity_stream_topsites_card.xml extra : rebase_source : cc6ad23ae223b01ab59071d986ab4ad2d41c929c
This commit is contained in:
parent
8de90ea489
commit
aab7c8b4f0
@ -22,10 +22,14 @@ import org.mozilla.gecko.home.HomeBanner;
|
||||
import org.mozilla.gecko.home.HomeFragment;
|
||||
import org.mozilla.gecko.home.HomeScreen;
|
||||
import org.mozilla.gecko.home.SimpleCursorLoader;
|
||||
import org.mozilla.gecko.home.activitystream.topsites.TopSitesPagerAdapter;
|
||||
|
||||
public class ActivityStream extends FrameLayout implements HomeScreen {
|
||||
private StreamRecyclerAdapter adapter;
|
||||
|
||||
private static final int LOADER_ID_HIGHLIGHTS = 0;
|
||||
private static final int LOADER_ID_TOPSITES = 1;
|
||||
|
||||
public ActivityStream(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
@ -71,16 +75,22 @@ public class ActivityStream extends FrameLayout implements HomeScreen {
|
||||
// Signal to load data from storage as needed, compare with HomePager
|
||||
RecyclerView rv = (RecyclerView) findViewById(R.id.activity_stream_main_recyclerview);
|
||||
|
||||
adapter = new StreamRecyclerAdapter();
|
||||
// TODO: we need to retrieve BrowserApp and pass it in as onUrlOpenListener. That will
|
||||
// be simpler once we're a HomeFragment, but isn't so simple while we're still a View.
|
||||
adapter = new StreamRecyclerAdapter(lm, null);
|
||||
rv.setAdapter(adapter);
|
||||
rv.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
rv.setHasFixedSize(true);
|
||||
|
||||
lm.initLoader(0, null, new CursorLoaderCallbacks());
|
||||
CursorLoaderCallbacks callbacks = new CursorLoaderCallbacks();
|
||||
lm.initLoader(LOADER_ID_HIGHLIGHTS, null, callbacks);
|
||||
lm.initLoader(LOADER_ID_TOPSITES, null, callbacks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
adapter.swapHighlightsCursor(null);
|
||||
adapter.swapTopSitesCursor(null);
|
||||
// Signal to clear data that has been loaded, compare with HomePager
|
||||
}
|
||||
|
||||
@ -105,17 +115,32 @@ public class ActivityStream extends FrameLayout implements HomeScreen {
|
||||
private class CursorLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
return new HistoryLoader(getContext());
|
||||
if (id == LOADER_ID_HIGHLIGHTS) {
|
||||
return new HistoryLoader(getContext());
|
||||
} else if (id == LOADER_ID_TOPSITES) {
|
||||
return GeckoProfile.get(getContext()).getDB().getActivityStreamTopSites(getContext(),
|
||||
TopSitesPagerAdapter.TOTAL_ITEMS);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't handle loader id " + id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
adapter.swapCursor(data);
|
||||
if (loader.getId() == LOADER_ID_HIGHLIGHTS) {
|
||||
adapter.swapHighlightsCursor(data);
|
||||
} else if (loader.getId() == LOADER_ID_TOPSITES) {
|
||||
adapter.swapTopSitesCursor(data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
adapter.swapCursor(null);
|
||||
if (loader.getId() == LOADER_ID_HIGHLIGHTS) {
|
||||
adapter.swapHighlightsCursor(null);
|
||||
} else if (loader.getId() == LOADER_ID_TOPSITES) {
|
||||
adapter.swapTopSitesCursor(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package org.mozilla.gecko.home.activitystream;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.View;
|
||||
@ -13,6 +14,8 @@ import android.widget.TextView;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.home.HomePager;
|
||||
import org.mozilla.gecko.home.activitystream.topsites.TopSitesPagerAdapter;
|
||||
|
||||
public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||
public StreamItem(View itemView) {
|
||||
@ -25,9 +28,18 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||
|
||||
public static class TopPanel extends StreamItem {
|
||||
public static final int LAYOUT_ID = R.layout.activity_stream_main_toppanel;
|
||||
private final ViewPager topSitesPager;
|
||||
|
||||
public TopPanel(View itemView) {
|
||||
public TopPanel(View itemView, HomePager.OnUrlOpenListener onUrlOpenListener) {
|
||||
super(itemView);
|
||||
|
||||
topSitesPager = (ViewPager) itemView.findViewById(R.id.topsites_pager);
|
||||
topSitesPager.setAdapter(new TopSitesPagerAdapter(itemView.getContext(), onUrlOpenListener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(Cursor cursor) {
|
||||
((TopSitesPagerAdapter) topSitesPager.getAdapter()).swapCursor(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,17 +5,30 @@
|
||||
package org.mozilla.gecko.home.activitystream;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.mozilla.gecko.home.HomePager;
|
||||
import org.mozilla.gecko.home.activitystream.StreamItem.BottomPanel;
|
||||
import org.mozilla.gecko.home.activitystream.StreamItem.CompactItem;
|
||||
import org.mozilla.gecko.home.activitystream.StreamItem.HighlightItem;
|
||||
import org.mozilla.gecko.home.activitystream.StreamItem.TopPanel;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> {
|
||||
private Cursor highlightsCursor;
|
||||
private Cursor topSitesCursor;
|
||||
|
||||
private final WeakReference<LoaderManager> loaderManagerWeakReference;
|
||||
private final HomePager.OnUrlOpenListener onUrlOpenListener;
|
||||
|
||||
StreamRecyclerAdapter(LoaderManager lm, HomePager.OnUrlOpenListener onUrlOpenListener) {
|
||||
loaderManagerWeakReference = new WeakReference<>(lm);
|
||||
this.onUrlOpenListener = onUrlOpenListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
@ -38,7 +51,7 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> {
|
||||
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
|
||||
if (type == TopPanel.LAYOUT_ID) {
|
||||
return new TopPanel(inflater.inflate(type, parent, false));
|
||||
return new TopPanel(inflater.inflate(type, parent, false), onUrlOpenListener);
|
||||
} else if (type == BottomPanel.LAYOUT_ID) {
|
||||
return new BottomPanel(inflater.inflate(type, parent, false));
|
||||
} else if (type == CompactItem.LAYOUT_ID) {
|
||||
@ -71,6 +84,8 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> {
|
||||
|
||||
highlightsCursor.moveToPosition(cursorPosition);
|
||||
holder.bind(highlightsCursor);
|
||||
} else if (type == TopPanel.LAYOUT_ID) {
|
||||
holder.bind(topSitesCursor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,9 +101,15 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> {
|
||||
return 2 + highlightsCount;
|
||||
}
|
||||
|
||||
public void swapCursor(Cursor cursor) {
|
||||
public void swapHighlightsCursor(Cursor cursor) {
|
||||
highlightsCursor = cursor;
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void swapTopSitesCursor(Cursor cursor) {
|
||||
this.topSitesCursor = cursor;
|
||||
|
||||
notifyItemChanged(0);
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
package org.mozilla.gecko.home.activitystream;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
class TopSitesRecyclerAdapter extends RecyclerView.Adapter<TopSitesRecyclerAdapter.ViewHolder> {
|
||||
|
||||
private final Context context;
|
||||
private final String[] items = {
|
||||
"FastMail",
|
||||
"Firefox",
|
||||
"Mozilla",
|
||||
"Hacker News",
|
||||
"Github",
|
||||
"YouTube",
|
||||
"Google Maps"
|
||||
};
|
||||
|
||||
TopSitesRecyclerAdapter(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater
|
||||
.from(context)
|
||||
.inflate(R.layout.activity_stream_card_top_sites_item, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
holder.vLabel.setText(items[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView vLabel;
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
vLabel = (TextView) itemView.findViewById(R.id.card_row_label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mozilla.gecko.home.activitystream.topsites;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.support.v7.widget.CardView;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.favicons.Favicons;
|
||||
import org.mozilla.gecko.home.UpdateViewFaviconLoadedListener;
|
||||
import org.mozilla.gecko.widget.FaviconView;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
class TopSitesCard extends RecyclerView.ViewHolder {
|
||||
private final FaviconView faviconView;
|
||||
|
||||
private final TextView title;
|
||||
private final View menuButton;
|
||||
|
||||
private final UpdateViewFaviconLoadedListener mFaviconListener;
|
||||
|
||||
private String url;
|
||||
|
||||
private int mLoadFaviconJobId = Favicons.NOT_LOADING;
|
||||
|
||||
public TopSitesCard(CardView card) {
|
||||
super(card);
|
||||
|
||||
faviconView = (FaviconView) card.findViewById(R.id.favicon);
|
||||
|
||||
title = (TextView) card.findViewById(R.id.title);
|
||||
menuButton = card.findViewById(R.id.menu);
|
||||
|
||||
mFaviconListener = new UpdateViewFaviconLoadedListener(faviconView);
|
||||
}
|
||||
|
||||
void bind(Cursor cursor) {
|
||||
this.url = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
|
||||
|
||||
title.setText(cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.TITLE)));
|
||||
|
||||
Favicons.cancelFaviconLoad(mLoadFaviconJobId);
|
||||
|
||||
mLoadFaviconJobId = Favicons.getSizedFaviconForPageFromLocal(faviconView.getContext(), url, mFaviconListener);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mozilla.gecko.home.activitystream.topsites;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import org.mozilla.gecko.home.HomePager;
|
||||
import org.mozilla.gecko.widget.RecyclerViewClickSupport;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class TopSitesPage
|
||||
extends RecyclerView
|
||||
implements RecyclerViewClickSupport.OnItemClickListener {
|
||||
public TopSitesPage(Context context,
|
||||
@Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
setLayoutManager(new GridLayoutManager(context, TopSitesPagerAdapter.GRID_WIDTH));
|
||||
|
||||
RecyclerViewClickSupport.addTo(this)
|
||||
.setOnItemClickListener(this);
|
||||
}
|
||||
|
||||
private HomePager.OnUrlOpenListener onUrlOpenListener = null;
|
||||
|
||||
public TopSitesPageAdapter getAdapter() {
|
||||
return (TopSitesPageAdapter) super.getAdapter();
|
||||
}
|
||||
|
||||
public void setOnUrlOpenListener(HomePager.OnUrlOpenListener onUrlOpenListener) {
|
||||
this.onUrlOpenListener = onUrlOpenListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
|
||||
if (onUrlOpenListener != null) {
|
||||
final String url = getAdapter().getURLForPosition(position);
|
||||
|
||||
onUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(HomePager.OnUrlOpenListener.Flags.class));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mozilla.gecko.home.activitystream.topsites;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.CursorWrapper;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.v7.widget.CardView;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
|
||||
public class TopSitesPageAdapter extends RecyclerView.Adapter<TopSitesCard> {
|
||||
|
||||
/**
|
||||
* Cursor wrapper that handles the offsets and limits that we expect.
|
||||
* This allows most of our code to completely ignore the fact that we're only touching part
|
||||
* of the cursor.
|
||||
*/
|
||||
private static final class SubsetCursor extends CursorWrapper {
|
||||
private final int start;
|
||||
private final int count;
|
||||
|
||||
public SubsetCursor(Cursor cursor, int start, int maxCount) {
|
||||
super(cursor);
|
||||
|
||||
this.start = start;
|
||||
|
||||
if (start + maxCount < cursor.getCount()) {
|
||||
count = maxCount;
|
||||
} else {
|
||||
count = cursor.getCount() - start;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToPosition(int position) {
|
||||
return super.moveToPosition(position + start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
private Cursor cursor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cursor
|
||||
* @param startIndex The first item that this topsites group should show. This item, and the following
|
||||
* 3 items will be displayed by this adapter.
|
||||
*/
|
||||
public void swapCursor(Cursor cursor, int startIndex) {
|
||||
if (cursor != null) {
|
||||
if (startIndex >= cursor.getCount()) {
|
||||
throw new IllegalArgumentException("startIndex must be within Cursor range");
|
||||
}
|
||||
|
||||
this.cursor = new SubsetCursor(cursor, startIndex, TopSitesPagerAdapter.ITEMS_PER_PAGE);
|
||||
} else {
|
||||
this.cursor = null;
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(TopSitesCard holder, int position) {
|
||||
cursor.moveToPosition(position);
|
||||
holder.bind(cursor);
|
||||
}
|
||||
|
||||
public TopSitesPageAdapter() {
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopSitesCard onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
|
||||
final CardView card = (CardView) inflater.inflate(R.layout.activity_stream_topsites_card, parent, false);
|
||||
|
||||
return new TopSitesCard(card);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public String getURLForPosition(int position) {
|
||||
cursor.moveToPosition(position);
|
||||
|
||||
return cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (cursor != null) {
|
||||
return cursor.getCount();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public long getItemId(int position) {
|
||||
cursor.moveToPosition(position);
|
||||
|
||||
// The Combined View only contains pages that have been visited at least once, i.e. any
|
||||
// page in the TopSites query will contain a HISTORY_ID. _ID however will be 0 for all rows.
|
||||
return cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.HISTORY_ID));
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mozilla.gecko.home.activitystream.topsites;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.home.HomePager;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* The primary / top-level TopSites adapter: it handles the ViewPager, and also handles
|
||||
* all lower-level Adapters that populate the individual topsite items.
|
||||
*/
|
||||
public class TopSitesPagerAdapter extends PagerAdapter {
|
||||
// Note: because of RecyclerView limitations we need to also adjust the layout height when
|
||||
// GRID_HEIGHT is changed.
|
||||
public static final int GRID_HEIGHT = 1;
|
||||
public static final int GRID_WIDTH = 4;
|
||||
public static final int PAGES = 4;
|
||||
|
||||
public static final int ITEMS_PER_PAGE = GRID_HEIGHT * GRID_WIDTH;
|
||||
public static final int TOTAL_ITEMS = ITEMS_PER_PAGE * PAGES;
|
||||
|
||||
private LinkedList<TopSitesPage> pages = new LinkedList<>();
|
||||
|
||||
private final Context context;
|
||||
private final HomePager.OnUrlOpenListener onUrlOpenListener;
|
||||
|
||||
private int count = 0;
|
||||
|
||||
public TopSitesPagerAdapter(Context context, HomePager.OnUrlOpenListener onUrlOpenListener) {
|
||||
this.context = context;
|
||||
this.onUrlOpenListener = onUrlOpenListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
return view == object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
TopSitesPage page = pages.get(position);
|
||||
|
||||
container.addView(page);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
container.removeView((View) object);
|
||||
}
|
||||
|
||||
public void swapCursor(Cursor cursor) {
|
||||
final int oldPages = getCount();
|
||||
|
||||
// Divide while rounding up: 0 items = 0 pages, 1-ITEMS_PER_PAGE items = 1 page, etc.
|
||||
if (cursor != null) {
|
||||
count = (cursor.getCount() - 1) / ITEMS_PER_PAGE + 1;
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
final int pageDelta = count - oldPages;
|
||||
|
||||
if (pageDelta > 0) {
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
for (int i = 0; i < pageDelta; i++) {
|
||||
final TopSitesPage page = (TopSitesPage) inflater.inflate(R.layout.activity_stream_topsites_page, null, false);
|
||||
|
||||
page.setOnUrlOpenListener(onUrlOpenListener);
|
||||
page.setAdapter(new TopSitesPageAdapter());
|
||||
pages.add(page);
|
||||
}
|
||||
} else if (pageDelta < 0) {
|
||||
for (int i = 0; i > pageDelta; i--) {
|
||||
final TopSitesPage page = pages.getLast();
|
||||
|
||||
// Ensure the page doesn't use the old/invalid cursor anymore
|
||||
page.getAdapter().swapCursor(null, 0);
|
||||
|
||||
pages.removeLast();
|
||||
}
|
||||
} else {
|
||||
// do nothing: we will be updating all the pages below
|
||||
}
|
||||
|
||||
int startIndex = 0;
|
||||
for (TopSitesPage page : pages) {
|
||||
page.getAdapter().swapCursor(cursor, startIndex);
|
||||
startIndex += ITEMS_PER_PAGE;
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
@ -433,7 +433,10 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'home/activitystream/ActivityStream.java',
|
||||
'home/activitystream/StreamItem.java',
|
||||
'home/activitystream/StreamRecyclerAdapter.java',
|
||||
'home/activitystream/TopSitesRecyclerAdapter.java',
|
||||
'home/activitystream/topsites/TopSitesCard.java',
|
||||
'home/activitystream/topsites/TopSitesPage.java',
|
||||
'home/activitystream/topsites/TopSitesPageAdapter.java',
|
||||
'home/activitystream/topsites/TopSitesPagerAdapter.java',
|
||||
'home/BookmarkFolderView.java',
|
||||
'home/BookmarkScreenshotRow.java',
|
||||
'home/BookmarksListAdapter.java',
|
||||
|
@ -6,9 +6,6 @@
|
||||
android:background="#FAFAFA">
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/activity_stream_main_recyclerview"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
|
@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v7.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/disabled_grey"
|
||||
android:layout_height="70dp">
|
||||
|
||||
<ImageView
|
||||
android:src="@drawable/favicon_globe"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"/>
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/card_row_label"
|
||||
tools:text="Firefox"
|
||||
android:textSize="10sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</android.support.v7.widget.CardView>
|
@ -31,10 +31,10 @@
|
||||
tools:text="More"
|
||||
android:layout_alignBottom="@+id/title_topsites"/>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
<android.support.v4.view.ViewPager
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="115dp"
|
||||
android:id="@+id/android.support.v7.widget.RecyclerView"
|
||||
android:id="@+id/topsites_pager"
|
||||
android:layout_below="@+id/title_topsites"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"/>
|
||||
@ -45,7 +45,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:layout_below="@+id/android.support.v7.widget.RecyclerView"
|
||||
android:layout_below="@+id/topsites_pager"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@+id/more_highlights"
|
||||
|
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.mozilla.gecko.widget.FilledCardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="115dp"
|
||||
android:layout_margin="1dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.mozilla.gecko.widget.FaviconView
|
||||
android:id="@+id/favicon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@+id/title"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_gravity="center"
|
||||
tools:background="@drawable/favicon_globe"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:lines="1"
|
||||
android:padding="4dp"
|
||||
android:textColor="@android:color/black"
|
||||
tools:text="Lorem Ipsum here is a title"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/menu_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="right|top"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/menu"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"/>
|
||||
|
||||
</RelativeLayout>
|
||||
</org.mozilla.gecko.widget.FilledCardView>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.mozilla.gecko.home.activitystream.topsites.TopSitesPage xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
Loading…
Reference in New Issue
Block a user