diff --git a/app/src/main/java/com/philliphsu/clock2/DurationDisplayer.java b/app/src/main/java/com/philliphsu/clock2/DurationDisplayer.java new file mode 100644 index 0000000..61473ce --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/DurationDisplayer.java @@ -0,0 +1,26 @@ +package com.philliphsu.clock2; + +import android.support.annotation.NonNull; + +/** + * Created by Phillip Hsu on 4/30/2016. + */ +public interface DurationDisplayer { + /** + * Callback interface to be implemented by a parent/host of this displayer. + * The host should use this to tell its displayer to update its duration text + * via showAsText(long). + */ + /*public*/ interface OnTickListener { + // Listeners implement this to be notified of when + // they should update this displayer's text + void onTick(); + } + + /** Hosts of this displayer use this to attach themselves */ + void setOnTickListener(@NonNull OnTickListener listener); + void startTicking(boolean resume); + void stopTicking(); + void forceTick(); + void showAsText(long duration); +} diff --git a/app/src/main/java/com/philliphsu/clock2/TickHandler.java b/app/src/main/java/com/philliphsu/clock2/TickHandler.java new file mode 100644 index 0000000..5e16ae2 --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/TickHandler.java @@ -0,0 +1,71 @@ +package com.philliphsu.clock2; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.support.annotation.NonNull; + +import com.philliphsu.clock2.DurationDisplayer.OnTickListener; + +import static com.philliphsu.clock2.util.Preconditions.checkNotNull; + +/** + * Created by Phillip Hsu on 4/18/2016. + */ +public class TickHandler extends Handler { + private static final int MSG_TICK = 0; + private static final int MSG_FORCE_TICK = 1; + + @NonNull private final OnTickListener mOnTickListener; + private final long mTickInterval; + + public TickHandler(@NonNull OnTickListener listener, long tickInterval) { + super(Looper.getMainLooper()); + mOnTickListener = checkNotNull(listener); + mTickInterval = tickInterval; + } + + @Override + public void handleMessage(Message msg) { + // Account for the time showDuration() takes to execute + // and subtract that off from the countdown interval + // (so the countdown doesn't get postponed by however long + // showDuration() takes) + long startOnTick = SystemClock.elapsedRealtime(); + mOnTickListener.onTick(); + long countdownRemainder = mTickInterval - + (SystemClock.elapsedRealtime() - startOnTick); + + // special case: onTick took longer than countdown + // interval to complete, skip to next interval + while (countdownRemainder < 0) + countdownRemainder += mTickInterval; + + if (msg.what == MSG_TICK) { // as opposed to MSG_FORCE_TICK + sendMessageDelayed(obtainMessage(MSG_TICK), mTickInterval); + } + } + + public void startTicking(boolean resume) { + if (hasMessages(MSG_TICK)) + return; + if (resume) { + sendMessage(obtainMessage(MSG_TICK)); + } else { + sendMessageDelayed(obtainMessage(MSG_TICK), mTickInterval); + } + } + + public void stopTicking() { + removeMessages(MSG_TICK); + } + + /** + * Forces a single call to {@link OnTickListener#onTick() onTick()} + * without scheduling looped messages on this handler. + */ + public void forceTick() { + sendMessage(obtainMessage(MSG_FORCE_TICK)); + } +} diff --git a/app/src/main/java/com/philliphsu/clock2/alarms/AlarmCountdown.java b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmCountdown.java new file mode 100644 index 0000000..ba987af --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmCountdown.java @@ -0,0 +1,53 @@ +package com.philliphsu.clock2.alarms; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.widget.TextView; + +import com.philliphsu.clock2.DurationDisplayer; +import com.philliphsu.clock2.TickHandler; +import com.philliphsu.clock2.util.DurationUtils; + +/** + * Created by Phillip Hsu on 4/30/2016. + */ +public class AlarmCountdown extends TextView implements DurationDisplayer { + private static final String TAG = "NextAlarmText"; + private static final int TICK_INTERVAL = 60000; // per minute + + private TickHandler mHandler; + + public AlarmCountdown(Context context) { + super(context); + } + + public AlarmCountdown(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void setOnTickListener(@NonNull OnTickListener listener) { + mHandler = new TickHandler(listener, TICK_INTERVAL); + } + + @Override + public void showAsText(long duration) { + setText(DurationUtils.toString(getContext(), duration, true)); + } + + @Override + public void startTicking(boolean resume) { + mHandler.startTicking(resume); + } + + @Override + public void stopTicking() { + mHandler.stopTicking(); + } + + @Override + public void forceTick() { + mHandler.forceTick(); + } +} diff --git a/app/src/main/java/com/philliphsu/clock2/alarms/AlarmViewHolder.java b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmViewHolder.java index 07278b0..0832d18 100644 --- a/app/src/main/java/com/philliphsu/clock2/alarms/AlarmViewHolder.java +++ b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmViewHolder.java @@ -31,18 +31,19 @@ import static com.philliphsu.clock2.util.DateFormatUtils.formatTime; /** * Created by Phillip Hsu on 5/31/2016. */ -public class AlarmViewHolder extends BaseViewHolder { +public class AlarmViewHolder extends BaseViewHolder implements AlarmCountdown.OnTickListener { private static final RelativeSizeSpan AMPM_SIZE_SPAN = new RelativeSizeSpan(0.5f); @Bind(R.id.time) TextView mTime; @Bind(R.id.on_off_switch) SwitchCompat mSwitch; @Bind(R.id.label) TextView mLabel; - @Bind(R.id.countdown) TextView mCountdown; // TODO: Change type to NextAlarmText, once you move that class to this project + @Bind(R.id.countdown) AlarmCountdown mCountdown; @Bind(R.id.recurring_days) TextView mDays; @Bind(R.id.dismiss) Button mDismissButton; public AlarmViewHolder(ViewGroup parent, OnListItemInteractionListener listener) { super(parent, R.layout.item_alarm, listener); + mCountdown.setOnTickListener(this); } @Override @@ -88,9 +89,14 @@ public class AlarmViewHolder extends BaseViewHolder { bindDays(num > 0, text); } + @Override + public void onTick() { + mCountdown.showAsText(getAlarm().ringsIn()); + } + @OnClick(R.id.dismiss) void onClick() { - AlarmUtils.cancelAlarm(getContext(), getItem()); + AlarmUtils.cancelAlarm(getContext(), getAlarm()); bindDismissButton(false, ""); // Will be set to correct text the next time we bind. // TODO: Check if alarm has no recurrence, then turn it off. } @@ -113,11 +119,11 @@ public class AlarmViewHolder extends BaseViewHolder { private void bindCountdown(boolean enabled, long remainingTime) { if (enabled) { - //TODO:mCountdown.showAsText(remainingTime); - //TODO:mCountdown.getTickHandler().startTicking(true) + mCountdown.showAsText(remainingTime); + mCountdown.startTicking(true); mCountdown.setVisibility(VISIBLE); } else { - //TODO:mCountdown.getTickHandler().stopTicking(); + mCountdown.stopTicking(); mCountdown.setVisibility(GONE); } } @@ -140,4 +146,8 @@ public class AlarmViewHolder extends BaseViewHolder { private void setVisibility(@NonNull View view, boolean visible) { view.setVisibility(visible ? VISIBLE : GONE); } + + private Alarm getAlarm() { + return getItem(); + } } diff --git a/app/src/main/java/com/philliphsu/clock2/util/DurationUtils.java b/app/src/main/java/com/philliphsu/clock2/util/DurationUtils.java index c727291..526f660 100644 --- a/app/src/main/java/com/philliphsu/clock2/util/DurationUtils.java +++ b/app/src/main/java/com/philliphsu/clock2/util/DurationUtils.java @@ -12,6 +12,10 @@ import java.util.concurrent.TimeUnit; * Created by Phillip Hsu on 6/6/2016. */ public class DurationUtils { + public static final int HOURS = 0; + public static final int MINUTES = 1; + public static final int SECONDS = 2; + public static final int MILLIS = 3; /** Return a string representing the duration, formatted in hours and minutes. * TODO: Need to adapt this to represent all time fields eventually */ diff --git a/app/src/main/res/layout/item_alarm.xml b/app/src/main/res/layout/item_alarm.xml index 31cbb75..9124519 100644 --- a/app/src/main/res/layout/item_alarm.xml +++ b/app/src/main/res/layout/item_alarm.xml @@ -42,7 +42,7 @@ android:layout_below="@id/time_layout" android:layout_marginBottom="@dimen/item_margin_between_elements"/> -