Bug 1511946 - Hint about "Switch to tab" option for AwesomeScreen's stream items; r=JanH

The behaviour of switching to an already opened tab for an item in the stream
list was already in place, this patch just modifies the item's layout by
adding a text hint about this possibility - "Switch to tab", dynamically,
depending on if a tab is already opened or not in the current session.

Each stream item will implement `Tabs.OnTabsChangedListener` and check if the
changed Tab had stream's Url.
If so it will pass this event to the list's Adapter which will refresh the
stream item's layout.

Differential Revision: https://phabricator.services.mozilla.com/D18997

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Petru Lingurar 2019-02-18 11:03:48 +00:00
Родитель 7996faf31b
Коммит 60f4606fbe
3 изменённых файлов: 147 добавлений и 10 удалений

Просмотреть файл

@ -87,15 +87,14 @@
tools:text="Descriptive title of a page that is veeeeeeery long - maybe even too long?" />
<LinearLayout
android:id="@+id/page_source_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="@id/page_title"
android:layout_toEndOf="@id/icon_wrapper"
android:layout_toRightOf="@id/icon_wrapper"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/activity_stream_base_margin"
android:paddingEnd="@dimen/activity_stream_base_margin"
android:paddingLeft="@dimen/activity_stream_base_margin"
android:paddingRight="@dimen/activity_stream_base_margin"
@ -126,4 +125,34 @@
tools:text="Bookmarked" />
</LinearLayout>
<TextView
android:id="@+id/switch_tab_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/page_source_layout"
android:layout_toEndOf="@id/icon_wrapper"
android:layout_toRightOf="@id/icon_wrapper"
android:drawableStart="@drawable/ic_url_bar_tab"
android:drawableLeft="@drawable/ic_url_bar_tab"
android:paddingStart="6dp"
android:paddingLeft="6dp"
android:paddingEnd="0dp"
android:paddingRight="0dp"
android:text="@string/switch_to_tab"
android:textColor="@color/activity_stream_subtitle"
android:textSize="12sp"
tools:drawableLeft="@drawable/ic_url_bar_tab"
tools:drawableStart="@drawable/ic_url_bar_tab"
tools:text="@string/switch_to_tab" />
<!-- Empty bottom space added irrespective of "switch_tab_hint" or "page_source_layout"
being the bottom view. ("switch_tab_hint" can have visibility="gone") -->
<View
android:id="@+id/layout_bottom_margin"
android:layout_width="match_parent"
android:layout_height="@dimen/activity_stream_base_margin"
android:layout_alignParentBottom="true"
android:layout_below="@id/switch_tab_hint" />
</RelativeLayout>

Просмотреть файл

@ -148,12 +148,20 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamViewHolder
return new StreamTitleRow(inflater.inflate(StreamTitleRow.LAYOUT_ID, parent, false), R.string.activity_stream_topstories, R.string.activity_stream_link_more, LINK_MORE_POCKET, onUrlOpenListener);
} else if (type == RowItemType.TOP_STORIES_ITEM.getViewType() ||
type == RowItemType.HIGHLIGHT_ITEM.getViewType()) {
return new WebpageItemRow(inflater.inflate(WebpageItemRow.LAYOUT_ID, parent, false), new WebpageItemRow.OnMenuButtonClickListener() {
@Override
public void onMenuButtonClicked(final WebpageItemRow row, final int position) {
openContextMenuForWebpageItemRow(row, position, parent, ActivityStreamTelemetry.Contract.INTERACTION_MENU_BUTTON);
}
});
return new WebpageItemRow(inflater.inflate(WebpageItemRow.LAYOUT_ID, parent, false),
new WebpageItemRow.OnMenuButtonClickListener() {
@Override
public void onMenuButtonClicked(final WebpageItemRow row, final int position) {
openContextMenuForWebpageItemRow(
row, position, parent, ActivityStreamTelemetry.Contract.INTERACTION_MENU_BUTTON);
}
}, new WebpageItemRow.OnContentChangedListener() {
@Override
public void onContentChanged(int itemPosition) {
notifyItemChanged(itemPosition);
}
}
);
} else if (type == RowItemType.HIGHLIGHTS_TITLE.getViewType()) {
return new StreamTitleRow(inflater.inflate(StreamTitleRow.LAYOUT_ID, parent, false), R.string.activity_stream_highlights);
} else if (type == RowItemType.HIGHLIGHTS_EMPTY_STATE.getViewType()) {
@ -216,6 +224,24 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamViewHolder
}
}
@Override
public void onViewAttachedToWindow(StreamViewHolder holder) {
super.onViewAttachedToWindow(holder);
if (holder instanceof WebpageItemRow) {
((WebpageItemRow) holder).initResources();
}
}
@Override
public void onViewDetachedFromWindow(StreamViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if (holder instanceof WebpageItemRow) {
((WebpageItemRow) holder).doCleanup();
}
}
/**
* This sets a child view of the adapter visible or hidden.
*

Просмотреть файл

@ -7,6 +7,7 @@ package org.mozilla.gecko.activitystream.homepanel.stream;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import android.text.TextUtils;
import android.view.View;
@ -14,8 +15,11 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.activitystream.Utils;
import org.mozilla.gecko.activitystream.homepanel.model.WebpageRowModel;
import org.mozilla.gecko.reader.ReaderModeUtils;
import org.mozilla.gecko.util.DrawableUtil;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.TouchTargetUtil;
@ -27,13 +31,14 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.UUID;
public class WebpageItemRow extends StreamViewHolder {
public class WebpageItemRow extends StreamViewHolder implements Tabs.OnTabsChangedListener {
private static final String LOGTAG = "GeckoWebpageItemRow";
public static final int LAYOUT_ID = R.layout.activity_stream_webpage_item_row;
private static final double SIZE_RATIO = 0.75;
private WebpageRowModel webpageModel;
private OnContentChangedListener contentChangedListener;
private int position;
private final StreamOverridablePageIconLayout pageIconLayout;
@ -42,15 +47,21 @@ public class WebpageItemRow extends StreamViewHolder {
private final ImageView pageSourceIconView;
private final TextView pageSourceView;
private final ImageView menuButton;
private final TextView switchToTabHint;
public WebpageItemRow(final View itemView, final OnMenuButtonClickListener onMenuButtonClickListener) {
public WebpageItemRow(final View itemView,
final OnMenuButtonClickListener onMenuButtonClickListener,
final OnContentChangedListener contentChangedListener) {
super(itemView);
this.contentChangedListener = contentChangedListener;
pageTitleView = (TextView) itemView.findViewById(R.id.page_title);
pageIconLayout = (StreamOverridablePageIconLayout) itemView.findViewById(R.id.page_icon);
pageSourceView = (TextView) itemView.findViewById(R.id.page_source);
pageDomainView = (TextView) itemView.findViewById(R.id.page_domain);
pageSourceIconView = (ImageView) itemView.findViewById(R.id.page_source_icon);
switchToTabHint = (TextView) itemView.findViewById(R.id.switch_tab_hint);
menuButton = (ImageView) itemView.findViewById(R.id.menu);
menuButton.setImageDrawable(
@ -83,6 +94,17 @@ public class WebpageItemRow extends StreamViewHolder {
updateUiForSource(model.getSource());
updatePageDomain();
pageIconLayout.updateIcon(model.getUrl(), model.getImageUrl());
final boolean isTabOpenedForItem = isTabOpenedForItem();
switchToTabHint.setVisibility(isTabOpenedForItem ? View.VISIBLE : View.GONE);
}
public void initResources() {
Tabs.registerOnTabsChangedListener(this);
}
public void doCleanup() {
Tabs.unregisterOnTabsChangedListener(this);
}
public void updateUiForSource(Utils.HighlightSource source) {
@ -172,11 +194,71 @@ public class WebpageItemRow extends StreamViewHolder {
}
}
@Override
public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
final String itemUrl = webpageModel.getUrl();
if (itemUrl == null || tab == null) {
return;
}
// Only interested if a matching tab has been opened/closed/switched to a different page
final boolean validEvent = msg.equals(Tabs.TabEvents.ADDED) ||
msg.equals(Tabs.TabEvents.CLOSED) ||
msg.equals(Tabs.TabEvents.LOCATION_CHANGE);
if (!validEvent) {
return;
}
// Actually check for any tab change regarding any of the currently displayed stream URLs
//
// "data" is an empty String for ADDED/CLOSED, and contains the previous/old URL during
// LOCATION_CHANGE (the new URL is retrieved using tab.getURL()).
//
// Normalized tabUrl and data using "ReaderModeUtils.stripAboutReaderUrl"
// because they can be about:reader URLs if the current or old tab page was a reader view
final String tabUrl = ReaderModeUtils.stripAboutReaderUrl(tab.getURL());
final String previousTabUrl = ReaderModeUtils.stripAboutReaderUrl(data);
if (itemUrl.equals(tabUrl) || itemUrl.equals(previousTabUrl)) {
notifyListenerAboutContentChange();
}
}
public View getTabletContextMenuAnchor() {
return menuButton;
}
/**
* @return true if there is an opened tab for this item's {@link #webpageModel} Url.
*/
private boolean isTabOpenedForItem() {
Tab tab = Tabs.getInstance().getFirstTabForUrl(webpageModel.getUrl(), isCurrentTabInPrivateMode());
return tab != null;
}
/**
* @return true if this view is shown inside a private tab, independent of whether
* a private mode theme is applied via <code>setPrivateMode(true)</code>.
*/
private boolean isCurrentTabInPrivateMode() {
final Tab tab = Tabs.getInstance().getSelectedTab();
return tab != null && tab.isPrivate();
}
private void notifyListenerAboutContentChange() {
if (contentChangedListener != null) {
contentChangedListener.onContentChanged(getAdapterPosition());
}
}
public interface OnMenuButtonClickListener {
void onMenuButtonClicked(WebpageItemRow row, int position);
}
/**
* Informs upstream about changes regarding this row's content.
*/
public interface OnContentChangedListener {
void onContentChanged(int itemPosition);
}
}