Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworked sleep timer #934

Open
wants to merge 3 commits into
base: edge
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.concurrent.TimeUnit;

import android.annotation.TargetApi;
import android.app.TimePickerDialog;
import android.support.v7.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
Expand Down Expand Up @@ -54,6 +55,8 @@
import android.widget.PopupMenu;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import android.widget.ViewFlipper;
import com.shehabic.droppy.DroppyClickCallbackInterface;
import com.shehabic.droppy.DroppyMenuPopup;
Expand Down Expand Up @@ -462,11 +465,14 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
} else {
menuInflater.inflate(R.menu.nowplaying, menu);
}
if(downloadService != null && downloadService.getSleepTimer()) {
int timeRemaining = downloadService.getSleepTimeRemaining();
if (downloadService != null) {
timerMenu = menu.findItem(R.id.menu_toggle_timer);
if(timeRemaining > 1){
timerMenu.setTitle(context.getResources().getString(R.string.download_stop_time_remaining, Util.formatDuration(timeRemaining)));
if (downloadService.getSleepTimer()) {
int timeRemaining = downloadService.getSleepTimeRemaining();
if (timeRemaining > 1)
timerMenu.setTitle(context.getResources().getString(R.string.download_stop_time_remaining, Util.formatDuration(timeRemaining)));
} else if (downloadService.getSleepTimerEndOfTrack()) {
timerMenu.setTitle(R.string.download_stop_at_end_of_track);
} else {
timerMenu.setTitle(R.string.menu_set_timer);
}
Expand Down Expand Up @@ -686,11 +692,11 @@ protected void done(Void result) {
UpdateHelper.setRating(context, song.getSong());
return true;
case R.id.menu_toggle_timer:
if(getDownloadService().getSleepTimer()) {
if(getDownloadService().getSleepTimer() || getDownloadService().getSleepTimerEndOfTrack()) {
getDownloadService().stopSleepTimer();
context.supportInvalidateOptionsMenu();
context.invalidateOptionsMenu();
} else {
startTimer();
startTimerDialog();
}
return true;
case R.id.menu_info:
Expand Down Expand Up @@ -913,72 +919,74 @@ private void update() {
}
}

protected void startTimer() {
View dialogView = context.getLayoutInflater().inflate(R.layout.start_timer, null);
protected void startTimerDialog() {
// Create list of common times
String[] timerOptions = {"5 minutes", "10 minutes", "15 minutes",
"30 minutes", "1 hour", "End of track", "Custom length"};

// Set up alert dialog builder
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.menu_set_timer)
.setNegativeButton(R.string.common_cancel, null)
.setItems(timerOptions, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int chosenOption) {
switch (chosenOption) {
// All options are in minutes, but pass length of milliseconds
// so multiply (minutes * 60 seconds * 1000 milliseconds)
case 0: startTimer(300000); break;
case 1: startTimer(600000); break;
case 2: startTimer(900000); break;
case 3: startTimer(1800000); break;
case 4: startTimer(3600000); break;
case 5: getDownloadService().setSleepTimerEndOfTrack(); break;
case 6: startCustomTimerDialog();
}
context.invalidateOptionsMenu();
}
}).create();

// Setup length label
final TextView lengthBox = (TextView) dialogView.findViewById(R.id.timer_length_label);
// Create and show list dialog
AlertDialog dialog = builder.create();
dialog.show();
}

protected void startCustomTimerDialog() {
// Retrieve previous custom time
final SharedPreferences prefs = Util.getPreferences(context);
String lengthString = prefs.getString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, "5");
int length = Integer.parseInt(lengthString);
lengthBox.setText(Util.formatDuration(length));

// Setup length slider
final SeekBar lengthBar = (SeekBar) dialogView.findViewById(R.id.timer_length_bar);
lengthBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
int length = getMinutes(progress);
lengthBox.setText(Util.formatDuration(length));
seekBar.setProgress(progress);
}
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
// Create TimePicker dialog
TimePickerDialog timePicker = new TimePickerDialog(context,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker timePicker, int i, int i1) {
// Parse length from dialog
int length = (timePicker.getCurrentHour() * 60) + timePicker.getCurrentMinute();

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
lengthBar.setProgress(length - 1);
// Store custom length preference
SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, Integer.toString(length));
editor.commit();

AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.menu_set_timer)
.setView(dialogView)
.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
int length = getMinutes(lengthBar.getProgress());
// Start timer
// length is in milliseconds so multiply (minutes * 60 seconds * 1000 milliseconds)
startTimer(length * 60000);

SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, Integer.toString(length));
editor.commit();
context.invalidateOptionsMenu();
}
},
0, 5, true);

getDownloadService().setSleepTimerDuration(length);
getDownloadService().startSleepTimer();
context.supportInvalidateOptionsMenu();
}
})
.setNegativeButton(R.string.common_cancel, null);
AlertDialog dialog = builder.create();
dialog.show();
timePicker.setTitle(R.string.menu_set_timer);
timePicker.updateTime((length/60),(length%60));
timePicker.show();
}

private int getMinutes(int progress) {
if(progress < 30) {
return progress + 1;
} else if(progress < 49) {
return (progress - 30) * 5 + getMinutes(29);
} else if(progress < 57) {
return (progress - 48) * 30 + getMinutes(48);
} else if(progress < 81) {
return (progress - 56) * 60 + getMinutes(56);
} else {
return (progress - 80) * 150 + getMinutes(80);
}
protected void startTimer(int length) {
getDownloadService().setSleepTimerDuration(length);
getDownloadService().startSleepTimer();
}

private void toggleFullscreenAlbumArt() {
Expand Down Expand Up @@ -1411,6 +1419,9 @@ public void onStateUpdate(DownloadFile downloadFile, PlayerState playerState) {
startButton.setVisibility(View.VISIBLE);
break;
}

// Reset options menu if sleep timer finished so text updates next time it's opened
context.invalidateOptionsMenu();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ public class DownloadService extends Service {
private Timer sleepTimer;
private int timerDuration;
private long timerStart;
private boolean stopAtEndOfTrack = false;
private boolean autoPlayStart = false;
private boolean runListenersOnInit = false;

Expand Down Expand Up @@ -951,7 +952,7 @@ synchronized void setNextPlaying() {
}
resetNext();

if(index < size() && index != -1 && index != currentPlayingIndex) {
if(index < size() && index != -1 && index != currentPlayingIndex && !stopAtEndOfTrack) {
nextPlaying = downloadList.get(index);

if(remoteState == LOCAL) {
Expand Down Expand Up @@ -1989,14 +1990,17 @@ public void onPrepared(MediaPlayer mediaPlayer) {

applyReplayGain(mediaPlayer, downloadFile);

if (start || autoPlayStart) {
if ((!stopAtEndOfTrack) && (start || autoPlayStart)) {
mediaPlayer.start();
applyPlaybackParamsMain();
setPlayerState(STARTED);

// Disable autoPlayStart after done
autoPlayStart = false;
} else {
if (stopAtEndOfTrack) {
stopSleepTimer();
}
setPlayerState(PAUSED);
onSongProgress();
}
Expand Down Expand Up @@ -2133,6 +2137,11 @@ public void setSleepTimerDuration(int duration){
timerDuration = duration;
}

public void setSleepTimerEndOfTrack() {
stopAtEndOfTrack = true;
setNextPlaying(); // Clear next playing state gracefully
}

public void startSleepTimer(){
if(sleepTimer != null){
sleepTimer.cancel();
Expand All @@ -2150,26 +2159,33 @@ public void run() {
sleepTimer = null;
}

}, timerDuration * 60 * 1000);
}, timerDuration);
timerStart = System.currentTimeMillis();
}

public int getSleepTimeRemaining() {
return (int) (timerStart + (timerDuration * 60 * 1000) - System.currentTimeMillis()) / 1000;
return (int) (timerStart + timerDuration - System.currentTimeMillis()) / 1000;
}

public void stopSleepTimer() {
if(sleepTimer != null){
sleepTimer.cancel();
sleepTimer.purge();
sleepTimer = null;
} else if (stopAtEndOfTrack) {
stopAtEndOfTrack = false;
setNextPlaying(); // Reset next playing state
}
sleepTimer = null;
}

public boolean getSleepTimer() {
return sleepTimer != null;
}

public boolean getSleepTimerEndOfTrack() {
return stopAtEndOfTrack;
}

public void setVolume(float volume) {
if(mediaPlayer != null && (playerState == STARTED || playerState == PAUSED || playerState == STOPPED)) {
try {
Expand Down
22 changes: 0 additions & 22 deletions app/src/main/res/layout/start_timer.xml

This file was deleted.

5 changes: 5 additions & 0 deletions app/src/main/res/values-v21/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,9 @@
<style name="NotificationDivider">
<item name="android:background">@drawable/notification_divider</item>
</style>

<style name="TimePickerDialogStyle" parent="Theme.AppCompat.Dialog">
<item name="android:timePickerMode">spinner</item>
</style>

</resources>
21 changes: 21 additions & 0 deletions app/src/main/res/values-v21/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
<resources>
<style name="Theme.DSub.Light" parent="Theme.DSub.Light.Base">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:timePickerDialogTheme">@style/Theme.DSub.Light.TimePickerDialog</item>
</style>

<style name="Theme.DSub.Dark" parent="Theme.DSub.Dark.Base">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:timePickerDialogTheme">@style/Theme.DSub.Dark.TimePickerDialog</item>
</style>
<style name="Theme.DSub.Black" parent="Theme.DSub.Black.Base">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:timePickerDialogTheme">@style/Theme.DSub.Black.TimePickerDialog</item>
</style>
<style name="Theme.DSub.Holo" parent="Theme.DSub.Holo.Base">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:timePickerDialogTheme">@style/Theme.DSub.Holo.TimePickerDialog</item>
</style>

<style name="Theme.DSub.Light.No_Color" parent="Theme.DSub.Light.No_Color.Base">
Expand All @@ -30,4 +34,21 @@
<item name="android:windowTranslucentStatus">false</item>
<item name="android:statusBarColor">@android:color/black</item>
</style>

<style name="Theme.DSub.Light.TimePickerDialog" parent="Theme.DSub.Light.Base">
<item name="android:timePickerStyle">@style/TimePickerDialogStyle</item>
<item name="android:windowIsFloating">true</item>
</style>
<style name="Theme.DSub.Dark.TimePickerDialog" parent="Theme.DSub.Dark.Base">
<item name="android:timePickerStyle">@style/TimePickerDialogStyle</item>
<item name="android:windowIsFloating">true</item>
</style>
<style name="Theme.DSub.Black.TimePickerDialog" parent="Theme.DSub.Black.Base">
<item name="android:timePickerStyle">@style/TimePickerDialogStyle</item>
<item name="android:windowIsFloating">true</item>
</style>
<style name="Theme.DSub.Holo.TimePickerDialog" parent="Theme.DSub.Holo.Base">
<item name="android:timePickerStyle">@style/TimePickerDialogStyle</item>
<item name="android:windowIsFloating">true</item>
</style>
</resources>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
<string name="download.jukebox_not_authorized">Remote control is not allowed. Please enable jukebox mode in <b>Users &gt; Settings</b> on your Subsonic server.</string>
<string name="download.start_timer">Start Timer</string>
<string name="download.stop_time_remaining">Stop in %1$s</string>
<string name="download.stop_at_end_of_track">Stop at end of track</string>
<string name="download.need_download">Video needs to be downloaded first</string>
<string name="download.no_streaming_player">No player can play this stream</string>
<string name="download.playing_out_of">Playing: %1$d/%2$d</string>
Expand Down