From 2c4db0c54b44bb2f952e880d39f72f52ff88eb30 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Sun, 21 Feb 2016 15:11:20 -0500 Subject: [PATCH] Animate tab addition/deletion in recyclerview, change full screen implementation to be simpler TODO still need to use correct animations for tab addition and removal --- .../lightning/activity/BrowserActivity.java | 152 ++++++++---------- .../lightning/activity/TabsManager.java | 9 ++ .../lightning/browser/BrowserPresenter.java | 13 +- .../lightning/browser/BrowserView.java | 6 + .../browser/lightning/browser/TabsView.java | 11 ++ .../lightning/controller/UIController.java | 2 + .../lightning/fragment/BookmarksFragment.java | 15 +- .../lightning/fragment/TabsFragment.java | 25 ++- .../browser/lightning/reading/MapEntry.java | 19 ++- .../lightning/view/LightningChromeClient.java | 4 +- .../browser/lightning/view/LightningView.java | 2 +- .../lightning/view/LightningWebClient.java | 4 +- app/src/main/res/layout/activity_main.xml | 34 ++-- 13 files changed, 167 insertions(+), 129 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/browser/TabsView.java 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 e304c61..23033d5 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -57,6 +57,7 @@ import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; import android.view.animation.Animation; @@ -96,6 +97,7 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.browser.BrowserPresenter; import acr.browser.lightning.browser.BrowserView; +import acr.browser.lightning.browser.TabsView; import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.bus.BrowserEvents; import acr.browser.lightning.bus.NavigationEvents; @@ -160,6 +162,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private AutoCompleteTextView mSearch; private ImageView mArrowImage; + // Current tab view being displayed + private View mCurrentView; + // Full Screen Video Views private FrameLayout mFullscreenContainer; private VideoView mVideoView; @@ -206,6 +211,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private Drawable mDeleteIcon, mRefreshIcon, mClearIcon, mIcon; private BrowserPresenter mPresenter; + private TabsView mTabsView; // Proxy @Inject ProxyUtils mProxyUtils; @@ -283,6 +289,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mWebpageBitmap = ThemeUtils.getThemedBitmap(this, R.drawable.ic_webpage, mDarkTheme); final TabsFragment tabsFragment = new TabsFragment(); + mTabsView = tabsFragment; final int containerId = mShowTabsInDrawer ? R.id.left_drawer : R.id.tabs_toolbar_container; final Bundle tabsFragmentArguments = new Bundle(); tabsFragmentArguments.putBoolean(TabsFragment.IS_INCOGNITO, isIncognito()); @@ -552,31 +559,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements changeToolbarBackground(currentView.getFavicon(), null); } - if (mFullScreen) { - mToolbarLayout.setTranslationY(0); - int height = mToolbarLayout.getHeight(); - if (height == 0) { - mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - height = mToolbarLayout.getMeasuredHeight(); - } - if (currentWebView != null) - currentWebView.setTranslationY(height); - mBrowserFrame.setLayoutTransition(null); - if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) { - mUiLayout.removeView(mToolbarLayout); - mBrowserFrame.addView(mToolbarLayout); - mToolbarLayout.bringToFront(); - } - } else { - mToolbarLayout.setTranslationY(0); - if (mBrowserFrame.findViewById(R.id.toolbar_layout) != null) { - mBrowserFrame.removeView(mToolbarLayout); - mUiLayout.addView(mToolbarLayout, 0); - } - mBrowserFrame.setLayoutTransition(new LayoutTransition()); - if (currentWebView != null) - currentWebView.setTranslationY(0); - } + mToolbarLayout.setTranslationY(0); + mBrowserFrame.setLayoutTransition(new LayoutTransition()); + initializeTabHeight(); + mBrowserFrame.setTranslationY(0); setFullscreen(mPreferences.getHideStatusBarEnabled(), false); switch (mPreferences.getSearchChoice()) { @@ -828,7 +814,28 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements builder.show(); } - private View mCurrentView; + @Override + public void notifyTabViewRemoved(int position) { + Log.d(Constants.TAG, "Notify Tab Removed: " + position); + mTabsView.tabRemoved(position); + } + + @Override + public void notifyTabViewAdded() { + Log.d(Constants.TAG, "Notify Tab Added"); + mTabsView.tabAdded(); + } + + @Override + public void notifyTabViewChanged(int position) { + Log.d(Constants.TAG, "Notify Tab Changed: " + position); + mTabsView.tabChanged(position); + } + + @Override + public void tabChanged(LightningView tab) { + mPresenter.tabChangeOccurred(tab); + } @Override public void removeTabView() { @@ -840,13 +847,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements removeViewFromParent(mCurrentView); - if (mFullScreen) { - // mToolbarLayout has already been removed - mBrowserFrame.addView(mToolbarLayout); - mToolbarLayout.bringToFront(); - mToolbarLayout.setTranslationY(0); - } - mCurrentView = null; // Use a delayed handler to make the transition smooth @@ -862,7 +862,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } @Override - public void setTabView(@NonNull View view) { + public void setTabView(@NonNull final View view) { if (mCurrentView == view) { return; } @@ -870,7 +870,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements // Set the background color so the color mode color doesn't show through mBrowserFrame.setBackgroundColor(mBackgroundColor); - final float translation = mToolbarLayout.getTranslationY(); mBrowserFrame.removeAllViews(); removeViewFromParent(view); @@ -880,22 +879,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements view.requestFocus(); - if (mFullScreen) { - // mToolbarLayout has already been removed - mBrowserFrame.addView(mToolbarLayout); - mToolbarLayout.bringToFront(); - Log.d(Constants.TAG, "Move view to browser frame"); - int height = mToolbarLayout.getHeight(); - if (height == 0) { - mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - height = mToolbarLayout.getMeasuredHeight(); - } - view.setTranslationY(translation + height); - mToolbarLayout.setTranslationY(translation); - } else { - view.setTranslationY(0); - } - mCurrentView = view; showActionBar(); @@ -1042,7 +1025,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (mCurrentView != null && mFullScreen) { showActionBar(); - mCurrentView.setTranslationY(toolbarSize); + mBrowserFrame.setTranslationY(0); mToolbarLayout.setTranslationY(0); } } @@ -1737,19 +1720,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Override public void hideActionBar() { - final WebView currentWebView = mTabsManager.getCurrentWebView(); if (mFullScreen) { - if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) { - mUiLayout.removeView(mToolbarLayout); - mBrowserFrame.addView(mToolbarLayout); - mToolbarLayout.bringToFront(); - Log.d(Constants.TAG, "Move view to browser frame"); - mToolbarLayout.setTranslationY(0); - if (currentWebView != null) { - currentWebView.setTranslationY(mToolbarLayout.getHeight()); - } - } - if (mToolbarLayout == null || currentWebView == null) + if (mToolbarLayout == null || mBrowserFrame == null) return; final int height = mToolbarLayout.getHeight(); @@ -1759,12 +1731,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements protected void applyTransformation(float interpolatedTime, Transformation t) { float trans = (1.0f - interpolatedTime) * height; mToolbarLayout.setTranslationY(trans - height); - currentWebView.setTranslationY(trans); + mBrowserFrame.setTranslationY(trans - height); } }; show.setDuration(250); show.setInterpolator(new DecelerateInterpolator()); - currentWebView.startAnimation(show); + mBrowserFrame.startAnimation(show); } } } @@ -1777,8 +1749,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void showActionBar() { if (mFullScreen) { - final WebView view = mTabsManager.getCurrentWebView(); - if (mToolbarLayout == null) return; @@ -1788,16 +1758,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements height = mToolbarLayout.getMeasuredHeight(); } - if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) { - mUiLayout.removeView(mToolbarLayout); - mBrowserFrame.addView(mToolbarLayout); - mToolbarLayout.bringToFront(); - Log.d(Constants.TAG, "Move view to browser frame"); - mToolbarLayout.setTranslationY(0); - if (view != null) { - view.setTranslationY(height); - } - } final LightningView currentTab = mTabsManager.getCurrentTab(); if (currentTab == null) return; @@ -1809,18 +1769,44 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements protected void applyTransformation(float interpolatedTime, Transformation t) { float trans = interpolatedTime * totalHeight; mToolbarLayout.setTranslationY(trans - totalHeight); - // null pointer here on close - if (view != null) - view.setTranslationY(trans); + mBrowserFrame.setTranslationY(trans - totalHeight); } }; show.setDuration(250); show.setInterpolator(new DecelerateInterpolator()); - if (view != null) { - view.startAnimation(show); + mBrowserFrame.startAnimation(show); + } + } + } + + private void initializeTabHeight() { + mUiLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + setTabHeight(); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + mUiLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } else { + mUiLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); } } + }); + + } + + private void setTabHeight() { + if (mUiLayout.getHeight() == 0) { + mUiLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); } + + if (mFullScreen) { + mBrowserFrame.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, mUiLayout.getHeight())); + } else { + mBrowserFrame.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + } + + mBrowserFrame.requestLayout(); } /** 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 0c7756d..3bc3604 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -396,6 +396,15 @@ public class TabsManager { return mTabList.indexOf(mCurrentTab); } + /** + * Returns the index of the tab. + * + * @return Return the index of the tab, or -1 if the tab isn't in the list. + */ + public int indexOfTab(LightningView tab) { + return mTabList.indexOf(tab); + } + /** * Return the current {@link LightningView} or null if * no current tab has been set. diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index 56cb496..0c7d9ae 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -67,6 +67,10 @@ public class BrowserPresenter { }); } + public void tabChangeOccurred(LightningView tab) { + mView.notifyTabViewChanged(mTabsModel.indexOfTab(tab)); + } + private void onTabChanged(@Nullable LightningView newTab) { Log.d(TAG, "On tab changed"); if (newTab == null) { @@ -95,6 +99,7 @@ public class BrowserPresenter { mView.setForwardButtonEnabled(newTab.canGoForward()); mView.updateUrl(newTab.getUrl(), true); mView.setTabView(newTab.getWebView()); + mView.notifyTabViewChanged(mTabsModel.indexOfTab(newTab)); } } @@ -141,6 +146,7 @@ public class BrowserPresenter { } } final LightningView afterTab = mTabsModel.getCurrentTab(); + mView.notifyTabViewRemoved(position); if (afterTab == null) { mView.closeBrowser(); return; @@ -150,10 +156,9 @@ public class BrowserPresenter { // if (currentTab != null) { // currentTab.pauseTimers(); // } + mView.notifyTabViewChanged(mTabsModel.indexOfCurrentTab()); } - mEventBus.post(new BrowserEvents.TabsChanged()); - if (shouldClose) { mIsNewIntent = false; mView.closeActivity(); @@ -231,8 +236,10 @@ public class BrowserPresenter { startingTab.resumeTimers(); } + mView.notifyTabViewAdded(); + if (show) { - LightningView tab = mTabsModel.switchToTab(mTabsModel.size() - 1); + LightningView tab = mTabsModel.switchToTab(mTabsModel.last()); onTabChanged(tab); } diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserView.java b/app/src/main/java/acr/browser/lightning/browser/BrowserView.java index 24691cf..4ef45f5 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserView.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserView.java @@ -29,4 +29,10 @@ public interface BrowserView { void setBackButtonEnabled(boolean enabled); + void notifyTabViewRemoved(int position); + + void notifyTabViewAdded(); + + void notifyTabViewChanged(int position); + } diff --git a/app/src/main/java/acr/browser/lightning/browser/TabsView.java b/app/src/main/java/acr/browser/lightning/browser/TabsView.java new file mode 100644 index 0000000..8c4e64e --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/browser/TabsView.java @@ -0,0 +1,11 @@ +package acr.browser.lightning.browser; + +public interface TabsView { + + void tabAdded(); + + void tabRemoved(int position); + + void tabChanged(int position); + +} diff --git a/app/src/main/java/acr/browser/lightning/controller/UIController.java b/app/src/main/java/acr/browser/lightning/controller/UIController.java index a7d1d30..b06e85a 100644 --- a/app/src/main/java/acr/browser/lightning/controller/UIController.java +++ b/app/src/main/java/acr/browser/lightning/controller/UIController.java @@ -59,4 +59,6 @@ public interface UIController { void setBackButtonEnabled(boolean enabled); + void tabChanged(LightningView tab); + } diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 55e4b70..748e6b4 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -57,22 +57,17 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, public final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE"; // Managers - @Inject - BookmarkManager mBookmarkManager; + @Inject BookmarkManager mBookmarkManager; // Event bus - @Inject - Bus mEventBus; + @Inject Bus mEventBus; // Dialog builder - @Inject - LightningDialogBuilder mBookmarksDialogBuilder; + @Inject LightningDialogBuilder mBookmarksDialogBuilder; - @Inject - PreferenceManager mPreferenceManager; + @Inject PreferenceManager mPreferenceManager; - @Inject - TabsManager mTabsManager; + @Inject TabsManager mTabsManager; // Adapter private BookmarkViewAdapter mBookmarkAdapter; diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index f0397cd..2b9c292 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -37,6 +37,7 @@ 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.browser.TabsView; import acr.browser.lightning.bus.BrowserEvents; import acr.browser.lightning.bus.NavigationEvents; import acr.browser.lightning.bus.TabEvents; @@ -53,7 +54,7 @@ import acr.browser.lightning.view.LightningView; * 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 { +public class TabsFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener, TabsView { private static final String TAG = TabsFragment.class.getSimpleName(); @@ -206,6 +207,27 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View return true; } + @Override + public void tabAdded() { + if (mTabsAdapter != null) { + mTabsAdapter.notifyItemInserted(tabsManager.last()); + } + } + + @Override + public void tabRemoved(int position) { + if (mTabsAdapter != null) { + mTabsAdapter.notifyItemRemoved(position); + } + } + + @Override + public void tabChanged(int position) { + if (mTabsAdapter != null) { + mTabsAdapter.notifyItemChanged(position); + } + } + public class LightningViewAdapter extends RecyclerView.Adapter { private final int mLayoutResourceId; @@ -298,6 +320,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View } holder.favicon.setImageBitmap(getDesaturatedBitmap(favicon)); } + holder.itemView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } @Override diff --git a/app/src/main/java/acr/browser/lightning/reading/MapEntry.java b/app/src/main/java/acr/browser/lightning/reading/MapEntry.java index e931062..7e1bef7 100644 --- a/app/src/main/java/acr/browser/lightning/reading/MapEntry.java +++ b/app/src/main/java/acr/browser/lightning/reading/MapEntry.java @@ -1,12 +1,12 @@ /** * Copyright (C) 2010 Peter Karich <> - * + *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + *

* http://www.apache.org/licenses/LICENSE-2.0 - * + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -20,7 +20,7 @@ import java.util.Map; /** * Simple impl of Map.Entry. So that we can have ordered maps. - * + * * @author Peter Karich, peat_hal ‘at’ users ‘dot’ sourceforge ‘dot’ * net */ @@ -60,13 +60,12 @@ public class MapEntry implements Map.Entry, Serializable { public boolean equals(Object obj) { if (obj == null) return false; - if (getClass() != obj.getClass()) - return false; - final MapEntry other = (MapEntry) obj; - if (this.key != other.key && (this.key == null || !this.key.equals(other.key))) + if (!(obj instanceof Map)) return false; - return !(this.value != other.value && (this.value == null || !this.value - .equals(other.value))); + final MapEntry other = (MapEntry) obj; + + return !(this.key != other.key && (this.key == null || !this.key.equals(other.key))) && + !(this.value != other.value && (this.value == null || !this.value.equals(other.value))); } @Override diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java index 5954a6d..de8c70c 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -57,7 +57,7 @@ class LightningChromeClient extends WebChromeClient { @Override public void onReceivedIcon(@NonNull WebView view, Bitmap icon) { mLightningView.getTitleInfo().setFavicon(icon); - eventBus.post(new BrowserEvents.TabsChanged()); + mUIController.tabChanged(mLightningView); cacheFavicon(view.getUrl(), icon, mActivity); } @@ -83,7 +83,7 @@ class LightningChromeClient extends WebChromeClient { } else { mLightningView.getTitleInfo().setTitle(mActivity.getString(R.string.untitled)); } - eventBus.post(new BrowserEvents.TabsChanged()); + mUIController.tabChanged(mLightningView); if (view != null) { mUIController.updateHistory(title, view.getUrl()); } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 215d1e7..4122aca 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -570,7 +570,7 @@ public class LightningView { */ public void setForegroundTab(boolean isForeground) { isForegroundTab = isForeground; - mEventBus.post(new BrowserEvents.TabsChanged()); + mUIController.tabChanged(this); } /** diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index 1a1f43f..e48433b 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -110,7 +110,7 @@ public class LightningWebClient extends WebViewClient { mLightningView.getInvertePage()) { view.evaluateJavascript(Constants.JAVASCRIPT_INVERT_PAGE, null); } - mEventBus.post(new BrowserEvents.TabsChanged()); + mUIController.tabChanged(mLightningView); } @Override @@ -120,7 +120,7 @@ public class LightningWebClient extends WebViewClient { mUIController.updateUrl(url, false); mUIController.showActionBar(); } - mEventBus.post(new BrowserEvents.TabsChanged()); + mUIController.tabChanged(mLightningView); } @Override diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index eae84d4..22b6eb4 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,10 +1,10 @@ - + - + - + - + + android:weightSum="1"/> + android:layout_height="match_parent" + android:layout_gravity="end" + android:background="?attr/drawerBackground" + android:fitsSystemWindows="true" + android:weightSum="1"/>