Skip to content

Commit

Permalink
Added interval alerts every 5min with short and fast blip vibration.
Browse files Browse the repository at this point in the history
  • Loading branch information
dliedke committed Jul 20, 2022
1 parent 5bbc773 commit 7a35105
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Meditate/manifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!-- This is a generated file. It is highly recommended that you DO NOT edit this file. -->
<iq:manifest xmlns:iq="http://www.garmin.com/xml/connectiq" version="3">
<iq:application entry="MeditateApp" id="57843a03841b4410aff4e4c427c42caf" launcherIcon="@Drawables.launcherIcon" minSdkVersion="1.4.0" name="@Strings.AppName" type="watch-app" version="2.6.1">
<iq:application entry="MeditateApp" id="57843a03841b4410aff4e4c427c42caf" launcherIcon="@Drawables.launcherIcon" minSdkVersion="1.4.0" name="@Strings.AppName" type="watch-app" version="2.7.0">
<iq:products>
<iq:product id="fr235"/>
</iq:products>
Expand Down
102 changes: 102 additions & 0 deletions Meditate/source/activity/IntervalAlerts.mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using Toybox.Graphics as Gfx;

module IntervalAlertType {
enum {
OneOff = 1,
Repeat = 2
}
}

class IntervalAlerts {
private var mAlerts;

function initialize() {
me.reset();
}

function addNew() {
me.mAlerts.add(new Alert());
var newAlertIndex = me.mAlerts.size() - 1;
return newAlertIndex;
}

function delete(index) {
var alert = me.mAlerts[index];
me.mAlerts.remove(alert);
}

function reset() {
me.mAlerts = [];
}

function get(index) {
return me.mAlerts[index];
}

function set(index, alert) {
me.mAlerts[index] = alert;
}

function count() {
return me.mAlerts.size();
}
}

class Alert {
function initialize() {
me.reset();
}

function reset() {
me.type = IntervalAlertType.Repeat;
me.time = 60 * 5;
me.color = Gfx.COLOR_YELLOW;
me.vibePattern = VibePattern.Blip;
}

function getAlertArcPercentageTimes(sessionTime) {
return me.getAlertPercentageTimes(sessionTime, ArcMaxRepeatExecutionsCount, ArcMinRepeatPercentageTime);
}

private function getAlertPercentageTimes(sessionTime, maxRepeatExecutionsCount, minRepeatPercentageTime) {
if (sessionTime < 1 || me.time < 1) {
return [];
}
var percentageTime = me.time.toDouble() / sessionTime.toDouble();
if (me.type == IntervalAlertType.OneOff) {
return [percentageTime];
}
else {
var executionsCount = (sessionTime / me.time);
if (executionsCount > maxRepeatExecutionsCount) {
executionsCount = maxRepeatExecutionsCount;
}
if (percentageTime < minRepeatPercentageTime) {
percentageTime = minRepeatPercentageTime;
}
var result = new [executionsCount];
for (var i = 0; i < executionsCount; i++) {
result[i] = percentageTime * (i + 1);
if (result[i] > 1.0) {
result[i] = 1.0;
}
}
return result;
}
}

function getAlertProgressBarPercentageTimes(sessionTime) {
return me.getAlertPercentageTimes(sessionTime, ProgressBarRepeatExecutionsCount, ProgressBarRepeatPercentageTime);
}

private const ProgressBarRepeatExecutionsCount = 20;
private const ProgressBarRepeatPercentageTime = 0.05;

private const ArcMaxRepeatExecutionsCount = 139;
private const ArcMinRepeatPercentageTime = 0.0072;

var type;
var time;//in seconds
var color;
var vibePattern;
}
75 changes: 75 additions & 0 deletions Meditate/source/activity/IntervalAlertsRenderer.mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using Toybox.Graphics as Gfx;
using Toybox.Lang;

class IntervalAlertsRenderer {
function initialize(sessionTime, repeatIntervalAlerts, radius, width) {
me.mSessionTime = sessionTime;
me.mRepeatIntervalAlerts = repeatIntervalAlerts;
me.mRadius = radius;
me.mWidth = width;
me.mRepeatPercentageTimes = me.createPercentageTimes(repeatIntervalAlerts);
}

private var mSessionTime;
private var mRepeatIntervalAlerts;
private var mRadius;
private var mWidth;
private var mRepeatPercentageTimes;
private const StartDegreeOffset = 90;

function drawRepeatIntervalAlerts(dc) {
me.drawIntervalAlerts(dc, me.mRepeatIntervalAlerts, me.mRepeatPercentageTimes);
}

private function createPercentageTimes(intervalAlerts) {
if (intervalAlerts.size() == 0) {
return [];
}
var resultPercentageTimes = new [intervalAlerts.size()];
for (var i = 0; i < intervalAlerts.size(); i++) {
var intervalAlert = intervalAlerts[i];
resultPercentageTimes[i] = intervalAlert.getAlertArcPercentageTimes(me.mSessionTime);
}
return resultPercentageTimes;
}

private function drawIntervalAlerts(dc, intervalAlerts, percentageTimes) {
for (var i = 0; i < intervalAlerts.size(); i++) {
for (var pIndex = 0; pIndex < percentageTimes[i].size(); pIndex++) {
me.drawIntervalAlert(dc, percentageTimes[i][pIndex], intervalAlerts[i].color);
}
}
}

private function getAlertProgressPercentage(percentageTime) {
var progressPercentage = percentageTime * 100;
if (progressPercentage > 100) {
progressPercentage = 100;
}
else {
if (progressPercentage == 0) {
progressPercentage = 0.05;
}
}
return progressPercentage;
}

private function drawIntervalAlert(dc, intervalAlertTime, color) {
var progressPercentage = me.getAlertProgressPercentage(intervalAlertTime);
dc.setColor(color, Gfx.COLOR_TRANSPARENT);

// Because 235 screen is not totally round we need this hack
if (progressPercentage == 0 || progressPercentage == 50) {
dc.setPenWidth(me.mWidth + 38);
} else {
dc.setPenWidth(me.mWidth);
}
var startDegree = percentageToArcDegree(progressPercentage);
var endDegree = startDegree - 1.2;
dc.drawArc(dc.getWidth() / 2, dc.getHeight() / 2, me.mRadius , Gfx.ARC_CLOCKWISE, startDegree, endDegree);
}

private static function percentageToArcDegree(percentage) {
return StartDegreeOffset - percentage * 3.6;
}
}
8 changes: 8 additions & 0 deletions Meditate/source/activity/MeditateModel.mc
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,12 @@ class MeditateModel {
function getActivityType() {
return me.mSession.activityType;
}

function getRepeatIntervalAlerts() {
var result = {};
var intervalAlerts = new IntervalAlerts();
intervalAlerts.addNew();
result.put(0,intervalAlerts.get(0));
return result;
}
}
16 changes: 14 additions & 2 deletions Meditate/source/activity/MeditateView.mc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class MeditateView extends Ui.View {
private var mHrvIcon;
private var mHrvText;
private var mMeditateIcon;

private var mIntervalAlertsRenderer;

private function createMeditateText(color, font, xPos, yPos, justification) {
return new Ui.Text({
:text => "",
Expand Down Expand Up @@ -77,7 +78,13 @@ class MeditateView extends Ui.View {
var durationArcRadius = dc.getWidth() / 2;
var mainDurationArcWidth = (dc.getWidth() / 4) - 10;
me.mMainDuationRenderer = new ElapsedDuationRenderer(me.mMeditateModel.getColor(), durationArcRadius, mainDurationArcWidth);



// Initialize interval alerts
var intervalAlertsArcRadius = dc.getWidth() / 2;
var intervalAlertsArcWidth = dc.getWidth() / 16;
me.mIntervalAlertsRenderer = new IntervalAlertsRenderer(me.mMeditateModel.getSessionTime(), me.mMeditateModel.getRepeatIntervalAlerts(), intervalAlertsArcRadius, intervalAlertsArcWidth);

renderHrStatusLayout(dc);
}

Expand Down Expand Up @@ -129,6 +136,11 @@ class MeditateView extends Ui.View {
var alarmTime = me.mMeditateModel.getSessionTime();
me.mMainDuationRenderer.drawOverallElapsedTime(dc, me.mMeditateModel.elapsedTime, alarmTime);

// Render interval alerts
if (me.mIntervalAlertsRenderer != null) {
me.mIntervalAlertsRenderer.drawRepeatIntervalAlerts(dc);
}

me.mHrStatusText.setText(me.formatHr(currentHr));
me.mHrStatusText.draw(dc);
me.mHrStatus.draw(dc);
Expand Down
24 changes: 22 additions & 2 deletions Meditate/source/activity/VibeAlertsExecutor.mc
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,51 @@ using Toybox.Attention;
class VibeAlertsExecutor {
function initialize(meditateModel) {
me.mMeditateModel = meditateModel;
me.mRepeatIntervalAlerts = me.mMeditateModel.getRepeatIntervalAlerts();
me.mIsFinalAlertPending = true;
}

private var mIsFinalAlertPending;
private var mMeditateModel;

private var mRepeatIntervalAlerts;

function firePendingAlerts() {
if (me.mIsFinalAlertPending == true) {
me.fireIfRequiredFinalAlert();
me.fireIfRequiredRepeatIntervalAlerts();
}
}

private function fireIfRequiredFinalAlert() {

if (me.mMeditateModel.elapsedTime >= me.mMeditateModel.getSessionTime()) {

// Vibrate
// Vibrate long continuous
Attention.vibrate(getLongContinuous());

me.mIsFinalAlertPending = false;
}
}

private function fireIfRequiredRepeatIntervalAlerts() {
for (var i = 0; i < me.mRepeatIntervalAlerts.size(); i++) {
if (me.mRepeatIntervalAlerts[i].time > 0 && me.mMeditateModel.elapsedTime % me.mRepeatIntervalAlerts[i].time == 0) {

// Vibrate blip
Attention.vibrate(getBlip());
}
}
}

private static function getLongContinuous() {
return [
new Attention.VibeProfile(100, 3000)
];
}

private static function getBlip() {
return [
new Attention.VibeProfile(100, 50)
];
}
}

0 comments on commit 7a35105

Please sign in to comment.