From 51f783cea435f01dd5c3f597d857854a31a726b1 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Mon, 14 Sep 2015 17:58:21 +0200 Subject: [PATCH] TabsFragment extracted --- .../lightning/activity/BrowserActivity.java | 290 ++++-------------- .../lightning/activity/TabsManager.java | 26 +- .../browser/lightning/app/AppComponent.java | 3 + .../browser/lightning/bus/BrowserEvents.java | 6 + .../acr/browser/lightning/bus/TabEvents.java | 49 +++ .../lightning/fragment/TabsFragment.java | 281 +++++++++++++++++ app/src/main/res/layout/activity_main.xml | 7 +- app/src/main/res/layout/tab_drawer.xml | 6 +- app/src/main/res/layout/tab_strip.xml | 9 + app/src/main/res/layout/toolbar.xml | 7 +- 10 files changed, 447 insertions(+), 237 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/bus/TabEvents.java create mode 100644 app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java create mode 100644 app/src/main/res/layout/tab_strip.xml diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index dfee365..d235410 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -106,6 +106,7 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.bus.BrowserEvents; +import acr.browser.lightning.bus.TabEvents; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.HistoryPage; @@ -113,6 +114,7 @@ import acr.browser.lightning.controller.BrowserController; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.dialog.BookmarksDialogBuilder; +import acr.browser.lightning.fragment.TabsFragment; import acr.browser.lightning.object.ClickHandler; import acr.browser.lightning.object.SearchAdapter; import acr.browser.lightning.preference.PreferenceManager; @@ -132,7 +134,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private DrawerLayout mDrawerLayout; private FrameLayout mBrowserFrame; private FullscreenHolder mFullscreenContainer; - private RecyclerView mDrawerListLeft; private ViewGroup mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout; private RelativeLayout mSearchBar; @@ -144,7 +145,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private View mCustomView; // Adapter - private LightningViewAdapter mTabAdapter; private SearchAdapter mSearchAdapter; // Callback @@ -247,7 +247,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mUiLayout = (LinearLayout) findViewById(R.id.ui_layout); mProgressBar = (AnimatedProgressBar) findViewById(R.id.progress_view); setupFrameLayoutButton(R.id.new_tab_button, R.id.icon_plus); - mDrawerLeft = (LinearLayout) findViewById(R.id.left_drawer); + mDrawerLeft = (FrameLayout) findViewById(R.id.left_drawer); // Drawer stutters otherwise mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); @@ -267,29 +267,19 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mHomepage = mPreferences.getHomepage(); - RecyclerView horizontalListView = (RecyclerView) findViewById(R.id.twv_list); - - + final TabsFragment tabsFragment = new TabsFragment(); + final int containerId = mShowTabsInDrawer ? R.id.left_drawer : R.id.tabs_toolbar_container; + final Bundle arguments = new Bundle(); + arguments.putBoolean(TabsFragment.VERTICAL_MODE, mShowTabsInDrawer); + tabsFragment.setArguments(arguments); + getSupportFragmentManager() + .beginTransaction() + .add(containerId, tabsFragment) + .commit(); if (mShowTabsInDrawer) { - mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item, tabsManager.getTabsList()); - mDrawerListLeft = (RecyclerView) findViewById(R.id.left_drawer_list); - mDrawerListLeft.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); - mDrawerListLeft.setLayoutManager(layoutManager); - mDrawerListLeft.setHasFixedSize(true); - mToolbarLayout.removeView(horizontalListView); - } else { - mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item_horizontal, tabsManager.getTabsList()); - mDrawerListLeft = horizontalListView; - mDrawerListLeft.setOverScrollMode(View.OVER_SCROLL_NEVER); - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerLeft); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); - mDrawerListLeft.setLayoutManager(layoutManager); - mDrawerListLeft.setHasFixedSize(true); + mToolbarLayout.removeView(findViewById(R.id.tabs_toolbar_container)); } - mDrawerListLeft.setAdapter(mTabAdapter); - mHistoryDatabase = HistoryDatabase.getInstance(); if (actionBar == null) @@ -872,56 +862,29 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements builder.show(); } - /** - * The click listener for ListView in the navigation drawer - */ - private class DrawerItemClickListener implements OnClickListener { - - @Override - public void onClick(View v) { - final LightningView currentTab = tabsManager.getCurrentTab(); - final int position = mDrawerListLeft.getChildAdapterPosition(v); - final LightningView tab = tabsManager.getTabAtPosition(position); - if (tab != null && currentTab != tab) { - mIsNewIntent = false; - showTab(tab); - } - } - } - - /** - * long click listener for Navigation Drawer - */ - private class DrawerItemLongClickListener implements OnLongClickListener { - - @Override - public boolean onLongClick(View v) { - int position = mDrawerListLeft.getChildAdapterPosition(v); - showCloseDialog(position); - return true; - } - } - /** * displays the WebView contained in the LightningView Also handles the * removal of previous views * - * @param newView the LightningView to show + * @param position the poition of the tab to display */ - private synchronized void showTab(LightningView newView) { + private synchronized void showTab(final int position) { final LightningView currentView = tabsManager.getCurrentTab(); + final LightningView newView = tabsManager.switchToTab(position); + // Set the background color so the color mode color doesn't show through mBrowserFrame.setBackgroundColor(mBackgroundColor); - if (newView == null) { + if (newView == null || currentView == newView) { return; } + mIsNewIntent = false; + final float translation = mToolbarLayout.getTranslationY(); mBrowserFrame.removeAllViews(); if (currentView != null) { currentView.setForegroundTab(false); currentView.onPause(); } - tabsManager.setCurrentTab(newView); final WebView currentWebView = currentView.getWebView(); newView.setForegroundTab(true); if (currentWebView != null) { @@ -1047,15 +1010,17 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mIdGenerator++; if (show) { - showTab(startingTab); + showTab(tabsManager.size() - 1); } updateTabs(); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1); - } - }, 300); + +// TODO Restore this +// new Handler().postDelayed(new Runnable() { +// @Override +// public void run() { +// mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1); +// } +// }, 300); return true; } @@ -1082,14 +1047,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } if (current > position) { tabsManager.deleteTab(position); - showTab(tabsManager.getTabAtPosition(current - 1)); + showTab(current - 1); updateTabs(); tabToDelete.onDestroy(); } else if (tabsManager.size() > position + 1) { if (current == position) { - showTab(tabsManager.getTabAtPosition(position + 1)); + showTab(position + 1); tabsManager.deleteTab(position); - showTab(tabsManager.getTabAtPosition(position)); + showTab(position); updateTabs(); } else { tabsManager.deleteTab(position); @@ -1098,9 +1063,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements tabToDelete.onDestroy(); } else if (tabsManager.size() > 1) { if (current == position) { - showTab(tabsManager.getTabAtPosition(position - 1)); + showTab(position - 1); tabsManager.deleteTab(position); - showTab(tabsManager.getTabAtPosition(position - 1)); + showTab(position - 1); updateTabs(); } else { tabsManager.deleteTab(position); @@ -1115,11 +1080,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements performExitCleanUp(); tabToDelete.pauseTimers(); tabToDelete.onDestroy(); - mTabAdapter.notifyDataSetChanged(); + eventBus.post(new BrowserEvents.TabsChanged()); finish(); } } - mTabAdapter.notifyDataSetChanged(); + eventBus.post(new BrowserEvents.TabsChanged()); if (mIsNewIntent && isShown) { mIsNewIntent = false; @@ -1167,7 +1132,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mBrowserFrame.setBackgroundColor(mBackgroundColor); performExitCleanUp(); tabsManager.shutdown(); - mTabAdapter.notifyDataSetChanged(); + eventBus.post(new BrowserEvents.TabsChanged()); finish(); } @@ -1293,157 +1258,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } - public class LightningViewAdapter extends RecyclerView.Adapter { - - private final Context context; - private final int layoutResourceId; - private List data = null; - private final CloseTabListener mExitListener; - private final Drawable mBackgroundTabDrawable; - private final Drawable mForegroundTabDrawable; - private final Bitmap mForegroundTabBitmap; - private final DrawerItemClickListener mClickListener; - private final DrawerItemLongClickListener mLongClickListener; - private ColorMatrix mColorMatrix; - private Paint mPaint; - private ColorFilter mFilter; - private static final float DESATURATED = 0.5f; - - public LightningViewAdapter(Context context, int layoutResourceId, List data) { - this.layoutResourceId = layoutResourceId; - this.context = context; - this.data = data; - this.mExitListener = new CloseTabListener(); - this.mClickListener = new DrawerItemClickListener(); - this.mLongClickListener = new DrawerItemLongClickListener(); - - if (mShowTabsInDrawer) { - mBackgroundTabDrawable = null; - mForegroundTabBitmap = null; - mForegroundTabDrawable = ThemeUtils.getSelectedBackground(context, mDarkTheme); - } else { - int backgroundColor = Utils.mixTwoColors(ThemeUtils.getPrimaryColor(mActivity), 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(context); - mForegroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888); - Utils.drawTrapezoid(new Canvas(mForegroundTabBitmap), foregroundColor, false); - mForegroundTabDrawable = null; - } - } - - @Override - public LightningViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { - LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); - View view = inflater.inflate(layoutResourceId, viewGroup, false); - return new LightningViewHolder(view); - } - - @Override - public void onBindViewHolder(final LightningViewHolder holder, int position) { - holder.exitButton.setTag(position); - holder.exitButton.setOnClickListener(mExitListener); - holder.layout.setOnClickListener(mClickListener); - holder.layout.setOnLongClickListener(mLongClickListener); - - ViewCompat.jumpDrawablesToCurrentState(holder.exitButton); - - LightningView web = data.get(position); - 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(context, R.style.boldText); - } - Drawable foregroundDrawable; - if (!mShowTabsInDrawer) { - foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap); - if (!isIncognito() && mColorMode) { - foregroundDrawable.setColorFilter(mCurrentUiColor, 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 (!isIncognito() && mColorMode) { - 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(context, 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 (data != null) ? data.size() : 0; - } - - public Bitmap getDesaturatedBitmap(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 { - - public LightningViewHolder(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); - } - - final TextView txtTitle; - final ImageView favicon; - final ImageView exit; - final FrameLayout exitButton; - final LinearLayout layout; - } - } - - private class CloseTabListener implements OnClickListener { - - @Override - public void onClick(View v) { - deleteTab((int) v.getTag()); - } - - } - /** * Animates the color of the toolbar from one color to another. Optionally animates * the color of the tab background, for use when the tabs are displayed on the top @@ -1684,7 +1498,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void updateTabs() { - mTabAdapter.notifyDataSetChanged(); + eventBus.post(new BrowserEvents.TabsChanged()); } /** @@ -2482,5 +2296,33 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements public void closeBookmarks(final BookmarkEvents.CloseBookmarks event) { mDrawerLayout.closeDrawer(mDrawerRight); } + + /** + * The user wants to close a tab + * + * @param event contains the position inside the tabs adapter + */ + @Subscribe + public void closeTab(final TabEvents.CloseTab event) { + deleteTab(event.position); + } + + /** + * The user clicked on a tab, let's show it + * + * @param event contains the tab position in the tabs adapter + */ + public void showTab(final TabEvents.ShowTab event) { + BrowserActivity.this.showTab(event.position); + } + + /** + * The user long pressed on a tab, ask him if he want to close the tab + * + * @param event contains the tab position in the tabs adapter + */ + public void showCloseDialog(final TabEvents.ShowCloseDialog event) { + BrowserActivity.this.showCloseDialog(event.position); + } }; } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 1c7d0fd..3f3a994 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -181,7 +181,7 @@ public class TabsManager { } /** - * TODO We should remove also this + * TODO We should remove also this, but probably not * @return */ public LightningView getCurrentTab() { @@ -189,9 +189,27 @@ public class TabsManager { } /** - * TODO We should remove also this + * Switch the current tab to the one at the given position. It returns the selected. After this + * call {@link TabsManager#getCurrentTab()} return the same reference returned by this method if + * position is valid. + * + * @return the selected tab or null if position is out of tabs range */ - public void setCurrentTab(final LightningView tab) { - mCurrentTab = tab; + @Nullable + public LightningView switchToTab(final int position) { + if (position < 0 || position >= mWebViewList.size()) { + return null; + } else { + final LightningView tab = mWebViewList.get(position); + mCurrentTab = tab; + return tab; + } } + +// /** +// * TODO We should remove also this +// */ +// public void setCurrentTab(final LightningView tab) { +// mCurrentTab = tab; +// } } diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index dbaf0bc..a3927bf 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -7,6 +7,7 @@ import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.dialog.BookmarksDialogBuilder; import acr.browser.lightning.fragment.BookmarkSettingsFragment; import acr.browser.lightning.fragment.BookmarksFragment; +import acr.browser.lightning.fragment.TabsFragment; import acr.browser.lightning.object.SearchAdapter; import dagger.Component; @@ -28,4 +29,6 @@ public interface AppComponent { void inject(BookmarksDialogBuilder builder); void inject(BookmarkPage bookmarkPage); + + void inject(TabsFragment fragment); } diff --git a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java index 15ff373..696f103 100644 --- a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java @@ -41,4 +41,10 @@ public final class BrowserEvents { */ public static class UserPressedBack { } + + /** + * Notify that the user closed or opened a tab + */ + public static class TabsChanged { + } } diff --git a/app/src/main/java/acr/browser/lightning/bus/TabEvents.java b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java new file mode 100644 index 0000000..5fd4118 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java @@ -0,0 +1,49 @@ +package acr.browser.lightning.bus; + +/** + * @author Stefano Pacifici + * @date 2015/09/14 + */ +public final class TabEvents { + + private TabEvents() { + // No instances + } + + + /** + * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user click on the + * tab exit button + */ + public static class CloseTab { + public final int position; + + public CloseTab(int position) { + this.position = position; + } + } + + /** + * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user click on the + * tab itself. + */ + public static class ShowTab { + public final int position; + + public ShowTab(int position) { + this.position = position; + } + } + + /** + * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user long press on the + * tab itself. + */ + public static class ShowCloseDialog { + public final int position; + + public ShowCloseDialog(int position) { + this.position = position; + } + } +} diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java new file mode 100644 index 0000000..d42aeb3 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -0,0 +1,281 @@ +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.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 java.util.List; + +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.TabEvents; +import acr.browser.lightning.utils.ThemeUtils; +import acr.browser.lightning.utils.Utils; +import acr.browser.lightning.view.LightningView; + +/** + * @author Stefano Pacifici based on Anthony C. Restaino's code + * @date 2015/09/14 + */ +public class TabsFragment extends Fragment { + + 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"; + + private boolean mDarkTheme = false; // TODO Only temporary + private int mIconColor = 0; // TODO Only temporary + private boolean mColorMode = true; // TODO Only temporary + private boolean isIncognito = false; // TODO Only temporary + private int mCurrentUiColor = 0; // TODO Only temporary + + private RecyclerView mRecyclerView; + private LightningViewAdapter mTabsAdapter; + + @Inject + TabsManager tabsManager; + + @Inject + Bus bus; + + public TabsFragment() { + BrowserApp.getAppComponent().inject(this); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final Bundle arguments = getArguments(); + final boolean vertical = arguments.getBoolean(VERTICAL_MODE, true); + final View view; + final LayoutManager layoutManager; + if (vertical) { + view = inflater.inflate(R.layout.tab_drawer, container, false); + layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); + } else { + view = inflater.inflate(R.layout.tab_strip, container, false); + layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false); + } + mRecyclerView = (RecyclerView) view.findViewById(R.id.tabs_list); + mRecyclerView.setLayoutManager(layoutManager); + mTabsAdapter = new LightningViewAdapter(vertical); + mRecyclerView.setAdapter(mTabsAdapter); + mRecyclerView.setHasFixedSize(true); + return view; + } + + @Override + public void onDestroyView() { + mRecyclerView = null; + mTabsAdapter = null; + } + + @Override + public void onStart() { + super.onStart(); + bus.register(this); + } + + @Override + public void onStop() { + super.onStop(); + bus.unregister(this); + } + + @Subscribe + public void tabsChanged(final BrowserEvents.TabsChanged event) { + if (mTabsAdapter != null) { + mTabsAdapter.notifyDataSetChanged(); + } + } + + public class LightningViewAdapter extends RecyclerView.Adapter { + + private final int layoutResourceId; + private final Drawable mBackgroundTabDrawable; + private final Drawable mForegroundTabDrawable; + private final Bitmap mForegroundTabBitmap; + private ColorMatrix mColorMatrix; + private Paint mPaint; + private ColorFilter mFilter; + private static final float DESATURATED = 0.5f; + + private final boolean vertical; + + public LightningViewAdapter(final boolean vertical) { + this.layoutResourceId = vertical ? R.layout.tab_list_item : R.layout.tab_list_item_horizontal; + this.vertical = 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; + } + } + + @Override + public LightningViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); + View view = inflater.inflate(layoutResourceId, viewGroup, false); + return new LightningViewHolder(view); + } + + @Override + public void onBindViewHolder(final LightningViewHolder holder, int position) { + holder.exitButton.setTag(position); + + ViewCompat.jumpDrawablesToCurrentState(holder.exitButton); + + LightningView web = tabsManager.getTabAtPosition(position); + 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 (!vertical) { + foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap); + if (!isIncognito && mColorMode) { + foregroundDrawable.setColorFilter(mCurrentUiColor, 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 (!isIncognito && mColorMode) { + // TODO Restore this + // 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(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(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); + } + + final TextView txtTitle; + final ImageView favicon; + final ImageView exit; + final FrameLayout exitButton; + final LinearLayout layout; + + @Override + public void onClick(View v) { + if (v == exitButton) { + // Close tab + bus.post(new TabEvents.CloseTab(getAdapterPosition())); + } + if (v == layout) { + bus.post(new TabEvents.ShowTab(getAdapterPosition())); + } + } + + @Override + public boolean onLongClick(View v) { + // Show close dialog + bus.post(new TabEvents.ShowCloseDialog(getAdapterPosition())); + return true; + } + } + } + +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 31777df..655df01 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -25,7 +25,12 @@ - + + android:dividerHeight="0dp" + android:overScrollMode="ifContentScrolls" /> + + diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml index 9b144f3..cc0fbcb 100644 --- a/app/src/main/res/layout/toolbar.xml +++ b/app/src/main/res/layout/toolbar.xml @@ -8,13 +8,10 @@ android:elevation="2dp" android:orientation="vertical"> - + android:id="@+id/tabs_toolbar_container"/>