not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

361 lines
11 KiB

  1. define(['sugar-web/activity/activity', 'webL10n', 'activity/progress', 'activity/stopwatch', 'sugar-web/env'], function (activity, l10n, Progress, Stopwatch, env) {
  2. // Manipulate the DOM only when it is ready.
  3. requirejs(['domReady!'], function (doc) {
  4. // Initialize the activity.
  5. activity.setup();
  6. env.getEnvironment(function(err, environment) {
  7. currentenv = environment;
  8. var defaultLanguage = (typeof chrome != 'undefined' && chrome.app && chrome.app.runtime) ? chrome.i18n.getUILanguage() : navigator.language;
  9. var language = environment.user ? environment.user.language : defaultLanguage;
  10. l10n.language.code = language;
  11. var datastore = activity.getDatastoreObject();
  12. main(Progress, Stopwatch, l10n, currentenv.user.colorvalue, datastore);
  13. });
  14. });
  15. });
  16. function convertReadableMS(timeInMs) {
  17. var parsedTime = parseMs(timeInMs);
  18. var timeStr = parsedTime.hours ? parsedTime.hours + parsedTime.days * 24 + ':' + parsedTime.minutes + ':' + parsedTime.seconds : parsedTime.minutes + ':' + parsedTime.seconds;
  19. return timeStr.split(':').map(function (num) {
  20. return ('' + num).padStart(2, '0');
  21. }).join(':');
  22. }
  23. var defaultWorkTimerLimit = 1;
  24. var defaultBreakTimerLimit = 1;
  25. function main(Progress, Stopwatch, l10n, color, datastore) {
  26. var _this = this;
  27. this.state = {
  28. status: 'work',
  29. workTimerLimit: defaultWorkTimerLimit,
  30. breakTimerLimit: defaultBreakTimerLimit,
  31. progress: 1,
  32. currentWorkText: convertReadableMS(defaultWorkTimerLimit * 1000 * 60),
  33. currentBreakText: convertReadableMS(defaultBreakTimerLimit * 1000 * 60),
  34. themeColor: '#FF0060',
  35. isButtonsDisable: false,
  36. timerLeftAt: false,
  37. progressLeftAt: false
  38. };
  39. datastore.loadAsText(function (err, metadata, data) {
  40. if (err) console.error(err)
  41. if (data) {
  42. _this.state = data.state;
  43. }
  44. enableButtons()
  45. afterDataLoad()
  46. });
  47. // this.state.progress = 1
  48. function afterDataLoad() {
  49. this.state.status === 'work'
  50. ? startWork()
  51. : startBreak();
  52. renderPomodoroText();
  53. renderStatusText(l10n.get(this.state.status));
  54. var pomodoroContainer = document.getElementById('pomodoro-container');
  55. this.pomodoro = new Progress(280, color.stroke, this.state.progress, pomodoroContainer);
  56. this.pomodoro.draw();
  57. this.state.status === 'work'
  58. ? renderTheme(color.stroke)
  59. : renderTheme(color.fill);
  60. }
  61. function mapRange(obj, num) {
  62. return (num - obj.from[0]) * (obj.to[1] - obj.to[0]) / (obj.from[1] - obj.from[0]) + obj.to[0];
  63. }
  64. function parseMs(ms) {
  65. if (typeof ms !== 'number') {
  66. throw new TypeError('Expected a number');
  67. }
  68. var roundTowardZero = ms > 0 ? Math.floor : Math.ceil;
  69. return {
  70. days: roundTowardZero(ms / 86400000),
  71. hours: roundTowardZero(ms / 3600000) % 24,
  72. minutes: roundTowardZero(ms / 60000) % 60,
  73. seconds: roundTowardZero(ms / 1000) % 60,
  74. milliseconds: roundTowardZero(ms) % 1000
  75. };
  76. }
  77. function saveInDataStore() {
  78. datastore.setDataAsText({
  79. state: this.state
  80. });
  81. datastore.save(function (err) {
  82. if (err) {
  83. console.errror(err);
  84. }
  85. });
  86. }
  87. function convertReadableMS(timeInMs) {
  88. var parsedTime = parseMs(timeInMs);
  89. var timeStr = parsedTime.hours
  90. ? parsedTime.hours + parsedTime.days * 24 + ':' + parsedTime.minutes + ':' + parsedTime.seconds
  91. : parsedTime.minutes + ':' + parsedTime.seconds;
  92. return timeStr.split(':').map(function (num) {
  93. return ('' + num).padStart(2, '0');
  94. }).join(':');
  95. }
  96. this.handlePausePlay = function () {
  97. var playPauseButton = document.getElementById('play-button');
  98. if (this.state.status === 'work') {
  99. if (this.workTimer.state === 1) {
  100. //if timer is running
  101. this.workTimer.stop();
  102. enableButtons();
  103. playPauseButton.classList.remove('pause');
  104. playPauseButton.classList.add('play');
  105. } else {
  106. this.workTimer.start();
  107. disableButtons();
  108. playPauseButton.classList.remove('play');
  109. playPauseButton.classList.add('pause');
  110. }
  111. } else {
  112. if (this.breakTimer.state === 1) {
  113. this.breakTimer.stop();
  114. enableButtons();
  115. playPauseButton.classList.remove('pause');
  116. playPauseButton.classList.add('play');
  117. } else {
  118. disableButtons();
  119. this.breakTimer.start();
  120. playPauseButton.classList.remove('play');
  121. playPauseButton.classList.add('pause');
  122. }
  123. }
  124. };
  125. function startWork() {
  126. var _this2 = this;
  127. var timerInMS = (this.state.timerLeftAt === false)
  128. ? (this.state.workTimerLimit * 60 * 1000)
  129. : this.state.timerLeftAt
  130. this.workTimer = new Stopwatch(timerInMS);
  131. this.state.status = 'work';
  132. const progressToStart = (this.state.progressLeftAt === false)
  133. ? 1
  134. : this.state.progressLeftAt
  135. this.workTimer.onTime(function (time) {
  136. var progress = mapRange({
  137. from: [timerInMS, 0],
  138. to: [progressToStart, 0]
  139. }, time.ms);
  140. setProgress(progress, time.ms);
  141. saveInDataStore()
  142. });
  143. this.workTimer.onDone(function () {
  144. renderTheme(color.fill);
  145. setTimeout(function () {
  146. this.state.timerLeftAt = false
  147. this.state.progressLeftAt = false
  148. renderStatusText(l10n.get('break'));
  149. startBreak();
  150. _this2.breakTimer.start();
  151. }, 1000);
  152. });
  153. }
  154. function startBreak() {
  155. var _this3 = this;
  156. var timerInMS = (this.state.timerLeftAt === false)
  157. ? this.state.breakTimerLimit * 60 * 1000
  158. : this.state.timerLeftAt
  159. this.breakTimer = new Stopwatch(timerInMS);
  160. this.state.status = 'break';
  161. const progressToStart = (this.state.progressLeftAt === false)
  162. ? 1
  163. : this.state.progressLeftAt
  164. this.breakTimer.onTime(function (time) {
  165. var progress = mapRange({
  166. from: [timerInMS, 0],
  167. to: [progressToStart, 0]
  168. }, time.ms);
  169. setProgress(progress, time.ms);
  170. saveInDataStore()
  171. });
  172. this.breakTimer.onDone(function () {
  173. renderTheme(color.stroke);
  174. setTimeout(function () {
  175. this.state.timerLeftAt = false
  176. this.state.progressLeftAt = false
  177. renderStatusText(l10n.get('work'));
  178. startWork();
  179. _this3.workTimer.start();
  180. }, 1000);
  181. });
  182. }
  183. function renderStatusText(text) {
  184. document.querySelector('.status').innerText = text;
  185. }
  186. function setProgress(progress, currentTimeMS) {
  187. this.state.progress = progress;
  188. if (this.state.status === 'work') {
  189. this.state.currentWorkText = convertReadableMS(currentTimeMS);
  190. } else {
  191. this.state.currentBreakText = convertReadableMS(currentTimeMS);
  192. }
  193. this.state.timerLeftAt = currentTimeMS
  194. this.state.progressLeftAt = progress
  195. renderPomodoro();
  196. renderPomodoroText();
  197. }
  198. function renderPomodoro() {
  199. this.pomodoro.update(this.state.progress);
  200. }
  201. function renderPomodoroText() {
  202. var timerTextElem = document.querySelector('.info-circle span');
  203. if (this.state.status === 'work') {
  204. timerTextElem.innerText = this.state.currentWorkText;
  205. } else {
  206. timerTextElem.innerText = this.state.currentBreakText;
  207. }
  208. }
  209. function renderTheme(themeColor) {
  210. this.state.themeColor = themeColor;
  211. document.querySelector('.info-circle').style.backgroundColor = themeColor;
  212. document.querySelector('.base-circle').style.backgroundColor = themeColor + '2b';
  213. this.pomodoro.updateColor(themeColor, this.state.progress);
  214. renderButtons();
  215. }
  216. function renderButtons() {
  217. var _this4 = this;
  218. document.querySelectorAll('.button').forEach(function (elem) {
  219. elem.style.background = _this4.state.themeColor;
  220. });
  221. document.querySelectorAll('.button-label, .button-time').forEach(function (elem) {
  222. elem.style.color = _this4.state.themeColor;
  223. });
  224. }
  225. function disableButtons() {
  226. this.state.isButtonsDisable = true;
  227. document.querySelectorAll('.button, .button-time, .button-label').forEach(function (elem) {
  228. elem.classList.add('disable');
  229. });
  230. }
  231. function enableButtons() {
  232. this.state.isButtonsDisable = false;
  233. document.querySelectorAll('.button, .button-time, .button-label').forEach(function (elem) {
  234. elem.classList.remove('disable');
  235. });
  236. }
  237. function updateWorkPomodoro() {
  238. this.state.currentWorkText = convertReadableMS(this.state.workTimerLimit * 60 * 1000);
  239. document.querySelector('.button-time.work').innerText = this.state.workTimerLimit;
  240. this.pomodoro.update(1);
  241. renderPomodoroText();
  242. if (this.state.status === 'work') {
  243. startWork();
  244. }
  245. }
  246. function updateBreakPomodoro() {
  247. this.state.currentBreakText = convertReadableMS(this.state.breakTimerLimit * 60 * 1000);
  248. document.querySelector('.button-time.break').innerText = this.state.breakTimerLimit;
  249. renderPomodoroText();
  250. if (this.state.status === 'break') {
  251. startBreak();
  252. }
  253. }
  254. this.handleWorkPlusClick = function () {
  255. if (!this.state.isButtonsDisable) {
  256. this.state.workTimerLimit = this.state.workTimerLimit + 1;
  257. resetTimer()
  258. updateWorkPomodoro();
  259. saveInDataStore()
  260. }
  261. };
  262. this.handleWorkMinusClick = function () {
  263. if (!this.state.isButtonsDisable && this.state.workTimerLimit > 1) {
  264. this.state.workTimerLimit = this.state.workTimerLimit - 1;
  265. resetTimer()
  266. updateWorkPomodoro();
  267. saveInDataStore()
  268. }
  269. };
  270. this.handleBreakPlusClick = function () {
  271. if (!this.state.isButtonsDisable) {
  272. this.state.breakTimerLimit = this.state.breakTimerLimit + 1;
  273. resetTimer()
  274. updateBreakPomodoro();
  275. saveInDataStore()
  276. }
  277. };
  278. this.handleBreakMinusClick = function () {
  279. if (!this.state.isButtonsDisable && this.state.breakTimerLimit > 1) {
  280. this.state.breakTimerLimit = this.state.breakTimerLimit - 1;
  281. resetTimer()
  282. updateBreakPomodoro();
  283. saveInDataStore()
  284. }
  285. };
  286. function resetTimer() {
  287. setProgress(1, this.state.workTimerLimit * 60 * 1000)
  288. this.state.timerLeftAt = false
  289. this.state.progressLeftAt = false
  290. }
  291. function initTimerText() {
  292. document.querySelector('.button-time.work').innerText = this.state.workTimerLimit;
  293. document.querySelector('.button-time.break').innerText = this.state.breakTimerLimit;
  294. }
  295. initTimerText();
  296. document.querySelector('.plus-button.work').addEventListener('click', handleWorkPlusClick.bind(this));
  297. document.querySelector('.minus-button.work').addEventListener('click', handleWorkMinusClick.bind(this));
  298. document.querySelector('.plus-button.break').addEventListener('click', handleBreakPlusClick.bind(this));
  299. document.querySelector('.minus-button.break').addEventListener('click', handleBreakMinusClick.bind(this));
  300. document.querySelector('#play-button').addEventListener('click', function () {
  301. _this.handlePausePlay();
  302. });
  303. document.querySelector('#replay-button').addEventListener('click', function () {
  304. var shouldPlay
  305. if (_this.workTimer && _this.breakTimer) {
  306. shouldPlay = _this.workTimer.state === 1 || _this.breakTimer.state === 1
  307. } else if (_this.workTimer) {
  308. shouldPlay = _this.workTimer.state === 1
  309. } else {
  310. shouldPlay = _this.breakTimer.state === 1
  311. }
  312. if (shouldPlay) {
  313. this.handlePausePlay()
  314. }
  315. resetTimer()
  316. startWork()
  317. if (_this.breakTimer) {
  318. _this.breakTimer.stop();
  319. }
  320. renderTheme(color.stroke)
  321. renderStatusText(l10n.get('work'));
  322. _this.pomodoro.update(1)
  323. }.bind(this));
  324. }