From dc45137eeedabf6d58c1e7e231a87a2c8523c32e Mon Sep 17 00:00:00 2001 From: Adrian Ulrich Date: Thu, 7 Jan 2016 09:16:24 +0100 Subject: [PATCH] squashed merge of hacky-bottom branch --- res/color/tab_text_selector.xml | 4 +- .../ic_menu_moreoverflow_normal_holo_dark.png | Bin 0 -> 144 bytes ...enu_search.png => ic_menu_search_holo.png} | Bin ...search.png => ic_menu_search_material.png} | Bin .../ic_menu_moreoverflow_normal_holo_dark.png | Bin 0 -> 122 bytes ...enu_search.png => ic_menu_search_holo.png} | Bin ...search.png => ic_menu_search_material.png} | Bin res/drawable-v21/ic_menu_moreoverflow.xml | 25 ++ res/drawable-v21/ic_menu_search.xml | 6 + res/drawable-v21/unbound_ripple_light.xml | 3 + .../ic_menu_moreoverflow_normal_holo_dark.png | Bin 0 -> 167 bytes ...enu_search.png => ic_menu_search_holo.png} | Bin ...search.png => ic_menu_search_material.png} | Bin .../ic_menu_moreoverflow_normal_holo_dark.png | Bin 0 -> 1167 bytes ...enu_search.png => ic_menu_search_holo.png} | Bin ...search.png => ic_menu_search_material.png} | Bin ...search.png => ic_menu_search_material.png} | Bin res/drawable/ic_menu_moreoverflow.xml | 6 + res/drawable/ic_menu_search.xml | 6 + res/drawable/unbound_ripple_light.xml | 6 + res/layout/actionbar_controls.xml | 62 ---- res/layout/bottombar_controls.xml | 85 ++++++ res/layout/library_content.xml | 2 + res/values-v21/colors.xml | 2 +- res/values-v21/theme.xml | 11 +- res/values/theme.xml | 6 +- .../iosched/tabs/VanillaTabLayout.java | 19 +- .../android/vanilla/ActionBarControls.java | 70 ----- .../android/vanilla/BottomBarControls.java | 283 ++++++++++++++++++ .../android/vanilla/LibraryActivity.java | 82 ++--- 30 files changed, 453 insertions(+), 225 deletions(-) create mode 100644 res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png rename res/drawable-hdpi/{ic_menu_search.png => ic_menu_search_holo.png} (100%) rename res/drawable-hdpi/{ic_action_search.png => ic_menu_search_material.png} (100%) create mode 100644 res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png rename res/drawable-mdpi/{ic_menu_search.png => ic_menu_search_holo.png} (100%) rename res/drawable-mdpi/{ic_action_search.png => ic_menu_search_material.png} (100%) create mode 100644 res/drawable-v21/ic_menu_moreoverflow.xml create mode 100644 res/drawable-v21/ic_menu_search.xml create mode 100644 res/drawable-v21/unbound_ripple_light.xml create mode 100644 res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png rename res/drawable-xhdpi/{ic_menu_search.png => ic_menu_search_holo.png} (100%) rename res/drawable-xhdpi/{ic_action_search.png => ic_menu_search_material.png} (100%) create mode 100644 res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_dark.png rename res/drawable-xxhdpi/{ic_menu_search.png => ic_menu_search_holo.png} (100%) rename res/drawable-xxhdpi/{ic_action_search.png => ic_menu_search_material.png} (100%) rename res/drawable-xxxhdpi/{ic_action_search.png => ic_menu_search_material.png} (100%) create mode 100644 res/drawable/ic_menu_moreoverflow.xml create mode 100644 res/drawable/ic_menu_search.xml create mode 100644 res/drawable/unbound_ripple_light.xml delete mode 100644 res/layout/actionbar_controls.xml create mode 100644 res/layout/bottombar_controls.xml delete mode 100644 src/ch/blinkenlights/android/vanilla/ActionBarControls.java create mode 100644 src/ch/blinkenlights/android/vanilla/BottomBarControls.java diff --git a/res/color/tab_text_selector.xml b/res/color/tab_text_selector.xml index 438fd917..2cebf881 100644 --- a/res/color/tab_text_selector.xml +++ b/res/color/tab_text_selector.xml @@ -1,5 +1,5 @@ - - + + diff --git a/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png b/res/drawable-hdpi/ic_menu_moreoverflow_normal_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..2abc45809c62513224e9d695542cb8dd8e8087b9 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezt=sPZ!6KjC*gdALL|E;9+*q=6m<7 zlueVX_4IZHnJ0qE#_rG0T(kiyWMEjjhCTn?qu5pu`=4q}27?c$C=-xvpo(CHaDZeV Zn6Yoz!5==w*?y}vd$@?2>|OKBsl;8 literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/ic_menu_search.png b/res/drawable-hdpi/ic_menu_search_holo.png similarity index 100% rename from res/drawable-hdpi/ic_menu_search.png rename to res/drawable-hdpi/ic_menu_search_holo.png diff --git a/res/drawable-hdpi/ic_action_search.png b/res/drawable-hdpi/ic_menu_search_material.png similarity index 100% rename from res/drawable-hdpi/ic_action_search.png rename to res/drawable-hdpi/ic_menu_search_material.png diff --git a/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png b/res/drawable-mdpi/ic_menu_moreoverflow_normal_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..ba704b67e3a25f1fb1b16a261c5a1b25fabd0c0d GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzM^6{Wkch)?uQ+l6B^Vrg + + + diff --git a/res/drawable-v21/ic_menu_search.xml b/res/drawable-v21/ic_menu_search.xml new file mode 100644 index 00000000..a5024140 --- /dev/null +++ b/res/drawable-v21/ic_menu_search.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/res/drawable-v21/unbound_ripple_light.xml b/res/drawable-v21/unbound_ripple_light.xml new file mode 100644 index 00000000..7788fa44 --- /dev/null +++ b/res/drawable-v21/unbound_ripple_light.xml @@ -0,0 +1,3 @@ + + diff --git a/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png b/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..a92fb1d4af622cfad770d7c494121719a7896e61 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=d7dtgAr-gYUQ-leFyLX@@b&p` z%gbN)&SLHDYV<0q^J4_6fq?|&@*V6j4#NRakTDF}Z~@#RP$drMna{J{ZM0wU(H|t@ M>FVdQ&MBb@0L8N*<^TWy literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_menu_search.png b/res/drawable-xhdpi/ic_menu_search_holo.png similarity index 100% rename from res/drawable-xhdpi/ic_menu_search.png rename to res/drawable-xhdpi/ic_menu_search_holo.png diff --git a/res/drawable-xhdpi/ic_action_search.png b/res/drawable-xhdpi/ic_menu_search_material.png similarity index 100% rename from res/drawable-xhdpi/ic_action_search.png rename to res/drawable-xhdpi/ic_menu_search_material.png diff --git a/res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_dark.png b/res/drawable-xxhdpi/ic_menu_moreoverflow_normal_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..498a9ff1c18f246a967b7c5f834e2a98f014cccc GIT binary patch literal 1167 zcmbVLO=uHA6rQ$HYHP4ULF;MQB6u*_*=@3aG}dHy(*{g`(ny0+=yrFKEbacdJ2h!R zDB{JNc=F(}H$f2epikKP^bY169YD!B{x(WX{Kpcq3h_FWndFR7SqguQ{}=GRJ{PhR073K zBp@ho32rzkisCiMBMz~MXE{F3iOMjqAOu?c@MkDTqLv0Hh4$Z*!iS4;CvS=)L%OuTEPY*(H{6gW-up71# zMN`H$44>r^h;^JOt|mGpMSSGOspzn@;$yamLvJ}S>3dX$+GLu$e+xxG>WwlP*z{41 zCCxLJ9qf|4mS*Tp!m=#|WhBILViJiw5+sh3GJ>WjwH(qVDaQ@x+BQz(s##uAWg)3^ z5@qTrD`!+4i8)QzWHGC%ZEoHTiQ$^Kt!q#T>(=y zk9c9t^PxJEf(660-Dn>@&q1^r4(xl_$_1VSoB37jQ}m@IpGgUb%O#KER{4x7XH%Sz zRRyNSwf-k(EOmyBisM+Zw2x>7M$5y}r<=p(!7lBXfVRf^>*r5sTW#jGOsVmC@6*fJ z7CZ;GAMb3uxzM%VcWL|n{`)cW1OH=sE=F;k;06Fa0CWHdz!|UxK>ynG!0yEU&+ZP; zfAW6z>nLU10ZqzQbvpUIKRnxaf(yW}E5ADc_}JN^?%f{Pefx0oJSCoxdUf>#?6?Qd a<}S{I!PNS<4XbvG@<3jn&|YNcAN&EM6H}`I literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/ic_menu_search.png b/res/drawable-xxhdpi/ic_menu_search_holo.png similarity index 100% rename from res/drawable-xxhdpi/ic_menu_search.png rename to res/drawable-xxhdpi/ic_menu_search_holo.png diff --git a/res/drawable-xxhdpi/ic_action_search.png b/res/drawable-xxhdpi/ic_menu_search_material.png similarity index 100% rename from res/drawable-xxhdpi/ic_action_search.png rename to res/drawable-xxhdpi/ic_menu_search_material.png diff --git a/res/drawable-xxxhdpi/ic_action_search.png b/res/drawable-xxxhdpi/ic_menu_search_material.png similarity index 100% rename from res/drawable-xxxhdpi/ic_action_search.png rename to res/drawable-xxxhdpi/ic_menu_search_material.png diff --git a/res/drawable/ic_menu_moreoverflow.xml b/res/drawable/ic_menu_moreoverflow.xml new file mode 100644 index 00000000..a79e6240 --- /dev/null +++ b/res/drawable/ic_menu_moreoverflow.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/res/drawable/ic_menu_search.xml b/res/drawable/ic_menu_search.xml new file mode 100644 index 00000000..8969a94a --- /dev/null +++ b/res/drawable/ic_menu_search.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/res/drawable/unbound_ripple_light.xml b/res/drawable/unbound_ripple_light.xml new file mode 100644 index 00000000..d1cf7a2a --- /dev/null +++ b/res/drawable/unbound_ripple_light.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/res/layout/actionbar_controls.xml b/res/layout/actionbar_controls.xml deleted file mode 100644 index 421634b7..00000000 --- a/res/layout/actionbar_controls.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - diff --git a/res/layout/bottombar_controls.xml b/res/layout/bottombar_controls.xml new file mode 100644 index 00000000..6b45fa82 --- /dev/null +++ b/res/layout/bottombar_controls.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/layout/library_content.xml b/res/layout/library_content.xml index 104852e9..4300f8a0 100644 --- a/res/layout/library_content.xml +++ b/res/layout/library_content.xml @@ -31,6 +31,7 @@ THE SOFTWARE. android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" + android:elevation="4dp" android:background="@color/tabs_background" /> + diff --git a/res/values-v21/colors.xml b/res/values-v21/colors.xml index d6c8ebdd..f86ed35f 100644 --- a/res/values-v21/colors.xml +++ b/res/values-v21/colors.xml @@ -23,7 +23,7 @@ @color/vanillaPrimary - @android:color/primary_text_dark + @android:color/background_light #ffeeeeee diff --git a/res/values-v21/theme.xml b/res/values-v21/theme.xml index 4240a4f2..2d19c4f0 100644 --- a/res/values-v21/theme.xml +++ b/res/values-v21/theme.xml @@ -39,7 +39,8 @@ Copyright (C) 2015 Adrian Ulrich @@ -48,11 +49,6 @@ Copyright (C) 2015 Adrian Ulrich @color/vanillaPrimary - - diff --git a/res/values/theme.xml b/res/values/theme.xml index b02f6eb1..dbf8f759 100644 --- a/res/values/theme.xml +++ b/res/values/theme.xml @@ -46,10 +46,8 @@ THE SOFTWARE. showTitle|homeAsUp - diff --git a/src/android/support/iosched/tabs/VanillaTabLayout.java b/src/android/support/iosched/tabs/VanillaTabLayout.java index b4294efc..2706c666 100644 --- a/src/android/support/iosched/tabs/VanillaTabLayout.java +++ b/src/android/support/iosched/tabs/VanillaTabLayout.java @@ -23,8 +23,6 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.widget.TextView; -import android.os.Build; - /** * Simple wrapper for SlidingTabLayout which takes * care of setting sane per-platform defaults @@ -52,26 +50,11 @@ public class VanillaTabLayout extends SlidingTabLayout { protected TextView createDefaultTabView(Context context) { TextView view = super.createDefaultTabView(context); view.setTextColor(getResources().getColorStateList(ch.blinkenlights.android.vanilla.R.color.tab_text_selector)); + view.setBackgroundResource(ch.blinkenlights.android.vanilla.R.drawable.unbound_ripple_light); view.setMaxLines(1); view.setEllipsize(TextUtils.TruncateAt.END); view.setTextSize(14); return view; } - /** - * Borrow elevation of given action bar - * - * @param ab The active action bar - */ - public void inheritElevation(ActionBar ab) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) - return; // noop on earlier releases - - float elevation = ab.getElevation(); - ab.setElevation(0.0f); - setElevation(elevation); - } - - - } diff --git a/src/ch/blinkenlights/android/vanilla/ActionBarControls.java b/src/ch/blinkenlights/android/vanilla/ActionBarControls.java deleted file mode 100644 index 3944c3ad..00000000 --- a/src/ch/blinkenlights/android/vanilla/ActionBarControls.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2015 Adrian Ulrich - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package ch.blinkenlights.android.vanilla; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.LinearLayout; -import android.os.Build; -import android.util.DisplayMetrics; - -/** - * LinearLayout that contains some hacks for sizing inside an ActionBar. - */ -public class ActionBarControls extends LinearLayout { - - private final int dpiElementLp = 52; // Size of the ActionBarSearch icon in 5.x (50 + some slack) - private final int dpiElementHolo = 64; // Size of the ActionBarSearch icon in HOLO - private final int dpiMaxWidth = 350; // Never use more then 350 DPIs - private final int visibleElements = 2; // The ActionBarSearch + Menu icons are visible - - public ActionBarControls(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void onMeasure(int ws, int hs) { - super.onMeasure(ws, hs); - - final float density = getResources().getDisplayMetrics().density; - final int dpiElement = ( android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? dpiElementLp : dpiElementHolo ); - int widthMode = MeasureSpec.getMode(ws); - - if (widthMode != MeasureSpec.EXACTLY) { - float dpiAvailable = (getSmallestAxisPx() / density) - (dpiElement * visibleElements); - if (dpiAvailable > dpiMaxWidth || dpiAvailable < 1) { - dpiAvailable = dpiMaxWidth; - } - setMeasuredDimension((int)(dpiAvailable * density), (int)(dpiElement * density)); - } - } - - /** - * Returns the smaller axis of the display dimensions - * @return The dimension of the smaller axis in pixels - */ - private final int getSmallestAxisPx() { - DisplayMetrics metrics = getResources().getDisplayMetrics(); - return (metrics.widthPixels > metrics.heightPixels ? metrics.heightPixels : metrics.widthPixels); - } - -} diff --git a/src/ch/blinkenlights/android/vanilla/BottomBarControls.java b/src/ch/blinkenlights/android/vanilla/BottomBarControls.java new file mode 100644 index 00000000..3721b9c0 --- /dev/null +++ b/src/ch/blinkenlights/android/vanilla/BottomBarControls.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2016 Adrian Ulrich + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package ch.blinkenlights.android.vanilla; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.graphics.Bitmap; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.PopupMenu; +import android.widget.SearchView; +import android.widget.TextView; + + +public class BottomBarControls extends LinearLayout + implements View.OnClickListener + , PopupMenu.OnMenuItemClickListener + { + /** + * The application context + */ + private final Context mContext; + /** + * The title of the currently playing song + */ + private TextView mTitle; + /** + * The artist of the currently playing song + */ + private TextView mArtist; + /** + * Cover image + */ + private ImageView mCover; + /** + * A layout hosting the song information + */ + private LinearLayout mControlsContent; + /** + * Standard android search view + */ + private SearchView mSearchView; + /** + * ControlsContent click consumer, may be null + */ + private View.OnClickListener mParentClickConsumer; + /** + * Owner of our options menu and consumer of clicks + */ + private Activity mParentMenuConsumer; + + + public BottomBarControls(Context context, AttributeSet attrs) { + super(context, attrs); + mContext = context; + } + + @Override + public void onFinishInflate() { + mTitle = (TextView)findViewById(R.id.title); + mArtist = (TextView)findViewById(R.id.artist); + mCover = (ImageView)findViewById(R.id.cover); + mSearchView = (SearchView)findViewById(R.id.search_view); + mControlsContent = (LinearLayout)findViewById(R.id.content_controls); + + styleSearchView(mSearchView, mContext.getResources().getColor(android.R.color.background_light)); + + super.onFinishInflate(); + } + + @Override + public void onClick(View view) { + Object tag = view.getTag(); + if (tag instanceof PopupMenu) { + ((PopupMenu)tag).show(); + } else if (tag instanceof MenuItem) { + mParentMenuConsumer.onOptionsItemSelected((MenuItem)tag); + } else if (view == mControlsContent && mParentClickConsumer != null) { + // dispatch this click to parent, claiming it came from + // the top view (= this) + mParentClickConsumer.onClick(this); + } + } + + @Override + public boolean onMenuItemClick(MenuItem item) { + return mParentMenuConsumer.onOptionsItemSelected(item); + } + + @Override + public Parcelable onSaveInstanceState() { + // Forcefully hide (and clear) search as we are not going to restore the state + showSearch(false); + return super.onSaveInstanceState(); + } + + /** + * Sets the ControlsContent to be clickable + */ + public void setOnClickListener(View.OnClickListener listener) { + mParentClickConsumer = listener; + mControlsContent.setOnClickListener(this); + } + + /** + * Configures a query text listener for the search view + */ + public void setOnQueryTextListener(SearchView.OnQueryTextListener owner) { + mSearchView.setOnQueryTextListener(owner); + } + + /** + * Boots the options menu + * + * @param owner the activity who will receive our callbacks + */ + public void enableOptionsMenu(Activity owner) { + mParentMenuConsumer = owner; + + ImageButton menuButton = getImageButton(getResources().getDrawable(R.drawable.ic_menu_moreoverflow)); + PopupMenu popupMenu = (menuMargin() ? new PopupMenu(mContext, menuButton, Gravity.RIGHT) : new PopupMenu(mContext, menuButton)); + popupMenu.setOnMenuItemClickListener(this); + + // Let parent populate the menu + mParentMenuConsumer.onCreateOptionsMenu(popupMenu.getMenu()); + + // The menu is now ready, we an now add all invisible + // items to the toolbar + Menu menu = popupMenu.getMenu(); + for (int i=0; i < menu.size(); i++) { + MenuItem menuItem = menu.getItem(i); + if (menuItem.isVisible() == false) { + ImageButton button = getImageButton(menuItem.getIcon()); + button.setTag(menuItem); + button.setOnClickListener(this); + mControlsContent.addView(button, -1); + } + } + + // Add menu button at end of view + menuButton.setTag(popupMenu); + menuButton.setOnClickListener(this); + mControlsContent.addView(menuButton, -1); + } + + /** + * Opens the OptionsMenu of this view + */ + public void openMenu() { + // simulates a click on the rightmost child which should be the options menu + mControlsContent.getChildAt(mControlsContent.getChildCount()-1).performClick(); + } + + /** + * Sets the search view to given state + * + * @param visible enables or disables the search box visibility + * @return boolean old state + */ + public boolean showSearch(boolean visible) { + boolean wasVisible = mSearchView.getVisibility() == View.VISIBLE; + if (wasVisible != visible) { + mSearchView.setVisibility(visible ? View.VISIBLE : View.GONE); + mControlsContent.setVisibility(visible ? View.GONE : View.VISIBLE); + if (visible) + mSearchView.setIconified(false); // requests focus AND shows the soft keyboard even if the view already was expanded + else + mSearchView.setQuery("", false); + } + return wasVisible; + } + + /** + * Updates the cover image of this view + * + * @param cover the bitmap to display. Will use a placeholder image if cover is null + */ + public void setCover(Bitmap cover) { + if (cover == null) + mCover.setImageResource(R.drawable.fallback_cover); + else + mCover.setImageBitmap(cover); + } + + /** + * Updates the song metadata + * + * @param song the song info to display, may be null + */ + public void setSong(Song song) { + if (song == null) { + mTitle.setText(null); + mArtist.setText(null); + mCover.setImageBitmap(null); + } else { + Resources res = mContext.getResources(); + String title = song.title == null ? res.getString(R.string.unknown) : song.title; + String artist = song.artist == null ? res.getString(R.string.unknown) : song.artist; + mTitle.setText(title); + mArtist.setText(artist); + } + } + + /** + * Returns a new image button to be placed on the bar + * + * @param drawable The icon to use + */ + private ImageButton getImageButton(Drawable drawable) { + + ImageButton button = new ImageButton(mContext); + button.setImageDrawable(drawable); + button.setBackgroundResource(R.drawable.unbound_ripple_light); + + if (menuMargin()) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + params.rightMargin = (int)(getResources().getDisplayMetrics().density * 4.0f); + button.setLayoutParams(params); + } + return button; + } + + /** + * Changing the colors of a search view is a MAJOR pain using XML + * This cheap trick just loop trough the view and changes the + * color of all text- and image views to 'style' + * + * @param view the view to search + * @param color the color to apply + */ + private void styleSearchView(View view, int color) { + if (view != null) { + if (view instanceof TextView) { + ((TextView)view).setTextColor(color); + } else if (view instanceof ImageView) { + ((ImageView)view).setColorFilter(color); + } else if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup)view; + for (int i=0; i< group.getChildCount(); i++) { + styleSearchView(group.getChildAt(i), color); + } + } + } + } + + /** + * Returns true if we need to add a margin to the menu. + * Because ...reasons. + */ + private boolean menuMargin() { + return ThemeHelper.usesHoloTheme() == false; + } +} diff --git a/src/ch/blinkenlights/android/vanilla/LibraryActivity.java b/src/ch/blinkenlights/android/vanilla/LibraryActivity.java index a4ecb57f..bfc5c382 100644 --- a/src/ch/blinkenlights/android/vanilla/LibraryActivity.java +++ b/src/ch/blinkenlights/android/vanilla/LibraryActivity.java @@ -129,12 +129,8 @@ public class LibraryActivity public ViewPager mViewPager; - private View mActionControls; - private TextView mTitle; - private TextView mArtist; - private ImageView mCover; + private BottomBarControls mBottomBarControls; private View mPermissionRequest; - private MenuItem mSearchMenuItem; private HorizontalScrollView mLimiterScroller; private ViewGroup mLimiterViews; @@ -186,12 +182,10 @@ public class LibraryActivity SharedPreferences settings = PlaybackService.getSettings(this); - View controls = getLayoutInflater().inflate(R.layout.actionbar_controls, null); - mTitle = (TextView)controls.findViewById(R.id.title); - mArtist = (TextView)controls.findViewById(R.id.artist); - mCover = (ImageView)controls.findViewById(R.id.cover); - controls.setOnClickListener(this); - mActionControls = controls; + mBottomBarControls = (BottomBarControls)findViewById(R.id.bottombar_controls); + mBottomBarControls.setOnClickListener(this); + mBottomBarControls.setOnQueryTextListener(this); + mBottomBarControls.enableOptionsMenu(this); mPermissionRequest = (View)findViewById(R.id.permission_request); @@ -202,7 +196,6 @@ public class LibraryActivity } mVanillaTabLayout = (VanillaTabLayout)findViewById(R.id.sliding_tabs); - mVanillaTabLayout.inheritElevation(getActionBar()); mVanillaTabLayout.setOnPageChangeListener(pagerAdapter); loadTabOrder(); @@ -291,17 +284,9 @@ public class LibraryActivity switch (keyCode) { case KeyEvent.KEYCODE_BACK: Limiter limiter = mPagerAdapter.getCurrentLimiter(); - MenuItem menu_item = mSearchMenuItem; - if (menu_item != null) { - // Check if we can collapse the search view - // if we can, then it was open and we handled this - // action - boolean did_collapse = menu_item.collapseActionView(); - if (did_collapse == true) { - break; - } - } + if (mBottomBarControls.showSearch(false)) + break; if (limiter != null) { int pos = -1; @@ -336,6 +321,10 @@ public class LibraryActivity finish(); } break; + case KeyEvent.KEYCODE_MENU: + // We intercept these to avoid showing the activity-default menu + mBottomBarControls.openMenu(); + break; default: return false; } @@ -522,10 +511,7 @@ public class LibraryActivity runOnUiThread(new Runnable() { @Override public void run() { - if (cover == null) - mCover.setImageResource(R.drawable.fallback_cover); - else - mCover.setImageBitmap(cover); + mBottomBarControls.setCover(cover); } }); } @@ -533,7 +519,7 @@ public class LibraryActivity @Override public void onClick(View view) { - if (view == mCover || view == mActionControls) { + if (view == mBottomBarControls) { openPlaybackActivity(); } else if (view == mPermissionRequest) { PermissionRequestActivity.requestPermissions(this, getIntent()); @@ -811,25 +797,12 @@ public class LibraryActivity @Override public boolean onCreateOptionsMenu(Menu menu) { - MenuItem controls = menu.add(0, MENU_PLAYBACK, 0, R.string.playback_view); - controls.setActionView(mActionControls); - controls.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - - // Call super after adding the now-playing view as this should be the first item + // called before super to have it on top + menu.add(0, MENU_PLAYBACK, 0, R.string.playback_view); super.onCreateOptionsMenu(menu); - // Check if we're running on Android 5.0 or higher - if (ThemeHelper.usesHoloTheme()) { - // Keep using the old icon - mSearchMenuItem = menu.add(0, MENU_SEARCH, 0, R.string.search).setIcon(R.drawable.ic_menu_search); - } else { - // Use the new material search icon - mSearchMenuItem = menu.add(0, MENU_SEARCH, 0, R.string.search).setIcon(R.drawable.ic_action_search); - } - mSearchMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItem.SHOW_AS_ACTION_ALWAYS); - SearchView mSearchView = new SearchView(getActionBar().getThemedContext()); - mSearchView.setOnQueryTextListener(this); - mSearchMenuItem.setActionView(mSearchView); + MenuItem search = menu.add(0, MENU_SEARCH, 0, R.string.search).setIcon(R.drawable.ic_menu_search); + search.setVisible(false); menu.add(0, MENU_SORT, 0, R.string.sort_by).setIcon(R.drawable.ic_menu_sort_alphabetically); menu.add(0, MENU_SHOW_QUEUE, 0, R.string.show_queue); @@ -850,7 +823,7 @@ public class LibraryActivity { switch (item.getItemId()) { case MENU_SEARCH: - // this does nothing: expanding ishandled by mSearchView + mBottomBarControls.showSearch(true); return true; case MENU_PLAYBACK: openPlaybackActivity(); @@ -963,22 +936,9 @@ public class LibraryActivity { super.onSongChange(song); - if (mTitle != null) { - if (song == null) { - mTitle.setText(null); - mArtist.setText(null); - mCover.setImageBitmap(null); - } else { - Resources res = getResources(); - String title = song.title == null ? res.getString(R.string.unknown) : song.title; - String artist = song.artist == null ? res.getString(R.string.unknown) : song.artist; - mTitle.setText(title); - mArtist.setText(artist); - // Update and generate the cover in a background thread - mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_COVER, song)); - } - mCover.setVisibility(CoverCache.mCoverLoadMode == 0 ? View.GONE : View.VISIBLE); - } + mBottomBarControls.setSong(song); + if (song != null) + mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_COVER, song)); } @Override