Commit 0cba097a authored by Alexis Lecanu's avatar Alexis Lecanu

Init project

parents
bin/
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>App-Timer</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>connectiq.builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>connectiq.projectNature</nature>
</natures>
</projectDescription>
# ConnectIQ-App-Timer
![0](https://gitlab.com/ravenfeld/Connect-IQ-App-Timer/raw/develop/screenshot/0.jpg)
![0](https://gitlab.com/ravenfeld/Connect-IQ-App-Timer/raw/develop/screenshot/1.png)
![0](https://gitlab.com/ravenfeld/Connect-IQ-App-Timer/raw/develop/screenshot/2.png)
![0](https://gitlab.com/ravenfeld/Connect-IQ-App-Timer/raw/develop/screenshot/3.png)
![0](https://gitlab.com/ravenfeld/Connect-IQ-App-Timer/raw/develop/screenshot/4.png)
# Link
[Connect IQ](https://apps.garmin.com/fr-FR/apps/12a98a6c-4909-41bc-b1aa-f8e2de2c9f59)
[Allprojet](https://apps.garmin.com/fr-FR/developer/9a164185-3030-48d9-9aef-f5351abe70d8/apps)
\ No newline at end of file
<!-- 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="TimerApp" id="9f349141d98a423dbb8575420d96c50d" launcherIcon="@Drawables.LauncherIcon" minSdkVersion="1.2.0" name="@Strings.AppName" type="watch-app" version="0.0.1">
<iq:products>
<iq:product id="fenix3"/>
</iq:products>
<iq:permissions/>
<iq:languages>
<iq:language>eng</iq:language>
<iq:language>fre</iq:language>
</iq:languages>
<iq:barrels/>
</iq:application>
</iq:manifest>
project.manifest = manifest.xml
<strings>
<string id="AppName">Timer</string>
<string id="Start">Lancer</string>
<string id="Remove">Supprimer</string>
<string id="Rename">Renommer</string>
<string id="Bip">Son</string>
<string id="Bip5s">Son 5'</string>
<string id="Vibrate">Vibration</string>
<string id="Alarms">Alarmes</string>
<string id="Enable">Activé</string>
<string id="Disable">Désactivé</string>
<string id="Timer">Cpte. à Reb.</string>
<string id="Add">Ajouter</string>
</strings>
<drawables>
<bitmap id="LauncherIcon" filename="launcher_icon.png" />
</drawables>
<resources>
<properties>
<property id="datas" type="string">""</property>
</properties>
</resources>
<strings>
<string id="AppName">Timer</string>
<string id="Start">Start</string>
<string id="Remove">Remove</string>
<string id="Rename">Rename</string>
<string id="Bip">Sound</string>
<string id="Bip5s">Sound 5'</string>
<string id="Vibrate">Vibrate</string>
<string id="Alarms">Alarms</string>
<string id="Enable">Enable</string>
<string id="Disable">Disable</string>
<string id="Timer">Timer</string>
<string id="Add">Add</string>
</strings>
import xml.etree.ElementTree as ET
import os
import time
import subprocess
import sys
tree = ET.parse('./manifest.xml')
manifest = tree.getroot()
application= manifest.find('{http://www.garmin.com/xml/connectiq}application')
products = application.find('{http://www.garmin.com/xml/connectiq}products')
for child in products:
print child.attrib.get('id')
sdk="1.2.0"
os.system("rm log.txt 2>/dev/null")
os.system('monkeyc -o ./bin/app.prg -w -y ../developer_key.der -d '+child.attrib.get('id')+' -s 1.2.0 -f ./monkey.jungle 2> log.txt > log.txt')
if os.stat('log.txt').st_size>0:
sdk="1.4.0"
os.system('monkeyc -o ./bin/app.prg -w -y ../developer_key.der -d '+child.attrib.get('id')+' -s 1.4.0 -f ./monkey.jungle 2> log.txt > log.txt')
if os.stat('log.txt').st_size>0:
sdk="2.3.0"
os.system('monkeyc -o ./bin/app.prg -w -y ../developer_key.der -d '+child.attrib.get('id')+' -s 2.3.0 -f ./monkey.jungle 2> log.txt > log.txt')
if os.stat('log.txt').st_size>0:
sdk="2.4.0"
os.system('monkeyc -o ./bin/app.prg -w -y ../developer_key.der -d '+child.attrib.get('id')+' -s 2.4.0 -f ./monkey.jungle 2> log.txt > log.txt')
print " build "+sdk
os.system('connectiq')
time.sleep(4)
for x in range(0, 2):
monkeydo = subprocess.Popen('monkeydo ./bin/app.prg '+child.attrib.get('id'), shell=True,stdout=subprocess.PIPE)
time.sleep(4)
if monkeydo.poll() == 0:
print " simulator error"
print monkeydo.communicate()
os.system("rm log.txt")
sys.exit(1)
print " simulator ok"
os.system("kill $(ps aux | grep simulator | grep -v 'grep' | awk '{print $2}')")
os.system("rm log.txt")
print "Fin"
sys.exit(0)
class Element {
var name;
var time;
var beep;
var beep5s;
var vibrate;
function initialize (json) {
self.name = extractValue("name",json);
var timeString = extractValue("time",json);
if(timeString.equals("")){
time=60;
}else{
time=timeString.toNumber();
}
self.beep = !extractValue("beep",json).equals("false")?true:false;
self.beep5s = !extractValue("beep5s",json).equals("false")?true:false;
self.vibrate = !extractValue("vibrate",json).equals("false")?true:false;
}
function extractValue(key,json){
var index =json.find("\""+key+"\":");
if(index != null){
var value = json.substring(index ,json.length());
var indexEnd = value.find("\",");
if(indexEnd == null){
indexEnd =value.length()-2;
}
value = value.substring(value.find(":\"")+2,indexEnd);
return value;
}
return "";
}
function getProperty(property){
System.print("getProperty "+property+ " "+beep+ " "+beep5s+ " "+vibrate);
if(property.equals("name")){
return name;
}else if(property.equals("time")){
return time;
}else if(property.equals("beep")){
System.print("cool");
return beep;
}else if(property.equals("beep5s")){
return beep5s;
}else if(property.equals("vibrate")){
return vibrate;
}else{
return null;
}
}
function toJson(){
return "{\"name\":\""+name+"\",\"time\":\""+time+"\",\"beep\":\""+beep+"\",\"beep5s\":\""+beep5s+"\",\"vibrate\":\""+vibrate+"\"}";
}
}
\ No newline at end of file
using Toybox.Application as App;
using Toybox.WatchUi as Ui;
var elements= new [0];
var model;
class TimerApp extends App.AppBase {
function initialize() {
AppBase.initialize();
}
function onStart(state) {
extract(App.getApp().getProperty("elements"));
}
function onStop(state) {
App.getApp().setProperty("elements",elementsToJson());
}
function getInitialView() {
var menu = new HomeMenu ();
return [ menu,new HomeMenuDelegate(menu) ];
}
function extract(json){
if(json!=null){
var index =json.find("{");
while(index != null){
json = json.substring(index +1 ,json.length());
var value = json.substring(0,json.find("}")+1);
elements.add(new Element("{"+value));
index =json.find("{");
}
}
}
function elementsToJson(){
var json;
for (var i=0; i<elements.size(); i++){
if(i==0){
json= "[";
}
json = json+elements[i].toJson();
if(i<elements.size()-1){
json = json+",";
}else{
json = json+"]";
}
}
return json;
}
}
using Toybox.WatchUi as Ui;
class TimerDelegate extends Ui.BehaviorDelegate {
hidden var alarms;
hidden var bip;
hidden var bip5S;
hidden var vibrate;
hidden var data;
function initialize(data) {
BehaviorDelegate.initialize();
self.data=data;
alarms = Ui.loadResource(Rez.Strings.Alarms);
bip = Ui.loadResource(Rez.Strings.Bip);
bip5S = Ui.loadResource(Rez.Strings.Bip5s);
vibrate = Ui.loadResource(Rez.Strings.Vibrate);
}
function onSelect() {
if(model.status==:Stop){
model.dropTimer();
Ui.popView(Ui.SLIDE_RIGHT);
}
}
function onMenu(){
var menuItems;
if(Attention has :playTone && Attention has :vibrate){
menuItems = new [3];
menuItems[0]=new StateMenuItem (:Beep,bip,data,"beep");
menuItems[1]=new StateMenuItem (:Beep5s,bip5S,data,"beep5s");
menuItems[2]=new StateMenuItem (:Vibrate,vibrate,data,"vibrate");
}else if(Attention has :playTone){
menuItems = new [2];
menuItems[0]=new StateMenuItem (:Beep,bip,data,"beep");
menuItems[1]=new StateMenuItem (:Beep5s,bip5S,data,"beep5s");
}else{
menuItems = new [1];
menuItems[0]=new StateMenuItem (:Vibrate,vibrate,data,"vibrate");
}
var menu = new Menu (menuItems, alarms);
Ui.pushView(menu,new AlarmMenuDelegate(menu) , Ui.SLIDE_RIGHT );
}
function onBack() {
model.dropTimer();
}
}
using Toybox.Application as App;
using Toybox.Timer as Timer;
using Toybox.WatchUi as Ui;
using Toybox.Attention as Attention;
using Toybox.ActivityRecording as ActivityRecording;
using Toybox.Sensor as Sensor;
using Toybox.Time as Time;
class TimerModel{
var counter;
var status=:Work;
var data;
hidden var refreshTimer = new Timer.Timer();
hidden var displayTimer = new Timer.Timer();
function initialize(data){
self.data=data;
counter = data.time;
startTimer();
}
function startTimer(){
refreshTimer.stop();
displayTimer.stop();
refreshTimer.start(method(:refresh), 1000, true);
startBuzz();
Ui.requestUpdate();
}
function stopTimer(beep){
if (status == :Work) {
status=:Stop;
if (beep) {
stopBuzz();
}
}
refreshTimer.stop();
displayTimer.stop();
Ui.requestUpdate();
}
function dropTimer() {
refreshTimer.stop();
displayTimer.stop();
}
function refresh(){
status=:Work;
if (counter > 1) {
counter--;
if (counter <= 5) {
buzz();
}
} else {
status=:Stop;
end();
}
Ui.requestUpdate();
}
function end(){
stopTimer(false);
endBuzz();
}
function startBuzz() {
if(data.beep && Attention has :playTone){
beep(Attention.TONE_START);
}
vibrate(1500);
}
function stopBuzz() {
if(data.beep && Attention has :playTone){
beep(Attention.TONE_STOP);
}
vibrate(1500);
}
function endBuzz() {
if(data.beep && Attention has :playTone){
beep(Attention.TONE_SUCCESS);
}
vibrate(1500);
}
function buzz() {
if(data.beep && data.beep5s && Attention has :playTone){
beep(Attention.TONE_LOUD_BEEP);
}
}
function vibrate(duration) {
if(Attention has :vibrate && data.vibrate){
var vibrateData = [ new Attention.VibeProfile( 100, duration ) ];
Attention.vibrate( vibrateData );
}
}
function beep(tone) {
if( Attention has :playTone ){
Attention.playTone(tone);
}
}
}
using Toybox.WatchUi as Ui;
using Toybox.Graphics as Gfx;
class TimerView extends Ui.View {
hidden var text_width_10;
hidden var text_width_1;
hidden var text_width_point;
hidden var cx;
hidden var cy;
function initialize () {
View.initialize();
}
function onShow () {
}
function onLayout(dc) {
cx = dc.getWidth() / 2;
cy = dc.getHeight() / 2;
text_width_10 = dc.getTextWidthInPixels("88",Gfx.FONT_NUMBER_THAI_HOT);
text_width_1 = dc.getTextWidthInPixels("8",Gfx.FONT_NUMBER_THAI_HOT);
text_width_point = dc.getTextWidthInPixels(":",Gfx.FONT_NUMBER_THAI_HOT);
}
function onUpdate (dc) {
dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
dc.clear();
if(model.status==:Work) {
drawTime(model.counter, dc);
drawArc(dc,model.counter, model.data.time);
}else{
dc.drawText(dc.getWidth()/2, dc.getHeight()/2, Gfx.FONT_LARGE, model.data.name, Gfx.TEXT_JUSTIFY_VCENTER|Gfx.TEXT_JUSTIFY_CENTER);
}
}
function drawTime(long, dc) {
var seconds = long % 60;
var minutes = (long / 60) % 60;
var start_x;
var start_point;
if (minutes>=10) {
start_x=(dc.getWidth()-(text_width_10+text_width_point+text_width_10+4))/2;
start_point=start_x+text_width_10+2;
}else{
start_x=(dc.getWidth()-(text_width_1+text_width_point+text_width_10+4))/2;
start_point=start_x+text_width_1+2;
}
dc.drawText(start_x, cy, Gfx.FONT_NUMBER_THAI_HOT, minutes, Gfx.TEXT_JUSTIFY_VCENTER | Gfx.TEXT_JUSTIFY_LEFT);
dc.drawText(start_point, cy, Gfx.FONT_NUMBER_THAI_HOT, ":", Gfx.TEXT_JUSTIFY_VCENTER | Gfx.TEXT_JUSTIFY_LEFT);
var start_seconds=start_point+text_width_point+2;
dc.drawText(start_seconds, cy, Gfx.FONT_NUMBER_THAI_HOT, seconds.format("%02d"), Gfx.TEXT_JUSTIFY_VCENTER | Gfx.TEXT_JUSTIFY_LEFT);
}
function drawArc(dc,counter,max){
var cx = dc.getWidth()/2;
var cy = dc.getHeight()/2;
dc.setPenWidth(6);
dc.setColor(Gfx.COLOR_BLACK,Gfx.COLOR_TRANSPARENT);
var angle = 0;
if(counter >0){
angle= counter*360/max;
}
if(angle>0){
dc.drawArc(cx,cy,dc.getHeight()/2-6,Gfx.ARC_CLOCKWISE,90,(360-angle.toLong()+90)%360);
}
}
}
module Utils{
function timeToString(long){
var seconds = long % 60;
var minutes = (long / 60) % 60;
return minutes+":"+seconds.format("%02d");
}
}
\ No newline at end of file
using Toybox.Application as App;
using Toybox.WatchUi as Ui;
class DataMenuItem extends MenuItem{
var data;
function initialize (id, label, data) {
self.data=data;
MenuItem.initialize(id, label);
}
}
\ No newline at end of file
using Toybox.WatchUi as Ui;
using Toybox.Graphics as Gfx;
class MenuItem
{
hidden const LABEL_FONT = Gfx.FONT_SMALL;
hidden const SELECTED_LABEL_FONT = Gfx.FONT_LARGE;
hidden const VALUE_FONT = Gfx.FONT_MEDIUM;
hidden const PAD = 0;
var id;
hidden var label;
hidden var value;
var index;
hidden var fontSelected=SELECTED_LABEL_FONT;
function initialize (id, label) {
self.id = id;
self.label = label;
}
function setLabel (label) {
self.label = label;
}
function setValue (value) {
self.value = value;
}
function setFont (font) {
self.fontSelected = font;
}
function onShow(){
}
function draw (dc, y, highlight) {
if (highlight) {
setHighlightColor (dc);
drawHighlightedLabel (dc, y);
} else {
setColor (dc);
drawLabel (dc, y);
}
}
function setHighlightColor (dc) {
dc.setColor (Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
}
function setColor (dc) {
dc.setColor (Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
}
function drawLabel (dc, y) {
var width = dc.getWidth ();
var h3 = dc.getHeight () / 3;
var lab = label.toString ();
var labDims = dc.getTextDimensions (lab, LABEL_FONT);
var yL = y + (h3 - labDims[1]) / 2;
dc.drawText (width / 2, yL, LABEL_FONT, lab, Gfx.TEXT_JUSTIFY_CENTER);
}
function drawHighlightedLabel (dc, y) {
var width = dc.getWidth ();
var h3 = dc.getHeight () / 3;
var lab = label.toString ();
var yL, yV, h;
var labDims = dc.getTextDimensions (lab, fontSelected);
if (value != null) {
// Show label and value.
var val = value.toString ();
var valDims = dc.getTextDimensions (val, VALUE_FONT);
h = labDims[1] + valDims[1] + PAD;
yL = y + (h3 - h) / 2;
yV = yL + labDims[1] + PAD;
dc.drawText (width / 2, yV, VALUE_FONT, val, Gfx.TEXT_JUSTIFY_CENTER);
} else {
yL = y + (h3 - labDims[1]) / 2;
}
dc.drawText (width / 2, yL, fontSelected, lab, Gfx.TEXT_JUSTIFY_CENTER);
}
}
class Menu extends Ui.View {
var menuArray;
var title;
var index;
var nextIndex;
var drawMenu;
function initialize (menuArray,title) {
self.menuArray = menuArray;
index = 0;
nextIndex = 0;
self.title = title;
View.initialize ();
}
function setTitle(menuTitle) {
title = menuTitle;
}
function setMenuArray(menuArray) {
self.menuArray = menuArray;
}
function onShow () {
drawMenu = new DrawMenu ();
for (var idx = 0; idx < menuArray.size (); idx++) {
menuArray[idx].onShow();
}
}
function onHide () {
drawMenu = null;
}
function itemWithId (id)
{
for (var idx = 0; idx < menuArray.size (); idx++) {
if (menuArray[idx].id == id) {
menuArray[idx].index = idx;
return menuArray[idx];
}
}
return null;
}
const ANIM_TIME = 0.2;
function updateIndex (offset) {
if (menuArray.size () <= 1) {
return;
}
nextIndex = index + offset;
// Cope with a 'feature' in modulo operator not handling -ve numbers as desired.
nextIndex = nextIndex < 0 ? menuArray.size() + nextIndex : nextIndex;
nextIndex = nextIndex % menuArray.size();
if ((offset == 1 && menuArray.size()-1!=index) ||(index==0 && offset==-1)) {
drawMenu.t = 1000;
Ui.animate (drawMenu, :t, Ui.ANIM_TYPE_LINEAR, 1000, 0, ANIM_TIME, method(:requestUpdate));
} else {
drawMenu.t = -1000;
Ui.animate (drawMenu, :t, Ui.ANIM_TYPE_LINEAR, -1000, 0, ANIM_TIME, method(:requestUpdate));
}
requestUpdate();
index = nextIndex;
}
function requestUpdate() {
Ui.requestUpdate();
}
function selectedItem () {
menuArray[index].index = index;
return menuArray[index];
}
function onUpdate (dc) {
var width = dc.getWidth ();
var height = dc.getHeight ();
dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_TRANSPARENT);
dc.fillRectangle(0, 0, width, height);
// Draw the menu items.
drawMenu.index = index;
drawMenu.nextIndex = nextIndex;
drawMenu.menu = self;
drawMenu.draw (dc);
// Draw the decorations.
var h3 = height / 3;
dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_TRANSPARENT);
dc.setPenWidth (2);
dc.drawLine (0, h3-5, width, h3-5);
dc.drawLine (0, h3 * 2+5, width, h3 * 2+5);
drawArrows (dc);
}
const GAP = 5;
const TS = 5;
// The arrows are drawn with lines as polygons don't give different sized triangles depending
// on their orientation.
function drawArrows (dc) {
var x = dc.getWidth () / 2;
var y;
dc.setPenWidth (1);
dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
if (nextIndex != 0) {
y = GAP;
for (var i = 0; i < TS; i++) {
dc.drawLine (x - i, y + i, x + i + 1, y + i);
}
}
if (nextIndex != menuArray.size () - 1) {
y = dc.getHeight () - TS - GAP;
var d;
for (var i = 0; i < TS; i++) {
d = TS - 1 - i;
dc.drawLine (x - d, y + i, x + d + 1, y + i);
}
}
}
}
// Done as a class so it can be animated.
class DrawMenu extends Ui.Drawable
{
const TITLE_FONT = Gfx.FONT_SMALL;
var t = 0;
var index;
var nextIndex;
var menu;
function initialize () {
Drawable.initialize ({});
}
function draw (dc) {
var width = dc.getWidth ();
var height = dc.getHeight ();
var h3 = height / 3;
var items = menu.menuArray.size ();