From 9e42e86296dc24aa987ddfe134fe76b664d3e5f4 Mon Sep 17 00:00:00 2001 From: Adrian Ulrich Date: Sat, 23 Apr 2016 08:47:40 +0200 Subject: [PATCH] Implement SlidingPlaybackActivity --- res/layout/library_content.xml | 33 +++ .../android/vanilla/FullPlaybackActivity.java | 141 +--------- .../android/vanilla/LibraryActivity.java | 8 +- .../android/vanilla/PlaybackActivity.java | 52 +--- .../vanilla/SlidingPlaybackActivity.java | 240 ++++++++++++++++++ 5 files changed, 291 insertions(+), 183 deletions(-) create mode 100644 src/ch/blinkenlights/android/vanilla/SlidingPlaybackActivity.java diff --git a/res/layout/library_content.xml b/res/layout/library_content.xml index e067bb09..e9267071 100644 --- a/res/layout/library_content.xml +++ b/res/layout/library_content.xml @@ -66,6 +66,39 @@ THE SOFTWARE. android:orientation="horizontal"> + + + + + + + + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ch.blinkenlights.android.vanilla; + +import android.text.format.DateUtils; +import android.os.Message; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.SeekBar; +import android.widget.TextView; + +public class SlidingPlaybackActivity extends PlaybackActivity + implements SlidingView.Callback, + SeekBar.OnSeekBarChangeListener +{ + /** + * Reference to the inflated menu + */ + private Menu mMenu; + /** + * SeekBar widget + */ + private SeekBar mSeekBar; + /** + * TextView indicating the elapsed playback time + */ + private TextView mElapsedView; + /** + * TextView indicating the total duration of the song + */ + private TextView mDurationView; + /** + * Current song duration in milliseconds. + */ + private long mDuration; + /** + * True if user tracks/drags the seek bar + */ + private boolean mSeekBarTracking; + /** + * True if the seek bar should not get periodic updates + */ + private boolean mPaused; + /** + * Cached StringBuilder for formatting track position. + */ + private final StringBuilder mTimeBuilder = new StringBuilder(); + /** + * Instance of the sliding view + */ + protected SlidingView mSlidingView; + + @Override + protected void bindControlButtons() { + super.bindControlButtons(); + + mSlidingView = (SlidingView)findViewById(R.id.sliding_view); + mSlidingView.setCallback(this); + mElapsedView = (TextView)findViewById(R.id.elapsed); + mDurationView = (TextView)findViewById(R.id.duration); + mSeekBar = (SeekBar)findViewById(R.id.seek_bar); + mSeekBar.setMax(1000); + mSeekBar.setOnSeekBarChangeListener(this); + setDuration(0); + } + + @Override + public void onResume() { + super.onResume(); + mPaused = false; + updateElapsedTime(); + } + + @Override + public void onPause() { + super.onPause(); + mPaused = true; + } + + @Override + protected void onSongChange(Song song) { + setDuration(song == null ? 0 : song.duration); + updateElapsedTime(); + super.onSongChange(song); + } + + @Override + protected void onStateChange(int state, int toggled) { + updateElapsedTime(); + super.onStateChange(state, toggled); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + mMenu = menu; + menu.add(0, MENU_SHOW_QUEUE, 20, R.string.show_queue); + menu.add(0, MENU_HIDE_QUEUE, 20, R.string.hide_queue); + menu.add(0, MENU_CLEAR_QUEUE, 20, R.string.dequeue_rest); + menu.add(0, MENU_EMPTY_QUEUE, 20, R.string.empty_the_queue); + menu.add(0, MENU_SAVE_QUEUE_AS_PLAYLIST, 20, R.string.save_as_playlist); + onSlideFullyExpanded(false); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_SHOW_QUEUE: + mSlidingView.expandSlide(); + break; + case MENU_HIDE_QUEUE: + mSlidingView.hideSlide(); + break; + default: + return super.onOptionsItemSelected(item); + } + return true; + } + + /** + * Update the seekbar progress with the current song progress. This must be + * called on the UI Handler. + */ + private static final int MSG_UPDATE_PROGRESS = 20; + /** + * Calls {@link PlaybackService#seekToProgress(int)}. + */ + private static final int MSG_SEEK_TO_PROGRESS = 21; + @Override + public boolean handleMessage(Message message) + { + switch (message.what) { + case MSG_UPDATE_PROGRESS: + updateElapsedTime(); + break; + case MSG_SEEK_TO_PROGRESS: + PlaybackService.get(this).seekToProgress(message.arg1); + updateElapsedTime(); + break; + default: + return super.handleMessage(message); + } + return true; + } + + /** + * Update the current song duration fields. + * + * @param duration The new duration, in milliseconds. + */ + private void setDuration(long duration) { + mDuration = duration; + mDurationView.setText(DateUtils.formatElapsedTime(mTimeBuilder, duration / 1000)); + } + + /** + * Update seek bar progress and schedule another update in one second + */ + private void updateElapsedTime() { + long position = PlaybackService.hasInstance() ? PlaybackService.get(this).getPosition() : 0; + + if (!mSeekBarTracking) { + long duration = mDuration; + mSeekBar.setProgress(duration == 0 ? 0 : (int)(1000 * position / duration)); + } + + mElapsedView.setText(DateUtils.formatElapsedTime(mTimeBuilder, position / 1000)); + + if (!mPaused && (mState & PlaybackService.FLAG_PLAYING) != 0) { + // Try to update right after the duration increases by one second + long next = 1050 - position % 1000; + mUiHandler.removeMessages(MSG_UPDATE_PROGRESS); + mUiHandler.sendEmptyMessageDelayed(MSG_UPDATE_PROGRESS, next); + } + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + mElapsedView.setText(DateUtils.formatElapsedTime(mTimeBuilder, progress * mDuration / 1000000)); + mUiHandler.removeMessages(MSG_SEEK_TO_PROGRESS); + mUiHandler.sendMessageDelayed(mUiHandler.obtainMessage(MSG_SEEK_TO_PROGRESS, progress, 0), 150); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + mSeekBarTracking = true; + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + mSeekBarTracking = false; + } + + /** + * Called by SlidingView to signal a visibility change. + * Toggles the visibility of menu items + * + * @param expanded true if slide fully expanded + */ + @Override + public void onSlideFullyExpanded(boolean expanded) { + if (mMenu == null) + return; // not initialized yet + + final int[] slide_visible = {MENU_HIDE_QUEUE, MENU_CLEAR_QUEUE, MENU_EMPTY_QUEUE, MENU_SAVE_QUEUE_AS_PLAYLIST}; + final int[] slide_hidden = {MENU_SHOW_QUEUE, MENU_SORT, MENU_DELETE, MENU_ENQUEUE_ALBUM, MENU_ENQUEUE_ARTIST, MENU_ENQUEUE_GENRE}; + + for (int id : slide_visible) { + MenuItem item = mMenu.findItem(id); + if (item != null) + item.setVisible(expanded); + } + + for (int id : slide_hidden) { + MenuItem item = mMenu.findItem(id); + if (item != null) + item.setVisible(!expanded); + } + } + +}