blob: d7248a7d06a0b02d00072af1a5a0145aa457b604 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.features.tasks;
import static org.chromium.chrome.features.tasks.SingleTabViewProperties.CLICK_LISTENER;
import static org.chromium.chrome.features.tasks.SingleTabViewProperties.FAVICON;
import static org.chromium.chrome.features.tasks.SingleTabViewProperties.IS_VISIBLE;
import static org.chromium.chrome.features.tasks.SingleTabViewProperties.LATERAL_MARGIN;
import static org.chromium.chrome.features.tasks.SingleTabViewProperties.TITLE;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelUtils;
import org.chromium.chrome.browser.tasks.tab_management.TabListFaviconProvider;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.url.GURL;
/** Mediator of the single tab switcher in the new tab page on tablet. */
public class SingleTabSwitcherOnTabletMediator implements ConfigurationChangedObserver {
private final PropertyModel mPropertyModel;
private final TabListFaviconProvider mTabListFaviconProvider;
private final int mMarginDefaut;
private final int mMarginSmallPortrait;
private Resources mResources;
private ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
private Tab mMostRecentTab;
private boolean mInitialized;
private boolean mIsScrollableMvtEnabled;
SingleTabSwitcherOnTabletMediator(PropertyModel propertyModel, Resources resources,
ActivityLifecycleDispatcher activityLifecycleDispatcher,
TabModelSelector tabModelSelector, TabListFaviconProvider tabListFaviconProvider,
Tab mostRecentTab, boolean isMultiColumnFeedEnabled, boolean isScrollableMvtEnabled) {
mPropertyModel = propertyModel;
mResources = resources;
mTabListFaviconProvider = tabListFaviconProvider;
mMostRecentTab = mostRecentTab;
mIsScrollableMvtEnabled = isScrollableMvtEnabled;
if (isMultiColumnFeedEnabled) {
mActivityLifecycleDispatcher = activityLifecycleDispatcher;
mMarginDefaut = mResources.getDimensionPixelSize(
R.dimen.single_tab_card_lateral_margin_landscape_tablet);
mMarginSmallPortrait =
mResources.getDimensionPixelSize(R.dimen.tile_grid_layout_bleed) / 2
+ mResources.getDimensionPixelSize(
R.dimen.single_tab_card_lateral_margin_portrait_tablet);
if (mActivityLifecycleDispatcher != null) {
mActivityLifecycleDispatcher.register(this);
}
} else {
mMarginDefaut = 0;
mMarginSmallPortrait = 0;
}
mPropertyModel.set(CLICK_LISTENER, v -> {
TabModel currentTabModel = tabModelSelector.getModel(false);
TabModelUtils.setIndex(currentTabModel,
TabModelUtils.getTabIndexById(currentTabModel, mMostRecentTab.getId()), false);
});
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
// The margin doesn't change when 2 row MV tiles are shown.
if (mIsScrollableMvtEnabled) {
updateMargins(newConfig.orientation);
}
}
private void updateMargins(int orientation) {
int lateralMargin =
mIsScrollableMvtEnabled && orientation == Configuration.ORIENTATION_PORTRAIT
? mMarginSmallPortrait
: mMarginDefaut;
mPropertyModel.set(LATERAL_MARGIN, lateralMargin);
}
/**
* Set the visibility of the single tab card of the {@link NewTabPageLayout} on tablet.
* @param isVisible Whether the single tab card is visible.
*/
void setVisibility(boolean isVisible) {
if (isVisible == mPropertyModel.get(IS_VISIBLE)) return;
if (!isVisible || mMostRecentTab == null) {
mPropertyModel.set(IS_VISIBLE, false);
mMostRecentTab = null;
return;
}
if (!mInitialized) {
mInitialized = true;
updateTitle();
updateFavicon();
}
mPropertyModel.set(IS_VISIBLE, true);
if (mResources != null) {
updateMargins(mResources.getConfiguration().orientation);
}
}
boolean isVisible() {
return mPropertyModel.get(IS_VISIBLE);
}
/**
* Update the most recent tab to track in the single tab card.
* @param tabToTrack The tab to track as the most recent tab.
* @return Whether has a Tab to track. Returns false if the Tab to track is set as null.
*/
boolean setTab(Tab tabToTrack) {
if (tabToTrack != null && UrlUtilities.isNTPUrl(tabToTrack.getUrl())) {
tabToTrack = null;
}
if (mMostRecentTab == tabToTrack) return tabToTrack != null;
if (tabToTrack == null) {
mMostRecentTab = null;
mPropertyModel.set(TITLE, "");
mPropertyModel.set(FAVICON, mTabListFaviconProvider.getDefaultFaviconDrawable(false));
return false;
} else {
mMostRecentTab = tabToTrack;
updateTitle();
updateFavicon();
return true;
}
}
void destroy() {
if (mActivityLifecycleDispatcher != null) {
mActivityLifecycleDispatcher.unregister(this);
mActivityLifecycleDispatcher = null;
}
if (mResources != null) {
mResources = null;
}
if (mPropertyModel != null) {
mPropertyModel.set(CLICK_LISTENER, null);
}
}
/**
* Update the favicon of the single tab switcher.
*/
private void updateFavicon() {
assert mTabListFaviconProvider.isInitialized();
mTabListFaviconProvider.getFaviconDrawableForUrlAsync(mMostRecentTab.getUrl(), false,
(Drawable favicon) -> { mPropertyModel.set(FAVICON, favicon); });
}
/**
* Update the title of the single tab switcher.
*/
@VisibleForTesting
void updateTitle() {
if (mMostRecentTab.isLoading() && TextUtils.isEmpty(mMostRecentTab.getTitle())) {
TabObserver tabObserver = new EmptyTabObserver() {
@Override
public void onPageLoadFinished(Tab tab, GURL url) {
super.onPageLoadFinished(tab, url);
mPropertyModel.set(TITLE, tab.getTitle());
tab.removeObserver(this);
}
};
mMostRecentTab.addObserver(tabObserver);
} else {
mPropertyModel.set(TITLE, mMostRecentTab.getTitle());
}
}
@VisibleForTesting
boolean getInitialized() {
return mInitialized;
}
@VisibleForTesting
void setMostRecentTab(Tab mostRecentTab) {
mMostRecentTab = mostRecentTab;
}
int getMarginDefaultForTesting() {
return mMarginDefaut;
}
int getMarginSmallPortraitForTesting() {
return mMarginSmallPortrait;
}
}