content: package de.danoeh.antennapod.ui.screen.playback;
  
  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);
              float textBaseY = (size - paintText.descent() - paintText.ascent()) / 2;
              if (from == to) {
                  String timeRange = getContext().getString(R.string.sleep_timer_always);
                  canvas.drawText(timeRange, size / 2, textBaseY, paintText);
              } else if (DateFormat.is24HourFormat(getContext())) {
                  String timeRange = String.format(Locale.getDefault(), "%02d:00 - %02d:00", from, to);
                  canvas.drawText(timeRange, size / 2, textBaseY, paintText);
              } else {
                  String timeFrom = String.format(Locale.getDefault(), "%02d:00 %s", from % 12, from >= 12 ? "PM" : "AM");
                  String timeTo = String.format(Locale.getDefault(), "%02d:00 %s", to % 12, to >= 12 ? "PM" : "AM");
                  canvas.drawText(timeFrom, size / 2, textBaseY - paintText.getTextSize(), paintText);
                  canvas.drawText("-", size / 2, textBaseY, paintText);
                  canvas.drawText(timeTo, size / 2, textBaseY + paintText.getTextSize(), paintText);
              }
          }
  
          protected Point radToPoint(float angle, float radius) {
              return new Point((int) (getWidth() / 2.0 + radius * Math.sin(-angle * Math.PI / 180.0 + Math.PI)),
                      (int) (getHeight() / 2.0 + radius * Math.cos(-angle * Math.PI / 180.0 + 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);
          }
      }
  }
  