Stefano Pacifici
9 years ago
10 changed files with 447 additions and 237 deletions
@ -0,0 +1,49 @@
@@ -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; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,281 @@
@@ -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; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,9 @@
@@ -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" /> |
||||
|
Loading…
Reference in new issue