diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/companion/package.json b/companion/package.json index 876ec56..82850fb 100644 --- a/companion/package.json +++ b/companion/package.json @@ -1,8 +1,7 @@ { "scripts": { - "start": "react-native start", - "android": "react-native run-android", - "android-prebuild": "npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/" + "dev": "react-native start", + "android": "react-native run-android" }, "dependencies": { "@expo/vector-icons": "^12.0.0", diff --git a/package.json b/package.json new file mode 100644 index 0000000..97e5101 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "focus", + "private": "true", + "version": "0.0.1", + "description": "Scripts for the Focus MonoRepo.", + "scripts": { + "dev": "npm run dev-watch & npm run dev-companion", + "dev-watch": "cd watch && npm run dev", + "dev-companion": "cd companion && npm run dev" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Aurailus/Focus.git" + }, + "keywords": [ + "watch", + "tizen", + "android", + "calendar", + "scheduling" + ], + "author": "Auri Collings ", + "license": "UNLICENSED", + "bugs": { + "url": "https://github.com/Aurailus/Focus/issues" + }, + "homepage": "https://github.com/Aurailus/Focus#readme" +} diff --git a/watch/Focus.wgt b/watch/Focus.wgt index 867ac7d..6462a05 100644 Binary files a/watch/Focus.wgt and b/watch/Focus.wgt differ diff --git a/watch/LICENSE.Flora b/watch/LICENSE.Flora deleted file mode 100644 index 4ab7e53..0000000 --- a/watch/LICENSE.Flora +++ /dev/null @@ -1,206 +0,0 @@ -Flora License - -Version 1.1, April, 2013 - -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 Tizen Compliance Specification -and passes the Tizen Compliance Tests 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 - and your own copyright statement or terms and conditions do not conflict - the conditions stated in the License including section 3. - -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 2015 Samsung Electronics Co., Ltd. - - Licensed under the Flora License, Version 1.1 (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. - diff --git a/watch/NOTICE b/watch/NOTICE deleted file mode 100644 index 419db21..0000000 --- a/watch/NOTICE +++ /dev/null @@ -1,3 +0,0 @@ -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, Version 1 terms and conditions. diff --git a/watch/version.txt b/watch/_maybe_unused_version.txt similarity index 100% rename from watch/version.txt rename to watch/_maybe_unused_version.txt diff --git a/watch/build/main.js b/watch/build/main.js new file mode 100644 index 0000000..8bd34b7 --- /dev/null +++ b/watch/build/main.js @@ -0,0 +1,222 @@ +"use strict"; +var theme = { + notches: 3, + events: true, + minutes: true, + glow: true, + glow_a: '#e838ff', + glow_b: 'rgba(255, 38, 56, 0.6)', + glow_c: 'rgba(179, 38, 255, 1)', +}; +var image_loaded = false; +var window_loaded = false; +window.onload = function () { + window_loaded = true; + if (image_loaded) + init(); +}; +var glow_image = document.createElement('img'); +glow_image.src = 'res/glow.png'; +glow_image.onload = function () { + image_loaded = true; + if (window_loaded) + init(); +}; +var glow_canvas = document.createElement('canvas'); +glow_canvas.width = 128; +glow_canvas.height = 128; +var glow_ctx = glow_canvas.getContext('2d'); +function init() { + var canvas = document.querySelector('canvas'); + var ctx = canvas.getContext('2d'); + canvas.width = document.body.clientWidth; + canvas.height = canvas.width; + var clockRadius = document.body.clientWidth / 2; + var rot = 0; + var ambient = false; + var EVENT_WIDTH = 22; + var EVENT_BUFFER = theme.notches === 0 ? 2 : 14; + var TITLE_BUFFER = 2; + var TITLE_SIZE = 16; + var NOTCH_BUFFER = 2; + var DATE_SIZE = 20; + var COLOR_LIGHT_DIM = 'rgba(65, 199, 232, 0.15)'; + var COLOR_LIGHT_OVERLAY = 'rgba(65, 199, 232, 0.33)'; + var COLOR_MINUTE_HAND = 'rgba(65, 199, 232, 0.8)'; + var degToRad = function (deg) { return deg * (Math.PI / 180); }; + var createDate = function (hour, minute) { + var date = new Date(); + date.setHours(hour, minute, 0); + return date; + }; + var events = [ + { start: createDate(9, 30), end: createDate(11, 20), color: '#33B679', title: 'PAAS' }, + { start: createDate(12, 30), end: createDate(1, 20), color: '#33B679', title: 'STAT' }, + { start: createDate(1, 30), end: createDate(2, 20), color: '#33B679', title: 'MATH' } + ]; + function getTime() { + try { + return tizen.time.getCurrentDateTime(); + } + catch (e) { + return new Date(); + } + } + function drawCircle(angle, distance, width, color) { + ctx.save(); + ctx.translate(canvas.width / 2, canvas.height / 2); + ctx.rotate(angle); + ctx.beginPath(); + ctx.arc(distance, 0, width / 2, 0, 2 * Math.PI, false); + ctx.fillStyle = color; + ctx.fill(); + ctx.closePath(); + ctx.restore(); + } + function drawRoundedRect(startDistance, endDistance, angle, width, fill, stroke, strokeWidth) { + ctx.save(); + ctx.translate(canvas.width / 2, canvas.height / 2); + ctx.rotate(angle); + ctx.beginPath(); + ctx.moveTo(-width / 2, startDistance); + ctx.lineTo(-width / 2, endDistance); + ctx.quadraticCurveTo(-width / 2, endDistance + width / 1.5, 0, endDistance + width / 1.5); + ctx.quadraticCurveTo(width / 2, endDistance + width / 1.5, width / 2, endDistance); + ctx.lineTo(width / 2, startDistance); + ctx.quadraticCurveTo(width / 2, startDistance - width / 1.5, 0, startDistance - width / 1.5); + ctx.quadraticCurveTo(-width / 2, startDistance - width / 1.5, -width / 2, startDistance); + ctx.closePath(); + if (fill) { + ctx.fillStyle = fill; + ctx.fill(); + } + if (stroke && strokeWidth) { + ctx.strokeStyle = stroke; + ctx.lineWidth = strokeWidth; + ctx.stroke(); + } + ctx.restore(); + } + function drawEvent(event) { + var startAngle = degToRad(((event.start.getHours() % 12) + + event.start.getMinutes() / 60) / 12 * 360 + EVENT_WIDTH / 6 - 90); + var endAngle = degToRad(((event.end.getHours() % 12) + + event.end.getMinutes() / 60) / 12 * 360 - EVENT_WIDTH / 8 - 90); + ctx.save(); + ctx.translate(canvas.width / 2, canvas.height / 2); + ctx.beginPath(); + ctx.fillStyle = COLOR_LIGHT_DIM; + ctx.arc(0, 0, clockRadius - EVENT_BUFFER, startAngle, endAngle, false); + var controlPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER); + var controlPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER); + var endPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); + var endPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); + ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); + controlPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + controlPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + endPosX = Math.cos(endAngle) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + endPosY = Math.sin(endAngle) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); + ctx.arc(0, 0, clockRadius - EVENT_BUFFER - EVENT_WIDTH, endAngle, startAngle, true); + controlPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + controlPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + endPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); + endPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); + ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); + controlPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER); + controlPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER); + endPosX = Math.cos(startAngle) * (clockRadius - EVENT_BUFFER); + endPosY = Math.sin(startAngle) * (clockRadius - EVENT_BUFFER); + ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); + ctx.fill(); + ctx.closePath(); + ctx.restore(); + drawCircle(startAngle, clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2, EVENT_WIDTH - 8, event.color); + ctx.font = "900 " + TITLE_SIZE + "px Arial sans-serif"; + ctx.fillStyle = '#fff'; + ctx.textBaseline = 'top'; + ctx.textAlign = 'center'; + var currentAngle = startAngle + degToRad(96); + for (var i = 0; i < event.title.length; i++) { + ctx.save(); + ctx.translate(canvas.width / 2, canvas.height / 2); + ctx.rotate(currentAngle); + ctx.fillText(event.title[i], 0, -(clockRadius - EVENT_BUFFER - TITLE_BUFFER)); + ctx.restore(); + if (i < event.title.length - 1) + currentAngle += ctx.measureText(event.title[i]).width * 0.0065 / 2 + + ctx.measureText(event.title[i + 1]).width * 0.0065 / 2; + } + } + function drawGlow(offsetX, offsetY, scaleMult, color) { + glow_ctx.fillStyle = color; + glow_ctx.globalCompositeOperation = 'source-over'; + glow_ctx.fillRect(0, 0, glow_canvas.width, glow_canvas.height); + glow_ctx.globalCompositeOperation = 'destination-in'; + glow_ctx.drawImage(glow_image, 0, 0); + var scale = 240 * scaleMult; + ctx.drawImage(glow_canvas, canvas.width / 2 + offsetX - scale / 2, canvas.height / 2 + offsetY - scale / 2, scale, scale); + } + function drawWatchFace() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + var time = getTime(); + ctx.font = "900 " + DATE_SIZE + "px Arial sans-serif"; + ctx.fillStyle = '#aaa'; + ctx.textBaseline = 'bottom'; + ctx.textAlign = 'center'; + ctx.fillText(['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'][time.getDay()] + " " + time.getDate(), clockRadius, clockRadius + clockRadius / 1.75); + ctx.fillStyle = '#666'; + ctx.fillRect(clockRadius - 1 * DATE_SIZE, clockRadius + clockRadius / 1.75 + 2, 2 * DATE_SIZE, 2); + if (!ambient) { + rot = (rot + 1) % 360; + var scaleA = 1 + (Math.sin(degToRad(rot + 180)) / 6); + var scaleB = 1 + (Math.cos(degToRad(rot)) / 6); + var scaleC = 1.3 + (Math.cos(degToRad(rot - 90)) / 6); + var offsetX = Math.cos(degToRad(rot + 90)) * 50 + (1 - scaleA); + var offsetY = Math.sin(degToRad(rot + 90)) * 50 + (1 - scaleB); + if (theme.glow) { + ctx.globalCompositeOperation = 'lighter'; + drawGlow(-offsetX, -offsetY, scaleA, theme.glow_b); + drawGlow(0, 0, scaleC, theme.glow_a); + drawGlow(offsetX, offsetY, scaleB, theme.glow_c); + ctx.globalCompositeOperation = 'source-over'; + } + if (theme.notches) { + for (var i = 0; i < 12 * 5; i++) { + if (i % 15 === 0) + drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 8, COLOR_MINUTE_HAND); + else if (i % 5 === 0 && theme.notches >= 2) + drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 6, COLOR_LIGHT_OVERLAY); + else if (theme.notches >= 3) + drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 4, COLOR_LIGHT_DIM); + } + } + } + if (theme.events) { + for (var _i = 0, events_1 = events; _i < events_1.length; _i++) { + var event_1 = events_1[_i]; + drawEvent(event_1); + } + } + drawCircle(0, 0, 36, COLOR_LIGHT_OVERLAY); + drawCircle(0, 0, 20, '#fff'); + if (theme.minutes) { + var minuteAngle = degToRad((time.getMinutes() + time.getSeconds() / 60) / 60 * 360 - 180); + drawRoundedRect(34, clockRadius - 64, minuteAngle, 16, COLOR_MINUTE_HAND, undefined, undefined); + } + var hourAngle = degToRad(((time.getHours() % 12) + time.getMinutes() / 60) / 12 * 360 - 180); + drawRoundedRect(36, clockRadius - 80, hourAngle, 16, 'rgba(0, 0, 0, 0.15)', '#fff', 4); + if (!ambient) + setTimeout(function () { return window.requestAnimationFrame(drawWatchFace); }, 1000 / 10); + } + window.requestAnimationFrame(drawWatchFace); + window.addEventListener('timetick', drawWatchFace); + window.addEventListener('ambientmodechanged', function (e) { + ambient = e.detail.ambientMode; + drawWatchFace(); + }); + document.addEventListener('visibilitychange', function () { + if (!document.hidden) + drawWatchFace(); + }); +} diff --git a/watch/css/style.css b/watch/css/style.css deleted file mode 100644 index 33887f8..0000000 --- a/watch/css/style.css +++ /dev/null @@ -1,24 +0,0 @@ -* { - margin: 0; - padding: 0 -} - -html, body { - width: 100%; - height: 100%; - color: #fff; - background: #000; -} - -#container { - display: -webkit-flex; - -webkit-align-items: center; - width: 100%; - height: 100%; -} - -#canvas { - width: 100%; - height: 100%; - margin: auto; -} diff --git a/watch/index.html b/watch/index.html index 2a4f6cd..a92ee10 100644 --- a/watch/index.html +++ b/watch/index.html @@ -1,17 +1,27 @@ + + + AmbientWatch + + + + + + diff --git a/watch/js/app.js b/watch/js/app.js deleted file mode 100644 index 9a8fad9..0000000 --- a/watch/js/app.js +++ /dev/null @@ -1,313 +0,0 @@ -'use strict'; - -(() => { - let theme = { - /** 0: none, 1: quarter, 2: hours, 3: hours + minute */ - notches: 3, - /** False: don't display, True: display */ - events: true, - /** False: don't show minute hand, True: show minute hand */ - minutes: true, - /** False: don't show center glow, True: show center glow */ - glow: true, - /** Center glow color. */ - glow_a: '#4294ff', - /** Moving glow 1 color. */ - glow_b: 'rgba(5, 124, 242, 0.6)', - /** Moving glow 2 color. */ - glow_c: 'rgba(198, 0, 237, 1)', - // /** Center glow color. */ - // glow_a: '#e838ff', - // /** Moving glow 1 color. */ - // glow_b: 'rgba(255, 38, 56, 0.6)', - // /** Moving glow 2 color. */ - // glow_c: 'rgba(179, 38, 255, 1)', - } - - let image_loaded = false; - let window_loaded = false; - - window.onload = () => { - window_loaded = true; - if (image_loaded) init(); - }; - - const glow_image = document.createElement('img'); - glow_image.src = 'res/glow.png'; - glow_image.onload = () => { - image_loaded = true; - if (window_loaded) init(); - }; - - const glow_canvas = document.createElement('canvas'); - glow_canvas.width = 128; - glow_canvas.height = 128; - const glow_ctx = glow_canvas.getContext('2d'); - - function init() { - const canvas = document.querySelector('#canvas'); - const ctx = canvas.getContext('2d'); - canvas.width = document.body.clientWidth; - canvas.height = canvas.width; - const clockRadius = document.body.clientWidth / 2; - - let rot = 0; - let ambient = false; - - const EVENT_WIDTH = 22; - let EVENT_BUFFER = theme.notches === 0 ? 2 : 14; - const TITLE_BUFFER = 2; - const TITLE_SIZE = 16; - const NOTCH_BUFFER = 2; - const DATE_SIZE = 20; - - const COLOR_LIGHT_DIM = 'rgba(65, 199, 232, 0.15)'; - const COLOR_LIGHT_OVERLAY = 'rgba(65, 199, 232, 0.33)'; - const COLOR_MINUTE_HAND = 'rgba(65, 199, 232, 0.8)'; - - const degToRad = (deg) => deg * (Math.PI / 180); - - const createDate = (hour, minute) => { - const date = new Date(); - date.setHours(hour, minute, 0); - return date; - }; - - const events = [ - { start: createDate(9, 30), end: createDate(11, 20), color: '#33B679', title: 'PAAS' }, - { start: createDate(12, 30), end: createDate(1, 20), color: '#33B679', title: 'STAT' }, - { start: createDate(1, 30), end: createDate(2, 20), color: '#33B679', title: 'MATH' } - // { start: createDate(9, 30), end: createDate(11, 20), color: '#59acff', title: 'Work' }, - // { start: createDate(12, 30), end: createDate(1, 20), color: '#59acff', title: 'Walk' }, - // { start: createDate(1, 30), end: createDate(2, 20), color: '#59acff', title: 'Bike' } - ]; - - function getTime() { - try { return tizen.time.getCurrentDateTime(); } - catch (e) { return new Date(); } - } - - function drawCircle(angle, distance, width, color) { - ctx.save(); - ctx.translate(canvas.width / 2, canvas.height / 2); - ctx.rotate(angle) - - ctx.beginPath(); - ctx.arc(distance, 0, width / 2, 0, 2 * Math.PI, false); - ctx.fillStyle = color; - ctx.fill(); - ctx.closePath(); - - ctx.restore(); - } - - // function drawLine(startDistance, endDistance, angle, width, color) { - // ctx.save(); - // ctx.translate(canvas.width / 2, canvas.height / 2); - // ctx.rotate(degToRad(angle + 90)); - - // ctx.beginPath(); - // ctx.lineWidth = width; - // ctx.strokeStyle = color; - // ctx.moveTo(startDistance, 0); - // ctx.lineTo(endDistance, 0); - // ctx.stroke(); - // ctx.closePath(); - - // ctx.restore(); - // } - - function drawRoundedRect(startDistance, endDistance, angle, width, fill, stroke, strokeWidth) { - ctx.save(); - ctx.translate(canvas.width / 2, canvas.height / 2); - ctx.rotate(angle); - - ctx.beginPath(); - ctx.moveTo(-width / 2, startDistance); - ctx.lineTo(-width / 2, endDistance); - ctx.quadraticCurveTo(-width / 2, endDistance + width / 1.5, 0, endDistance + width / 1.5); - ctx.quadraticCurveTo(width / 2, endDistance + width / 1.5, width / 2, endDistance); - ctx.lineTo(width / 2, startDistance); - ctx.quadraticCurveTo(width / 2, startDistance - width / 1.5, 0, startDistance - width / 1.5); - ctx.quadraticCurveTo(-width / 2, startDistance - width / 1.5, -width / 2, startDistance); - ctx.closePath(); - - if (fill) { - ctx.fillStyle = fill; - ctx.fill(); - } - - if (stroke && strokeWidth) { - ctx.strokeStyle = stroke; - ctx.lineWidth = strokeWidth; - ctx.stroke(); - } - - ctx.restore() - } - - function drawEvent(event) { - const startAngle = degToRad(((event.start.getHours() % 12) + - event.start.getMinutes() / 60) / 12 * 360 + EVENT_WIDTH / 6 - 90); - const endAngle = degToRad(((event.end.getHours() % 12) + - event.end.getMinutes() / 60) / 12 * 360 - EVENT_WIDTH / 8 - 90); - - ctx.save(); - ctx.translate(canvas.width / 2, canvas.height / 2); - - ctx.beginPath(); - ctx.fillStyle = COLOR_LIGHT_DIM; - - ctx.arc(0, 0, clockRadius - EVENT_BUFFER, startAngle, endAngle, false); - - let controlPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER); - let controlPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER); - let endPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); - let endPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); - - ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); - - controlPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); - controlPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); - endPosX = Math.cos(endAngle) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); - endPosY = Math.sin(endAngle) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); - - ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); - - ctx.arc(0, 0, clockRadius - EVENT_BUFFER - EVENT_WIDTH, endAngle, startAngle, true); - - controlPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); - controlPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); - endPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); - endPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); - - ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); - - controlPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER); - controlPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER); - endPosX = Math.cos(startAngle) * (clockRadius - EVENT_BUFFER); - endPosY = Math.sin(startAngle) * (clockRadius - EVENT_BUFFER); - - ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); - - ctx.fill(); - ctx.closePath(); - - ctx.restore(); - - drawCircle(startAngle, clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2, EVENT_WIDTH - 8, event.color); - - ctx.font = `900 ${TITLE_SIZE}px Arial sans-serif`; - ctx.fillStyle = '#fff'; - ctx.textBaseline = 'top'; - ctx.textAlign = 'center'; - - let currentAngle = startAngle + degToRad(96); - for (let i = 0; i < event.title.length; i++) { - ctx.save(); - ctx.translate(canvas.width / 2, canvas.height / 2); - ctx.rotate(currentAngle); - - ctx.fillText(event.title[i], 0, -(clockRadius - EVENT_BUFFER - TITLE_BUFFER)); - - ctx.restore(); - if (i < event.title.length - 1) - currentAngle += ctx.measureText(event.title[i]).width * 0.0065 / 2 - + ctx.measureText(event.title[i + 1]).width * 0.0065 / 2; - } - } - - function drawGlow(offsetX, offsetY, scaleMult, color) { - glow_ctx.fillStyle = color; - glow_ctx.globalCompositeOperation = 'source-over'; - glow_ctx.fillRect(0, 0, glow_canvas.width, glow_canvas.height); - glow_ctx.globalCompositeOperation = 'destination-in'; - glow_ctx.drawImage(glow_image, 0, 0); - - const scale = 240 * scaleMult; - - ctx.drawImage(glow_canvas, - canvas.width / 2 + offsetX - scale / 2, - canvas.height / 2 + offsetY - scale / 2, - scale, scale); - } - - function drawWatchFace() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - const time = getTime(); - - ctx.font = `900 ${DATE_SIZE}px Arial sans-serif`; - ctx.fillStyle = '#aaa'; - ctx.textBaseline = 'bottom'; - ctx.textAlign = 'center'; - - ctx.fillText(`${['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'][time.getDay()]} ${time.getDate()}`, - clockRadius, clockRadius + clockRadius / 1.75); - - ctx.fillStyle = '#666' - ctx.fillRect(clockRadius - 1 * DATE_SIZE, clockRadius + clockRadius / 1.75 + 2, 2 * DATE_SIZE, 2); - - if (!ambient) { - rot = (rot + 1) % 360; - - let scaleA = 1 + (Math.sin(degToRad(rot + 180)) / 6); - let scaleB = 1 + (Math.cos(degToRad(rot)) / 6); - let scaleC = 1.3 + (Math.cos(degToRad(rot - 90)) / 6); - let offsetX = Math.cos(degToRad(rot + 90)) * 50 + (1 - scaleA); - let offsetY = Math.sin(degToRad(rot + 90)) * 50 + (1 - scaleB); - - if (theme.glow) { - ctx.globalCompositeOperation = 'lighter'; - drawGlow(-offsetX, -offsetY, scaleA, theme.glow_b); - drawGlow(0, 0, scaleC, theme.glow_a); - drawGlow(offsetX, offsetY, scaleB, theme.glow_c); - ctx.globalCompositeOperation = 'source-over'; - } - - if (theme.notches) { - for (let i = 0; i < 12 * 5; i++) { - if (i % 15 === 0) - drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 8, COLOR_MINUTE_HAND) - else if (i % 5 === 0 && theme.notches >= 2) - drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 6, COLOR_LIGHT_OVERLAY) - else if (theme.notches >= 3) - drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 4, COLOR_LIGHT_DIM) - } - } - } - - if (theme.events) { - for (let event of events) { - drawEvent(event); - } - } - - drawCircle(0, 0, 36, COLOR_LIGHT_OVERLAY); - drawCircle(0, 0, 20, '#fff'); - - if (theme.minutes) { - const minuteAngle = degToRad((time.getMinutes() + time.getSeconds() / 60) / 60 * 360 - 180); - drawRoundedRect(34, clockRadius - 64, minuteAngle, 16, COLOR_MINUTE_HAND); - } - - const hourAngle = degToRad(((time.getHours() % 12) + time.getMinutes() / 60) / 12 * 360 - 180); - drawRoundedRect(36, clockRadius - 80, hourAngle, 16, 'rgba(0, 0, 0, 0.15)', '#fff', 4); - - if (!ambient) setTimeout(() => window.requestAnimationFrame(drawWatchFace), 1000/10); - } - - window.requestAnimationFrame(drawWatchFace); - - window.addEventListener('timetick', drawWatchFace); - - window.addEventListener('ambientmodechanged', (e) => { - ambient = e.detail.ambientMode; - drawWatchFace(); - }); - - document.addEventListener('visibilitychange', () => { - if (!document.hidden) drawWatchFace(); - }); - } -})(); diff --git a/watch/package-lock.json b/watch/package-lock.json new file mode 100644 index 0000000..620b014 --- /dev/null +++ b/watch/package-lock.json @@ -0,0 +1,1109 @@ +{ + "name": "focus-watch", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", + "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", + "dev": true, + "requires": { + "@cspotcode/source-map-consumer": "0.8.0" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "@types/tizen-common-web": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/tizen-common-web/-/tizen-common-web-2.0.1.tgz", + "integrity": "sha512-C8j8UYDuuJ6DT0pC+qc6pTkiVPW693Z6wd5eCddKgJOXsRzRNGov7eupiTjO5cSJ3IMa3LqNdE1i8ng95PB6WA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dev": true, + "requires": { + "ini": "1.3.7" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nodemon": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.12.tgz", + "integrity": "sha512-egCTmNZdObdBxUBw6ZNwvZ/xzk24CKRs5K6d+5zbmrMr7rOpPmfPeF6OxM3DDpaRx331CQRFEktn+wrFFfBSOA==", + "dev": true, + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^4.1.0" + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "ts-node": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", + "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "0.6.1", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "dev": true + }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "requires": { + "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dev": true, + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/watch/package.json b/watch/package.json new file mode 100644 index 0000000..537f8e3 --- /dev/null +++ b/watch/package.json @@ -0,0 +1,39 @@ +{ + "name": "focus-watch", + "version": "0.0.1", + "description": "Tizen application for the Focus Watch Face.", + "main": "build/Main.js", + "scripts": { + "dev": "nodemon" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Aurailus/Focus.git" + }, + "keywords": [ + "watch", + "tizen", + "calendar", + "scheduling" + ], + "nodemonConfig": { + "watch": [ + "src" + ], + "extensions": ".js", + "quiet": true, + "exec": "tsc" + }, + "author": "Auri Collings ", + "license": "UNLICENSED", + "bugs": { + "url": "https://github.com/Aurailus/Focus/issues" + }, + "homepage": "https://github.com/Aurailus/Focus#readme", + "devDependencies": { + "@types/tizen-common-web": "^2.0.1", + "nodemon": "^2.0.12", + "ts-node": "^10.2.1", + "typescript": "^4.4.3" + } +} diff --git a/watch/res/icon.svg b/watch/res/icon.svg deleted file mode 100644 index 46907e0..0000000 --- a/watch/res/icon.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/watch/src/Main.ts b/watch/src/Main.ts new file mode 100644 index 0000000..ad04b16 --- /dev/null +++ b/watch/src/Main.ts @@ -0,0 +1,310 @@ +let theme = { + /** 0: none, 1: quarter, 2: hours, 3: hours + minute */ + notches: 3, + /** False: don't display, True: display */ + events: true, + /** False: don't show minute hand, True: show minute hand */ + minutes: true, + /** False: don't show center glow, True: show center glow */ + glow: true, + /** Center glow color. */ + glow_a: '#4294ff', + /** Moving glow 1 color. */ + glow_b: 'rgba(5, 124, 242, 0.6)', + /** Moving glow 2 color. */ + glow_c: 'rgba(198, 0, 237, 1)', + // /** Center glow color. */ + // glow_a: '#e838ff', + // /** Moving glow 1 color. */ + // glow_b: 'rgba(255, 38, 56, 0.6)', + // /** Moving glow 2 color. */ + // glow_c: 'rgba(179, 38, 255, 1)', +} + +let image_loaded = false; +let window_loaded = false; + +window.onload = () => { + window_loaded = true; + if (image_loaded) init(); +}; + +const glow_image = document.createElement('img'); +glow_image.src = 'res/glow.png'; +glow_image.onload = () => { + image_loaded = true; + if (window_loaded) init(); +}; + +const glow_canvas = document.createElement('canvas'); +glow_canvas.width = 128; +glow_canvas.height = 128; +const glow_ctx = glow_canvas.getContext('2d')!; + +function init() { + const canvas = document.querySelector('canvas')!; + const ctx = canvas.getContext('2d')!; + canvas.width = document.body.clientWidth; + canvas.height = canvas.width; + const clockRadius = document.body.clientWidth / 2; + + let rot = 0; + let ambient = false; + + const EVENT_WIDTH = 22; + let EVENT_BUFFER = theme.notches === 0 ? 2 : 14; + const TITLE_BUFFER = 2; + const TITLE_SIZE = 16; + const NOTCH_BUFFER = 2; + const DATE_SIZE = 20; + + const COLOR_LIGHT_DIM = 'rgba(65, 199, 232, 0.15)'; + const COLOR_LIGHT_OVERLAY = 'rgba(65, 199, 232, 0.33)'; + const COLOR_MINUTE_HAND = 'rgba(65, 199, 232, 0.8)'; + + const degToRad = (deg: number) => deg * (Math.PI / 180); + + const createDate = (hour: number, minute: number) => { + const date = new Date(); + date.setHours(hour, minute, 0); + return date; + }; + + const events = [ + { start: createDate(9, 30), end: createDate(11, 20), color: '#33B679', title: 'PAAS' }, + { start: createDate(12, 30), end: createDate(1, 20), color: '#33B679', title: 'STAT' }, + { start: createDate(1, 30), end: createDate(2, 20), color: '#33B679', title: 'MATH' } + // { start: createDate(9, 30), end: createDate(11, 20), color: '#59acff', title: 'Work' }, + // { start: createDate(12, 30), end: createDate(1, 20), color: '#59acff', title: 'Walk' }, + // { start: createDate(1, 30), end: createDate(2, 20), color: '#59acff', title: 'Bike' } + ]; + + function getTime() { + try { return tizen.time.getCurrentDateTime(); } + catch (e) { return new Date(); } + } + + function drawCircle(angle: number, distance: number, width: number, color: string) { + ctx.save(); + ctx.translate(canvas.width / 2, canvas.height / 2); + ctx.rotate(angle) + + ctx.beginPath(); + ctx.arc(distance, 0, width / 2, 0, 2 * Math.PI, false); + ctx.fillStyle = color; + ctx.fill(); + ctx.closePath(); + + ctx.restore(); + } + + // function drawLine(startDistance, endDistance, angle, width, color) { + // ctx.save(); + // ctx.translate(canvas.width / 2, canvas.height / 2); + // ctx.rotate(degToRad(angle + 90)); + + // ctx.beginPath(); + // ctx.lineWidth = width; + // ctx.strokeStyle = color; + // ctx.moveTo(startDistance, 0); + // ctx.lineTo(endDistance, 0); + // ctx.stroke(); + // ctx.closePath(); + + // ctx.restore(); + // } + + function drawRoundedRect(startDistance: number, endDistance: number, angle: number, width: number, + fill?: string, stroke?: string, strokeWidth?: number) { + ctx.save(); + ctx.translate(canvas.width / 2, canvas.height / 2); + ctx.rotate(angle); + + ctx.beginPath(); + ctx.moveTo(-width / 2, startDistance); + ctx.lineTo(-width / 2, endDistance); + ctx.quadraticCurveTo(-width / 2, endDistance + width / 1.5, 0, endDistance + width / 1.5); + ctx.quadraticCurveTo(width / 2, endDistance + width / 1.5, width / 2, endDistance); + ctx.lineTo(width / 2, startDistance); + ctx.quadraticCurveTo(width / 2, startDistance - width / 1.5, 0, startDistance - width / 1.5); + ctx.quadraticCurveTo(-width / 2, startDistance - width / 1.5, -width / 2, startDistance); + ctx.closePath(); + + if (fill) { + ctx.fillStyle = fill; + ctx.fill(); + } + + if (stroke && strokeWidth) { + ctx.strokeStyle = stroke; + ctx.lineWidth = strokeWidth; + ctx.stroke(); + } + + ctx.restore() + } + + function drawEvent(event: any) { + const startAngle = degToRad(((event.start.getHours() % 12) + + event.start.getMinutes() / 60) / 12 * 360 + EVENT_WIDTH / 6 - 90); + const endAngle = degToRad(((event.end.getHours() % 12) + + event.end.getMinutes() / 60) / 12 * 360 - EVENT_WIDTH / 8 - 90); + + ctx.save(); + ctx.translate(canvas.width / 2, canvas.height / 2); + + ctx.beginPath(); + ctx.fillStyle = COLOR_LIGHT_DIM; + + ctx.arc(0, 0, clockRadius - EVENT_BUFFER, startAngle, endAngle, false); + + let controlPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER); + let controlPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER); + let endPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); + let endPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); + + ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); + + controlPosX = Math.cos(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + controlPosY = Math.sin(endAngle + degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + endPosX = Math.cos(endAngle) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + endPosY = Math.sin(endAngle) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + + ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); + + ctx.arc(0, 0, clockRadius - EVENT_BUFFER - EVENT_WIDTH, endAngle, startAngle, true); + + controlPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + controlPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH); + endPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); + endPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2); + + ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); + + controlPosX = Math.cos(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER); + controlPosY = Math.sin(startAngle - degToRad(4.25)) * (clockRadius - EVENT_BUFFER); + endPosX = Math.cos(startAngle) * (clockRadius - EVENT_BUFFER); + endPosY = Math.sin(startAngle) * (clockRadius - EVENT_BUFFER); + + ctx.quadraticCurveTo(controlPosX, controlPosY, endPosX, endPosY); + + ctx.fill(); + ctx.closePath(); + + ctx.restore(); + + drawCircle(startAngle, clockRadius - EVENT_BUFFER - EVENT_WIDTH / 2, EVENT_WIDTH - 8, event.color); + + ctx.font = `900 ${TITLE_SIZE}px Arial sans-serif`; + ctx.fillStyle = '#fff'; + ctx.textBaseline = 'top'; + ctx.textAlign = 'center'; + + let currentAngle = startAngle + degToRad(96); + for (let i = 0; i < event.title.length; i++) { + ctx.save(); + ctx.translate(canvas.width / 2, canvas.height / 2); + ctx.rotate(currentAngle); + + ctx.fillText(event.title[i], 0, -(clockRadius - EVENT_BUFFER - TITLE_BUFFER)); + + ctx.restore(); + if (i < event.title.length - 1) + currentAngle += ctx.measureText(event.title[i]).width * 0.0065 / 2 + + ctx.measureText(event.title[i + 1]).width * 0.0065 / 2; + } + } + + function drawGlow(offsetX: number, offsetY: number, scaleMult: number, color: string) { + glow_ctx.fillStyle = color; + glow_ctx.globalCompositeOperation = 'source-over'; + glow_ctx.fillRect(0, 0, glow_canvas.width, glow_canvas.height); + glow_ctx.globalCompositeOperation = 'destination-in'; + glow_ctx.drawImage(glow_image, 0, 0); + + const scale = 240 * scaleMult; + + ctx.drawImage(glow_canvas, + canvas.width / 2 + offsetX - scale / 2, + canvas.height / 2 + offsetY - scale / 2, + scale, scale); + } + + function drawWatchFace() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + const time = getTime(); + + ctx.font = `900 ${DATE_SIZE}px Arial sans-serif`; + ctx.fillStyle = '#aaa'; + ctx.textBaseline = 'bottom'; + ctx.textAlign = 'center'; + + ctx.fillText(`${['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'][time.getDay()]} ${time.getDate()}`, + clockRadius, clockRadius + clockRadius / 1.75); + + ctx.fillStyle = '#666' + ctx.fillRect(clockRadius - 1 * DATE_SIZE, clockRadius + clockRadius / 1.75 + 2, 2 * DATE_SIZE, 2); + + if (!ambient) { + rot = (rot + 1) % 360; + + let scaleA = 1 + (Math.sin(degToRad(rot + 180)) / 6); + let scaleB = 1 + (Math.cos(degToRad(rot)) / 6); + let scaleC = 1.3 + (Math.cos(degToRad(rot - 90)) / 6); + let offsetX = Math.cos(degToRad(rot + 90)) * 50 + (1 - scaleA); + let offsetY = Math.sin(degToRad(rot + 90)) * 50 + (1 - scaleB); + + if (theme.glow) { + ctx.globalCompositeOperation = 'lighter'; + drawGlow(-offsetX, -offsetY, scaleA, theme.glow_b); + drawGlow(0, 0, scaleC, theme.glow_a); + drawGlow(offsetX, offsetY, scaleB, theme.glow_c); + ctx.globalCompositeOperation = 'source-over'; + } + + if (theme.notches) { + for (let i = 0; i < 12 * 5; i++) { + if (i % 15 === 0) + drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 8, COLOR_MINUTE_HAND) + else if (i % 5 === 0 && theme.notches >= 2) + drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 6, COLOR_LIGHT_OVERLAY) + else if (theme.notches >= 3) + drawCircle(degToRad(i / (12 * 5) * 360 - 90), clockRadius - NOTCH_BUFFER - 4, 4, COLOR_LIGHT_DIM) + } + } + } + + if (theme.events) { + for (let event of events) { + drawEvent(event); + } + } + + drawCircle(0, 0, 36, COLOR_LIGHT_OVERLAY); + drawCircle(0, 0, 20, '#fff'); + + if (theme.minutes) { + const minuteAngle = degToRad((time.getMinutes() + time.getSeconds() / 60) / 60 * 360 - 180); + drawRoundedRect(34, clockRadius - 64, minuteAngle, 16, COLOR_MINUTE_HAND, undefined, undefined); + } + + const hourAngle = degToRad(((time.getHours() % 12) + time.getMinutes() / 60) / 12 * 360 - 180); + drawRoundedRect(36, clockRadius - 80, hourAngle, 16, 'rgba(0, 0, 0, 0.15)', '#fff', 4); + + if (!ambient) setTimeout(() => window.requestAnimationFrame(drawWatchFace), 1000/10); + } + + window.requestAnimationFrame(drawWatchFace); + + window.addEventListener('timetick', drawWatchFace); + + window.addEventListener('ambientmodechanged', (e: any) => { + ambient = e.detail.ambientMode; + drawWatchFace(); + }); + + document.addEventListener('visibilitychange', () => { + if (!document.hidden) drawWatchFace(); + }); +} diff --git a/watch/tsconfig.json b/watch/tsconfig.json new file mode 100644 index 0000000..20d6c50 --- /dev/null +++ b/watch/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "strict": true, + "alwaysStrict": true, + + "target": "es5", + "outFile": "build/main.js", + "esModuleInterop": true, + "moduleResolution": "node", + + "typeRoots": [ "./node_modules/@types/" ], + + "removeComments": true, + "noUnusedLocals": true, + "noImplicitReturns": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": [ + "./src/**/*.ts" + ], + "exclude": [ + "./node_modules" + ] +}