Add a Jump to Time dialog (#868)
* Add a Jump to Time dialog This implements #827 by adding a context menu entry to open a dialog that allows the user to input a time/position to seek to for the current song. * Use callback interface for JumpToTimeDialog position submission * Automatically show soft keyboard for JumpToTimeDialog * Automatically move to next EditText in JumpToTimeDialog * Crash if JumpToTimeDialog is started by wrong activity
This commit is contained in:
parent
c112925890
commit
d00b3e4769
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Toby Hsieh
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ch.blinkenlights.android.vanilla;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* A dialog for the user to input a specific time to jump to for the current song
|
||||
*/
|
||||
public class JumpToTimeDialog extends DialogFragment implements DialogInterface.OnClickListener {
|
||||
private EditText hoursView;
|
||||
private EditText minutesView;
|
||||
private EditText secondsView;
|
||||
|
||||
/**
|
||||
* Callback interface for an activity that shows JumpToTimeDialog
|
||||
*/
|
||||
public interface OnPositionSubmitListener {
|
||||
/**
|
||||
* Called when the user submits a position to jump/seek to for the current song.
|
||||
*
|
||||
* @param position position to seek/jump to in milliseconds
|
||||
*/
|
||||
void onPositionSubmit(int position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and shows the dialog
|
||||
*
|
||||
* @param manager the FragmentManager to add the newly created dialog to
|
||||
*/
|
||||
public static void show(FragmentManager manager) {
|
||||
new JumpToTimeDialog().show(manager, "JumpToTimeDialog");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// Watcher that moves to the next EditText when 2 digits are inserted
|
||||
TextWatcher textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
EditText editText = (EditText) getDialog().getCurrentFocus();
|
||||
if (editText.length() == 2) {
|
||||
View view = editText.focusSearch(View.FOCUS_RIGHT);
|
||||
if (view != null) {
|
||||
view.requestFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
};
|
||||
|
||||
View view = LayoutInflater.from(getActivity()).inflate(R.layout.duration_input, null);
|
||||
hoursView = view.findViewById(R.id.hours);
|
||||
hoursView.addTextChangedListener(textWatcher);
|
||||
minutesView = view.findViewById(R.id.minutes);
|
||||
minutesView.addTextChangedListener(textWatcher);
|
||||
secondsView = view.findViewById(R.id.seconds);
|
||||
secondsView.addTextChangedListener(textWatcher);
|
||||
|
||||
Dialog dialog = new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.jump_to_time)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, this)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
hoursView.requestFocus();
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
Activity activity = getActivity();
|
||||
try {
|
||||
int hours = parseInteger(hoursView.getText().toString());
|
||||
int minutes = parseInteger(minutesView.getText().toString());
|
||||
int seconds = parseInteger(secondsView.getText().toString());
|
||||
int position = (hours * 3600 + minutes * 60 + seconds) * 1000;
|
||||
((OnPositionSubmitListener) activity).onPositionSubmit(position);
|
||||
} catch (NumberFormatException e) {
|
||||
Toast.makeText(activity, R.string.error_invalid_position, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given string as an integer. This returns 0 if the given string is empty.
|
||||
*
|
||||
* @param s the string to parse
|
||||
* @return the integer result
|
||||
*/
|
||||
static int parseInteger(String s) {
|
||||
if (s.length() == 0) {
|
||||
return 0;
|
||||
}
|
||||
return Integer.parseInt(s);
|
||||
}
|
||||
}
|
@ -430,6 +430,7 @@ public abstract class PlaybackActivity extends Activity
|
||||
static final int MENU_MORE_ARTIST = 23;
|
||||
static final int MENU_MORE_GENRE = 24;
|
||||
static final int MENU_MORE_FOLDER = 25;
|
||||
static final int MENU_JUMP_TO_TIME = 26;
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
|
@ -1737,7 +1737,19 @@ public final class PlaybackService extends Service
|
||||
if (!mMediaPlayerInitialized)
|
||||
return;
|
||||
long position = (long)mMediaPlayer.getDuration() * progress / 1000;
|
||||
mMediaPlayer.seekTo((int)position);
|
||||
seekToPosition((int) position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks to the given position in the current song.
|
||||
*
|
||||
* @param msec the offset in milliseconds from the start to seek to
|
||||
*/
|
||||
public void seekToPosition(int msec) {
|
||||
if (!mMediaPlayerInitialized) {
|
||||
return;
|
||||
}
|
||||
mMediaPlayer.seekTo(msec);
|
||||
mHandler.sendEmptyMessage(MSG_BROADCAST_SEEK);
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,8 @@ import java.net.InetAddress;
|
||||
public class SlidingPlaybackActivity extends PlaybackActivity
|
||||
implements SlidingView.Callback,
|
||||
SeekBar.OnSeekBarChangeListener,
|
||||
PlaylistDialog.Callback
|
||||
PlaylistDialog.Callback,
|
||||
JumpToTimeDialog.OnPositionSubmitListener
|
||||
{
|
||||
/**
|
||||
* Reference to the inflated menu
|
||||
@ -127,6 +128,7 @@ public class SlidingPlaybackActivity extends PlaybackActivity
|
||||
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, 20, R.string.save_as_playlist);
|
||||
menu.add(0, MENU_JUMP_TO_TIME, 20, R.string.jump_to_time);
|
||||
// This should only be required on ICS.
|
||||
onSlideExpansionChanged(SlidingView.EXPANSION_PARTIAL);
|
||||
return true;
|
||||
@ -147,6 +149,9 @@ public class SlidingPlaybackActivity extends PlaybackActivity
|
||||
PlaylistDialog dialog = PlaylistDialog.newInstance(this, null, null);
|
||||
dialog.show(getFragmentManager(), "PlaylistDialog");
|
||||
break;
|
||||
case MENU_JUMP_TO_TIME:
|
||||
JumpToTimeDialog.show(getFragmentManager());
|
||||
break;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
@ -336,4 +341,9 @@ public class SlidingPlaybackActivity extends PlaybackActivity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionSubmit(int position) {
|
||||
PlaybackService.get(this).seekToPosition(position);
|
||||
updateElapsedTime();
|
||||
}
|
||||
}
|
||||
|
59
app/src/main/res/layout/duration_input.xml
Normal file
59
app/src/main/res/layout/duration_input.xml
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 Toby Hsieh
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/hours"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:maxLength="2"
|
||||
android:hint="@string/hour_hint" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/time_separator"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/minutes"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:maxLength="2"
|
||||
android:hint="@string/minute_hint" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/time_separator"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/seconds"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:maxLength="2"
|
||||
android:hint="@string/second_hint" />
|
||||
|
||||
</LinearLayout>
|
@ -329,6 +329,13 @@ THE SOFTWARE.
|
||||
<string name="preferences_action_enqueue_current_artist">Enqueue artist</string>
|
||||
<string name="preferences_action_enqueue_current_genre">Enqueue genre</string>
|
||||
|
||||
<string name="jump_to_time">Jump to Time</string>
|
||||
<string name="time_separator">:</string>
|
||||
<string name="hour_hint">HH</string>
|
||||
<string name="minute_hint">MM</string>
|
||||
<string name="second_hint">SS</string>
|
||||
<string name="error_invalid_position">Invalid position</string>
|
||||
|
||||
<string name="filebrowser_start">Filebrowser home</string>
|
||||
<string name="customize_filebrowser_start">Filebrowser starts at this directory</string>
|
||||
<string name="select">Select</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user