356 lines
14 KiB
Java
356 lines
14 KiB
Java
package acr.browser.lightning.fragment;
|
|
|
|
import android.content.Context;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.ColorFilter;
|
|
import android.graphics.ColorMatrix;
|
|
import android.graphics.ColorMatrixColorFilter;
|
|
import android.graphics.Paint;
|
|
import android.graphics.PorterDuff;
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
import android.support.annotation.IdRes;
|
|
import android.support.annotation.NonNull;
|
|
import android.support.annotation.Nullable;
|
|
import android.support.v4.app.Fragment;
|
|
import android.support.v4.view.ViewCompat;
|
|
import android.support.v7.widget.LinearLayoutManager;
|
|
import android.support.v7.widget.RecyclerView;
|
|
import android.support.v7.widget.RecyclerView.LayoutManager;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.TextView;
|
|
|
|
import com.squareup.otto.Bus;
|
|
import com.squareup.otto.Subscribe;
|
|
|
|
import javax.inject.Inject;
|
|
|
|
import acr.browser.lightning.R;
|
|
import acr.browser.lightning.activity.TabsManager;
|
|
import acr.browser.lightning.app.BrowserApp;
|
|
import acr.browser.lightning.bus.BrowserEvents;
|
|
import acr.browser.lightning.bus.NavigationEvents;
|
|
import acr.browser.lightning.bus.TabEvents;
|
|
import acr.browser.lightning.controller.UIController;
|
|
import acr.browser.lightning.preference.PreferenceManager;
|
|
import acr.browser.lightning.utils.ThemeUtils;
|
|
import acr.browser.lightning.utils.Utils;
|
|
import acr.browser.lightning.view.LightningView;
|
|
|
|
/**
|
|
* A fragment that holds and manages the tabs and interaction with the tabs.
|
|
* It is reliant on the BrowserController in order to get the current UI state
|
|
* of the browser. It also uses the BrowserController to signal that the UI needs
|
|
* to change. This class contains the adapter used by both the drawer tabs and
|
|
* the desktop tabs. It delegates touch events for the tab UI appropriately.
|
|
*/
|
|
public class TabsFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
|
|
|
|
private static final String TAG = TabsFragment.class.getSimpleName();
|
|
|
|
/**
|
|
* Arguments boolean to tell the fragment it is displayed in the drawner or on the tab strip
|
|
* If true, the fragment is in the left drawner in the strip otherwise.
|
|
*/
|
|
public static final String VERTICAL_MODE = TAG + ".VERTICAL_MODE";
|
|
public static final String IS_INCOGNITO = TAG + ".IS_INCOGNITO";
|
|
|
|
private boolean mIsIncognito, mDarkTheme;
|
|
private int mIconColor;
|
|
private boolean mColorMode = true;
|
|
private boolean mShowInNavigationDrawer;
|
|
|
|
@Nullable private LightningViewAdapter mTabsAdapter;
|
|
private UIController mUiController;
|
|
|
|
@Inject TabsManager tabsManager;
|
|
@Inject Bus mBus;
|
|
@Inject PreferenceManager mPreferences;
|
|
|
|
public TabsFragment() {
|
|
BrowserApp.getAppComponent().inject(this);
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
final Bundle arguments = getArguments();
|
|
final Context context = getContext();
|
|
mUiController = (UIController) getActivity();
|
|
mIsIncognito = arguments.getBoolean(IS_INCOGNITO, false);
|
|
mShowInNavigationDrawer = arguments.getBoolean(VERTICAL_MODE, true);
|
|
mDarkTheme = mPreferences.getUseTheme() != 0 || mIsIncognito;
|
|
mColorMode = mPreferences.getColorModeEnabled();
|
|
mColorMode &= !mDarkTheme;
|
|
mIconColor = mDarkTheme ?
|
|
ThemeUtils.getIconDarkThemeColor(context) :
|
|
ThemeUtils.getIconLightThemeColor(context);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
final View view;
|
|
final LayoutManager layoutManager;
|
|
if (mShowInNavigationDrawer) {
|
|
view = inflater.inflate(R.layout.tab_drawer, container, false);
|
|
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
|
|
setupFrameLayoutButton(view, R.id.tab_header_button, R.id.plusIcon);
|
|
setupFrameLayoutButton(view, R.id.new_tab_button, R.id.icon_plus);
|
|
setupFrameLayoutButton(view, R.id.action_back, R.id.icon_back);
|
|
setupFrameLayoutButton(view, R.id.action_forward, R.id.icon_forward);
|
|
setupFrameLayoutButton(view, R.id.action_home, R.id.icon_home);
|
|
} else {
|
|
view = inflater.inflate(R.layout.tab_strip, container, false);
|
|
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
|
|
}
|
|
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.tabs_list);
|
|
recyclerView.setLayoutManager(layoutManager);
|
|
mTabsAdapter = new LightningViewAdapter(mShowInNavigationDrawer);
|
|
recyclerView.setAdapter(mTabsAdapter);
|
|
recyclerView.setHasFixedSize(true);
|
|
return view;
|
|
}
|
|
|
|
private void setupFrameLayoutButton(@NonNull final View root, @IdRes final int buttonId,
|
|
@IdRes final int imageId) {
|
|
final View frameButton = root.findViewById(buttonId);
|
|
final ImageView buttonImage = (ImageView) root.findViewById(imageId);
|
|
frameButton.setOnClickListener(this);
|
|
frameButton.setOnLongClickListener(this);
|
|
buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
|
|
}
|
|
|
|
@Override
|
|
public void onDestroyView() {
|
|
super.onDestroyView();
|
|
mTabsAdapter = null;
|
|
}
|
|
|
|
@Override
|
|
public void onStart() {
|
|
super.onStart();
|
|
mBus.register(this);
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
// Force adapter refresh
|
|
if (mTabsAdapter != null) {
|
|
mTabsAdapter.notifyDataSetChanged();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onStop() {
|
|
super.onStop();
|
|
mBus.unregister(this);
|
|
}
|
|
|
|
@Subscribe
|
|
public void tabsChanged(final BrowserEvents.TabsChanged event) {
|
|
if (mTabsAdapter != null) {
|
|
mTabsAdapter.notifyDataSetChanged();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onClick(@NonNull View v) {
|
|
switch (v.getId()) {
|
|
case R.id.new_tab_button:
|
|
mBus.post(new TabEvents.NewTab());
|
|
break;
|
|
case R.id.action_back:
|
|
mBus.post(new NavigationEvents.GoBack());
|
|
break;
|
|
case R.id.action_forward:
|
|
mBus.post(new NavigationEvents.GoForward());
|
|
break;
|
|
case R.id.action_home:
|
|
mBus.post(new NavigationEvents.GoHome());
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onLongClick(@NonNull View v) {
|
|
switch (v.getId()) {
|
|
case R.id.action_new_tab:
|
|
mBus.post(new TabEvents.NewTabLongPress());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public class LightningViewAdapter extends RecyclerView.Adapter<LightningViewAdapter.LightningViewHolder> {
|
|
|
|
private final int mLayoutResourceId;
|
|
@Nullable private final Drawable mBackgroundTabDrawable;
|
|
@Nullable private final Drawable mForegroundTabDrawable;
|
|
@Nullable private final Bitmap mForegroundTabBitmap;
|
|
private ColorMatrix mColorMatrix;
|
|
private Paint mPaint;
|
|
private ColorFilter mFilter;
|
|
private static final float DESATURATED = 0.5f;
|
|
|
|
private final boolean mDrawerTabs;
|
|
|
|
public LightningViewAdapter(final boolean vertical) {
|
|
this.mLayoutResourceId = vertical ? R.layout.tab_list_item : R.layout.tab_list_item_horizontal;
|
|
this.mDrawerTabs = vertical;
|
|
|
|
if (vertical) {
|
|
mBackgroundTabDrawable = null;
|
|
mForegroundTabBitmap = null;
|
|
mForegroundTabDrawable = ThemeUtils.getSelectedBackground(getContext(), mDarkTheme);
|
|
} else {
|
|
int backgroundColor = Utils.mixTwoColors(ThemeUtils.getPrimaryColor(getContext()), Color.BLACK, 0.75f);
|
|
Bitmap backgroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888);
|
|
Utils.drawTrapezoid(new Canvas(backgroundTabBitmap), backgroundColor, true);
|
|
mBackgroundTabDrawable = new BitmapDrawable(getResources(), backgroundTabBitmap);
|
|
|
|
int foregroundColor = ThemeUtils.getPrimaryColor(getContext());
|
|
mForegroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888);
|
|
Utils.drawTrapezoid(new Canvas(mForegroundTabBitmap), foregroundColor, false);
|
|
mForegroundTabDrawable = null;
|
|
}
|
|
}
|
|
|
|
@NonNull
|
|
@Override
|
|
public LightningViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
|
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
|
|
View view = inflater.inflate(mLayoutResourceId, viewGroup, false);
|
|
return new LightningViewHolder(view);
|
|
}
|
|
|
|
@Override
|
|
public void onBindViewHolder(@NonNull final LightningViewHolder holder, int position) {
|
|
holder.exitButton.setTag(position);
|
|
|
|
ViewCompat.jumpDrawablesToCurrentState(holder.exitButton);
|
|
|
|
LightningView web = tabsManager.getTabAtPosition(position);
|
|
if (web == null) {
|
|
return;
|
|
}
|
|
holder.txtTitle.setText(web.getTitle());
|
|
|
|
final Bitmap favicon = web.getFavicon();
|
|
if (web.isForegroundTab()) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
holder.txtTitle.setTextAppearance(R.style.boldText);
|
|
} else {
|
|
holder.txtTitle.setTextAppearance(getContext(), R.style.boldText);
|
|
}
|
|
Drawable foregroundDrawable;
|
|
if (!mDrawerTabs) {
|
|
foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap);
|
|
if (!mIsIncognito && mColorMode) {
|
|
foregroundDrawable.setColorFilter(mUiController.getUiColor(), PorterDuff.Mode.SRC_IN);
|
|
}
|
|
} else {
|
|
foregroundDrawable = mForegroundTabDrawable;
|
|
}
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
holder.layout.setBackground(foregroundDrawable);
|
|
} else {
|
|
holder.layout.setBackgroundDrawable(foregroundDrawable);
|
|
}
|
|
if (!mIsIncognito && mColorMode) {
|
|
mUiController.changeToolbarBackground(favicon, foregroundDrawable);
|
|
}
|
|
holder.favicon.setImageBitmap(favicon);
|
|
} else {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
holder.txtTitle.setTextAppearance(R.style.normalText);
|
|
} else {
|
|
holder.txtTitle.setTextAppearance(getContext(), R.style.normalText);
|
|
}
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
holder.layout.setBackground(mBackgroundTabDrawable);
|
|
} else {
|
|
holder.layout.setBackgroundDrawable(mBackgroundTabDrawable);
|
|
}
|
|
holder.favicon.setImageBitmap(getDesaturatedBitmap(favicon));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getItemCount() {
|
|
return tabsManager.size();
|
|
}
|
|
|
|
public Bitmap getDesaturatedBitmap(@NonNull Bitmap favicon) {
|
|
Bitmap grayscaleBitmap = Bitmap.createBitmap(favicon.getWidth(),
|
|
favicon.getHeight(), Bitmap.Config.ARGB_8888);
|
|
|
|
Canvas c = new Canvas(grayscaleBitmap);
|
|
if (mColorMatrix == null || mFilter == null || mPaint == null) {
|
|
mPaint = new Paint();
|
|
mColorMatrix = new ColorMatrix();
|
|
mColorMatrix.setSaturation(DESATURATED);
|
|
mFilter = new ColorMatrixColorFilter(mColorMatrix);
|
|
mPaint.setColorFilter(mFilter);
|
|
}
|
|
|
|
c.drawBitmap(favicon, 0, 0, mPaint);
|
|
return grayscaleBitmap;
|
|
}
|
|
|
|
public class LightningViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
|
|
|
public LightningViewHolder(@NonNull View view) {
|
|
super(view);
|
|
txtTitle = (TextView) view.findViewById(R.id.textTab);
|
|
favicon = (ImageView) view.findViewById(R.id.faviconTab);
|
|
exit = (ImageView) view.findViewById(R.id.deleteButton);
|
|
layout = (LinearLayout) view.findViewById(R.id.tab_item_background);
|
|
exitButton = (FrameLayout) view.findViewById(R.id.deleteAction);
|
|
exit.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
|
|
|
|
exitButton.setOnClickListener(this);
|
|
layout.setOnClickListener(this);
|
|
layout.setOnLongClickListener(this);
|
|
}
|
|
|
|
@NonNull final TextView txtTitle;
|
|
@NonNull final ImageView favicon;
|
|
@NonNull final ImageView exit;
|
|
@NonNull final FrameLayout exitButton;
|
|
@NonNull final LinearLayout layout;
|
|
|
|
@Override
|
|
public void onClick(View v) {
|
|
if (v == exitButton) {
|
|
// Close tab
|
|
mBus.post(new TabEvents.CloseTab(getAdapterPosition()));
|
|
}
|
|
if (v == layout) {
|
|
mBus.post(new TabEvents.ShowTab(getAdapterPosition()));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onLongClick(View v) {
|
|
// Show close dialog
|
|
mBus.post(new TabEvents.ShowCloseDialog(getAdapterPosition()));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|