diff options
author | HyungKyu Song <hk76.song@samsung.com> | 2013-02-15 15:11:56 +0900 |
---|---|---|
committer | HyungKyu Song <hk76.song@samsung.com> | 2013-02-15 15:11:56 +0900 |
commit | e57be6b17bee9e3939dce6a63dd641966b553a1e (patch) | |
tree | 70e1363f0431f391e7214651c00fcd35f8b1d705 | |
parent | 21de49ef41802bf9c43dfc543534cfeac0b6093b (diff) | |
download | ExercisePlanner-2.0_release.tar.gz ExercisePlanner-2.0_release.tar.bz2 ExercisePlanner-2.0_release.zip |
Tizen 2.0 Release2.0_release
-rw-r--r-- | AUTHORS | 5 | ||||
-rw-r--r-- | LICENSE.Flora | 206 | ||||
-rw-r--r-- | NOTICE | 4 | ||||
-rw-r--r-- | config.xml | 13 | ||||
-rw-r--r-- | css/GraphSchedule.css | 122 | ||||
-rw-r--r-- | css/jquery.ui.layout.css | 33 | ||||
-rw-r--r-- | css/style.css | 279 | ||||
-rwxr-xr-x | icon.png | bin | 0 -> 17581 bytes | |||
-rw-r--r-- | images/background.png | bin | 0 -> 201 bytes | |||
-rw-r--r-- | images/longBothHorizonGradient.png | bin | 0 -> 773 bytes | |||
-rw-r--r-- | images/longBothHorizonGradient2.png | bin | 0 -> 1540 bytes | |||
-rw-r--r-- | images/markers.png | bin | 0 -> 437 bytes | |||
-rw-r--r-- | images/state_lazy.png | bin | 0 -> 62060 bytes | |||
-rw-r--r-- | images/state_run.png | bin | 0 -> 27376 bytes | |||
-rw-r--r-- | index.html | 229 | ||||
-rw-r--r-- | js/GraphSchedule.js | 186 | ||||
-rw-r--r-- | js/UI.js | 415 | ||||
-rw-r--r-- | js/UI.simpleTemplate.js | 25 | ||||
-rw-r--r-- | js/app.alarms.js | 55 | ||||
-rw-r--r-- | js/app.alarmsGenerating.js | 153 | ||||
-rw-r--r-- | js/app.js | 450 | ||||
-rw-r--r-- | js/app.onAlarm.js | 66 | ||||
-rw-r--r-- | js/app.timeRange.js | 386 | ||||
-rw-r--r-- | js/ext.jqMobile.js | 17 | ||||
-rw-r--r-- | js/main.js | 21 | ||||
-rw-r--r-- | music/Runner.mp3 | bin | 0 -> 495598 bytes | |||
-rw-r--r-- | signature1.xml | 160 | ||||
-rw-r--r-- | templates/GraphSchedule.tmpl | 91 |
28 files changed, 2916 insertions, 0 deletions
@@ -0,0 +1,5 @@ +Tomasz Lukawski <t.lukawski at samsung dot com> +Artur Kobylinski <a.kobylinski at samsung dot com> +Piotr Wronski <p.wronski at samsung dot com> +Pawel Sierszen <p.sierszen at samsung dot com> +Tomasz Paciorek <t.paciorek at samsung dot com> diff --git a/LICENSE.Flora b/LICENSE.Flora new file mode 100644 index 0000000..9c95663 --- /dev/null +++ b/LICENSE.Flora @@ -0,0 +1,206 @@ +Flora License + +Version 1.0, May, 2012 + +http://floralicense.org/license/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and +all other entities that control, are controlled by, or are +under common control with that entity. For the purposes of +this definition, "control" means (i) the power, direct or indirect, +to cause the direction or management of such entity, +whether by contract or otherwise, or (ii) ownership of fifty percent (50%) +or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice +that is included in or attached to the work (an example is provided +in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, +or merely link (or bind by name) to the interfaces of, the Work and +Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor +for inclusion in the Work by the copyright owner or by an individual or +Legal Entity authorized to submit on behalf of the copyright owner. +For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or +its representatives, including but not limited to communication on +electronic mailing lists, source code control systems, and issue +tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated +in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +"Tizen Certified Platform" shall mean a software platform that complies +with the standards set forth in the Compatibility Definition Document +and passes the Compatibility Test Suite as defined from time to time +by the Tizen Technical Steering Group and certified by the Tizen +Association or its designated agent. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work +solely as incorporated into a Tizen Certified Platform, where such +license applies only to those patent claims licensable by such +Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work solely +as incorporated into a Tizen Certified Platform to which such +Contribution(s) was submitted. If You institute patent litigation +against any entity (including a cross-claim or counterclaim +in a lawsuit) alleging that the Work or a Contribution incorporated +within the Work constitutes direct or contributory patent infringement, +then any patent licenses granted to You under this License for that +Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof pursuant to the copyright license +above, in any medium, with or without modifications, and in Source or +Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works + a copy of this License; and + 2. You must cause any modified files to carry prominent notices stating + that You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that + You distribute, all copyright, patent, trademark, and attribution + notices from the Source form of the Work, excluding those notices + that do not pertain to any part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable + copy of the attribution notices contained within such NOTICE file, + excluding those notices that do not pertain to any part of + the Derivative Works, in at least one of the following places: + within a NOTICE text file distributed as part of the Derivative Works; + within the Source form or documentation, if provided along with the + Derivative Works; or, within a display generated by the Derivative Works, + if and wherever such third-party notices normally appear. + The contents of the NOTICE file are for informational purposes only + and do not modify the License. + +You may add Your own attribution notices within Derivative Works +that You distribute, alongside or as an addendum to the NOTICE text +from the Work, provided that such additional attribution notices +cannot be construed as modifying the License. You may add Your own +copyright statement to Your modifications and may provide additional or +different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works +as a whole, provided Your use, reproduction, and distribution of +the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Flora License to your work + +To apply the Flora License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Flora License, Version 1.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://floralicense.org/license/ + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + @@ -0,0 +1,4 @@ +Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Flora License, Version 1. +Please, see the LICENSE.Flora file for Flora License terms and conditions. + diff --git a/config.xml b/config.xml new file mode 100644 index 0000000..d28b78c --- /dev/null +++ b/config.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<widget xmlns="http://www.w3.org/ns/widgets" xmlns:tizen="http://tizen.org/ns/widgets" id="http://sample-web-application.tizen.org/ExercisePlanner" version="2.0.0" viewmodes="maximized"> + <tizen:application id="3YbLJNtYMR" required_version="1.0"/> + <content src="index.html"/> + <tizen:privilege name="http://tizen.org/privilege/alarm"/> + <tizen:privilege name="http://tizen.org/privilege/application.launch"/> + <tizen:privilege name="http://tizen.org/privilege/application.read"/> + <tizen:privilege name="http://tizen.org/privilege/time"/> + <icon src="icon.png"/> + <name>ExercisePlanner</name> + <tizen:setting screen-orientation="portrait" context-menu="disable"/> +</widget> + diff --git a/css/GraphSchedule.css b/css/GraphSchedule.css new file mode 100644 index 0000000..61da77d --- /dev/null +++ b/css/GraphSchedule.css @@ -0,0 +1,122 @@ +.GraphSchedule { + position: relative; + overflow-x: scroll; + width: 100%; + height: 100px; + background-color: transparent; + z-index: 1000; +} + +.GraphSchedule .container { + width: 600px; + bottom: 5px; + position: absolute; +} + +.GraphSchedule table { + pointer-events: none; +} + +.GraphSchedule td { + width: 70px; + text-align: left; + color: gray; + height: 10px; +} + +.GraphSchedule table .grid td { + border-width: 1px 0 0px 1px; + border-style: solid; + border-color: white; + font-size: 13px; + font-family: Helvetica; + position: relative; +} + +.GraphSchedule table .ranges td { + border-width: 1px 0 0 1px; + border-style: solid; + border-color: gray; + position: relative; +} + +.GraphSchedule table .ranges .th { + border-width: 0px; + background-color: rgba(50, 50, 50, 0.2); + position: relative; + padding: 0; +} + +.GraphSchedule table .rangesWeekend td { + border-width: 1px 0 0 1px; + border-style: solid; + border-color: gray; + position: relative; +} + +.GraphSchedule table .rangesWeekend .th { + border-width: 0px; + background-color: rgba(50, 50, 250, 0.2); + position: relative; + padding: 0; +} + +.GraphSchedule .flag { + position: absolute; + width: 10px; + height: 60px; + background-color: transparent; + bottom: 19px; +} + +.GraphSchedule .flag .container { + position: relative; + width: 10px; + bottom: -1px; + height: 60px; +} + +.GraphSchedule .flag .rod { + position: absolute; + width: 2px; + height: 55px; + left: 0; + background-color: brown; + bottom: 0; + border-width: 0 1px 0 0; + border-style: solid; + border-color: #aaa; +} + +.GraphSchedule .flag p { + position: absolute; + width: 15px; + left: 3px; + background-color: #f88; + height: 15px; + top: -10px; + background-image: -webkit-linear-gradient(left, #F88 18%, #E31448 59%); +} + +.GraphSchedule .flag .hint { + display: none; + position: absolute; + width: 42px; + height: 18px; + top: 8px; + left: 2px; + background-color: #FF9; + -webkit-border-radius: 5px 5px 5px; + position: absolute; +} + +.currentTimeBar { + position: absolute; + height: 100px; + background-color: yellow; + width: 2px; + bottom: -20px; + border-width: 0 1px 0 0; + border-style: solid; + border-color: #FC0; +}
\ No newline at end of file diff --git a/css/jquery.ui.layout.css b/css/jquery.ui.layout.css new file mode 100644 index 0000000..bcecced --- /dev/null +++ b/css/jquery.ui.layout.css @@ -0,0 +1,33 @@ +.ui-myHeader {
+ background-color: #293d5e;
+ height: 70px;
+}
+
+.ui-myContent {
+ overflow: auto;
+ -webkit-box-flex: 1;
+ height: 0px;
+}
+
+.ui-myFooter {
+ background-color: #192333;
+ height: 70px;
+}
+
+.ui-myExit {
+ float: right;
+ background-color: #555;
+ width: 70px;
+ height: 50px;
+ margin-top: 10px;
+ margin-right: 10px;
+ border-radius: 5px;
+ background-image: url('../images/00_winset_Back.png');
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-size: 50%;
+}
+
+.ui-myHeader {
+ text-align: center;
+}
\ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..e1eff8f --- /dev/null +++ b/css/style.css @@ -0,0 +1,279 @@ +#one { + background-image: url('../images/background.png'); +} + +.screen { + font-family: serif; + color: white; + font-size: 17pt; +} + +#sentence { + margin: 10px 30px 0 30px; + position: relative; + float: right; + text-indent: 30px; +} + +#signature { + margin: 0px 30px 0 auto; + position: relative; + float: right; +} + +#logo { + font-family: courier; + font-size: 36px; + width: 100%; + background-repeat: no-repeat; + margin: 0px 40px 0 auto; + color: white; + border-bottom: 1px solid white; + font-weight: bolder; + text-align: right; + line-height: 43px; +} + +#status { + width: 400px; + height: 350px; + margin: 0 auto; + background-repeat: no-repeat; +} + +#status.lazy { + background-image: url('../images/state_lazy.png'); +} + +#status.run { + background-image: url('../images/state_run.png'); +} + +#communicate { + font-size: 17pt; + text-align: center; + min-height: 70px; +} + +#communicate.onAlert { + font-size: 60px; + text-align: center; + text-shadow: 5px 5px 5px black; +} + +#communicate b { + font-size: 25px; +} + +#communicate div { + font-size: 32px; + font-weight: bold; +} + +.schedule { + height: 100px; +} + +.scheduleOptions { + height: 100px; +} + +.increasingStrength { + display: none; +} + +.strength { + margin: 0 0 20px 0; +} + +.timeRangeLabel { + height: 50px; +} + +.activeStatus { + display: inline; + float: right; + color: blue; +} + +.activeStatusDisable { + color: red; +} + +.times li { + float: left; + width: 200px; +} + +.times { + width: 100%; + float: left; + margin: 0; + padding: 10px; +} + +.times .ui-datefield { + font-size: 60px; +} + +/** + +old styles; + +*/ +.exerciseView { + width: 80%; + height: 200px; + border-width: 1px; + border-color: #888 #DDD #DDD #888; + border-style: solid; + background-color: #578; + -webkit-border-radius: 0.6em; + -webkit-box-align: center; + margin: 0 auto; + box-shadow: 0px 0px 20px #000; + position: relative; +} + +.optionsExercises label { + line-height: 44px; +} + +#exercises { + margin-bottom: 10px; +} + +.myHeader { + +} + +.ui-controlgroup .ui-radio { + width: 20%; +} + +.myContent { + margin: auto 10px 10px 10px; +} + +.footerContent { + margin: 0 auto; + text-align: center; + padding-top: 20px; +} + +.newExerciseName label { + width: 100%; +} + +.newExerciseName input { /*background-color:white;*/ + +} + +.ui-footer { + z-index: 1000; +} + +#availableTime { + margin-top: 12px; + overflow: hidden; + margin-left: 0; + margin-right: 0; +} + +#availableTime li { + margin-left: 0; + margin-right: 0; +} + +.ui-swipelist-item .ui-btn { + padding: 4px; + margin-right: 12px; +} + +.ui-li-text-sub-right { + font-size: 18px; + margin-right: 17px; + float: right; + margin-top: 2px; + color: #08f; +} + +.disabled { + color: #f00; +} + +ul { + list-style-type: none; +} + +.goToOptionsPack { + width: 100%; +} + +.goToOptions { + width: 80%; + margin-left: 10%; + margin-right: 10%; +} + +.buttonOptions { + float: right; + box-shadow: 0px 0px 10px #000; +} + +.buttonStop { + background-color: #F40; + box-shadow: 0px 0px 10px #000; +} + +.selectPeriodType .ui-radio { + width: 100%; +} + +#formEnablePeriod { + margin-bottom: 20px; +} + +#ok_wait { + position: absolute; + bottom: 0; + width: 100%; +} + +#ok_wait .ok { + left: 50px; +} + +#ok_wait .wait { + right: 50px; + position: absolute; +} + +span.meterDesc { + position: absolute; + z-index: 100; + display: block; + text-align: center; + width: inherit; + padding-top: 8px; + color: #333; +} + +.enableOption { + padding-bottom: 20px; +} + +.enableOption>div { + display: table-cell; +} + +.enableOption>label { + float: left; + padding-right: 20px; + padding-top: 8px; + vertical-align: middle; +} + +div.period { + padding-left: 10px; +} diff --git a/icon.png b/icon.png Binary files differnew file mode 100755 index 0000000..983c883 --- /dev/null +++ b/icon.png diff --git a/images/background.png b/images/background.png Binary files differnew file mode 100644 index 0000000..532ca02 --- /dev/null +++ b/images/background.png diff --git a/images/longBothHorizonGradient.png b/images/longBothHorizonGradient.png Binary files differnew file mode 100644 index 0000000..946d3cd --- /dev/null +++ b/images/longBothHorizonGradient.png diff --git a/images/longBothHorizonGradient2.png b/images/longBothHorizonGradient2.png Binary files differnew file mode 100644 index 0000000..5ff092a --- /dev/null +++ b/images/longBothHorizonGradient2.png diff --git a/images/markers.png b/images/markers.png Binary files differnew file mode 100644 index 0000000..23feef7 --- /dev/null +++ b/images/markers.png diff --git a/images/state_lazy.png b/images/state_lazy.png Binary files differnew file mode 100644 index 0000000..c2e67dd --- /dev/null +++ b/images/state_lazy.png diff --git a/images/state_run.png b/images/state_run.png Binary files differnew file mode 100644 index 0000000..a72d60e --- /dev/null +++ b/images/state_run.png diff --git a/index.html b/index.html new file mode 100644 index 0000000..631602b --- /dev/null +++ b/index.html @@ -0,0 +1,229 @@ +<!DOCTYPE html> +<html> + +<head> +<meta charset="utf-8" /> +<meta name="description" content="Alerts" /> +<meta name="viewport" content="width=480, user-scalable=no" /> + +<title>ExercisePlanner</title> + +<script src="/usr/share/tizen-web-ui-fw/latest/js/jquery.js"></script> +<script src="/usr/share/tizen-web-ui-fw/latest/js/tizen-web-ui-fw-libs.js"></script> +<script src="/usr/share/tizen-web-ui-fw/latest/js/tizen-web-ui-fw.js" + data-framework-theme="tizen-white"></script> + +<script src="./js/UI.js"></script> +<script src="./js/UI.simpleTemplate.js"></script> +<script src="./js/ext.jqMobile.js"></script> +<script src="./js/GraphSchedule.js"></script> + +<script src="./js/app.js"></script> +<script src="./js/app.alarms.js"></script> +<script src="./js/app.timeRange.js"></script> +<script src="./js/app.alarmsGenerating.js"></script> +<script src="./js/app.onAlarm.js"></script> +<script type="text/javascript" src="./js/main.js"></script> + +<link rel="stylesheet" type="text/css" href="./css/style.css" /> +<link rel="stylesheet" type="text/css" href="./css/GraphSchedule.css" /> +</head> + +<body> + <div data-role="page" id="one" data-add-back-btn="footer" data-footer-exist="true"> + <div data-role="content" data-scroll="none"> + <div class="screen"> + <div id="logo">Exercise Planner</div> + <div id="status"></div> + <div class="schedule"></div> + <div id="communicate"></div> + <div id="sentence"></div> + <div id="signature"></div> + </div> + </div> + + <div data-role="footer" data-position="fixed"> + <div data-role="tabbar" id="mainControl" data-style="tabbar"> + <ul> + <li><a href="#" id="startStop">stop training</a></li> + <li><a href="#two" id="options">options</a></li> + </ul> + </div> + + <div id="onAlertControl" data-style="tabbar" + style="display: none;"> + <ul> + <li><a href="#" id="ok">OK</a></li> + <li><a href="#" id="wait">Wait</a></li> + <li><a href="#" id="todayOffAll">Today off all</a></li> + </ul> + </div> + </div> + </div> + + <div data-role="page" id="two" data-add-back-btn="footer"> + <div data-role="header" data-position="fixed"> + <h1>ExercisePlanner > options</h1> + </div> + + <div data-role="content"> + <div class="myContent"> + + <div data-role="fieldcontain" class="frequency"> + <div>Frequency</div> + <fieldset data-role="controlgroup" data-type="horizontal" id="frequency"> + <input type="radio" name="radioFrequency" + data-icon="segment-titlestyle-segonly" id="freq1" value="1" /> + <label for="freq1">1</label> + <input type="radio" name="radioFrequency" + data-icon="segment-titlestyle-segonly" id="freq2" value="2" /> + <label for="freq2">2</label> + <input type="radio" name="radioFrequency" + data-icon="segment-titlestyle-segonly" id="freq3" value="3" /> + <label for="freq3">3</label> + <input type="radio" name="radioFrequency" + data-icon="segment-titlestyle-segonly" id="freq4" value="4" /> + <label for="freq4">4</label> + <input type="radio" name="radioFrequency" + data-icon="segment-titlestyle-segonly" id="freq5" value="5" /> + <label for="freq5">5</label> + </fieldset> + </div> + + <div class="scheduleOptions"></div> + + <div data-role="tabbar" data-style="tabbar" class="typeOfPeriods"> + <ul> + <li id="workdaysType"><a>workday</a></li> + <li id="weekendType"><a>weekend</a></li> + </ul> + </div> + + <div data-role="fieldcontain" class="strength"> + <div>Strength</div> + <fieldset data-role="controlgroup" data-type="horizontal" + id="strength"> + <input type="radio" name="radioStrength" + data-icon="segment-titlestyle-segonly" id="stre1" value="1" /> + <label for="stre1">1</label> + <input type="radio" name="radioStrength" + data-icon="segment-titlestyle-segonly" id="stre2" value="2" /> + <label for="stre2">2</label> + <input type="radio" name="radioStrength" + data-icon="segment-titlestyle-segonly" id="stre3" value="3" /> + <label for="stre3">3</label> + <input type="radio" name="radioStrength" + data-icon="segment-titlestyle-segonly" id="stre4" value="4" /> + <label for="stre4">4</label> + <input type="radio" name="radioStrength" + data-icon="segment-titlestyle-segonly" id="stre5" value="5" /> + <label for="stre5">5</label> + </fieldset> + </div> + + <div class="increasingStrength"> + <input type="checkbox" name="tizen-check1-1" + id="increasingStrength" /> + <label for="increasingStrength">progressive effort</label> + </div> + + <a data-role="button" data-icon="plus" id="addTimeRange" data-inline="false">add time</a> + <ul data-role="swipelist" id="availableTime"></ul> + + </div> + </div> + + <div data-role="footer" data-position="fixed"> + <div data-role="tabbar" data-style="toolbar"> + <ul> + <li><a href="#selectExercises">select workouts</a></li> + </ul> + </div> + </div> + </div> + + <div data-role="page" id="selectExercises" data-add-back-btn="footer"> + <div data-role="header" data-position="fixed"> + <h2>ExercisePlanner > select workouts</h2> + </div> + + <div data-role="content"> + <div class="optionsExercises"> + <div>Select workouts</div> + <ul data-role="listview" id="exercises"></ul> + <a data-role="button" data-icon="plus" href="#customExercises">add custom workout</a> + </div> + </div> + + <div data-role="footer" data-position="fixed"></div> + </div> + + <div data-role="page" id="customExercises" data-add-back-btn="footer"> + <div data-role="header" data-position="fixed"> + <h1>ExercisePlanner > add custom workout</h1> + </div> + + <div data-role="content"> + <div class="newExerciseName"> + <div>Enter workout name:</div> + <input data-role="input" type="text" name="newExercise" + id="newExerciseName" maxlength="20"/> + <input data-role="button" id="btnNewExercise" data-inline="true" type="button" + value="add"/> + </div> + </div> + + <div data-role="footer" data-position="fixed"></div> + </div> + + <div data-role="page" id="rangesOfTimes" data-add-back-btn="footer"> + <div data-role="header"> + <h1>add time</h1> + </div> + + <div data-role="content"> + <div> + <ul class="times"> + <li class="ui-li-3-2-2">Start: <span class="ui-li-text-main"> + <input type="time" name="dateStart" id="startTime" + data-format="H" /> + </span>hour + </li> + <li class="ui-li-3-2-2">Duration: <span class="ui-li-text-main"> + <input type="time" name="duration" id="duration" data-format="H" /> + </span> hours + </li> + </ul> + + <fieldset data-role="controlgroup" class="selectPeriodType"> + <legend>Choose a type of period:</legend> + <input type="radio" name="periodType" id="periodType1" + value="everyday" checked="checked" /> + <label for="periodType1">everyday</label> + + <input type="radio" name="periodType" id="periodType2" + value="weekend" /> + <label for="periodType2">weekend</label> + + <input type="radio" name="periodType" id="periodType3" + value="workday" /> + <label for="periodType3">workday</label> + </fieldset> + <div class="enableOption"> + <span>Enabled</span> + <select id="formEnablePeriod" data-role="slider"> + <option value="off"></option> + <option value="on"></option> + </select> + </div> + </div> + + <input data-role="button" data-inline="true" type="button" + id="updateTime" value="add" /> + </div> + + <div data-role="footer"></div> + </div> + +</body> +</html> diff --git a/js/GraphSchedule.js b/js/GraphSchedule.js new file mode 100644 index 0000000..72df6f8 --- /dev/null +++ b/js/GraphSchedule.js @@ -0,0 +1,186 @@ +/*jslint devel: true*/ +/*global $ */ +/** + * Constructor + * + * @param {object} params + * @returns + */ +function GraphSchedule(params) { + "use strict"; + this.init(params); +} + +(function () { + "use strict"; + GraphSchedule.prototype = { + template: '', + ui: null, + $flag: null, + $graph: null, + timeRanges: { + workday: [], + weekend: [] + }, + flags: [] + }; + + GraphSchedule.prototype.createUI = function createUI() { + var $tmp = $('<div></div>'); + + $tmp.html(this.template); + this.$flag = $tmp.find('.flag'); + this.$graph = $tmp.find('.GraphSchedule'); + this.ui = this.$graph; + + this.addCurrentTimeBar(); + this.showFlags(); + + this.center(); + }; + + GraphSchedule.prototype.center = function center() { + // set scroll position; + this.$graph[0].scrollLeft = 1000 * ((new Date().getHours() - 4) / 24); + }; + + GraphSchedule.prototype.refresh = function refresh() { + this.updateTimeRanges(); + this.showFlags(); + this.center(); + }; + + GraphSchedule.prototype.onTemplateLoad = function onTemplateLoad() { + }; + + GraphSchedule.prototype.init = function init(params) { + var $loader = $('<div></div>'); + + if (params && params.onSuccess) { + this.onTemplateLoad = params.onSuccess; + } + + this.flags = []; + $loader.load('templates/GraphSchedule.tmpl', null, function (data) { + this.template = data; + this.createUI(); + this.onTemplateLoad(); + }.bind(this)); + }; + + /** + * + * @param {Array} times + * @returns + */ + GraphSchedule.prototype.pushTimeOfFlags = function pushTimeOfFlags(times) { + var i, count; + + // clear previous times; + this.flags = []; + + if (times instanceof Array) { + count = times.length; + for (i = 0; i < count; i += 1) { + if (times[i] instanceof Date) { + this.flags.push({ time: times[i] }); + } else { + throw {message: 'Bag argument at [' + i + '] element of Array. Expected {Date}'}; + } + } + } else { + throw {message: 'Bad argument. Expected {Array} of {Date}'}; + } + }; + + GraphSchedule.prototype.addCurrentTimeBar = function addCurrentTimeBar() { + // remove old time bar; + var $currentTimeBar = this.$graph.find('.currentTimeBar'), + currentTime = new Date(), + hours = currentTime.getHours(); + + if ($currentTimeBar.length === 0) { + // add new; + $currentTimeBar = $('<div class="currentTimeBar"></div>'); + } + + if (hours < 10) { + hours = '0' + hours; + } + + this.$graph.find('.ranges .h' + hours).append($currentTimeBar); + $currentTimeBar.css('left', 100 * currentTime.getMinutes() / 60 + '%'); + + setTimeout(this.addCurrentTimeBar.bind(this), 5 * 60 * 1000); + }; + + GraphSchedule.prototype.addFlag = function addFlag(newFlag) { + var $flagClone, hours = newFlag.time.getHours(); + if (hours < 10) { + hours = '0' + hours; + } + $flagClone = this.$flag.clone(); + this.$graph.find('.grid td:contains(' + hours + ')').append($flagClone); + $flagClone.css('left', 100 * newFlag.time.getMinutes() / 60 + '%'); + }; + + GraphSchedule.prototype.showFlags = function showFlags() { + var i, len = this.flags.length; + // remove old flags; + this.removeFlags(); + + // add all flags to view; + for (i = 0; i < len; i += 1) { + this.addFlag(this.flags[i]); + } + + this.center(); + }; + + GraphSchedule.prototype.removeFlags = function removeFlags() { + this.$graph.find('.flag').remove(); + }; + + GraphSchedule.prototype.setTimeRanges = function setTimeRanges(ranges) { + this.timeRanges = ranges; + }; + + GraphSchedule.prototype.setVisibleWeekend = function (bool) { + var row = this.ui.find('.rangesWeekend'); + return bool ? row.show() : row.hide(); + }; + + GraphSchedule.prototype.setVisibleWorkdays = function (bool) { + var row = this.ui.find('.ranges'); + return bool ? row.show() : row.hide(); + }; + + /** + * Update time ranges on graph + * @param ranges {array} array of boolen, keys are hours, example: [false, false, false, true, true] + */ + GraphSchedule.prototype.updateTimeRanges = function updateTimeRanges() { + var i, len, hours; + + this.$graph.find('.th').removeClass('th'); + + // workdays; + hours = this.timeRanges.workday; + len = hours.length; + for (i = 0; i < len; i += 1) { + if (hours[i]) { + this.$graph.find('.ranges .h' + ((i < 10) ? '0' + i : i)).addClass('th'); + } + } + + //weekends; + hours = this.timeRanges.weekend; + len = hours.length; + for (i = 0; i < len; i += 1) { + if (hours[i]) { + this.$graph.find('.rangesWeekend .h' + ((i < 10) ? '0' + i : i)).addClass('th'); + } + } + }; + +}()); diff --git a/js/UI.js b/js/UI.js new file mode 100644 index 0000000..7d3d334 --- /dev/null +++ b/js/UI.js @@ -0,0 +1,415 @@ +/*jslint nomen: true*/ +/*global $, GraphSchedule, confirm, range, history, setTimeout */ +function UI() { + "use strict"; +} + +(function () { + "use strict"; + UI.prototype = { + sentence : { + 'lazy' : { + text : 'He does not seem to me to be a free man who does not sometimes do nothing.', + signature : 'Marcus T. Cicero' + }, + 'run' : { + text : 'A journey of a thousand miles begins with a single step.', + signature : 'Lao-tzu' + } + }, + graphSchedule : null, + app : null + }; + + UI.prototype.fillExercises = function (exercisesData) { + var i, len, self = this; + + $('#exercises').replaceWith( + $('<ul data-role="listview" id="exercises"></ul>') + ); + for (i = 0, len = exercisesData.length; i < len; i += 1) { + $('#exercises').append( + $(this.getExercisesTemplate(exercisesData[i], i)) + ); + } + $('#exercises').listview(); + $('#exercises :jqmData(role="slider")').slider(); + $('#exercises li').on('tap', function () { + var $toggle = $(this).find(':jqmData(role="slider")'); + $toggle.val(($toggle.val() === 'off') ? 'on' : 'off'); + $toggle.slider('refresh'); + self.app.saveExercises(self.getExercisesList()); + }); + $('#exercises :jqmData(role="slider")').on('change', function (e) { + e.preventDefault(); + e.stopPropagation(); + self.app.saveExercises(self.getExercisesList()); + }); + }; + + UI.prototype.fillTimesRanges = function (timesData) { + var self = this, len, i; + + $('#availableTime').replaceWith( + $('<ul data-role="listview" id="availableTime"></ul>') + ); + for (i = 0, len = timesData.length; i < len; i += 1) { + $('#availableTime') + .append($(this.getAvailableTimeTemplate(timesData[i]))); + } + $('#availableTime').trigger('create'); + $('#availableTime').listview().listview('refresh'); + $('#availableTime :jqmData(name=edit)').on('tap', function (e) { + e.preventDefault(); + e.stopPropagation(); + self.editTimeRange($(this).data('val')); + }); + $('#availableTime :jqmData(name=disable)').on('tap', function (e) { + e.stopPropagation(); + self.app.disableTimeRange($(this).data('val')); + }); + $('#availableTime :jqmData(name=delete)').on('tap', function (e) { + e.stopPropagation(); + if (confirm('Are you sure?')) { + self.app.deleteTimeRange($(this).data('val')); + } + }); + }; + + UI.prototype.fillTimeRangeForm = function fillTimeRangeForm(timeRange) { + var tmpData = new Date(); + // Filling form; + $('#startTime').attr('data-val', + new Date(tmpData.setHours(timeRange.start))); + $('#duration').attr('data-val', timeRange.duration); + + if ($('#startTime').data('datetimepicker')) { + $('#startTime').data('datetimepicker').options.date + .setHours(timeRange.start); + $('#startTime').data('datetimepicker').ui + .find('.ui-datefield-hour').html( + (timeRange.start < 10) ? '0' + timeRange.start : timeRange.start + ); + } + if ($('#duration').data('datetimepicker')) { + $('#duration').data('datetimepicker').options.date + .setHours(timeRange.duration); + $('#duration').data('datetimepicker').ui.find('.ui-datefield-hour') + .html( + (timeRange.duration < 10) ? '0' + + timeRange.duration : timeRange.duration + ); + $('#duration').data('datetimepicker')._populateDataSelector = function (field, pat) { + var result = $.tizen.datetimepicker.prototype._populateDataSelector + .call(this, field, pat); + result.values = range(1, 20); + result.data = range(1, 20); + result.current -= 1; + return result; + }; + } + + $('#formEnablePeriod')[0].value = timeRange.enabled ? 'on' : 'off'; + $('#formEnablePeriod').slider('refresh'); + }; + + UI.prototype.editTimeRange = function (nr, event) { + if (event && typeof event.stopPropagation === 'function') { + event.preventDefault(); + event.stopPropagation(); + } + + if (this.app.editTimeRange(nr) >= 0) { + $('#updateTime').val('modify'); + } else { + $('#updateTime').val('add'); + } + + // change page to form; + $.mobile.changePage("#rangesOfTimes"); + }; + + UI.prototype.getExercisesList = function () { + return $('#exercises :jqmData(role=slider)').map(function (o, v) { + return ({ + index : $(v).attr('data-index'), + checked : ($(v).val() === 'on') ? true : false + }); + }); + }; + + UI.prototype.addExercise = function () { + if ($("#newExerciseName").val()) { + if (this.app.addExercise($("#newExerciseName").val())) { + $("#newExerciseName").trigger('blur'); + setTimeout(history.back.bind(history), 50); + } + } else { + this.showErrors([ { + name : 'Name of exercise is not correct.', + code : 100 + } ]); + } + }; + + UI.prototype.configToUI = function () { + }; + + UI.prototype.updateMainUI = function () { + this.setStatusRun(this.app.config.trainingEnabled); + this.graphSchedule.setTimeRanges(this.app.periodsWeekToBoolArray()); + }; + + UI.prototype.getTimeRangeFromForm = function () { + return { + start : $('#startTime').data('datetimepicker').options.date + .getHours(), + duration : $('#duration').data('datetimepicker').options.date + .getHours(), + stop : $('#startTime').data('datetimepicker').options.date + .getHours() + + $('#duration').data('datetimepicker').options.date + .getHours(), + style : $('.selectPeriodType :radio:checked').val(), + enabled : ($('#formEnablePeriod')[0].value === 'on' ? true : false) + }; + }; + + UI.prototype.editTimeRangeAction = function (nr) { + if (this.app.saveTimeRange(nr, this.getTimeRangeFromForm())) { + history.back(); + } else { + throw ({ + message : 'Time start and stop is not present.', + code : 1 + }); + } + }; + + UI.prototype.showNoticeInMonitor = function (notice, alarm) { + $('#communicate').html(notice); + $('#communicate').toggleClass('onAlert', alarm); + }; + + UI.prototype.changeButtonAddTime = function (text) { + $('#addTime').html(text); + }; + + UI.prototype.showErrors = function (errors) { + var i; // count; + for (i = 0; i < errors.length; i += 1) { + alert(errors[i].name); + } + }; + + UI.prototype.showAlarmInMonitor = function (data) { + var notice = ''; + function formatNN(val) { + return (val < 10) ? ('0' + val) : val; + } + + if (data && data.alarm && this.app.config.trainingEnabled) { + this.app.currentAlarm = this.app.findCurrentAlarm(); + if (this.app.currentAlarm.length > 0) { + notice += 'Go... go... go...!<br>' + data.exerciseName + ' x ' + + data.numberOfTimes; + } else { + notice += 'Next exercises set at: ' + + formatNN(data.alarm.getHours()) + ':' + + formatNN(data.alarm.getMinutes()) + '<br>' + + data.exerciseName + ' x ' + data.numberOfTimes; + } + } else { + notice += '<br/>You have no workouts scheduled for now.<br/>'; + } + this.showNoticeInMonitor(notice, false); + }; + + UI.prototype.getSentence = function UI_getSentence(type) { + return (this.sentence[type] || { + text : 'No sentence', + signature : 'anonymous' + }); + }; + + UI.prototype.setSentence = function (type) { + var sentence = this.getSentence(type); + $('#sentence').html('"' + sentence.text + '"'); + $('#signature').html('- ' + sentence.signature); + }; + + UI.prototype.showWaitOk = function () { + $('#mainControl').hide(); + $('#one .ui-btn-back').hide(); + + $('#onAlertControl').tabbar(); + $('#onAlertControl').show(); + $('#onAlertControl').css('width', ''); + }; + + UI.prototype.setStatusRun = function (bool) { + if (bool) { + // icon; + $('#status').removeClass('lazy').addClass('run'); + // sentence; + this.setSentence('run'); + // button in control bar; + $('#startStop .ui-btn-text').html('stop training'); + } else { + $('#status').removeClass('run').addClass('lazy'); + this.setSentence('lazy'); + $('#communicate').html(''); + $('#startStop .ui-btn-text').html('start training'); + } + }; + + UI.prototype.bindEvents = function bindEvents() { + var self = this; + + // bind events; + $('#one .ui-btn-back').on('tap', this.app.exit.bind(this.app)); + + $('#ok').on('tap', self.app.ok.bind(self.app)); + $('#wait').on('tap', self.app.wait.bind(self.app)); + $('#todayOffAll').on('tap', self.app.todayOffAll.bind(self.app)); + + $('#startStop').on('tap', function () { + self.app.appStartStop(); + }); + + $('#one').on( + 'pageshow', + function (page, options) { + if (self.graphSchedule.ui) { + $('#one .schedule').append(self.graphSchedule.ui); + self.app.updateGraph(); + self.graphSchedule.refresh(); + self.graphSchedule.setVisibleWeekend(!self.app + .todayIsWorkday()); + self.graphSchedule.setVisibleWorkdays(self.app + .todayIsWorkday()); + } + $('#one .schedule').on('touchstart', function (ev) { + ev.stopPropagation(); + }); + + // workaround for scroll lock; + $.mobile.activePage.css('position', 'fixed'); + } + ); + + $('#two').on('pageshow', function (page, options) { + + //FIXME (two scrollbar workaround) + setTimeout( + function () { + var newHeight = $('#two').find('[data-role="content"]').prop('style').height; + $('#two').css({'min-height': newHeight, 'height': newHeight}); + }, + 0 + ); + + if (self.graphSchedule.ui) { + $('#two .scheduleOptions').append(self.graphSchedule.ui); + self.graphSchedule.refresh(); + self.graphSchedule.setVisibleWeekend(true); + self.graphSchedule.setVisibleWorkdays(true); + } + }); + + $('#two').on('pageinit', function (page, options) { + $('.ui-radio input', $('#frequency')).change(function (ev) { + self.app.setFrequency(this.value); + self.updateMainUI(); + }); + + $('.ui-radio input', $('#strength')).change(function (ev) { + self.app.setStrength(this.value); + self.updateMainUI(); + }); + + $('#frequency')[0].select(self.app.config.frequency); + $('#strength')[0].select(self.app.config.strength); + + $('#two .scheduleOptions').append(self.graphSchedule.ui); + $('#two .scheduleOptions').on('touchstart', function (ev) { + ev.stopPropagation(); + }); + + $('#workdaysType').on('tap', function (ev) { + self.app.changeTypeOfPeriods('workday'); + }); + + $('#weekendType').on('tap', function (ev) { + self.app.changeTypeOfPeriods('weekend'); + }); + + $('#addTimeRange').on('tap', self.editTimeRange.bind(self, -1)); + + self.app.updateTimesRanges(); + self.configToUI(); + }); + + $('#selectExercises').on('pageinit', function (page, options) { + self.app.updateExercises(); + self.configToUI(); + }); + + $('#customExercises').on('pageinit', function (page, options) { + $('#btnNewExercise').on('click', self.addExercise.bind(self)); + }); + + $('#customExercises').on('pageshow', function (page, options) { + $('#newExerciseName').val(''); + $('#newExerciseName').trigger('focus'); + }); + + $('#rangesOfTimes').on('pageinit', function (page, options) { + $("#updateTime").on("tap", function (e) { + e.preventDefault(); + e.stopPropagation(); + self.editTimeRangeAction(self.app.currentEditingTimePeriodId); + }); + }); + + $('#rangesOfTimes').on('pageshow', function (page, options) { + $('#updateTime').data('button').refresh(); + self.fillTimeRangeForm(self.app.currentEditingTimePeriod); + }); + + $('#increasingStrength').on('change', function () { + self.app.config.increasingStrength = this.checked; + self.app.saveConfig(); + + self.configToUI(); + }); + }; + + UI.prototype.onGraphSchedule = function onGraphSchedule(onInitEnd) { + this.updateMainUI(); + + $('#one .schedule').append(this.graphSchedule.ui); + this.app.updateGraph(); + this.graphSchedule.refresh(); + this.graphSchedule.setVisibleWeekend(!this.app.todayIsWorkday()); + this.graphSchedule.setVisibleWorkdays(this.app.todayIsWorkday()); + + if (typeof onInitEnd === 'function') { + onInitEnd(); + } + }; + + UI.prototype.initialize = function (onInitEnd) { + $.mobile.tizen.disableSelection(document); + + this.bindEvents(); + + $('html').css('font-size', ''); + $('body').css('font-size', ''); + + this.graphSchedule = new GraphSchedule({ + onSuccess : this.onGraphSchedule.bind(this, onInitEnd) + }); + }; + +}()); diff --git a/js/UI.simpleTemplate.js b/js/UI.simpleTemplate.js new file mode 100644 index 0000000..8ce5874 --- /dev/null +++ b/js/UI.simpleTemplate.js @@ -0,0 +1,25 @@ +/*global UI */ +(function () { + "use strict"; + UI.prototype.getAvailableTimeTemplate = function getAvailableTimeTemplate(obj) { + return '<li>' + '<div class="timeRangeLabel">start: ' + obj.start + + ' (duration: ' + obj.duration + 'h) ' + obj.style + '</div>' + + '<div class="timeRangeButtons">' + + '<div data-role="button" data-inline="true" data-name="edit" data-val="' + obj.nr + '">Edit</div>' + + '<div data-role="button" data-inline="true" data-name="disable" data-val="' + obj.nr + '">' + + ((obj.enabled) ? 'Dis' : 'En') + 'able</div>' + + '<div data-role="button" data-inline="true" data-name="delete" data-val="' + obj.nr + '">Delete</div>' + + '<div class="activeStatus' + ((obj.enabled) ? '' : ' activeStatusDisable') + '" data-inline="true">' + ((obj.enabled) ? 'En' : 'Dis') + 'abled</div>' + + '</div>' + '</li>'; + }; + + UI.prototype.getExercisesTemplate = function (obj, i) { + return '<li>' + + '<span>' + obj.name + '</span>' + + '<select data-role="slider" data-index="' + i + '">' + + '<option value="off" ' + (obj.enabled ? '' : 'selected="selected"') + '></option>' + + '<option value="on" ' + (obj.enabled ? 'selected="selected"' : '') + '></option>' + + '</select>' + '</li>'; + }; +}()); + diff --git a/js/app.alarms.js b/js/app.alarms.js new file mode 100644 index 0000000..3c6c17e --- /dev/null +++ b/js/app.alarms.js @@ -0,0 +1,55 @@ +/*jslint devel:true*/ +/*global ExercisePlanner:false, tizen:false*/ +/** + * Methods for add / remove alarms by API; + */ +(function () { + "use strict"; + /** + * Wrapper on remove all alarms joined with app + */ + ExercisePlanner.prototype.removeAllAlarms = function () { + tizen.alarm.removeAll(); + }; + + ExercisePlanner.prototype.WORKDAYS = ["MO", "TU", "WE", "TH", "FR"]; + ExercisePlanner.prototype.WEEKEND = ["SA", "SU"]; + + /** + * Add alarms from Array + * + * @param tabOfAlarm + * @param defOfPeriod + */ + ExercisePlanner.prototype.addAlarmFromArray = function addAlarmFromArray(tabOfAlarm, defOfPeriod) { + var i, len = tabOfAlarm.length, alarm; + + for (i = 0; i < len; i += 1) { + alarm = new tizen.AlarmAbsolute(tabOfAlarm[i], defOfPeriod); + try { + tizen.alarm.add(alarm, this.selfId); + } catch (e) { + console.error(e.message); + } + } + }; + + /** + * Add alarms to API DataBase + * + * @param {object} alarms + */ + ExercisePlanner.prototype.addAlarmsAllWeek = function addAlarmsAllWeek(alarms) { + if (alarms.everyday.length > 0) { + this.addAlarmFromArray(alarms.everyday, tizen.alarm.PERIOD_DAY); + } + if (alarms.workday.length > 0) { + this.addAlarmFromArray(alarms.workday, this.WORKDAYS); + } + if (alarms.weekend.length > 0) { + this.addAlarmFromArray(alarms.weekend, this.WEEKEND); + } + }; + +}()); + diff --git a/js/app.alarmsGenerating.js b/js/app.alarmsGenerating.js new file mode 100644 index 0000000..37ae7b0 --- /dev/null +++ b/js/app.alarmsGenerating.js @@ -0,0 +1,153 @@ +/*jslint devel: true*/ +/*global ExercisePlanner: true, ONE_DAY:false, TIME_OF_SLEEP:false */ +/** + * + */ +(function () { + "use strict"; + /** + * + * + * @param availableTime + * @param typeOfPeriod + * @returns {object} + */ + ExercisePlanner.prototype.calculateFactor = function calculateFactors(availableTime, typeOfPeriod) { + var factor, + result = { + count: 0, + period: 0 + }; + + if (availableTime === 0) { + return result; + } + + factor = availableTime / (this.ONE_DAY - this.TIME_OF_SLEEP); + result.proportionalFrequency = this.getNumberOfWorkoutsByFrequency(this.config.frequency[typeOfPeriod]) * factor; + + if ((Math.round(result.proportionalFrequency) - 1) > 0) { + result.count = (Math.round(result.proportionalFrequency)); + result.period = availableTime / (result.count - 1); + } else { + result.count = 1; + result.period = 0; + } + + return result; + }; + + /** + * + * + * @param availableTime + * @returns {object} + */ + ExercisePlanner.prototype.calculateFactors = function calculateFactors(availableTime) { + return { + weekend: this.calculateFactor(availableTime.weekend, 'weekend'), + workday: this.calculateFactor(availableTime.workday, 'workday'), + everyday: this.calculateFactor(availableTime.everyday, 'workday') + }; + }; + + /** + * + * + * @param factor + * @param tmpPeriods + * @returns {Array} + */ + ExercisePlanner.prototype.generateAlarmsByFactor = function (factor, tmpPeriods) { + var i, numberOfPeriods = tmpPeriods.length, + period, + begin, + end = 0, + tableOfAlarms = [], + optimalTime, + deltaTime = 0, + dayTime = this.beginDate || new Date(); + + if (numberOfPeriods === 0) { + return []; + } + + begin = tmpPeriods[0].start; + + for (i = 0; i < numberOfPeriods; i += 1) { + if (tmpPeriods[i].stop > end) { + end = tmpPeriods[i].stop; + } + } + + dayTime.setSeconds(0); + + if (factor.count === 1) { + // One alarm per day, default placed in middle of available time; + optimalTime = this.findNearestTimeRange((end + begin) / 2, tmpPeriods); + + dayTime.setHours(parseInt(optimalTime.optimalHour, 10)); + dayTime.setMinutes(60 * (optimalTime.optimalHour - parseInt(optimalTime.optimalHour, 10))); + tableOfAlarms.push(new Date(dayTime.getTime())); + } else { + // set time for begin; + dayTime.setHours(tmpPeriods[0].start); + dayTime.setMinutes(0); + tableOfAlarms.push(new Date(dayTime.getTime())); + + // set time for next hop; + for (i = 0; i < numberOfPeriods; i += 1) { + period = tmpPeriods[i]; + deltaTime += period.duration; + // if available period is too small, then accumulate time + // and continue to next period; + while (deltaTime >= factor.period * 0.999) { + deltaTime -= factor.period; + + dayTime.setHours(parseInt(period.stop - deltaTime, 10)); + dayTime.setMinutes(60 * (period.stop - deltaTime - parseInt(period.stop - deltaTime, 10))); + + tableOfAlarms.push(new Date(dayTime.getTime())); + } + } + } + + return tableOfAlarms; + }; + + /** + * Generate table of alarms => this.alarms + * @param {Date} customDate; + */ + ExercisePlanner.prototype.generateAlarms = function () { + var factors, + alarms = this.alarms, + periodsWeek = { + everyday: [], + workday: [], + weekend: [] + }; + + // some periods may overlap, must be merged + periodsWeek = this.mergePeriods(); + // store in cache for later reuse + this.cache.periodsWeek = periodsWeek; + + // factors to correct how often may workouts per day + factors = this.calculateFactors(this.getSummaryAvailableTime()); + + // Set new alarms; + if (periodsWeek.everyday.length > 0) { + alarms.everyday = this.generateAlarmsByFactor(factors.everyday, periodsWeek.everyday); + } else { + alarms.workday = this.generateAlarmsByFactor(factors.workday, periodsWeek.workday); + alarms.weekend = this.generateAlarmsByFactor(factors.weekend, periodsWeek.weekend); + } + + // if trainig is in run then resinstall alarm imediately + if (this.config.trainingEnabled) { + this.startAlarms(); + } + }; +}()); + diff --git a/js/app.js b/js/app.js new file mode 100644 index 0000000..3ab9bd8 --- /dev/null +++ b/js/app.js @@ -0,0 +1,450 @@ +/*jslint devel:true*/ +/*global tizen, $, app, localStorage, Audio, document, unlockScreen, UI */ +var ExercisePlanner = function () { + "use strict"; +}; + +(function () { + "use strict"; + + ExercisePlanner.prototype = { + /** + * Definition of time for sleep + */ + TIME_OF_SLEEP: 8, + + /** + * Definition one day in hours + */ + ONE_DAY: 24, + + /** + * Stored time of application start + */ + applicationStartTime: new Date(), + + /** + * Cofiguration data will saved for next launch; + * There are default values after install; + */ + config: { + + frequency: { + workday: 3, // 6 for test + weekend: 3 + }, + + strength: { + workday: 1, + weekend: 1 + }, + + /** + * List of workouts; + * - timeRanges:style [ everyday, weekend, workday ]; ( workday : mon-fri ) + */ + exercises: [{ + name: 'bends', + enabled: true + }, { + name: 'squats', + enabled: true + }, { + name: 'push-ups', + enabled: false + }], + + // deprecated for this version; + increasingStrength: true, + + /** + * Default time ranges + */ + timesRanges: [{ + nr: 0, + start: 8, + stop: 16, + duration: 8, + enabled: true, + style: 'everyday' + }, { + nr: 1, + start: 18, + stop: 22, + duration: 4, + enabled: true, + style: 'weekend' + }], + + nearestExercise: -1, + + count: 0, + + trainingEnabled: false + }, + alarms: { + everyday: [], + workday: [], + weekend: [] + }, + + /** + * Used for update GraphSchedule; + * [ workday / weekend ] + */ + currentTypeOfPeriods: 'workday', + /** + * Use on form to edit time period; + */ + currentEditingTimePeriod: null, + currentEditingTimePeriodId: -1, + + /** + * Date when alarm will start generating + */ + beginDate: null, + + /** + * use store temporary data for alarms; + */ + cache: {}, + + /** + * HTML5 audio element for play audio when alarm is called + */ + audioOfAlert: null, + + /** + * Instance of User Interface + */ + ui: null + }; + + /** + * Load configuration of application + * (use localStorage) + */ + ExercisePlanner.prototype.loadConfig = function () { + var configStr = localStorage.getItem('config'); + if (configStr) { + this.config = JSON.parse(configStr); + } else { + this.removeAllAlarms(); + this.sortTimeRanges(); + } + }; + + /** + * Save configuration of application + * (use localStorage) + */ + ExercisePlanner.prototype.saveConfig = function () { + localStorage.setItem('config', JSON.stringify(this.config)); + }; + + ExercisePlanner.prototype.stopTraining = function () { + this.removeAllAlarms(); + this.ui.setStatusRun(this.config.trainingEnabled); + }; + + ExercisePlanner.prototype.startTraining = function () { + this.ui.setStatusRun(this.config.trainingEnabled); + this.startAlarms(); + }; + + /** + * Toggle start/stop alarms for workouts + */ + ExercisePlanner.prototype.appStartStop = function () { + this.config.trainingEnabled = !this.config.trainingEnabled; + if (this.config.trainingEnabled) { + this.startTraining(); + } else { + this.stopTraining(); + } + this.saveConfig(); + }; + + /** + * Closing application with the configuration data saving + */ + ExercisePlanner.prototype.exit = function () { + this.saveConfig(); + this.stopMusic(); + tizen.application.getCurrentApplication().exit(); + }; + + /** + * Sets frequency value and calculates new alarms + * @param value + */ + ExercisePlanner.prototype.setFrequency = function (value) { + this.config.frequency[this.config.currentTypeOfPeriods] = parseInt(value, 10); + + this.saveConfig(); + this.generateAlarms(); + this.updateGraph(this.config.currentTypeOfPeriods); + this.showNextAlarm(); + }; + + /** + * Set Strength value + * @param value + */ + ExercisePlanner.prototype.setStrength = function (value) { + this.config.strength[this.config.currentTypeOfPeriods] = parseInt(value, 10); + this.saveConfig(); + }; + + /** + * Sending array of exercises to UI for update + */ + ExercisePlanner.prototype.updateExercises = function () { + this.ui.fillExercises(this.config.exercises); + }; + + /** + * Sending array of time ranges to UI for update + * & update graph schedule + */ + ExercisePlanner.prototype.updateTimesRanges = function () { + + this.ui.fillTimesRanges(this.config.timesRanges); + this.ui.graphSchedule.updateTimeRanges(); + }; + + /** + * Store exercises in config (and save) + * @param newData + */ + ExercisePlanner.prototype.saveExercises = function (newData) { + var i, l; + + if (newData) { + for (i = 0, l = newData.length; i < l; i += 1) { + this.config.exercises[i].enabled = newData[i].checked; + } + this.generateNearestExercise(); + this.saveConfig(); + } + }; + + /** + * When will earliest workout + * and show in UI + */ + ExercisePlanner.prototype.showNextAlarm = function showNextAlarm() { + var alarms, + currentDate = new Date(); + + if (this.alarms.everyday.length > 0) { + alarms = this.alarms.everyday; + } else { + alarms = (this.todayIsWorkday()) ? this.alarms.workday : this.alarms.weekend; + } + + alarms = alarms.filter(function (item) { + return (item.getTime() > currentDate.getTime()); + }).sort(function (a, b) { + return a.date - b.date; + }); + + if (this.config.nearestExercise > -1) { + this.ui.showAlarmInMonitor({ + alarm: alarms[0], + exerciseName: this.config.exercises[this.config.nearestExercise].name, + numberOfTimes: this.getStrength(this.config.strength.workday, this.config.count) + }); + + this.config.count += 1; + } + this.saveConfig(); + }; + + /** + * Change type of periods [workday/weekend] and update graph + * @param type + */ + ExercisePlanner.prototype.changeTypeOfPeriods = function changeTypeOfPeriods(type) { + if (this.config.currentTypeOfPeriods !== type) { + this.config.currentTypeOfPeriods = type; + this.updateGraph(this.config.currentTypeOfPeriods); + } + }; + + /** + * Check new exercise name for duplication in existings; + * @param name + * @returns + */ + ExercisePlanner.prototype.checkExerciseName = function (name) { + var i, l; + + if (name) { + for (i = 0, l = this.config.exercises.length; i < l; i += 1) { + if (this.config.exercises[i].name === name) { + return i; + } + } + return -1; + } + return undefined; + }; + + /** + * Add new exercise sent from UI + * @param name + * @returns {Boolean} + */ + ExercisePlanner.prototype.addExercise = function (name) { + if (this.checkExerciseName(name) < 0) { + this.config.exercises.push({ + name: name, + enabled: false + }); + this.saveConfig(); + this.ui.fillExercises(this.config.exercises); + return true; + } + this.ui.showErrors([{name: 'Element exists!'}]); + return false; + }; + + /** + * Get number of workouts by frequency + * @param value + * @returns {number} + */ + ExercisePlanner.prototype.getNumberOfWorkoutsByFrequency = function getNumberOfWorkoutsByFrequency(value) { + var iMap = [1, 2, 4, 8, 16, 24, 150], + // -- times per 24h; proportion to set periods of available time; + numberOfWorkouts = iMap[value]; + + return numberOfWorkouts || 2; + }; + + /** + * Get number of exercises in workout by strength value and optional ; + * @param value + * @param count + * @returns {number} + */ + ExercisePlanner.prototype.getStrength = function strengthMap(value, count) { + var sMap = [1, 1, 2, 4, 10, 20], + base = sMap[value] || 2; + + count = count || 1; + return Math.round(base * (count / 10 + 1)); + }; + + /** + * Generate name of exercise for nearest workout + */ + ExercisePlanner.prototype.generateNearestExercise = function () { + var tmp = this.config.exercises.filter(function (item) { + return item.enabled; + }); + this.config.nearestExercise = parseInt(Math.random() * tmp.length, 10); + }; + + + /** + * If user want change work days this method will changing; + * @returns {Boolean} + */ + ExercisePlanner.prototype.todayIsWorkday = function todayIsWorkday() { + var day = (new Date()).getDay(); + return (day >= 1 && day <= 5); + }; + + /** + * Activate alarms in API. + */ + ExercisePlanner.prototype.startAlarms = function startAlarms() { + // clear old alarms; + this.removeAllAlarms(); + + // add new alarms + this.addAlarmsAllWeek(this.alarms); + + this.generateNearestExercise(); + this.showNextAlarm(); + }; + + /** + * Update Graph object + * @param {String} typeOfPeriods ['workday'|'weekend'] + */ + ExercisePlanner.prototype.updateGraph = function updateGraph(typeOfPeriods) { + var alarms; + if (!this.ui.graphSchedule) { + throw { + message: 'graph schedule not exists.' + }; + } + + typeOfPeriods = typeOfPeriods || ((this.todayIsWorkday()) ? 'workday' : 'weekend'); + + if (typeOfPeriods === 'workday') { + alarms = this.alarms.workday; + } else { + alarms = this.alarms.weekend; + } + if (alarms.length === 0) { + alarms = this.alarms.everyday; + } + this.ui.graphSchedule.setTimeRanges(this.periodsWeekToBoolArray()); + this.ui.graphSchedule.pushTimeOfFlags(alarms); + this.ui.graphSchedule.showFlags(); + }; + + /** + * Callback function on visibility change; + */ + ExercisePlanner.prototype.onVisibilityChange = function () { + + switch (document.webkitVisibilityState) { + case 'visible': + this.applicationStartTime = new Date(); + this.currentAlarm = this.findCurrentAlarm(); + if (this.currentAlarm.length > 0) { + this.ui.showWaitOk(); + this.startMusic(); + } + break; + } + }; + + /** + * Turn off all alarms today + */ + ExercisePlanner.prototype.todayOffAll = function todayOffAll() { + // set begin date to tomorrow; + this.beginDate = new Date(); + this.beginDate.setDate(this.beginDate.getDate() + 1); + // recreate alarms; + this.generateAlarms(); + this.exit(); + }; + + // Initialize function + ExercisePlanner.prototype.init = function init() { + var onUiInitialize = function onUiInitialize() { + // register watcher on visibility change; + document.addEventListener('webkitvisibilitychange', this.onVisibilityChange.bind(this)); + this.showNextAlarm(); + this.onVisibilityChange(); + }.bind(this); + + this.selfId = tizen.application.getAppContext().appId; + this.ui = new UI(); + this.ui.app = this; + + this.loadConfig(); + this.config.currentTypeOfPeriods = (this.todayIsWorkday()) ? 'workday' : 'weekend'; + + this.generateAlarms(); + + this.ui.initialize(onUiInitialize); + }; +}()); diff --git a/js/app.onAlarm.js b/js/app.onAlarm.js new file mode 100644 index 0000000..14f734d --- /dev/null +++ b/js/app.onAlarm.js @@ -0,0 +1,66 @@ +/*jslint devel:true*/ +/*global ExercisePlanner:false, tizen:false, Audio:false*/ +/** + * These method are using when alarm is call. + */ +(function () { + "use strict"; + ExercisePlanner.prototype.findCurrentAlarm = function () { + var currentTimeInMinutes = parseInt(this.applicationStartTime.getTime() / 1000, 10), + listOfAlarms = tizen.alarm.getAll(); + + return listOfAlarms.filter(function (item) { + // alarm relative has not date property; + if (!item.date) { + return false; + } + + // +40/-10 seconds tolerance; + if (parseInt(item.date.getTime() / 1000, 10) < (currentTimeInMinutes + 40) + && parseInt(item.date.getTime() / 1000, 10) > (currentTimeInMinutes - 10)) { + return true; + } + }); + }; + + ExercisePlanner.prototype.wait = function () { + // lastAlert -> change +1min + var snozeTime = 1, currentAlarm = this.currentAlarm, newDate = new Date(), alarm; + + if (currentAlarm) { + newDate.setMinutes(newDate.getMinutes() + snozeTime); + // period value must be set so application started by alert will know current alert; + alarm = new tizen.AlarmAbsolute(newDate, tizen.alarm.PERIOD_WEEK * 10); + tizen.alarm.add(alarm, this.selfId); + // -- remove old snooze alarm + if (currentAlarm.period === tizen.alarm.PERIOD_WEEK * 10) { + tizen.alarm.remove(currentAlarm.id); + } + this.stopMusic(); + } + + this.exit(); + // or tizen.application.hide(); + }; + + ExercisePlanner.prototype.ok = function () { + this.exit(); + }; + + ExercisePlanner.prototype.startMusic = function () { + + if (!this.audioOfAlert) { + this.audioOfAlert = new Audio(); + } + this.audioOfAlert.src = 'WebContent/Runner.mp3'; + this.audioOfAlert.load(); + this.audioOfAlert.play(); + }; + + ExercisePlanner.prototype.stopMusic = function () { + if (this.audioOfAlert) { + this.audioOfAlert.pause(); + } + }; +}()); + diff --git a/js/app.timeRange.js b/js/app.timeRange.js new file mode 100644 index 0000000..374fde6 --- /dev/null +++ b/js/app.timeRange.js @@ -0,0 +1,386 @@ +/*jslint devel: true*/ +/*global $, ExercisePlanner: true*/ +/** + * + */ +(function () { + "use strict"; + ExercisePlanner.prototype.checkNewTimeRange = function (start, duration, style) { + var result = []; + if (duration < 1 || duration > 24) { + result.push({ + name: 'Duration is not set properly.', + code: 2 + }); + } + return result; + }; + + /** + * Sort method for time ranges; + */ + ExercisePlanner.prototype.sortTimeRanges = function () { + this.config.timesRanges.sort(function (a, b) { + return a.start - b.start; + }); + }; + + /** + * Find and return max value of nr in time ranges array; + * @returns {Number} + */ + ExercisePlanner.prototype.getMaxNrOfTimeRange = function getMaxNrOfTimeRange() { + var maxNr = -1, i, len = this.config.timesRanges.length; + for (i = 0; i < len; i += 1) { + if (maxNr < this.config.timesRanges[i].nr) { + maxNr = this.config.timesRanges[i].nr; + } + } + return maxNr; + }; + + /** + * + * @param nr + * @returns {Boolean} + */ + ExercisePlanner.prototype.getTimeRangeByNr = function getTimeRangeByNr(nr) { + var result = this.config.timesRanges.filter(function (item) { + return (item.nr === nr); + }); + return result[0]; + }; + + /** + * Save time range + * + * @param nr + * @param timeRange + * @returns {Boolean} + */ + ExercisePlanner.prototype.saveTimeRange = function (nr, timeRange) { + var index = -1, + errors = this.checkNewTimeRange(timeRange.start, timeRange.duration, timeRange.style); + + // new timeRanges has nr === -1; this mean we must get max number from config + if (nr === -1) { + nr = this.getMaxNrOfTimeRange() + 1; + } else { + index = this.config.timesRanges.indexOf(this.getTimeRangeByNr(nr)); + } + + timeRange.nr = nr; + + if (errors.length > 0) { + this.ui.showErrors(errors); + return false; + } + + if (index !== -1) { + this.config.timesRanges[index] = timeRange; + } else { + this.config.timesRanges.push(timeRange); + } + + this.sortTimeRanges(); + this.saveConfig(); + this.ui.fillTimesRanges(this.config.timesRanges); + this.generateAlarms(); + this.updateGraph(); + + return true; + }; + + /** + * + * @param {nymber} + * @returns {number} + */ + ExercisePlanner.prototype.editTimeRange = function editTimeRange(nr) { + var timeRange = this.getTimeRangeByNr(nr); + + if (timeRange !== undefined) { + this.currentEditingTimePeriod = timeRange; + this.currentEditingTimePeriodId = timeRange.nr; + } else { + this.currentEditingTimePeriod = { + nr: -1, + start: 10, + duration: 1, + stop: 11, + enabled: true, + style: 'everyday' + }; + this.currentEditingTimePeriodId = -1; + } + return this.currentEditingTimePeriodId; + }; + + /** + * Delete time range by number on list + * + * @param nr + * @returns {Boolean} + */ + ExercisePlanner.prototype.deleteTimeRange = function (nr) { + + var index, + timeRange = this.getTimeRangeByNr(nr); + + if (timeRange === undefined) { + return false; + } + + index = this.config.timesRanges.indexOf(timeRange); + if (index === -1) { + return false; + } + + // delete time range from array; + this.config.timesRanges.splice(index, 1); + + this.saveConfig(); + this.ui.fillTimesRanges(this.config.timesRanges); + this.generateAlarms(); + // update time periods on graph; + this.ui.graphSchedule.setTimeRanges(this.periodsWeekToBoolArray()); + this.ui.graphSchedule.refresh(); + + this.updateGraph(); + this.showNextAlarm(); + return true; + }; + + /** + * Disable time range by number on list + * + * @param nr + * @returns {Boolean} + */ + ExercisePlanner.prototype.disableTimeRange = function (nr) { + var timeRange = this.getTimeRangeByNr(nr); + + if (timeRange === undefined) { + return false; + } + + timeRange.enabled = !timeRange.enabled; + + this.saveConfig(); + this.ui.fillTimesRanges(this.config.timesRanges); + this.generateAlarms(); + // update time periods on graph; + this.ui.graphSchedule.setTimeRanges(this.periodsWeekToBoolArray()); + this.ui.graphSchedule.refresh(); + + this.updateGraph(this.config.currentTypeOfPeriods); + this.showNextAlarm(); + return true; + }; + + /** + * Combines a overlapped time periods & delete not necesary + * This method modifies exisiting array in cache. + * + * @param periods + * @returns + */ + ExercisePlanner.prototype.mergeOverlapPeriods = function mergeOverlapPeriods(periods) { + var i, len = periods.length, wasOverlap = true, mergePeriod; + + periods.sort(function (a, b) { + return a - b; + }); + + if (len < 2) { + return periods; + } + + while (wasOverlap) { + wasOverlap = false; + len = periods.length; + for (i = 0; i < len - 1; i += 1) { + if (periods[i].stop > periods[i + 1].start) { + mergePeriod = $.extend({}, periods[i]); + if (mergePeriod.stop < periods[i + 1].stop) { + mergePeriod.stop = periods[i + 1].stop; + mergePeriod.duration = mergePeriod.stop - mergePeriod.start; + } + mergePeriod.nr = -1; + periods.splice(i, 2, mergePeriod); + wasOverlap = true; + break; + } + } + } + + return periods; + }; + + ExercisePlanner.prototype.mergePeriods = function mergePeriods() { + var i, len, onlyEveryDay = true, + ranges = this.config.timesRanges, + result = { + everyday : [], + weekend: [], + workday: [] + }; + + // checking time ranges for different to the "everyday" + for (i = 0, len = ranges.length; i < len; i += 1) { + if (ranges[i].style !== 'everyday') { + onlyEveryDay = false; + break; + } + } + + if (onlyEveryDay) { + for (i = 0, len = this.config.timesRanges.length; i < len; i += 1) { + if (this.config.timesRanges[i].enabled) { + result.everyday.push(this.config.timesRanges[i]); + } + } + } else { + // divide 'everyday' periods at workday/weekend + for (i = 0, len = this.config.timesRanges.length; i < len; i += 1) { + // if time range is disabled do not append to cache; + if (this.config.timesRanges[i].enabled) { + switch (this.config.timesRanges[i].style) { + case 'everyday': + result.workday.push(this.config.timesRanges[i]); + result.weekend.push(this.config.timesRanges[i]); + break; + case 'workday': + result.workday.push(this.config.timesRanges[i]); + break; + case 'weekend': + result.weekend.push(this.config.timesRanges[i]); + break; + } + } + } + } + + // check and correct overlaped time periods + this.mergeOverlapPeriods(result.everyday); + this.mergeOverlapPeriods(result.workday); + this.mergeOverlapPeriods(result.weekend); + + return result; + }; + + ExercisePlanner.prototype.getSummaryAvailableTime = function getSummaryAvailableTime() { + var i, len, + periods = this.cache.periodsWeek, + sum = { + weekend: 0, + workday: 0, + everyday: 0 + }; + + for (i = 0, len = periods.everyday.length; i < len; i += 1) { + if (periods.everyday[i].enabled) { + sum.everyday += periods.everyday[i].duration; + } + } + for (i = 0, len = periods.workday.length; i < len; i += 1) { + if (periods.workday[i].enabled) { + sum.workday += periods.workday[i].duration; + } + } + for (i = 0, len = periods.weekend.length; i < len; i += 1) { + if (periods.weekend[i].enabled) { + sum.weekend += periods.weekend[i].duration; + } + } + + return sum; + }; + + ExercisePlanner.prototype.findNearestTimeRange = function (hour, ranges) { + var nearResult, + result = { + requestedHour: hour, + optimalHour: -1 + }; + + if (!ranges.length) { + return result; + } + + /** + * Function search ranges of time for nearest to a hour + */ + nearResult = ranges.reduce(function (previous, element, index) { + var delta = 0; + + if (element.start < hour && element.stop < hour) { + delta = hour - element.stop; + } + + if (element.start > hour && element.stop > hour) { + delta = element.start - hour; + } + + return (delta < previous.delta) ? { index: index, delta: delta } : previous; + }, { index: -1, delta: 100 }); + + if (ranges[nearResult.index].start <= hour && ranges[nearResult.index].stop >= hour) { + result.optimalHour = Math.round((ranges[nearResult.index].start + ranges[nearResult.index].stop) / 2); + } else { + result.optimalHour = (ranges[nearResult.index].start > hour) ? ranges[nearResult.index].start : ranges[nearResult.index].stop; + } + + return result; + }; + + /** + * Export time period to array of boolen [boolean x 24] + * @returns {object} + */ + ExercisePlanner.prototype.periodsWeekToBoolArray = function periodsWeekToBoolArray() { + var i, j, len, periods, + result = { + workday: [], + weekend: [] + }; + + // fill default result; + for (i = 0; i < 24; i += 1) { + result.workday[i] = false; + result.weekend[i] = false; + } + + // set values; + periods = this.cache.periodsWeek.everyday; + len = periods.length; + for (i = 0; i < len; i += 1) { + for (j = periods[i].start; j < periods[i].start + periods[i].duration; j += 1) { + result.workday[j] = true; + result.weekend[j] = true; + } + } + + // set values; + periods = this.cache.periodsWeek.workday; + len = periods.length; + for (i = 0; i < len; i += 1) { + for (j = periods[i].start; j < periods[i].start + periods[i].duration; j += 1) { + result.workday[j] = true; + } + } + + // set values; + periods = this.cache.periodsWeek.weekend; + len = periods.length; + for (i = 0; i < len; i += 1) { + for (j = periods[i].start; j < periods[i].start + periods[i].duration; j += 1) { + result.weekend[j] = true; + } + } + return result; + }; + + +}()); + diff --git a/js/ext.jqMobile.js b/js/ext.jqMobile.js new file mode 100644 index 0000000..9de50b5 --- /dev/null +++ b/js/ext.jqMobile.js @@ -0,0 +1,17 @@ +/*global $*/ +// customize JQueryMobile controlgroup +$.fn.oldControlgroup = $.fn.controlgroup; +$.fn.controlgroup = function (options) { + "use strict"; + return this.oldControlgroup(options).each(function () { + this.deselectAll = function () { + return $('input', this).attr('checked', false).checkboxradio('refresh'); + }; + + this.select = function (value) { + this.deselectAll(); + return $('input[value$="' + value + '"]', this).attr('checked', true).checkboxradio('refresh'); + }; + }); +}; + diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..c3d8a85 --- /dev/null +++ b/js/main.js @@ -0,0 +1,21 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*global ExercisePlanner, tizen, $, document*/ +var c = null, exercisePlanner = null, appService = null, ui = null; + +exercisePlanner = new ExercisePlanner(); +$(document).ready(exercisePlanner.init.bind(exercisePlanner)); + diff --git a/music/Runner.mp3 b/music/Runner.mp3 Binary files differnew file mode 100644 index 0000000..620aba5 --- /dev/null +++ b/music/Runner.mp3 diff --git a/signature1.xml b/signature1.xml new file mode 100644 index 0000000..bee47b5 --- /dev/null +++ b/signature1.xml @@ -0,0 +1,160 @@ +<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="DistributorSignature"> +<SignedInfo> +<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod> +<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"></SignatureMethod> +<Reference URI="templates/GraphSchedule.tmpl"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>deYSqUgxc88hVjk5a7xUn3Oy2THk0VIYt5J51C/luIY=</DigestValue> +</Reference> +<Reference URI="music/Runner.mp3"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>sN0gBCSppwupIISCWk9SKbhuih2BlUxwcFgys6SIzHE=</DigestValue> +</Reference> +<Reference URI="AUTHORS"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>FANWRSdDi4T/f2CqQe56fL8NMZfewK2azWEBAfnjbQg=</DigestValue> +</Reference> +<Reference URI="images/background.png"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>Y4XligVqi8vVA74GUDSAUawxYuomV/h4ozXffrH+hhU=</DigestValue> +</Reference> +<Reference URI="images/longBothHorizonGradient2.png"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>Dq5u5V1W1FL9N+KMTKfBJTEiW0aTVHUWx0utuciKSIo=</DigestValue> +</Reference> +<Reference URI="images/markers.png"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>FX2aaCklIguMzPy9rZPS0vY7qWsZ2idyx6ZPUUzQzrU=</DigestValue> +</Reference> +<Reference URI="images/state_run.png"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>Z7lFDN5i8vTxs/CnSisNoLvcKDtQEqd6K0E5KUjNgHg=</DigestValue> +</Reference> +<Reference URI="images/state_lazy.png"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>s8Dc9i4P69eEp8ULwUL36ZpcSLzjQ02DDL8ozuB6HJw=</DigestValue> +</Reference> +<Reference URI="images/longBothHorizonGradient.png"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>1WwlyV7JaL1IyVaPS14yN3wxOngbmuvC2OgVMM9RvpQ=</DigestValue> +</Reference> +<Reference URI="LICENSE.Flora"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>fskt8W7B8EMb3DQsvwT98x4fPKKIjY9sS5E0eSGenFA=</DigestValue> +</Reference> +<Reference URI="js/app.alarms.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>7t0Zyyn9Cu0/HXEXaxEinFCFYpmDDgP7vdyN5UVWkQk=</DigestValue> +</Reference> +<Reference URI="js/app.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>MtoxmfFtOOUWSBu/kfMTnCeClw9RLIjMS77IWrMG7wg=</DigestValue> +</Reference> +<Reference URI="js/ext.jqMobile.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>7iRwb6yZgM18/ZU4M8pBpsYb0xXylyPJhsqzbV1eLyY=</DigestValue> +</Reference> +<Reference URI="js/main.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>lwMHcPXzvcu+hIVItWfT7RIQgrJvRi9mCrq/i38fRGc=</DigestValue> +</Reference> +<Reference URI="js/app.onAlarm.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>A52TbnmMcr8G0QDY86BmznRMEAVLMrBShC2E51RITb4=</DigestValue> +</Reference> +<Reference URI="js/app.timeRange.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>4cLd4pP/oi83KOcF8LVUJB6gxUWBsE8ZiDBCoJzjE/o=</DigestValue> +</Reference> +<Reference URI="js/UI.simpleTemplate.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>xcxpAXCb5SX9K2yPYnYXSg/lFPbD5exPgfKQcvSSqr4=</DigestValue> +</Reference> +<Reference URI="js/UI.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>oQLj5QS+lsqDZxd0xEQFMBQ4spZ7J0qVvd6OaEiMgQQ=</DigestValue> +</Reference> +<Reference URI="js/GraphSchedule.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>ZpmuwAVONsdanK1S4KQPaHj1EYC8Ezs1QDZQbaFWm4M=</DigestValue> +</Reference> +<Reference URI="js/app.alarmsGenerating.js"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>1i4kpyIdtiDzToEKnuhiGitX2hVtPRVto9KixvY1B+s=</DigestValue> +</Reference> +<Reference URI="config.xml"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>XTYWoMBP0dm54DvvQmpdv0uG7UuU8wt06y9PfLGVI8E=</DigestValue> +</Reference> +<Reference URI="icon.png"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>Nz+SecsjmNuidhKNvmQ5+3nasrw8vI4q/bjPgbfx5fI=</DigestValue> +</Reference> +<Reference URI="index.html"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>xX14SRqSRUj4eElU8av1uUFNdNCNFlCUxZcrs8q4xUw=</DigestValue> +</Reference> +<Reference URI="css/jquery.ui.layout.css"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>4v30rSrxvLzjKEHb3fjwwzJHfYs4SuPd2opc+CDv77g=</DigestValue> +</Reference> +<Reference URI="css/style.css"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>miNScnFdCe9HXHU/gs87RJdJDHJahAKjhCNH6w6MhFE=</DigestValue> +</Reference> +<Reference URI="css/GraphSchedule.css"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>FMRxMozySMCFzVvfumNqZOHA+/qDtj84zddroztYWME=</DigestValue> +</Reference> +<Reference URI="NOTICE.Flora"> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>M7oEsiEdLNeaSAYdtR7uR5WGeAELG/V70u7Huzl42Xs=</DigestValue> +</Reference> +<Reference URI="#prop"> +<Transforms> +<Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"></Transform> +</Transforms> +<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod> +<DigestValue>u/jU3U4Zm5ihTMSjKGlGYbWzDfRkGphPPHx3gJIYEJ4=</DigestValue> +</Reference> +</SignedInfo> +<SignatureValue> +BOQ2cEF2grAU8uRj4s7asgejDpRN26vGa4TJxe6xdBULJ1th7w6mB9czrghnsNZu/yGCCMCep9I0 +cu1Wdyly3mSd3Z/HlR5meFHYekMaY1e2goXatc+jjayWuIxFFIG6FG0UvjY8nc/Ft1vgiwdI0e/Y +KgsF6y2N3mnliXB9rOU= +</SignatureValue> +<KeyInfo> +<X509Data> +<X509Certificate> +MIICnTCCAgYCCQDE9MbMmJ/yCzANBgkqhkiG9w0BAQUFADCBkDELMAkGA1UEBhMCS1IxDjAMBgNV +BAgMBVN1d29uMQ4wDAYDVQQHDAVTdXdvbjEWMBQGA1UECgwNVGl6ZW4gVGVzdCBDQTEiMCAGA1UE +CwwZVGl6ZW4gRGlzdHJpYnV0b3IgVGVzdCBDQTElMCMGA1UEAwwcVGl6ZW4gUGFydG5lciBEaXN0 +cmlidXRvciBDQTAeFw0xMjEwMjcwNzQ4MzNaFw0yMjEwMjUwNzQ4MzNaMIGUMQswCQYDVQQGEwJL +UjEOMAwGA1UECAwFU3V3b24xDjAMBgNVBAcMBVN1d29uMRYwFAYDVQQKDA1UaXplbiBUZXN0IENB +MSIwIAYDVQQLDBlUaXplbiBEaXN0cmlidXRvciBUZXN0IENBMSkwJwYDVQQDDCBUaXplbiBQYXJ0 +bmVyIERpc3RyaWJ1dG9yIFNpZ25lcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAy9mg2x4B +zxlK3LJL81GsLq/pJfK1evdCKG/IOBpdoRO0rLhYnsL5+KvToPFa5g9GTZo32LikpW1NZ7++3EHE +fnO2IGLUau4kquvhmz1LNg5xBTx7IbucmwLMRGo1BPGdsAQQLyXeQKJ5PCERmVg4MIoiL2zT/JsL +sZ9UPT6GEB8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAw5xPBFR1XKuZ8QpsCtSE0zXVHvwIa+Ha4 +YBdRtGwEoZmiKGZV/wAhPRdmR0kISkTz20kIGz/ZwRZCVGhsr5hkkpFknYlKeKkEJ/tJfZl4D7ec +GFAnynOzlWZqSIPz+yxX8ah9E6lTv4Vs9DhNb08nxVvxLqlpyVdk9RUsCx/yIA== +</X509Certificate> +<X509Certificate> +MIICtTCCAh6gAwIBAgIJAKORBcIiXygIMA0GCSqGSIb3DQEBBQUAMIGVMQswCQYDVQQGEwJLUjEO +MAwGA1UECAwFU3V3b24xDjAMBgNVBAcMBVN1d29uMRYwFAYDVQQKDA1UaXplbiBUZXN0IENBMSIw +IAYDVQQLDBlUaXplbiBEaXN0cmlidXRvciBUZXN0IENBMSowKAYDVQQDDCFUaXplbiBQYXJ0bmVy +IERpc3RyaWJ1dG9yIFJvb3QgQ0EwHhcNMTIxMDI3MDc0NTIwWhcNMjIxMDI1MDc0NTIwWjCBkDEL +MAkGA1UEBhMCS1IxDjAMBgNVBAgMBVN1d29uMQ4wDAYDVQQHDAVTdXdvbjEWMBQGA1UECgwNVGl6 +ZW4gVGVzdCBDQTEiMCAGA1UECwwZVGl6ZW4gRGlzdHJpYnV0b3IgVGVzdCBDQTElMCMGA1UEAwwc +VGl6ZW4gUGFydG5lciBEaXN0cmlidXRvciBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +2ZQrdEowjqxUmB8FX8ej19VKY6jGHKNIRE5wrhBkuZ1b0FLRPiN3/Cl9wMkCnyJui4QhC28g1aBg +w/JnaObcDqW1NgFVH3006+gZvCTDlw1nIEjvZa6P+uWOOi05xPPAE0feKPkO1POnOjnapfkkEVNU +8TXsLbLYBylWT8rxZC8CAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBJ +yJ7p6qs0JI+1iKOk/sYWVP6dMueY72qOc/wVj5c3ejOlgJNNXDMAQ14QcRRexffc68ipTwybU/3m +tcNwydzKJe+GFa4b2zyKOvOgrfs4MKSR0T9XEPmTKeR+NDT2CbA6/kQoRYm0fSORzD2UXJzNZWe/ +WjwSA66hv4q+0QZQFQ== +</X509Certificate> +</X509Data> +</KeyInfo> +<Object Id="prop"><SignatureProperties xmlns:dsp="http://www.w3.org/2009/xmldsig-properties"><SignatureProperty Id="profile" Target="#DistributorSignature"><dsp:Profile URI="http://www.w3.org/ns/widgets-digsig#profile"></dsp:Profile></SignatureProperty><SignatureProperty Id="role" Target="#DistributorSignature"><dsp:Role URI="http://www.w3.org/ns/widgets-digsig#role-distributor"></dsp:Role></SignatureProperty><SignatureProperty Id="identifier" Target="#DistributorSignature"><dsp:Identifier></dsp:Identifier></SignatureProperty></SignatureProperties></Object> +</Signature>
\ No newline at end of file diff --git a/templates/GraphSchedule.tmpl b/templates/GraphSchedule.tmpl new file mode 100644 index 0000000..0dc59d7 --- /dev/null +++ b/templates/GraphSchedule.tmpl @@ -0,0 +1,91 @@ +<div class="GraphSchedule"> + <div class="container"> + <table> + <tr class="rangesWeekend"> + <td class="h00"></td> + <td class="h01"></td> + <td class="h02"></td> + <td class="h03"></td> + <td class="h04"></td> + <td class="h05 th"></td> + <td class="h06 th"></td> + <td class="h07"></td> + <td class="h08"></td> + <td class="h09"></td> + <td class="h10"></td> + <td class="h11"></td> + <td class="h12"></td> + <td class="h13"></td> + <td class="h14"></td> + <td class="h15"></td> + <td class="h16"></td> + <td class="h17"></td> + <td class="h18"></td> + <td class="h19"></td> + <td class="h20"></td> + <td class="h21"></td> + <td class="h22"></td> + <td class="h23"></td> + </tr> + <tr class="ranges"> + <td class="h00"></td> + <td class="h01"></td> + <td class="h02"></td> + <td class="h03"></td> + <td class="h04"></td> + <td class="h05"></td> + <td class="h06"></td> + <td class="h07"></td> + <td class="h08"></td> + <td class="h09"></td> + <td class="h10"></td> + <td class="h11"></td> + <td class="h12"></td> + <td class="h13"></td> + <td class="h14"></td> + <td class="h15"></td> + <td class="h16"></td> + <td class="h17"></td> + <td class="h18"></td> + <td class="h19"></td> + <td class="h20"></td> + <td class="h21"></td> + <td class="h22"></td> + <td class="h23"></td> + </tr> + <tr class="grid"> + <td>00</td> + <td>01</td> + <td>02</td> + <td>03</td> + <td>04</td> + <td>05</td> + <td>06</td> + <td>07</td> + <td>08</td> + <td>09</td> + <td>10</td> + <td>11</td> + <td>12</td> + <td>13</td> + <td>14</td> + <td>15</td> + <td>16</td> + <td>17</td> + <td>18</td> + <td>19</td> + <td>20</td> + <td>21</td> + <td>22</td> + <td>23</td> + </tr> + </table> + </div> +</div> +<div class="flag"> + <div class="container"> + <div class="rod"></div> + <p></p> + <div class="hint"></div> + </div> +</div> |