summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authormueller-ma <mueller-ma@users.noreply.github.com>2023-04-15 21:08:03 +0200
committerGitHub <noreply@github.com>2023-04-15 21:08:03 +0200
commit0bdf9d9e28572bba38fd36ad518e817dbdd04fe5 (patch)
tree5711d01accb4b0d42815d2a6c51277e51aaca6ff /app
parent8396a346707677ce22373a96e905bb1763d5cfb9 (diff)
downloadAntennaPod-0bdf9d9e28572bba38fd36ad518e817dbdd04fe5.zip
Add option to enable sleep timer based on current time (#6384)
Diffstat (limited to 'app')
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/SleepTimerPreferencesTest.java22
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java66
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java187
-rw-r--r--app/src/main/res/layout/time_dialog.xml8
4 files changed, 274 insertions, 9 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/SleepTimerPreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/SleepTimerPreferencesTest.java
new file mode 100644
index 000000000..4339d6cd7
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/SleepTimerPreferencesTest.java
@@ -0,0 +1,22 @@
+package de.test.antennapod.service.playback;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
+
+public class SleepTimerPreferencesTest {
+ @Test
+ public void testIsInTimeRange() {
+ assertTrue(SleepTimerPreferences.isInTimeRange(0, 10, 8));
+ assertTrue(SleepTimerPreferences.isInTimeRange(1, 10, 8));
+ assertTrue(SleepTimerPreferences.isInTimeRange(1, 10, 1));
+ assertTrue(SleepTimerPreferences.isInTimeRange(20, 10, 8));
+ assertTrue(SleepTimerPreferences.isInTimeRange(20, 20, 8));
+ assertFalse(SleepTimerPreferences.isInTimeRange(1, 6, 8));
+ assertFalse(SleepTimerPreferences.isInTimeRange(1, 6, 6));
+ assertFalse(SleepTimerPreferences.isInTimeRange(20, 6, 8));
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
index 52e6f7807..ecbc1d873 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/SleepTimerDialog.java
@@ -4,6 +4,7 @@ import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
+import android.text.format.DateFormat;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
@@ -11,19 +12,25 @@ import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import androidx.annotation.NonNull;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import androidx.fragment.app.DialogFragment;
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.Locale;
+
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
+import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
public class SleepTimerDialog extends DialogFragment {
private PlaybackController controller;
@@ -31,6 +38,7 @@ public class SleepTimerDialog extends DialogFragment {
private LinearLayout timeSetup;
private LinearLayout timeDisplay;
private TextView time;
+ private CheckBox chAutoEnable;
public SleepTimerDialog() {
@@ -99,20 +107,38 @@ public class SleepTimerDialog extends DialogFragment {
imm.showSoftInput(etxtTime, InputMethodManager.SHOW_IMPLICIT);
}, 100);
- CheckBox cbShakeToReset = content.findViewById(R.id.cbShakeToReset);
- CheckBox cbVibrate = content.findViewById(R.id.cbVibrate);
- CheckBox chAutoEnable = content.findViewById(R.id.chAutoEnable);
+ final CheckBox cbShakeToReset = content.findViewById(R.id.cbShakeToReset);
+ final CheckBox cbVibrate = content.findViewById(R.id.cbVibrate);
+ chAutoEnable = content.findViewById(R.id.chAutoEnable);
+ final TextView changeTimesButton = content.findViewById(R.id.changeTimes);
cbShakeToReset.setChecked(SleepTimerPreferences.shakeToReset());
cbVibrate.setChecked(SleepTimerPreferences.vibrate());
chAutoEnable.setChecked(SleepTimerPreferences.autoEnable());
+ changeTimesButton.setEnabled(chAutoEnable.isChecked());
cbShakeToReset.setOnCheckedChangeListener((buttonView, isChecked)
-> SleepTimerPreferences.setShakeToReset(isChecked));
cbVibrate.setOnCheckedChangeListener((buttonView, isChecked)
-> SleepTimerPreferences.setVibrate(isChecked));
chAutoEnable.setOnCheckedChangeListener((compoundButton, isChecked)
- -> SleepTimerPreferences.setAutoEnable(isChecked));
+ -> {
+ SleepTimerPreferences.setAutoEnable(isChecked);
+ changeTimesButton.setEnabled(isChecked);
+ });
+ updateAutoEnableText();
+
+ changeTimesButton.setOnClickListener(changeTimesBtn -> {
+ int from = SleepTimerPreferences.autoEnableFrom();
+ int to = SleepTimerPreferences.autoEnableTo();
+ TimeRangeDialog dialog = new TimeRangeDialog(getContext(), from, to);
+ dialog.setOnDismissListener(v -> {
+ SleepTimerPreferences.setAutoEnableFrom(dialog.getFrom());
+ SleepTimerPreferences.setAutoEnableTo(dialog.getTo());
+ updateAutoEnableText();
+ });
+ dialog.show();
+ });
Button disableButton = content.findViewById(R.id.disableSleeptimerButton);
disableButton.setOnClickListener(v -> {
@@ -144,6 +170,28 @@ public class SleepTimerDialog extends DialogFragment {
return builder.create();
}
+ private void updateAutoEnableText() {
+ String text;
+ int from = SleepTimerPreferences.autoEnableFrom();
+ int to = SleepTimerPreferences.autoEnableTo();
+
+ if (from == to) {
+ text = getString(R.string.auto_enable_label);
+ } else if (DateFormat.is24HourFormat(getContext())) {
+ String formattedFrom = String.format(Locale.getDefault(), "%02d:00", from);
+ String formattedTo = String.format(Locale.getDefault(), "%02d:00", to);
+ text = getString(R.string.auto_enable_label_with_times, formattedFrom, formattedTo);
+ } else {
+ String formattedFrom = String.format(Locale.getDefault(), "%02d:00 %s",
+ from % 12, from >= 12 ? "PM" : "AM");
+ String formattedTo = String.format(Locale.getDefault(), "%02d:00 %s",
+ to % 12, to >= 12 ? "PM" : "AM");
+ text = getString(R.string.auto_enable_label_with_times, formattedFrom, formattedTo);
+
+ }
+ chAutoEnable.setText(text);
+ }
+
@Subscribe(threadMode = ThreadMode.MAIN)
@SuppressWarnings("unused")
public void timerUpdated(SleepTimerUpdatedEvent event) {
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java
new file mode 100644
index 000000000..85913043e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/TimeRangeDialog.java
@@ -0,0 +1,187 @@
+package de.danoeh.antennapod.dialog;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.text.format.DateFormat;
+import android.view.MotionEvent;
+import android.view.View;
+import androidx.annotation.NonNull;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.ui.common.ThemeUtils;
+
+import java.util.Locale;
+
+public class TimeRangeDialog extends MaterialAlertDialogBuilder {
+ private final TimeRangeView view;
+
+ public TimeRangeDialog(@NonNull Context context, int from, int to) {
+ super(context);
+ view = new TimeRangeView(context, from, to);
+ setView(view);
+ setPositiveButton(android.R.string.ok, null);
+ }
+
+ public int getFrom() {
+ return view.from;
+ }
+
+ public int getTo() {
+ return view.to;
+ }
+
+ static class TimeRangeView extends View {
+ private static final int DIAL_ALPHA = 120;
+ private final Paint paintDial = new Paint();
+ private final Paint paintSelected = new Paint();
+ private final Paint paintText = new Paint();
+ private int from;
+ private int to;
+ private final RectF bounds = new RectF();
+ int touching = 0;
+
+ public TimeRangeView(Context context) { // Used by Android tools
+ this(context, 0, 0);
+ }
+
+ public TimeRangeView(Context context, int from, int to) {
+ super(context);
+ this.from = from;
+ this.to = to;
+ setup();
+ }
+
+ private void setup() {
+ paintDial.setAntiAlias(true);
+ paintDial.setStyle(Paint.Style.STROKE);
+ paintDial.setStrokeCap(Paint.Cap.ROUND);
+ paintDial.setColor(ThemeUtils.getColorFromAttr(getContext(), android.R.attr.textColorPrimary));
+ paintDial.setAlpha(DIAL_ALPHA);
+
+ paintSelected.setAntiAlias(true);
+ paintSelected.setStyle(Paint.Style.STROKE);
+ paintSelected.setStrokeCap(Paint.Cap.ROUND);
+ paintSelected.setColor(ThemeUtils.getColorFromAttr(getContext(), R.attr.colorAccent));
+
+ paintText.setAntiAlias(true);
+ paintText.setStyle(Paint.Style.FILL);
+ paintText.setColor(ThemeUtils.getColorFromAttr(getContext(), android.R.attr.textColorPrimary));
+ paintText.setTextAlign(Paint.Align.CENTER);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
+ && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ } else if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
+ super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+ } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
+ super.onMeasure(heightMeasureSpec, heightMeasureSpec);
+ } else if (MeasureSpec.getSize(widthMeasureSpec) < MeasureSpec.getSize(heightMeasureSpec)) {
+ super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+ } else {
+ super.onMeasure(heightMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ float size = getHeight(); // square
+ float padding = size * 0.1f;
+ paintDial.setStrokeWidth(size * 0.005f);
+ bounds.set(padding, padding, size - padding, size - padding);
+
+ paintText.setAlpha(DIAL_ALPHA);
+ canvas.drawArc(bounds, 0, 360, false, paintDial);
+ for (int i = 0; i < 24; i++) {
+ paintDial.setStrokeWidth(size * 0.005f);
+ if (i % 6 == 0) {
+ paintDial.setStrokeWidth(size * 0.01f);
+ Point textPos = radToPoint(i / 24.0f * 360.f, size / 2 - 2.5f * padding);
+ paintText.setTextSize(0.4f * padding);
+ canvas.drawText(String.valueOf(i), textPos.x,
+ textPos.y + (-paintText.descent() - paintText.ascent()) / 2, paintText);
+ }
+ Point outer = radToPoint(i / 24.0f * 360.f, size / 2 - 1.7f * padding);
+ Point inner = radToPoint(i / 24.0f * 360.f, size / 2 - 1.9f * padding);
+ canvas.drawLine(outer.x, outer.y, inner.x, inner.y, paintDial);
+ }
+ paintText.setAlpha(255);
+
+ float angleFrom = (float) from / 24 * 360 - 90;
+ float angleDistance = (float) ((to - from + 24) % 24) / 24 * 360;
+ paintSelected.setStrokeWidth(padding / 6);
+ paintSelected.setStyle(Paint.Style.STROKE);
+ canvas.drawArc(bounds, angleFrom, angleDistance, false, paintSelected);
+ paintSelected.setStyle(Paint.Style.FILL);
+ Point p1 = radToPoint(angleFrom + 90, size / 2 - padding);
+ canvas.drawCircle(p1.x, p1.y, padding / 2, paintSelected);
+ Point p2 = radToPoint(angleFrom + angleDistance + 90, size / 2 - padding);
+ canvas.drawCircle(p2.x, p2.y, padding / 2, paintSelected);
+
+ paintText.setTextSize(0.6f * padding);
+ String timeRange;
+ if (from == to) {
+ timeRange = getContext().getString(R.string.sleep_timer_always);
+ } else if (DateFormat.is24HourFormat(getContext())) {
+ timeRange = String.format(Locale.getDefault(), "%02d:00 - %02d:00", from, to);
+ } else {
+ timeRange = String.format(Locale.getDefault(), "%02d:00 %s - %02d:00 %s", from % 12,
+ from >= 12 ? "PM" : "AM", to % 12, to >= 12 ? "PM" : "AM");
+ }
+ canvas.drawText(timeRange, size / 2, (size - paintText.descent() - paintText.ascent()) / 2, paintText);
+ }
+
+ protected Point radToPoint(float angle, float radius) {
+ return new Point((int) (getWidth() / 2 + radius * Math.sin(-angle * Math.PI / 180 + Math.PI)),
+ (int) (getHeight() / 2 + radius * Math.cos(-angle * Math.PI / 180 + Math.PI)));
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ getParent().requestDisallowInterceptTouchEvent(true);
+ Point center = new Point(getWidth() / 2, getHeight() / 2);
+ double angleRad = Math.atan2(center.y - event.getY(), center.x - event.getX());
+ float angle = (float) (angleRad * (180 / Math.PI));
+ angle += 360 + 360 - 90;
+ angle %= 360;
+
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ float fromDistance = Math.abs(angle - (float) from / 24 * 360);
+ float toDistance = Math.abs(angle - (float) to / 24 * 360);
+ if (fromDistance < 15 || fromDistance > (360 - 15)) {
+ touching = 1;
+ return true;
+ } else if (toDistance < 15 || toDistance > (360 - 15)) {
+ touching = 2;
+ return true;
+ }
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ int newTime = (int) (24 * (angle / 360.0));
+ if (from == to && touching != 0) {
+ // Switch which handle is focussed such that selection is the smaller arc
+ touching = (((newTime - to + 24) % 24) < 12) ? 2 : 1;
+ }
+ if (touching == 1) {
+ from = newTime;
+ invalidate();
+ return true;
+ } else if (touching == 2) {
+ to = newTime;
+ invalidate();
+ return true;
+ }
+ } else if (touching != 0) {
+ touching = 0;
+ return true;
+ }
+ return super.onTouchEvent(event);
+ }
+ }
+}
diff --git a/app/src/main/res/layout/time_dialog.xml b/app/src/main/res/layout/time_dialog.xml
index 50001bf9c..1a8f02c7c 100644
--- a/app/src/main/res/layout/time_dialog.xml
+++ b/app/src/main/res/layout/time_dialog.xml
@@ -141,6 +141,14 @@
android:layout_height="wrap_content"
android:text="@string/auto_enable_label" />
+ <Button
+ android:id="@+id/changeTimes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/auto_enable_change_times"
+ android:layout_gravity="center"
+ style="@style/Widget.MaterialComponents.Button.TextButton" />
+
</LinearLayout>
</LinearLayout>