Browse Source

TabsFragment extracted

master
Stefano Pacifici 9 years ago
parent
commit
51f783cea4
  1. 290
      app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java
  2. 24
      app/src/main/java/acr/browser/lightning/activity/TabsManager.java
  3. 3
      app/src/main/java/acr/browser/lightning/app/AppComponent.java
  4. 6
      app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java
  5. 49
      app/src/main/java/acr/browser/lightning/bus/TabEvents.java
  6. 281
      app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java
  7. 7
      app/src/main/res/layout/activity_main.xml
  8. 6
      app/src/main/res/layout/tab_drawer.xml
  9. 9
      app/src/main/res/layout/tab_strip.xml
  10. 7
      app/src/main/res/layout/toolbar.xml

290
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.app.BrowserApp;
import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.bus.BookmarkEvents;
import acr.browser.lightning.bus.BrowserEvents; import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.bus.TabEvents;
import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.constant.HistoryPage; 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.BookmarkManager;
import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryDatabase;
import acr.browser.lightning.dialog.BookmarksDialogBuilder; import acr.browser.lightning.dialog.BookmarksDialogBuilder;
import acr.browser.lightning.fragment.TabsFragment;
import acr.browser.lightning.object.ClickHandler; import acr.browser.lightning.object.ClickHandler;
import acr.browser.lightning.object.SearchAdapter; import acr.browser.lightning.object.SearchAdapter;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;
@ -132,7 +134,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
private DrawerLayout mDrawerLayout; private DrawerLayout mDrawerLayout;
private FrameLayout mBrowserFrame; private FrameLayout mBrowserFrame;
private FullscreenHolder mFullscreenContainer; private FullscreenHolder mFullscreenContainer;
private RecyclerView mDrawerListLeft;
private ViewGroup mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout; private ViewGroup mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout;
private RelativeLayout mSearchBar; private RelativeLayout mSearchBar;
@ -144,7 +145,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
private View mCustomView; private View mCustomView;
// Adapter // Adapter
private LightningViewAdapter mTabAdapter;
private SearchAdapter mSearchAdapter; private SearchAdapter mSearchAdapter;
// Callback // Callback
@ -247,7 +247,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mUiLayout = (LinearLayout) findViewById(R.id.ui_layout); mUiLayout = (LinearLayout) findViewById(R.id.ui_layout);
mProgressBar = (AnimatedProgressBar) findViewById(R.id.progress_view); mProgressBar = (AnimatedProgressBar) findViewById(R.id.progress_view);
setupFrameLayoutButton(R.id.new_tab_button, R.id.icon_plus); 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 // Drawer stutters otherwise
mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null); mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
@ -267,29 +267,19 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mHomepage = mPreferences.getHomepage(); 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) { if (mShowTabsInDrawer) {
mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item, tabsManager.getTabsList()); mToolbarLayout.removeView(findViewById(R.id.tabs_toolbar_container));
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);
} }
mDrawerListLeft.setAdapter(mTabAdapter);
mHistoryDatabase = HistoryDatabase.getInstance(); mHistoryDatabase = HistoryDatabase.getInstance();
if (actionBar == null) if (actionBar == null)
@ -872,56 +862,29 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
builder.show(); 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 * displays the WebView contained in the LightningView Also handles the
* removal of previous views * 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 currentView = tabsManager.getCurrentTab();
final LightningView newView = tabsManager.switchToTab(position);
// Set the background color so the color mode color doesn't show through // Set the background color so the color mode color doesn't show through
mBrowserFrame.setBackgroundColor(mBackgroundColor); mBrowserFrame.setBackgroundColor(mBackgroundColor);
if (newView == null) { if (newView == null || currentView == newView) {
return; return;
} }
mIsNewIntent = false;
final float translation = mToolbarLayout.getTranslationY(); final float translation = mToolbarLayout.getTranslationY();
mBrowserFrame.removeAllViews(); mBrowserFrame.removeAllViews();
if (currentView != null) { if (currentView != null) {
currentView.setForegroundTab(false); currentView.setForegroundTab(false);
currentView.onPause(); currentView.onPause();
} }
tabsManager.setCurrentTab(newView);
final WebView currentWebView = currentView.getWebView(); final WebView currentWebView = currentView.getWebView();
newView.setForegroundTab(true); newView.setForegroundTab(true);
if (currentWebView != null) { if (currentWebView != null) {
@ -1047,15 +1010,17 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mIdGenerator++; mIdGenerator++;
if (show) { if (show) {
showTab(startingTab); showTab(tabsManager.size() - 1);
} }
updateTabs(); updateTabs();
new Handler().postDelayed(new Runnable() {
@Override // TODO Restore this
public void run() { // new Handler().postDelayed(new Runnable() {
mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1); // @Override
} // public void run() {
}, 300); // mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1);
// }
// }, 300);
return true; return true;
} }
@ -1082,14 +1047,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
if (current > position) { if (current > position) {
tabsManager.deleteTab(position); tabsManager.deleteTab(position);
showTab(tabsManager.getTabAtPosition(current - 1)); showTab(current - 1);
updateTabs(); updateTabs();
tabToDelete.onDestroy(); tabToDelete.onDestroy();
} else if (tabsManager.size() > position + 1) { } else if (tabsManager.size() > position + 1) {
if (current == position) { if (current == position) {
showTab(tabsManager.getTabAtPosition(position + 1)); showTab(position + 1);
tabsManager.deleteTab(position); tabsManager.deleteTab(position);
showTab(tabsManager.getTabAtPosition(position)); showTab(position);
updateTabs(); updateTabs();
} else { } else {
tabsManager.deleteTab(position); tabsManager.deleteTab(position);
@ -1098,9 +1063,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
tabToDelete.onDestroy(); tabToDelete.onDestroy();
} else if (tabsManager.size() > 1) { } else if (tabsManager.size() > 1) {
if (current == position) { if (current == position) {
showTab(tabsManager.getTabAtPosition(position - 1)); showTab(position - 1);
tabsManager.deleteTab(position); tabsManager.deleteTab(position);
showTab(tabsManager.getTabAtPosition(position - 1)); showTab(position - 1);
updateTabs(); updateTabs();
} else { } else {
tabsManager.deleteTab(position); tabsManager.deleteTab(position);
@ -1115,11 +1080,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
performExitCleanUp(); performExitCleanUp();
tabToDelete.pauseTimers(); tabToDelete.pauseTimers();
tabToDelete.onDestroy(); tabToDelete.onDestroy();
mTabAdapter.notifyDataSetChanged(); eventBus.post(new BrowserEvents.TabsChanged());
finish(); finish();
} }
} }
mTabAdapter.notifyDataSetChanged(); eventBus.post(new BrowserEvents.TabsChanged());
if (mIsNewIntent && isShown) { if (mIsNewIntent && isShown) {
mIsNewIntent = false; mIsNewIntent = false;
@ -1167,7 +1132,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mBrowserFrame.setBackgroundColor(mBackgroundColor); mBrowserFrame.setBackgroundColor(mBackgroundColor);
performExitCleanUp(); performExitCleanUp();
tabsManager.shutdown(); tabsManager.shutdown();
mTabAdapter.notifyDataSetChanged(); eventBus.post(new BrowserEvents.TabsChanged());
finish(); finish();
} }
@ -1293,157 +1258,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
} }
public class LightningViewAdapter extends RecyclerView.Adapter<LightningViewAdapter.LightningViewHolder> {
private final Context context;
private final int layoutResourceId;
private List<LightningView> 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<LightningView> 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 * 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 * 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 @Override
public void updateTabs() { 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) { public void closeBookmarks(final BookmarkEvents.CloseBookmarks event) {
mDrawerLayout.closeDrawer(mDrawerRight); 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);
}
}; };
} }

24
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 * @return
*/ */
public LightningView getCurrentTab() { 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) { @Nullable
public LightningView switchToTab(final int position) {
if (position < 0 || position >= mWebViewList.size()) {
return null;
} else {
final LightningView tab = mWebViewList.get(position);
mCurrentTab = tab; mCurrentTab = tab;
return tab;
}
} }
// /**
// * TODO We should remove also this
// */
// public void setCurrentTab(final LightningView tab) {
// mCurrentTab = tab;
// }
} }

3
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.dialog.BookmarksDialogBuilder;
import acr.browser.lightning.fragment.BookmarkSettingsFragment; import acr.browser.lightning.fragment.BookmarkSettingsFragment;
import acr.browser.lightning.fragment.BookmarksFragment; import acr.browser.lightning.fragment.BookmarksFragment;
import acr.browser.lightning.fragment.TabsFragment;
import acr.browser.lightning.object.SearchAdapter; import acr.browser.lightning.object.SearchAdapter;
import dagger.Component; import dagger.Component;
@ -28,4 +29,6 @@ public interface AppComponent {
void inject(BookmarksDialogBuilder builder); void inject(BookmarksDialogBuilder builder);
void inject(BookmarkPage bookmarkPage); void inject(BookmarkPage bookmarkPage);
void inject(TabsFragment fragment);
} }

6
app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java

@ -41,4 +41,10 @@ public final class BrowserEvents {
*/ */
public static class UserPressedBack { public static class UserPressedBack {
} }
/**
* Notify that the user closed or opened a tab
*/
public static class TabsChanged {
}
} }

49
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;
}
}
}

281
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<LightningViewAdapter.LightningViewHolder> {
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;
}
}
}
}

7
app/src/main/res/layout/activity_main.xml

@ -25,7 +25,12 @@
<include layout="@layout/search_interface" /> <include layout="@layout/search_interface" />
</LinearLayout> </LinearLayout>
<include layout="@layout/tab_drawer" /> <FrameLayout
android:layout_width="@dimen/navigation_width"
android:layout_height="match_parent"
android:background="?attr/drawerBackground"
android:id="@+id/left_drawer"
android:fitsSystemWindows="true" />
<FrameLayout <FrameLayout
android:weightSum="1" android:weightSum="1"

6
app/src/main/res/layout/tab_drawer.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/left_drawer"
android:layout_width="@dimen/navigation_width" android:layout_width="@dimen/navigation_width"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="start" android:layout_gravity="start"
@ -45,12 +44,13 @@
</LinearLayout> </LinearLayout>
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/left_drawer_list" android:id="@+id/tabs_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:divider="@null" android:divider="@null"
android:dividerHeight="0dp" /> android:dividerHeight="0dp"
android:overScrollMode="ifContentScrolls" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

9
app/src/main/res/layout/tab_strip.xml

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@color/black"
android:overScrollMode="never"
android:scrollbars="none"
android:id="@+id/tabs_list" />

7
app/src/main/res/layout/toolbar.xml

@ -8,13 +8,10 @@
android:elevation="2dp" android:elevation="2dp"
android:orientation="vertical"> android:orientation="vertical">
<android.support.v7.widget.RecyclerView <FrameLayout
android:id="@+id/twv_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="30dp" android:layout_height="30dp"
android:background="@color/black" android:id="@+id/tabs_toolbar_container"/>
android:overScrollMode="never"
android:scrollbars="none" />
<android.support.v7.widget.Toolbar <android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"

Loading…
Cancel
Save