├── .gitignore
├── LICENSE
├── README.md
├── manifest.xml
├── monkey.jungle
├── resources-rectangle
└── strings.xml
├── resources-semiround
├── resources
├── drawables
│ ├── drawables.xml
│ ├── launcher_icon.png
│ └── weather
│ │ ├── clearsky_day.png
│ │ ├── clearsky_night.png
│ │ ├── clearsky_polartwilight.png
│ │ ├── cloudy.png
│ │ ├── fair_day.png
│ │ ├── fair_night.png
│ │ ├── fair_polartwilight.png
│ │ ├── fog.png
│ │ ├── heavyrain.png
│ │ ├── heavyrainandthunder.png
│ │ ├── heavyrainshowers_day.png
│ │ ├── heavyrainshowers_night.png
│ │ ├── heavyrainshowers_polartwilight.png
│ │ ├── heavyrainshowersandthunder_day.png
│ │ ├── heavyrainshowersandthunder_night.png
│ │ ├── heavyrainshowersandthunder_polartwilight.png
│ │ ├── heavysleet.png
│ │ ├── heavysleetandthunder.png
│ │ ├── heavysleetshowers_day.png
│ │ ├── heavysleetshowers_night.png
│ │ ├── heavysleetshowers_polartwilight.png
│ │ ├── heavysleetshowersandthunder_day.png
│ │ ├── heavysleetshowersandthunder_night.png
│ │ ├── heavysleetshowersandthunder_polartwilight.png
│ │ ├── heavysnow.png
│ │ ├── heavysnowandthunder.png
│ │ ├── heavysnowshowers_day.png
│ │ ├── heavysnowshowers_night.png
│ │ ├── heavysnowshowers_polartwilight.png
│ │ ├── heavysnowshowersandthunder_day.png
│ │ ├── heavysnowshowersandthunder_night.png
│ │ ├── heavysnowshowersandthunder_polartwilight.png
│ │ ├── lightrain.png
│ │ ├── lightrainandthunder.png
│ │ ├── lightrainshowers_day.png
│ │ ├── lightrainshowers_night.png
│ │ ├── lightrainshowers_polartwilight.png
│ │ ├── lightrainshowersandthunder_day.png
│ │ ├── lightrainshowersandthunder_night.png
│ │ ├── lightrainshowersandthunder_polartwilight.png
│ │ ├── lightsleet.png
│ │ ├── lightsleetandthunder.png
│ │ ├── lightsleetshowers_day.png
│ │ ├── lightsleetshowers_night.png
│ │ ├── lightsleetshowers_polartwilight.png
│ │ ├── lightsnow.png
│ │ ├── lightsnowandthunder.png
│ │ ├── lightsnowshowers_day.png
│ │ ├── lightsnowshowers_night.png
│ │ ├── lightsnowshowers_polartwilight.png
│ │ ├── lightssleetshowersandthunder_day.png
│ │ ├── lightssleetshowersandthunder_night.png
│ │ ├── lightssleetshowersandthunder_polartwilight.png
│ │ ├── lightssnowshowersandthunder_day.png
│ │ ├── lightssnowshowersandthunder_night.png
│ │ ├── lightssnowshowersandthunder_polartwilight.png
│ │ ├── partlycloudy_day.png
│ │ ├── partlycloudy_night.png
│ │ ├── partlycloudy_polartwilight.png
│ │ ├── rain.png
│ │ ├── rainandthunder.png
│ │ ├── rainshowers_day.png
│ │ ├── rainshowers_night.png
│ │ ├── rainshowers_polartwilight.png
│ │ ├── rainshowersandthunder_day.png
│ │ ├── rainshowersandthunder_night.png
│ │ ├── rainshowersandthunder_polartwilight.png
│ │ ├── sleet.png
│ │ ├── sleetandthunder.png
│ │ ├── sleetshowers_day.png
│ │ ├── sleetshowers_night.png
│ │ ├── sleetshowers_polartwilight.png
│ │ ├── sleetshowersandthunder_day.png
│ │ ├── sleetshowersandthunder_night.png
│ │ ├── sleetshowersandthunder_polartwilight.png
│ │ ├── snow.png
│ │ ├── snowandthunder.png
│ │ ├── snowshowers_day.png
│ │ ├── snowshowers_night.png
│ │ ├── snowshowers_polartwilight.png
│ │ ├── snowshowersandthunder_day.png
│ │ ├── snowshowersandthunder_night.png
│ │ └── snowshowersandthunder_polartwilight.png
├── properties.xml
└── strings.xml
└── source
├── App.mc
├── BaseData.mc
├── FullData.mc
├── Resources.mc
└── view
├── AuroraView.mc
├── BaseDelegate.mc
├── BaseView.mc
├── CelestialView.mc
├── DailyView.mc
├── GraphView.mc
├── HourlyView.mc
├── SummaryView.mc
├── UvView.mc
├── WaterView.mc
└── special
├── AppGlanceView.mc
├── HintDelegate.mc
├── HintView.mc
├── RegisterDelegate.mc
├── RegisterView.mc
├── SettingsDelegate.mc
└── SpellSearchDelegate.mc
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Rainy (Garmin App) 
2 |
3 | A weather app i made because i wanted to make something "simple" for my watch (And Garmins weather app kinda sucks).
4 | The app has more features, is more accurate and is prettier than Garmins weather app!
5 |
6 | App supports most (CIQ 3.0+) watches and a few Edge devices.
7 | Download on the [Connect IQ store](https://apps.garmin.com/en-US/apps/e7c0c39c-cb76-475f-b5bc-7811b0fee104).
8 |
9 | ## 2.x Branch
10 |
11 | This is the 2.x (App Version) version which is a "Device App" and has more available memory.
12 | This branch has more features than 1.x but drops support for Instinct watches.
13 |
14 | ### Showcase of pages
15 |
16 |
17 | ## Contributing
18 |
19 | 1. Follow Garmins SDK and VSCode Setup.
20 | 2. Select **SDK 7.1.1** and install all the neccesary watches in Garmins SDK Manager.
21 | 3. Clone and Import the project into VSCode.
22 | 4. Maybe it works?? ¯\\\_(ツ)_/¯
23 | 5. Create a Pull Request.
--------------------------------------------------------------------------------
/manifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
121 |
122 |
123 |
124 |
125 |
129 |
130 | eng
131 |
132 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/monkey.jungle:
--------------------------------------------------------------------------------
1 | project.manifest = manifest.xml
2 |
--------------------------------------------------------------------------------
/resources-rectangle/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 1
3 |
4 |
--------------------------------------------------------------------------------
/resources-semiround:
--------------------------------------------------------------------------------
1 | resources-rectangle
--------------------------------------------------------------------------------
/resources/drawables/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/resources/drawables/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/launcher_icon.png
--------------------------------------------------------------------------------
/resources/drawables/weather/clearsky_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/clearsky_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/clearsky_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/clearsky_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/clearsky_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/clearsky_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/cloudy.png
--------------------------------------------------------------------------------
/resources/drawables/weather/fair_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/fair_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/fair_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/fair_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/fair_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/fair_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/fog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/fog.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavyrain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavyrain.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavyrainandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavyrainandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavyrainshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavyrainshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavyrainshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavyrainshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavyrainshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavyrainshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavyrainshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavyrainshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavyrainshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavyrainshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavyrainshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavyrainshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysleet.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysleetandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysleetandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysleetshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysleetshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysleetshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysleetshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysleetshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysleetshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysleetshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysleetshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysleetshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysleetshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysleetshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysleetshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysnow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysnow.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysnowandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysnowandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysnowshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysnowshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysnowshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysnowshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysnowshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysnowshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysnowshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysnowshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysnowshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysnowshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/heavysnowshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/heavysnowshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightrain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightrain.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightrainandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightrainandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightrainshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightrainshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightrainshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightrainshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightrainshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightrainshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightrainshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightrainshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightrainshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightrainshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightrainshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightrainshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsleet.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsleetandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsleetandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsleetshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsleetshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsleetshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsleetshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsleetshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsleetshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsnow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsnow.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsnowandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsnowandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsnowshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsnowshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsnowshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsnowshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightsnowshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightsnowshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightssleetshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightssleetshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightssleetshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightssleetshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightssleetshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightssleetshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightssnowshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightssnowshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightssnowshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightssnowshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/lightssnowshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/lightssnowshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/partlycloudy_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/partlycloudy_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/partlycloudy_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/partlycloudy_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/partlycloudy_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/partlycloudy_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/rain.png
--------------------------------------------------------------------------------
/resources/drawables/weather/rainandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/rainandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/rainshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/rainshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/rainshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/rainshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/rainshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/rainshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/rainshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/rainshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/rainshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/rainshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/rainshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/rainshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/sleet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/sleet.png
--------------------------------------------------------------------------------
/resources/drawables/weather/sleetandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/sleetandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/sleetshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/sleetshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/sleetshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/sleetshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/sleetshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/sleetshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/sleetshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/sleetshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/sleetshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/sleetshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/sleetshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/sleetshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/snow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/snow.png
--------------------------------------------------------------------------------
/resources/drawables/weather/snowandthunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/snowandthunder.png
--------------------------------------------------------------------------------
/resources/drawables/weather/snowshowers_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/snowshowers_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/snowshowers_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/snowshowers_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/snowshowers_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/snowshowers_polartwilight.png
--------------------------------------------------------------------------------
/resources/drawables/weather/snowshowersandthunder_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/snowshowersandthunder_day.png
--------------------------------------------------------------------------------
/resources/drawables/weather/snowshowersandthunder_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/snowshowersandthunder_night.png
--------------------------------------------------------------------------------
/resources/drawables/weather/snowshowersandthunder_polartwilight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BleachDev/Rainy/de79034a7854b03838d53cb649a7971571190533/resources/drawables/weather/snowshowersandthunder_polartwilight.png
--------------------------------------------------------------------------------
/resources/properties.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 |
6 | false
7 | 0
8 | 0
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Celsius
24 | Fahrenheit
25 |
26 |
27 |
28 |
29 | m/s
30 | km/h
31 | mph
32 | Bft.
33 | Knots
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/resources/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Rainy Pro
3 | 0
4 |
5 |
--------------------------------------------------------------------------------
/source/App.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Application;
2 | import Toybox.Lang;
3 | import Toybox.Math;
4 | import Toybox.System;
5 | import Toybox.WatchUi;
6 |
7 | public var data as FullData?;
8 | public var res as Resources?;
9 | (:glance) public var VERSION = "2.2.3";
10 | (:glance) public var IS_GLANCE as Boolean = false;
11 | public var SQUARE_MODE as Boolean = false; // Whether the watch is rectangle/semiround
12 |
13 | (:glance)
14 | class App extends Application.AppBase {
15 |
16 | function initialize() {
17 | AppBase.initialize();
18 | }
19 |
20 | // onStart() is called on application start up
21 | function onStart(state as Dictionary?) as Void {
22 | }
23 |
24 | // onStop() is called when your application is exiting
25 | function onStop(state as Dictionary?) as Void {
26 | Position.enableLocationEvents(Position.LOCATION_DISABLE, null);
27 | }
28 |
29 | // Return the initial view of your application here
30 | function getInitialView() as [ WatchUi.Views ] or [ WatchUi.Views, WatchUi.InputDelegates ] {
31 | SQUARE_MODE = "1".equals(WatchUi.loadResource(Rez.Strings.SQUARE_MODE));
32 |
33 | res = new Resources();
34 | data = new FullData();
35 | data.load();
36 |
37 | return [ new SummaryView(), new BaseDelegate() ];
38 | }
39 |
40 | function getGlanceView() as [ WatchUi.GlanceView ] or [ WatchUi.GlanceView, WatchUi.GlanceViewDelegate ] or Null {
41 | IS_GLANCE = true;
42 |
43 | var data = new BaseData();
44 | data.load();
45 |
46 | return [ new AppGlanceView(data) ];
47 | }
48 | }
49 |
50 | // This definetely shouldn't be here but thats a later problem
51 | (:glance)
52 | function generateArrow(centerPoint as [Float, Float], angle as Float, length as Number) as Array {
53 | // Map out the coordinates of the arrow
54 | var coords = [[0, length / 2] as Array,
55 | [(length * 0.07).toNumber(), (-length / 2 * 0.5).toNumber()] as Array,
56 | [(length * 0.3).toNumber(), (-length / 2 * 0.3).toNumber()] as Array,
57 | [0, -length / 2] as Array,
58 | [-(length * 0.3).toNumber(), (-length / 2 * 0.3).toNumber()] as Array,
59 | [-(length * 0.07).toNumber(), (-length / 2 * 0.5).toNumber()] as Array] as Array>;
60 | var result = new Array[coords.size()];
61 | var rad = Toybox.Math.toRadians(angle);
62 | var cos = Toybox.Math.cos(rad);
63 | var sin = Toybox.Math.sin(rad);
64 |
65 | // Transform the coordinates
66 | for (var i = 0; i < coords.size(); i++) {
67 | var x = (coords[i][0] * cos) - (coords[i][1] * sin);
68 | var y = (coords[i][0] * sin) + (coords[i][1] * cos);
69 |
70 | result[i] = [centerPoint[0] + x + length / 2, centerPoint[1] + y + length / 2];
71 | }
72 |
73 | return result;
74 | }
75 |
76 | (:glance)
77 | function degrees(c as Float, unit as Number) {
78 | return (unit == 0 ? c : c * (9.0/5.0) + 32).toNumber();
79 | }
80 |
81 | (:glance)
82 | function wind(ms as Float, unit as Number) {
83 | return (unit == 0 ? ms : unit == 1 ? ms * 3.6 : unit == 2 ? ms * 2.237 : unit == 3 ? Math.round(Math.pow(ms / 0.836, 2.0 / 3)) : ms * 1.9438).toNumber();
84 | }
--------------------------------------------------------------------------------
/source/BaseData.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Communications;
2 | import Toybox.Position;
3 | import Toybox.Lang;
4 | import Toybox.Application;
5 | import Toybox.Time;
6 |
7 | (:glance)
8 | class BaseData {
9 |
10 | public var autoLocation as Boolean = true;
11 | public var tempUnits as Number = System.getDeviceSettings().temperatureUnits; // 0 = C, 1 = F
12 | public var windUnits as Number = 0; // 0 = m/s, 1 = km/h, 2 = mph, 3 = bft., 4 = knots
13 |
14 | public var position as Array?;
15 | public var location as String = "..";
16 | public var time as Moment = Time.now();
17 | // Forecast
18 | public var nowRainfall as Array?; // Null (If unavailable) or empty (If outdated) or list of next 90 mins of rain
19 | public var temperatures as Array = [];
20 | public var windSpeeds as Array = [];
21 | public var windDirections as Array = [];
22 | public var rainfall as Array = [];
23 | public var humidity as Array = [];
24 | public var symbols as Array = [];
25 | public var hours as Number = 0;
26 |
27 | function update(coords as Array) as Void {
28 | System.println("Refreshing, " + coords);
29 | if (coords == null) {
30 | return;
31 | }
32 |
33 | position = coords;
34 | Storage.setValue("geo", position);
35 |
36 | var hours = IS_GLANCE ? 6 : 48;
37 | var days = IS_GLANCE ? 0 : 22;
38 | request("https://api.bleach.dev/weather/forecast?hourly=" + hours + "&daily=" + days + "&lat=" + position[0] + "&lon=" + position[1], method(:fetchForecastData));
39 | request("https://api.bleach.dev/weather/search?limit=1&lat=" + position[0] + "&lon=" + position[1], method(:fetchGeoData));
40 | }
41 |
42 | // Request order
43 | // -> Forecast
44 | // -> Geo ----> (F) Celestial ---> (F) Aurora
45 | // |---> (F) License
46 | // \---> (F) Water
47 | function request(url, callback) {
48 | Communications.makeWebRequest(url, null, {
49 | :method => Communications.HTTP_REQUEST_METHOD_GET,
50 | :headers => { "User-Agent" => "GarminYr/" + VERSION + " me@bleach.dev" },
51 | :responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
52 | }, callback);
53 | }
54 |
55 | function load() {
56 | if (Properties.getValue("autoLocation") != null) { autoLocation = Properties.getValue("autoLocation"); }
57 | if (Properties.getValue("tempUnits") != null) { tempUnits = Properties.getValue("tempUnits"); }
58 | if (Properties.getValue("windUnits") != null) { windUnits = Properties.getValue("windUnits"); }
59 |
60 | if (Storage.getValue("geo") != null) { position = Storage.getValue("geo"); }
61 | if (Storage.getValue("location") != null) { location = Storage.getValue("location"); }
62 | if (Storage.getValue("time") != null) { time = new Moment(Storage.getValue("time")); }
63 |
64 | if (Storage.getValue("nowRainfall") != null) { nowRainfall = Storage.getValue("nowRainfall"); }
65 | if (Storage.getValue("temperatures") != null) { temperatures = Storage.getValue("temperatures"); }
66 | if (Storage.getValue("windSpeeds") != null) { windSpeeds = Storage.getValue("windSpeeds"); }
67 | if (Storage.getValue("windDirections") != null) { windDirections = Storage.getValue("windDirections"); }
68 | if (Storage.getValue("rainfall") != null) { rainfall = Storage.getValue("rainfall"); }
69 | if (Storage.getValue("humidity") != null) { humidity = Storage.getValue("humidity"); }
70 | if (Storage.getValue("symbols") != null) { symbols = Storage.getValue("symbols"); }
71 | if (Storage.getValue("hours") != null) { hours = Storage.getValue("hours"); }
72 |
73 | // Sync Data
74 | var now = Time.now().value();
75 | for (var i = time.value(); i + 3600 < now; i += 3600) {
76 | removeHour();
77 | }
78 |
79 | WatchUi.requestUpdate();
80 |
81 | // Update if we have a valid position
82 | if (!autoLocation && Properties.getValue("manLocation").length() > 0) {
83 | return;
84 | }
85 |
86 | var pos = Position.getInfo().position.toDegrees();
87 | if (autoLocation && pos[0] > -90 && pos[0] < 90 && pos[1] > -180 && pos[1] < 180) {
88 | update(pos);
89 | } else if (autoLocation && Activity.getActivityInfo() != null && Activity.getActivityInfo().currentLocation != null) {
90 | update(Activity.getActivityInfo().currentLocation.toDegrees());
91 | } else if (autoLocation && Toybox has :Weather
92 | && Weather.getCurrentConditions() != null && Weather.getCurrentConditions().observationLocationPosition != null) {
93 | update(Weather.getCurrentConditions().observationLocationPosition.toDegrees());
94 | } else if (position != null) {
95 | update(position);
96 | }
97 | }
98 |
99 | function removeHour() {
100 | if (nowRainfall != null) {
101 | nowRainfall = []; // No more 90 minute rain
102 | }
103 | if (temperatures.size() > 0) { temperatures.remove(temperatures[0]); }
104 | if (windSpeeds.size() > 0) { windSpeeds.remove(windSpeeds[0]); }
105 | if (windDirections.size() > 0) { windDirections.remove(windDirections[0]); }
106 | if (rainfall.size() > 0) { rainfall.remove(rainfall[0]); }
107 | if (humidity.size() > 0) { humidity.remove(humidity[0]); }
108 | if (symbols.size() > 0) { symbols.remove(symbols[0]); }
109 | hours--;
110 | }
111 |
112 | // Fetching Methods
113 |
114 | function fetchForecastData(responseCode as Number, data as Dictionary?) as Boolean {
115 | System.println("FC " + responseCode);
116 | if (responseCode != 200 || data == null || data["forecast"] == null) {
117 | return false;
118 | }
119 |
120 | time = Time.now();
121 | hours = data["hourly"];
122 |
123 | var forecastData = data["forecast"] as Dictionary;
124 |
125 | var size = forecastData.size();
126 | temperatures = new [size];
127 | windSpeeds = new [size];
128 | windDirections = new [size];
129 | rainfall = new [size];
130 | humidity = new [size];
131 | symbols = new [size];
132 | for (var i = 0; i < size; i++) {
133 | var hour = forecastData[i];
134 | temperatures[i] = hour["air_temperature"];
135 | windSpeeds[i] = hour["wind_speed"];
136 | windDirections[i] = hour["wind_from_direction"];
137 | rainfall[i] = hour["precipitation_amount"];
138 | humidity[i] = hour["relative_humidity"];
139 | symbols[i] = hour["symbol_code"].hashCode();
140 | }
141 |
142 | if (data["nowcast"] != null) {
143 | var nowData = data["nowcast"] as Dictionary;
144 | nowRainfall = new [nowData.size() < 19 ? nowData.size() : 19];
145 | for (var i = 0; i < nowRainfall.size(); i++) {
146 | nowRainfall[i] = nowData[i];
147 | }
148 | }
149 |
150 | WatchUi.requestUpdate();
151 | if (!IS_GLANCE) {
152 | Storage.setValue("time", time.value());
153 | Storage.setValue("hours", hours);
154 |
155 | Storage.setValue("nowRainfall", nowRainfall);
156 | Storage.setValue("temperatures", temperatures);
157 | Storage.setValue("windSpeeds", windSpeeds);
158 | Storage.setValue("windDirections", windDirections);
159 | Storage.setValue("rainfall", rainfall);
160 | Storage.setValue("humidity", humidity);
161 | Storage.setValue("symbols", symbols);
162 | }
163 | return true;
164 | }
165 |
166 | function fetchGeoData(responseCode as Number, data as Dictionary?) as Boolean {
167 | System.println("GEO " + responseCode);
168 | if (responseCode != 200 || data == null || data.size() == 0) {
169 | System.println("GEO EXIT " + data);
170 | return false;
171 | }
172 |
173 | location = data[0]["name"];
174 | Storage.setValue("location", location);
175 |
176 | if (IS_GLANCE) {
177 | WatchUi.requestUpdate();
178 | }
179 | return true;
180 | }
181 | }
--------------------------------------------------------------------------------
/source/FullData.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Communications;
2 | import Toybox.Position;
3 | import Toybox.Lang;
4 | import Toybox.Application;
5 | import Toybox.Time;
6 | import Toybox.WatchUi;
7 |
8 | class FullData extends BaseData {
9 |
10 | public var DEVICE_ID = uniqueId();
11 | public var blocked = false;
12 |
13 | public var hints as Number = 0;
14 | public var pageOrder as Boolean = false;
15 | // Forecast
16 | public var maxRainfall as Array = [];
17 | // Aurora
18 | public var hourlyAurora as Array = [];
19 | public var hourlyClouds as Array = [];
20 | // Uv
21 | public var uv as Array = [];
22 | // Celestial
23 | public var sunLength as Number = 0;
24 | public var sunDifference as Number = 0;
25 | public var sunRise as Number = 0;
26 | public var sunMax as Number = 0;
27 | public var sunSet as Number = 0;
28 | public var sunElevation as Array = [];
29 | public var sunNextEclipse as Number = 0;
30 | public var sunEclipseObsc as Float = 0.0;
31 | public var moonNextNew as Number = 0;
32 | public var moonNextFull as Number = 0;
33 | public var moonIllumination as Number = 0;
34 | public var moonPhase as String = "";
35 | // Water
36 | public var waterNames as Array = [];
37 | public var waterTemperatures as Array = [];
38 | public var waterDistances as Array = [];
39 | public var waterTimestamps as Array = [];
40 |
41 | function initialize() {
42 | BaseData.initialize();
43 | }
44 |
45 | // Callback function for Position.enableLocationEvents
46 | function posCB(loc as Position.Info) as Void {
47 | if (loc.position != null) {
48 | update(loc.position.toDegrees());
49 | }
50 | }
51 |
52 | function load() {
53 | if (Storage.getValue("hints") != null) { hints = Storage.getValue("hints"); }
54 |
55 | if (Properties.getValue("pageOrder") != null) { pageOrder = Properties.getValue("pageOrder"); }
56 |
57 | if (Storage.getValue("maxRainfall") != null) { maxRainfall = Storage.getValue("maxRainfall"); }
58 |
59 | if (Storage.getValue("hourlyAurora") != null) { hourlyAurora = Storage.getValue("hourlyAurora"); }
60 | if (Storage.getValue("hourlyClouds") != null) { hourlyClouds = Storage.getValue("hourlyClouds"); }
61 |
62 | if (Storage.getValue("uv") != null) { uv = Storage.getValue("uv"); }
63 |
64 | if (Storage.getValue("sunLength") != null) { sunLength = Storage.getValue("sunLength"); }
65 | if (Storage.getValue("sunDifference") != null) { sunDifference = Storage.getValue("sunDifference"); }
66 | if (Storage.getValue("sunRise") != null) { sunRise = Storage.getValue("sunRise"); }
67 | if (Storage.getValue("sunMax") != null) { sunMax = Storage.getValue("sunMax"); }
68 | if (Storage.getValue("sunSet") != null) { sunSet = Storage.getValue("sunSet"); }
69 | if (Storage.getValue("sunElevation") != null) { sunElevation = Storage.getValue("sunElevation"); }
70 | if (Storage.getValue("sunNextEclipse") != null) { sunNextEclipse = Storage.getValue("sunNextEclipse"); }
71 | if (Storage.getValue("sunEclipseObsc") != null) { sunEclipseObsc = Storage.getValue("sunEclipseObsc"); }
72 | if (Storage.getValue("moonNextNew") != null) { moonNextNew = Storage.getValue("moonNextNew"); }
73 | if (Storage.getValue("moonNextFull") != null) { moonNextFull = Storage.getValue("moonNextFull"); }
74 | if (Storage.getValue("moonIllumination") != null) { moonIllumination = Storage.getValue("moonIllumination"); }
75 | if (Storage.getValue("moonPhase") != null) { moonPhase = Storage.getValue("moonPhase"); }
76 |
77 | if (Storage.getValue("waterNames") != null) { waterNames = Storage.getValue("waterNames"); }
78 | if (Storage.getValue("waterTemperatures") != null) { waterTemperatures = Storage.getValue("waterTemperatures"); }
79 | if (Storage.getValue("waterDistances") != null) { waterDistances = Storage.getValue("waterDistances"); }
80 | if (Storage.getValue("waterTimestamps") != null) { waterTimestamps = Storage.getValue("waterTimestamps"); }
81 |
82 | BaseData.load();
83 |
84 | Position.enableLocationEvents(Position.LOCATION_ONE_SHOT, method(:posCB));
85 | }
86 |
87 | function removeHour() {
88 | BaseData.removeHour();
89 |
90 | if (maxRainfall.size() > 0) { maxRainfall.remove(maxRainfall[0]); }
91 | if (hourlyAurora.size() > 0) { hourlyAurora.remove(hourlyAurora[0]); }
92 | if (hourlyClouds.size() > 0) { hourlyClouds.remove(hourlyClouds[0]); }
93 | if (uv.size() > 0) { uv.remove(uv[0]); }
94 | }
95 |
96 | // Fetching Methods
97 |
98 | function fetchForecastData(responseCode as Number, data as Dictionary?) as Boolean {
99 | if (!BaseData.fetchForecastData(responseCode, data)) {
100 | return false;
101 | }
102 |
103 | var forecastData = data["forecast"] as Dictionary;
104 |
105 | var hours = forecastData.size();
106 | maxRainfall = new [hours];
107 | hourlyClouds = new [hours];
108 | uv = new [hours];
109 | for (var i = 0; i < hours; i++) {
110 | var hour = forecastData[i];
111 | maxRainfall[i] = hour["precipitation_max"] != null ? hour["precipitation_max"] : rainfall[i];
112 | hourlyClouds[i] = hour["cloud_area_fraction"];
113 | uv[i] = hour["uv"];
114 | }
115 |
116 | Storage.setValue("maxRainfall", maxRainfall);
117 | Storage.setValue("hourlyClouds", hourlyClouds);
118 | Storage.setValue("uv", uv);
119 | return true;
120 | }
121 |
122 | function fetchGeoData(responseCode as Number, data as Dictionary?) as Boolean {
123 | if (!BaseData.fetchGeoData(responseCode, data)) {
124 | return false;
125 | }
126 |
127 | request("https://api.bleach.dev/rainy/license?id=" + DEVICE_ID, method(:fetchLicense));
128 |
129 | var showWater = "NO".equals(data[0]["code"]);
130 | BaseDelegate.pageCount = showWater ? 8 : 7;
131 |
132 | request("https://api.bleach.dev/weather/celestial?lat=" + position[0] + "&lon=" + position[1], method(:fetchCelestialData));
133 | if (showWater) {
134 | request("https://api.bleach.dev/weather/water?lat=" + position[0] + "&lon=" + position[1], method(:fetchWaterData));
135 | }
136 | return true;
137 | }
138 |
139 | function fetchAuroraData(responseCode as Number, data as Dictionary?) as Void {
140 | System.println("AUR " + responseCode);
141 | if (responseCode != 200 || data == null) {
142 | System.println("AUR EXIT " + data);
143 | return;
144 | }
145 |
146 | hourlyAurora = new [data["aurora"].size()];
147 | for (var i = 0; i < data["aurora"].size(); i++) {
148 | hourlyAurora[i] = data["aurora"][i]["activity"];
149 | }
150 |
151 | Storage.setValue("hourlyAurora", hourlyAurora);
152 | WatchUi.requestUpdate();
153 | }
154 |
155 | function fetchCelestialData(responseCode as Number, data as Dictionary?) as Void {
156 | System.println("CST " + responseCode);
157 | if (responseCode != 200 || data == null) {
158 | System.println("CST EXIT " + data);
159 | return;
160 | }
161 |
162 | sunLength = data["sun"]["day_length"];
163 | sunDifference = data["sun"]["difference"];
164 | sunRise = data["sun"]["rise"];
165 | sunMax = data["sun"]["max"];
166 | sunSet = data["sun"]["set"];
167 | sunElevation = data["sun"]["elevation"];
168 | sunNextEclipse = data["sun"]["next_eclipse_time"];
169 | sunEclipseObsc = data["sun"]["next_eclipse_obscuration"];
170 | moonNextNew = data["moon"]["next_new"];
171 | moonNextFull = data["moon"]["next_full"];
172 | moonIllumination = data["moon"]["illumination_percent"];
173 | moonPhase = data["moon"]["phase"];
174 |
175 | Storage.setValue("sunLength", sunLength);
176 | Storage.setValue("sunDifference", sunDifference);
177 | Storage.setValue("sunRise", sunRise);
178 | Storage.setValue("sunMax", sunMax);
179 | Storage.setValue("sunSet", sunSet);
180 | Storage.setValue("sunElevation", sunElevation);
181 | Storage.setValue("sunNextEclipse", sunNextEclipse);
182 | Storage.setValue("sunEclipseObsc", sunEclipseObsc);
183 | Storage.setValue("moonNextNew", moonNextNew);
184 | Storage.setValue("moonNextFull", moonNextFull);
185 | Storage.setValue("moonIllumination", moonIllumination);
186 | Storage.setValue("moonPhase", moonPhase);
187 | WatchUi.requestUpdate();
188 |
189 | request("https://api.bleach.dev/weather/aurora?noclouds&limit=32&lat=" + position[0] + "&lon=" + position[1], method(:fetchAuroraData));
190 | }
191 |
192 | function fetchWaterData(responseCode as Number, data as Dictionary?) as Void {
193 | System.println("WTR " + responseCode);
194 | if (responseCode != 200 || data == null) {
195 | System.println("WTR EXIT " + data);
196 | return;
197 | }
198 |
199 | var len = data["water"].size();
200 | waterNames = new [len];
201 | waterTemperatures = new [len];
202 | waterDistances = new [len];
203 | waterTimestamps = new [len];
204 | for (var i = 0; i < len; i++) {
205 | var waterData = data["water"][i];
206 | waterNames[i] = waterData["name"];
207 | waterTemperatures[i] = waterData["temperature"];
208 | waterDistances[i] = waterData["distance"];
209 | waterTimestamps[i] = waterData["time"];
210 | }
211 |
212 | Storage.setValue("waterNames", waterNames);
213 | Storage.setValue("waterTemperatures", waterTemperatures);
214 | Storage.setValue("waterDistances", waterDistances);
215 | Storage.setValue("waterTimestamps", waterTimestamps);
216 | WatchUi.requestUpdate();
217 | }
218 |
219 | function fetchLicense(responseCode as Number, data as Dictionary?) as Void {
220 | System.println("LIC " + responseCode);
221 | if (responseCode == 200 && data != null) {
222 | if (data["demo"]) {
223 | blocked = data["demo"] == 0;
224 | WatchUi.pushView(new RegisterView(data["demo"]), new RegisterDelegate(), WatchUi.SLIDE_BLINK);
225 | }
226 | }
227 | }
228 |
229 | // Helper Methods
230 |
231 | function hourlyEntries() {
232 | return hours < symbols.size() ? hours : symbols.size();
233 | }
234 |
235 | function uniqueId() {
236 | var alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
237 | var deviceId = System.getDeviceSettings().uniqueIdentifier.toUpper().toCharArray();
238 | var rainyId = "";
239 | for (var i = 0; i < 5; i++) {
240 | rainyId = rainyId + alphabet[alphabet.indexOf(deviceId[i * 2]) + alphabet.indexOf(deviceId[i * 2 + 1])];
241 | }
242 | return rainyId;
243 | }
244 |
245 | function enterText(text) {
246 | var menu = new Menu2({:title => "Location"});
247 | menu.addItem(new MenuItem("Loading Locations..", "Please Wait :)", 0, {}));
248 |
249 | WatchUi.pushView(menu, new Menu2InputDelegate(), WatchUi.SLIDE_IMMEDIATE);
250 | data.request("https://api.bleach.dev/weather/search?q=" + text, method(:fetchSearch));
251 | }
252 |
253 | function fetchSearch(responseCode as Number, data as Dictionary?) as Boolean {
254 | if (responseCode != 200 || data == null) {
255 | var menu = new Menu2({:title => "Location"});
256 | menu.addItem(new MenuItem("Error", "Connection Error", 0, {}));
257 | WatchUi.switchToView(menu, new Menu2InputDelegate(), WatchUi.SLIDE_BLINK);
258 | return false;
259 | }
260 |
261 | var menu = new Menu2({:title => "Location" });
262 | for (var i = 0; i < data.size(); i++) {
263 | menu.addItem(new MenuItem(data[i]["name"], data[i]["region"] + " (" + data[i]["code"] + "), El. " + data[i]["elevation"] + "m", i, {}));
264 | }
265 |
266 | WatchUi.switchToView(menu, new SpellListDelegate(data), WatchUi.SLIDE_BLINK);
267 | return true;
268 | }
269 | }
--------------------------------------------------------------------------------
/source/Resources.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Application;
2 | import Toybox.Lang;
3 | import Toybox.WatchUi;
4 |
5 | class Resources {
6 |
7 | // The micro-optimizations are real
8 | private var resources as Dictionary = {};
9 | private var resourceNames as Dictionary = {
10 | -1331507130 => :clearsky_day,
11 | -1535495851 => :clearsky_night,
12 | -1219673323 => :clearsky_polartwilight,
13 | 2118327279 => :cloudy,
14 | 2018941991 => :fair_day,
15 | 1971704425 => :fair_night,
16 | 223183045 => :fair_polartwilight,
17 | 104671553 => :fog,
18 | 44038243 => :heavyrain,
19 | 340693381 => :heavyrainandthunder,
20 | -838448405 => :heavyrainshowers_day,
21 | 530501279 => :heavyrainshowers_night,
22 | -679099218 => :heavyrainshowers_polartwilight,
23 | 275421535 => :heavyrainshowersandthunder_day,
24 | 608654722 => :heavyrainshowersandthunder_night,
25 | 411129877 => :heavyrainshowersandthunder_polartwilight,
26 | -2083185603 => :heavysleet,
27 | 737898598 => :heavysleetandthunder,
28 | 843467800 => :heavysleetshowers_day,
29 | -1951529380 => :heavysleetshowers_night,
30 | 693091304 => :heavysleetshowers_polartwilight,
31 | 1781829784 => :heavysleetshowersandthunder_day,
32 | 527239930 => :heavysleetshowersandthunder_night,
33 | 319532770 => :heavysleetshowersandthunder_polartwilight,
34 | 1079366920 => :heavysnow,
35 | 317439734 => :heavysnowandthunder,
36 | -1876409313 => :heavysnowshowers_day,
37 | 1264317029 => :heavysnowshowers_night,
38 | -2055361185 => :heavysnowshowers_polartwilight,
39 | -966622704 => :heavysnowshowersandthunder_day,
40 | -235523705 => :heavysnowshowersandthunder_night,
41 | 1868186092 => :heavysnowshowersandthunder_polartwilight,
42 | 116707690 => :lightrain,
43 | 726025730 => :lightrainandthunder,
44 | -2001193696 => :lightrainshowers_day,
45 | -503752469 => :lightrainshowers_night,
46 | 2020764452 => :lightrainshowers_polartwilight,
47 | -1185464364 => :lightrainshowersandthunder_day,
48 | -250495803 => :lightrainshowersandthunder_night,
49 | -2108073736 => :lightrainshowersandthunder_polartwilight,
50 | -1438230832 => :lightsleet,
51 | -290628965 => :lightsleetandthunder,
52 | 2032889179 => :lightsleetshowers_day,
53 | -2041929173 => :lightsleetshowers_night,
54 | 452199269 => :lightsleetshowers_polartwilight,
55 | 1017818640 => :lightsnow,
56 | 702772083 => :lightsnowandthunder,
57 | 1255812693 => :lightsnowshowers_day,
58 | 95845553 => :lightsnowshowers_night,
59 | 644502485 => :lightsnowshowers_polartwilight,
60 | -150750682 => :lightssleetshowersandthunder_day,
61 | 119919348 => :lightssleetshowersandthunder_night,
62 | -763981242 => :lightssleetshowersandthunder_polartwilight,
63 | 962854891 => :lightssnowshowersandthunder_day,
64 | -1262287275 => :lightssnowshowersandthunder_night,
65 | 10936797 => :lightssnowshowersandthunder_polartwilight,
66 | 822101396 => :partlycloudy_day,
67 | 1887971799 => :partlycloudy_night,
68 | 413412525 => :partlycloudy_polartwilight,
69 | 1448337921 => :rain,
70 | 1451666232 => :rainandthunder,
71 | -494771989 => :rainshowers_day,
72 | -496560659 => :rainshowers_night,
73 | 1779947666 => :rainshowers_polartwilight,
74 | -1426281150 => :rainshowersandthunder_day,
75 | 866900721 => :rainshowersandthunder_night,
76 | 1206449457 => :rainshowersandthunder_polartwilight,
77 | -1618873504 => :sleet,
78 | 1081575014 => :sleetandthunder,
79 | -1853359748 => :sleetshowers_day,
80 | 564902271 => :sleetshowers_night,
81 | -331927723 => :sleetshowers_polartwilight,
82 | 622593029 => :sleetshowersandthunder_day,
83 | 1105769884 => :sleetshowersandthunder_night,
84 | 429035076 => :sleetshowersandthunder_polartwilight,
85 | -1811300697 => :snow,
86 | 1428412585 => :snowandthunder,
87 | -1532732897 => :snowshowers_day,
88 | 103037363 => :snowshowers_night,
89 | 403685698 => :snowshowers_polartwilight,
90 | 1492424179 => :snowshowersandthunder_day,
91 | 22722294 => :snowshowersandthunder_night,
92 | -1631461623 => :snowshowersandthunder_polartwilight,
93 | 0 => :LauncherIcon
94 | };
95 |
96 | function getSymbol(code as Number) {
97 | if (resources[code] != null) {
98 | return resources[code];
99 | }
100 |
101 | if (resourceNames[code] == null) {
102 | System.println("! " + code);
103 | if (resources[/*"clearsky_day"*/ -1331507130] != null) {
104 | return resources[/*"clearsky_day"*/ -1331507130];
105 | }
106 | code = -1331507130;
107 | }
108 |
109 | System.println("Loading Res: " + code);
110 | resources[code] = WatchUi.loadResource(Rez.Drawables[resourceNames[code]]) as BitmapResource;
111 | resourceNames.remove(code);
112 | return resources[code];
113 | }
114 | }
--------------------------------------------------------------------------------
/source/view/AuroraView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 |
5 | class AuroraView extends BaseView {
6 |
7 | function initialize() {
8 | BaseView.initialize(1);
9 | }
10 |
11 | // Update the view
12 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
13 | drawHeader(dc, W, H, "Aurora");
14 | if (data.hourlyClouds.size() == 0) {
15 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
16 | dc.drawText(W / 2, H / 2.5, Graphics.FONT_TINY, "Aurora & Cloud Data\nUnavailable.", Graphics.TEXT_JUSTIFY_CENTER);
17 | } else {
18 | var mw = W * 0.15; // Margin Width
19 | var mh = H * 0.23; // Margin Height
20 | var cw = W - mw * 2.0; // Chart Width
21 | var ch = H - mh * 2.0; // Chart Height
22 |
23 | // Aurora guidelines
24 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
25 | dc.drawLine(mw, mh + ch - ch * 0.4 * 0.15, mw + cw, mh + ch - ch * 0.4 * 0.15);
26 | dc.drawLine(mw, mh + ch - ch * 0.4 * 0.5, mw + cw, mh + ch - ch * 0.4 * 0.5);
27 | dc.drawLine(mw, mh + ch - ch * 0.4, mw + cw, mh + ch - ch * 0.4);
28 | dc.drawText(mw + cw + 3, mh + ch - ch * 0.4 * 0.15 - H / 26, Graphics.FONT_XTINY, "Lo", Graphics.TEXT_JUSTIFY_LEFT);
29 | dc.drawText(mw + cw + 3, mh + ch - ch * 0.4 * 0.5 - H / 26, Graphics.FONT_XTINY, "Hi", Graphics.TEXT_JUSTIFY_LEFT);
30 |
31 | var len = data.hourlyEntries() > 32 ? 32 : data.hourlyEntries();
32 | var cloudPoints = new [len * 2];
33 | var auroraPoints = new [len + 2];
34 |
35 | var hour = Time.Gregorian.info(Time.now(), Time.FORMAT_SHORT).hour;
36 | var maxAurora = 0;
37 | var cloudY = mh + FONT_HEIGHT + ch * 0.12;
38 | for (var i = 0; i < len; i++) {
39 | var x = mw + (cw / (len - 1.0) * i);
40 | cloudPoints[i] = [ x, cloudY + ch * data.hourlyClouds[i] / 1000 ];
41 | cloudPoints[len * 2 - 1 - i] = [ x, cloudY - ch * data.hourlyClouds[i] / 1000 ];
42 |
43 | var aurStrength = data.hourlyAurora.size() > i ? data.hourlyAurora[i] : 0;
44 | auroraPoints[i] = [ x, mh + ch - (ch * aurStrength * 0.4)];
45 | maxAurora = aurStrength > maxAurora ? aurStrength : maxAurora;
46 |
47 | if (i % 6 == 0) {
48 | dc.drawText(x, mh + ch, Graphics.FONT_XTINY, ((hour + i) % 24).format("%02d"), Graphics.TEXT_JUSTIFY_CENTER);
49 | }
50 | if ((hour + i) % 24 == 0) {
51 | dc.drawLine(x, mh + ch * 0.6, x, mh + ch - 1);
52 | }
53 | }
54 |
55 | auroraPoints[len] = [ mw + cw, mh + ch ];
56 | auroraPoints[len + 1] = [ mw, mh + ch ];
57 |
58 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
59 | dc.fillPolygon(cloudPoints);
60 |
61 | if (len > 0) {
62 | dc.drawText(mw, mh, Graphics.FONT_XTINY, data.hourlyClouds[0].format("%d") + "% Cloudy", Graphics.TEXT_JUSTIFY_LEFT);
63 | }
64 |
65 | dc.setColor(Graphics.COLOR_GREEN, Graphics.COLOR_TRANSPARENT);
66 | dc.fillPolygon(auroraPoints);
67 |
68 | dc.drawText(mw + cw, mh, Graphics.FONT_XTINY,
69 | (maxAurora == 0 ? "No" : maxAurora < 0.5 ? "Low" : "High") + " Kp", Graphics.TEXT_JUSTIFY_RIGHT);
70 | }
71 |
72 | // Page Indicator
73 | drawIndicator(dc, 4);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/source/view/BaseDelegate.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Lang;
2 | import Toybox.WatchUi;
3 |
4 | class BaseDelegate extends BehaviorDelegate {
5 |
6 | public static var pageCount = 7;
7 | private static var page as Number = 0;
8 | private var startX as Number = 0;
9 |
10 | function initialize() {
11 | BehaviorDelegate.initialize();
12 | }
13 |
14 | function onMenu() {
15 | var menu = new Menu2({:title=> "Rainy " + VERSION });
16 | menu.addItem(new MenuItem("Location", data.autoLocation ? "Automatic (GPS)" : data.location, 0, {}));
17 | menu.addItem(new MenuItem("Show Graph First", data.pageOrder ? "Yes" : "No", 1, {}));
18 | menu.addItem(new MenuItem("Temp Units", data.tempUnits == 0 ? "Celsius" : "Fahrenheit", 2, {}));
19 | menu.addItem(new MenuItem("Wind Units", SettingsDelegate.WIND_UNITS[data.windUnits], 3, {}));
20 | menu.addItem(new MenuItem("Refresh Weather", "Updated " + ((Time.now().value() - data.time.value()) / 60) + " minutes ago", 4, {}));
21 | WatchUi.pushView(menu, new SettingsDelegate(), WatchUi.SLIDE_BLINK);
22 | return true;
23 | }
24 |
25 | function onNextPage() as Boolean {
26 | if (data.temperatures.size() < 1) {
27 | return false;
28 | }
29 |
30 | page = page == (pageCount - 1) ? 0 : page + 1;
31 |
32 | var view = getView(page);
33 | WatchUi.switchToView(view[0], view[1], WatchUi.SLIDE_UP);
34 | return true;
35 | }
36 |
37 | function onPreviousPage() as Boolean {
38 | if (data.temperatures.size() < 1) {
39 | return false;
40 | }
41 |
42 | page = page == 0 ? pageCount - 1 : page - 1;
43 |
44 | var view = getView(page);
45 | WatchUi.switchToView(view[0], view[1], WatchUi.SLIDE_DOWN);
46 | return true;
47 | }
48 |
49 | // Swipe left to go to next page in multiplage views
50 | function onDrag(event as DragEvent) as Boolean {
51 | if (event.getType() == 0 /* START */) {
52 | startX = event.getCoordinates()[0];
53 | } else if (event.getType() == 2 /* STOP */) {
54 | if (startX - event.getCoordinates()[0] > (System.getDeviceSettings().screenWidth / 4)) {
55 | onSelectOrSwipe(false);
56 | }
57 | }
58 |
59 | return BehaviorDelegate.onDrag(event);
60 | }
61 |
62 | function onSelect() as Boolean {
63 | return onSelectOrSwipe(false);
64 | }
65 |
66 | // If softAction then only iterate through information and don't open any menus
67 | // Returns whether the next page should be displayed in softAction mode
68 | function onSelectOrSwipe(softAction as Boolean) as Boolean {
69 | BaseView.page = (BaseView.page + 1) % BaseView.pages;
70 | WatchUi.requestUpdate();
71 | return BaseView.page != 0 || !softAction;
72 | }
73 |
74 | function getView(page as Number) as Array {
75 | switch (data.pageOrder ? (page == 1 ? 3 : page == 3 ? 1 : page) : page) {
76 | case 0: return [ new SummaryView(), new BaseDelegate() ];
77 | case 1: return [ new DailyView(), new BaseDelegate() ];
78 | case 2: return [ new HourlyView(), new BaseDelegate() ];
79 | case 3: return [ new GraphView(), new BaseDelegate() ];
80 | case 4: return [ new AuroraView(), new BaseDelegate() ];
81 | case 5: return [ new UvView(), new BaseDelegate() ];
82 | case 6: return [ new CelestialView(), new BaseDelegate() ];
83 | default: return [ new WaterView(), new BaseDelegate() ];
84 | }
85 | }
86 | }
--------------------------------------------------------------------------------
/source/view/BaseView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Application;
2 | import Toybox.Graphics;
3 | import Toybox.WatchUi;
4 | import Toybox.Lang;
5 |
6 | class BaseView extends WatchUi.View {
7 | public static var page as Number = 0;
8 | public static var pages as Number = 1; // Super not correct use of static but we do what the voices in my head tell us to
9 |
10 | function initialize(pages) {
11 | View.initialize();
12 | self.pages = pages;
13 | self.page = 0;
14 | }
15 |
16 | // Update the view
17 | function onUpdate(dc as Dc) as Void {
18 | // Call the parent onUpdate function to redraw the layout
19 | View.onUpdate(dc);
20 |
21 | // Bad place but yeah
22 | if (Properties.getValue("manLocation").length() > 0) {
23 | data.enterText(Properties.getValue("manLocation"));
24 | Properties.setValue("manLocation", "");
25 | return;
26 | }
27 |
28 | var W = dc.getWidth();
29 | var H = dc.getHeight();
30 | if (data.blocked) {
31 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
32 | dc.drawText(W / 2, H / 4, Graphics.FONT_MEDIUM, "Relaunch App and\nfollow activation\ninstructions.", Graphics.TEXT_JUSTIFY_CENTER);
33 | return;
34 | }
35 |
36 | onDraw(dc, W, H, dc.getFontHeight(Graphics.FONT_XTINY));
37 | }
38 |
39 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
40 | }
41 |
42 | function drawHeader(dc as Dc, W as Number, H as Number, text as String) {
43 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
44 | var font = text.length() > 16 ? Graphics.FONT_XTINY : text.length() > 13 ? Graphics.FONT_TINY : text.length() > 11 ? Graphics.FONT_SMALL : Graphics.FONT_MEDIUM;
45 | dc.drawText(W / 2, H / 5.1 - dc.getFontHeight(font), font, text, Graphics.TEXT_JUSTIFY_CENTER);
46 | }
47 |
48 | public static function drawIndicator(dc as Dc, selectedIndex as Number) as Void {
49 | drawDots(dc, BaseDelegate.pageCount, selectedIndex, 3.14, 0.1);
50 | }
51 |
52 | public static function drawDots(dc as Dc, count as Number, selected as Number, angle as Float, space as Float) as Void {
53 | var height = dc.getWidth() / 30;
54 | for (var i = 0; i < count; i++) {
55 | var b = dc.getWidth() / 2 - height + 2;
56 |
57 | //round page indicator
58 | var x_i = b * Toybox.Math.cos(angle + ((count - 1f) / 2) * space - i * space) + dc.getWidth() / 2;
59 | var y_i = b * Toybox.Math.sin(angle + ((count - 1f) / 2) * space - i * space) + dc.getHeight() / 2;
60 |
61 | if (SQUARE_MODE) {
62 | x_i = x_i < dc.getWidth() / 2 ? height - 2 : dc.getWidth() - height + 2;
63 | }
64 |
65 | if (i == selected || selected == -1) {
66 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
67 | dc.fillCircle(x_i, y_i, height / 2);
68 | } else {
69 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
70 | dc.drawCircle(x_i, y_i, height / 2);
71 | }
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/source/view/CelestialView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 | import Toybox.Time;
5 |
6 | class CelestialView extends BaseView {
7 |
8 | function initialize() {
9 | BaseView.initialize(2);
10 | }
11 |
12 | // Update the view
13 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
14 | drawHeader(dc, W, H, page == 0 ? "Sun" : "Moon");
15 |
16 | var mw = W * ((dc.getFontHeight(Graphics.FONT_XTINY).toFloat() / H > 0.09) ? 0.1 : 0.13); // Margin Width (Less for devices with bigger fonts)
17 | var mh = H * 0.23; // Margin Height
18 | var cw = W - mw * 2.0; // Chart Width
19 | var ch = (H - mh * 2.0) * 0.4; // Chart Height
20 |
21 | // Sun line
22 | if (page == 0) {
23 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
24 | dc.drawLine(mw, H - mh, mw + cw, H - mh);
25 | dc.drawLine(mw, H - mh - ch * 0.5, mw + cw, H - mh - ch * 0.5);
26 | dc.drawLine(mw, H - mh - ch, mw + cw, H - mh - ch);
27 |
28 | var len = data.sunElevation.size();
29 | var sunPoints = new [len * 2] as Array<[Float, Float]>;
30 | var lightPoints = [];
31 | for (var i = 0; i < len; i++) {
32 | var x = mw + (cw / (len - 1.0) * i);
33 |
34 | sunPoints[i] = [ x, H - mh - ch * 0.5 - (data.sunElevation[i] / 150.0) * ch];
35 | sunPoints[len * 2 - 1 - i] = [ x, H - mh - ch * 0.5 - H / 150 - (data.sunElevation[i] / 150.0) * ch];
36 | if (data.sunElevation[i] >= 0) {
37 | lightPoints.add(sunPoints[i]);
38 | }
39 | }
40 |
41 | dc.setColor(Graphics.COLOR_YELLOW, Graphics.COLOR_TRANSPARENT);
42 | dc.fillPolygon(lightPoints);
43 |
44 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
45 | dc.fillPolygon(sunPoints);
46 |
47 | // Sun ball
48 | var time = Gregorian.info(Time.now(), Time.FORMAT_SHORT);
49 | var minute = time.hour * 60 + time.min;
50 | var sunY = sunPoints[(sunPoints.size() / 2 * (minute / 1441.0)).toNumber()][1];
51 |
52 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
53 | dc.fillCircle(mw + cw * (minute / 1440.0), sunY, W / 28);
54 | dc.setColor(sunY > H - mh - ch * 0.5 ? Graphics.COLOR_BLACK : Graphics.COLOR_YELLOW, Graphics.COLOR_TRANSPARENT);
55 | dc.fillCircle(mw + cw * (minute / 1440.0), sunY, W / 32);
56 |
57 | // Timestamps
58 | var riseTime = Gregorian.info(new Moment(data.sunRise), Time.FORMAT_SHORT);
59 | var maxTime = Gregorian.info(new Moment(data.sunMax), Time.FORMAT_SHORT);
60 | var setTime = Gregorian.info(new Moment(data.sunSet), Time.FORMAT_SHORT);
61 |
62 | var riseX = mw + cw * ((riseTime.hour * 60 + riseTime.min) / 1440.0);
63 | var maxX = mw + cw * ((maxTime.hour * 60 + maxTime.min) / 1440.0);
64 | var setX = mw + cw * ((setTime.hour * 60 + setTime.min) / 1440.0);
65 |
66 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
67 | dc.drawText(riseX, H - mh - ch - FONT_HEIGHT, Graphics.FONT_XTINY, "RISE", Graphics.TEXT_JUSTIFY_CENTER);
68 | dc.drawText(riseX, H - mh, Graphics.FONT_XTINY,
69 | riseTime.hour.format("%02d") + ":" + riseTime.min.format("%02d"), Graphics.TEXT_JUSTIFY_CENTER);
70 |
71 | dc.drawText(maxX, H - mh - ch - FONT_HEIGHT, Graphics.FONT_XTINY, "HIGH", Graphics.TEXT_JUSTIFY_CENTER);
72 | dc.drawText(maxX, H - mh, Graphics.FONT_XTINY,
73 | maxTime.hour.format("%02d") + ":" + maxTime.min.format("%02d"), Graphics.TEXT_JUSTIFY_CENTER);
74 |
75 | dc.drawText(setX, H - mh - ch - FONT_HEIGHT, Graphics.FONT_XTINY, "SET", Graphics.TEXT_JUSTIFY_CENTER);
76 | dc.drawText(setX, H - mh, Graphics.FONT_XTINY,
77 | setTime.hour.format("%02d") + ":" + setTime.min.format("%02d"), Graphics.TEXT_JUSTIFY_CENTER);
78 |
79 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
80 | dc.drawLine(riseX, H - mh - ch, riseX, H - mh);
81 | dc.drawLine(maxX, H - mh - ch, maxX, H - mh);
82 | dc.drawLine(setX, H - mh - ch, setX, H - mh);
83 |
84 | // Top Text
85 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
86 | dc.drawText(mw, mh, Graphics.FONT_XTINY,
87 | "Daylight " + (data.sunLength / 3600).format("%d") +
88 | "h " + ((data.sunLength / 60) % 60).format("%d") + "m", Graphics.TEXT_JUSTIFY_LEFT);
89 | dc.drawText(mw, mh + FONT_HEIGHT, Graphics.FONT_XTINY,
90 | "Today " + (data.sunDifference >= 0 ? "+" : "-") + (data.sunDifference.abs() / 60).format("%d") +
91 | "m " + (data.sunDifference.abs() % 60).format("%d") + "s", Graphics.TEXT_JUSTIFY_LEFT);
92 |
93 | // Sun Icon
94 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
95 | dc.fillCircle(W - mw - W / 10, mh + H / 10, W / 13);
96 | dc.setColor(Graphics.COLOR_ORANGE, Graphics.COLOR_TRANSPARENT);
97 | dc.fillCircle(W - mw - W / 10, mh + H / 10, W / 15);
98 | dc.setColor(Graphics.COLOR_YELLOW, Graphics.COLOR_TRANSPARENT);
99 | dc.fillCircle(W - mw - W / 10, mh + H / 10, W / 17);
100 | } else {
101 | // Top Text
102 | var eclipseTime = Gregorian.info(new Moment(data.sunNextEclipse), Time.FORMAT_MEDIUM);
103 | dc.drawText(mw, mh, Graphics.FONT_XTINY,
104 | "Next Solar", Graphics.TEXT_JUSTIFY_LEFT);
105 | dc.drawText(mw, mh + FONT_HEIGHT, Graphics.FONT_XTINY,
106 | "Eclipse (" + (data.sunEclipseObsc > 0.99 ? "total" : "partial") + ")", Graphics.TEXT_JUSTIFY_LEFT);
107 | dc.drawText(mw, mh + FONT_HEIGHT * 2, Graphics.FONT_XTINY,
108 | eclipseTime.day + " " + eclipseTime.month + " " + eclipseTime.year, Graphics.TEXT_JUSTIFY_LEFT);
109 |
110 | // Moon Icon
111 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
112 | dc.fillCircle(W - mw - W / 10, mh + H / 10, W / 13);
113 | dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_TRANSPARENT);
114 | dc.fillCircle(W - mw - W / 10 + (W / 13) * data.moonIllumination / 100, mh + H / 10 - (W / 13) * data.moonIllumination / 100, W / 13);
115 |
116 | // Bottom Text
117 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
118 | dc.drawText(mw, H - mh - FONT_HEIGHT * 2, Graphics.FONT_XTINY, "Now: " + data.moonIllumination.toNumber() + "%", Graphics.TEXT_JUSTIFY_LEFT);
119 | dc.drawText(mw, H - mh - FONT_HEIGHT, Graphics.FONT_XTINY,
120 | data.moonPhase.substring(0, data.moonPhase.find(" ")), Graphics.TEXT_JUSTIFY_LEFT);
121 | dc.drawText(mw, H - mh, Graphics.FONT_XTINY,
122 | data.moonPhase.substring(data.moonPhase.find(" ") + 1, data.moonPhase.length()), Graphics.TEXT_JUSTIFY_LEFT);
123 |
124 | var fullTime = Gregorian.info(new Moment(data.moonNextFull), Time.FORMAT_MEDIUM);
125 | var newTime = Gregorian.info(new Moment(data.moonNextNew), Time.FORMAT_MEDIUM);
126 | dc.drawText(W - mw, H - mh - FONT_HEIGHT * 3, Graphics.FONT_XTINY, "Full Moon", Graphics.TEXT_JUSTIFY_RIGHT);
127 | dc.drawText(W - mw, H - mh - FONT_HEIGHT * 2, Graphics.FONT_XTINY,
128 | fullTime.month + " " + fullTime.day + " " + fullTime.hour.format("%02d") + ":" + fullTime.min.format("%02d"), Graphics.TEXT_JUSTIFY_RIGHT);
129 | dc.drawText(W - mw, H - mh - FONT_HEIGHT, Graphics.FONT_XTINY, "New Moon", Graphics.TEXT_JUSTIFY_RIGHT);
130 | dc.drawText(W - mw, H - mh, Graphics.FONT_XTINY,
131 | newTime.month + " " + newTime.day + " " + newTime.hour.format("%02d") + ":" + newTime.min.format("%02d"), Graphics.TEXT_JUSTIFY_RIGHT);
132 | }
133 |
134 | // Local Page Indicator
135 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
136 | dc.drawText(W / 2, H * 0.8 + FONT_HEIGHT, Graphics.FONT_TINY, (page + 1) + "/2", Graphics.TEXT_JUSTIFY_CENTER);
137 |
138 | // Page Indicator
139 | drawIndicator(dc, 6);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/source/view/DailyView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Application;
2 | import Toybox.Graphics;
3 | import Toybox.WatchUi;
4 | import Toybox.Lang;
5 |
6 | class DailyView extends BaseView {
7 |
8 | function initialize() {
9 | BaseView.initialize(Math.floor(dailyIndices().size() / 4));
10 | }
11 |
12 | // Update the view
13 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
14 | if (data.hints & 2 == 0) {
15 | data.hints |= 2;
16 | Storage.setValue("hints", data.hints);
17 | WatchUi.pushView(new HintView("Press Select to scroll\non pages with\nmultiple slides.", [ 0 ]), new HintDelegate([ 0 ]), WatchUi.SLIDE_BLINK);
18 | return;
19 | }
20 |
21 | var indices = dailyIndices();
22 |
23 | var realHour = Time.Gregorian.info(data.time, Time.FORMAT_SHORT).hour;
24 | var hour = realHour % 6 == 0 ? realHour : realHour + (6 - (realHour % 6));
25 | var date = Time.Gregorian.info(new Time.Moment(data.time.value() + 86400 * (page + (realHour > 18 ? 1 : 0))), Time.FORMAT_MEDIUM);
26 | drawHeader(dc, W, H, page ? date.day_of_week + " " + date.day + "." : "Daily");
27 |
28 | var filler = (hour % 24) / 6;
29 | for (var i = 0; i < 4; i++) {
30 | var entry = page * 4 + i - filler;
31 | if (indices.size() <= entry) {
32 | break;
33 | }
34 |
35 | if (entry == -1 && realHour % 6 != 0) {
36 | HourlyView.drawTableEntry(dc, W, H, realHour, indices[0], i);
37 | } else if (entry <= -1) {
38 | HourlyView.drawTableEntry(dc, W, H, "--", null, i);
39 | } else {
40 | HourlyView.drawTableEntry(dc, W, H, (hour + entry * 6) % 24, indices[entry], i);
41 | }
42 | }
43 |
44 | // Local Page Indicator
45 | dc.drawText(W / 2, H * 0.75 + FONT_HEIGHT, Graphics.FONT_TINY, (page + 1) + "/" + pages, Graphics.TEXT_JUSTIFY_CENTER);
46 |
47 | // Page Indicator
48 | drawIndicator(dc, data.pageOrder ? 3 : 1);
49 | }
50 |
51 | function dailyIndices() as Array {
52 | var hour = Time.Gregorian.info(data.time, Time.FORMAT_SHORT).hour;
53 | var entries = [];
54 | for (var i = 0; i < data.symbols.size(); i++) {
55 | if ((hour + i) % 6 == 0 || i >= data.hours) {
56 | entries.add(i);
57 | }
58 | }
59 |
60 | return entries;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/source/view/GraphView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 |
5 | class GraphView extends BaseView {
6 |
7 | function initialize() {
8 | BaseView.initialize((data.hourlyEntries() - 2) / 12 + 1);
9 | }
10 |
11 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
12 | drawHeader(dc, W, H, page ? "In " + (page * 12) + " Hours" : "Now");
13 | dc.setColor(Graphics.COLOR_DK_GRAY, Graphics.COLOR_TRANSPARENT);
14 |
15 | var offset = page * 12;
16 | var mw = W * 0.16; // Margin Width
17 | var mh = H * 0.25; // Margin Height
18 | var lw = (W - mw * 2) / 12.0; // Line Width
19 | var lh = (H - mh * 2) / 9.0; // Line Height
20 | var points = data.hourlyEntries() - offset > 12 ? 12 : data.hourlyEntries() - offset - 1;
21 | var startHour = Time.Gregorian.info(data.time, Time.FORMAT_SHORT).hour;
22 |
23 | var minTemp = data.temperatures[0];
24 | var maxTemp = data.temperatures[0];
25 | for (var i = 0; i < data.temperatures.size(); i++) {
26 | if (data.temperatures[i] - 2 < minTemp) {
27 | minTemp = data.temperatures[i] - 2;
28 | }
29 | if (data.temperatures[i] + 2 > maxTemp) {
30 | maxTemp = data.temperatures[i] + 2;
31 | }
32 | }
33 | var diffTemp = maxTemp - minTemp;
34 |
35 | // Horizontal Graph Background
36 | dc.setColor(Graphics.COLOR_DK_GRAY, Graphics.COLOR_TRANSPARENT);
37 | for (var i = 0; i < 10; i++) {
38 | dc.drawLine(mw, mh + lh * i, W - mw - lw * (12 - points), mh + lh * i);
39 | }
40 |
41 | // 0 Degree line
42 | if (minTemp < 0 && maxTemp > 0) {
43 | var freezingY = H - mh - (-minTemp / diffTemp) * (H - mh * 2);
44 | dc.setColor(Graphics.COLOR_BLUE, Graphics.COLOR_TRANSPARENT);
45 | dc.drawLine(mw, freezingY, W - mw - lw * (12 - points), freezingY);
46 | }
47 |
48 | // Vertical Graph Background + Timestamps
49 | for (var i = 0; i < points + 1; i++) {
50 | dc.setColor((startHour + offset + i) % 24 == 0 ? Graphics.COLOR_LT_GRAY : Graphics.COLOR_DK_GRAY, Graphics.COLOR_TRANSPARENT);
51 | dc.drawLine(mw + lw * i, mh, mw + lw * i, H - mh);
52 |
53 | // Bottom time text
54 | if (i % 3 == 0) {
55 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
56 | dc.drawText(mw + lw * i, H - mh, Graphics.FONT_XTINY, ((startHour + offset + i) % 24).format("%02d"), Graphics.TEXT_JUSTIFY_CENTER);
57 | }
58 | }
59 |
60 | var tempPoints = new [points * 2 + 2];
61 | for (var i = 0; i < points; i++) {
62 | // Rain (fillRectancle uses wh instead of xy :troll:)
63 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
64 | var maxRain = data.maxRainfall[offset + i];
65 | dc.fillRectangle(mw + lw * i, H - mh - lh * maxRain, lw, lh * maxRain);
66 |
67 | dc.setColor(Graphics.COLOR_BLUE, Graphics.COLOR_TRANSPARENT);
68 | var rain = data.rainfall[offset + i];
69 | dc.fillRectangle(mw + lw * i, H - mh - lh * rain, lw, lh * rain);
70 |
71 | // Temperature
72 | var t1 = H - mh - ((data.temperatures[offset + i].toFloat() - minTemp) / diffTemp) * (H - mh * 2);
73 | tempPoints[i] = [ mw + lw * i, t1 ];
74 | tempPoints[tempPoints.size() - 1 - i] = [ mw + lw * i, t1 - lh / 4 ];
75 | if (i + 1 == points) {
76 | var t2 = H - mh - ((data.temperatures[offset + i + 1].toFloat() - minTemp) / diffTemp) * (H - mh * 2);
77 | tempPoints[i + 1] = [ mw + lw * (i + 1), t2 ];
78 | tempPoints[i + 2] = [ mw + lw * (i + 1), t2 - lh / 4 ];
79 | }
80 | }
81 |
82 | dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_TRANSPARENT);
83 | dc.fillPolygon(tempPoints);
84 |
85 | // Left side temperature text
86 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
87 | dc.drawText(mw - 3, mh, Graphics.FONT_XTINY, degrees(maxTemp, data.tempUnits) + "°", Graphics.TEXT_JUSTIFY_RIGHT);
88 | dc.drawText(mw - 3, mh + (H - mh * 2) * 0.27, Graphics.FONT_XTINY, degrees(maxTemp - diffTemp * 0.33, data.tempUnits) + "°", Graphics.TEXT_JUSTIFY_RIGHT);
89 | dc.drawText(mw - 3, mh + (H - mh * 2) * 0.55, Graphics.FONT_XTINY, degrees(maxTemp - diffTemp * 0.66, data.tempUnits) + "°", Graphics.TEXT_JUSTIFY_RIGHT);
90 | dc.drawText(mw - 3, H - mh - FONT_HEIGHT, Graphics.FONT_XTINY, degrees(minTemp, data.tempUnits) + "°", Graphics.TEXT_JUSTIFY_RIGHT);
91 |
92 | // Right side rainfall text
93 | dc.drawText(W - mw + 3, mh, Graphics.FONT_XTINY, "9", Graphics.TEXT_JUSTIFY_LEFT);
94 | dc.drawText(W - mw + 3, mh + (H - mh * 2) * 0.27, Graphics.FONT_XTINY, "6", Graphics.TEXT_JUSTIFY_LEFT);
95 | dc.drawText(W - mw + 3, mh + (H - mh * 2) * 0.55, Graphics.FONT_XTINY, "3", Graphics.TEXT_JUSTIFY_LEFT);
96 | dc.drawText(W - mw + 3, H - mh - FONT_HEIGHT, Graphics.FONT_XTINY, "0", Graphics.TEXT_JUSTIFY_LEFT);
97 |
98 | // Local Page Indicator
99 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
100 | dc.drawText(W / 2, H - mh + FONT_HEIGHT, Graphics.FONT_TINY, (page + 1) + "/" + pages, Graphics.TEXT_JUSTIFY_CENTER);
101 |
102 | // Page Indicator
103 | drawIndicator(dc, data.pageOrder ? 1 : 3);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/source/view/HourlyView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 | import Toybox.Math;
5 |
6 | class HourlyView extends BaseView {
7 |
8 | function initialize() {
9 | BaseView.initialize(6);
10 | }
11 |
12 | // Update the view
13 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
14 | drawHeader(dc, W, H, page ? "In " + (page * 4) + " Hours" : "Hourly");
15 |
16 | var hour = Time.Gregorian.info(data.time, Time.FORMAT_SHORT).hour;
17 | for (var i = 0; i < 4; i++) {
18 | var entry = page * 4 + i;
19 | if (data.hourlyEntries() <= entry) {
20 | break;
21 | }
22 |
23 | drawTableEntry(dc, W, H, (hour + entry) % 24, entry, i);
24 | }
25 |
26 | // Local Page Indicator
27 | dc.drawText(W / 2, H * 0.75 + FONT_HEIGHT, Graphics.FONT_TINY, (page + 1) + "/" + pages, Graphics.TEXT_JUSTIFY_CENTER);
28 |
29 | // Page Indicator
30 | drawIndicator(dc, 2);
31 | }
32 |
33 | static function drawTableEntry(dc as Dc, W as Number, H as Number, hour as Number or String, dataIndex as Number?, entry as Number) {
34 | var mh = H * 0.2;
35 | var lh = H / 6.75;
36 | var offset = entry * lh;
37 |
38 | // Time
39 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
40 | dc.drawText(W / 15, mh + lh / 4 + offset, Graphics.FONT_XTINY, hour instanceof String ? hour : hour.format("%02d"), Graphics.TEXT_JUSTIFY_LEFT);
41 | if (dataIndex == null) {
42 | return;
43 | }
44 |
45 | // Temperature
46 | dc.drawBitmap(W / 7, mh + offset, res.getSymbol(data.symbols[dataIndex]));
47 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
48 | dc.drawText(W / 7 + 47, mh + offset, Graphics.FONT_MEDIUM, degrees(data.temperatures[dataIndex], data.tempUnits) + "°", Graphics.TEXT_JUSTIFY_LEFT);
49 |
50 | // Rainfall
51 | var rain = data.rainfall[dataIndex];
52 | dc.setColor(Graphics.COLOR_BLUE, Graphics.COLOR_TRANSPARENT);
53 | dc.drawText(W / 1.62,
54 | mh + offset, Graphics.FONT_MEDIUM,
55 | rain.format(Math.round(rain) == rain ? "%d" : "%.1f"), Graphics.TEXT_JUSTIFY_CENTER);
56 |
57 | // Wind
58 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
59 | dc.drawText(W - lh * 0.9,
60 | mh + offset,
61 | Graphics.FONT_MEDIUM, wind(data.windSpeeds[dataIndex], data.windUnits), Graphics.TEXT_JUSTIFY_RIGHT);
62 | dc.fillPolygon(generateArrow([ W - lh * 0.84, mh + lh / 8 + offset ],
63 | data.windDirections[dataIndex] + 180, (lh * 0.73).toNumber()));
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/source/view/SummaryView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 |
5 | class SummaryView extends BaseView {
6 |
7 | function initialize() {
8 | BaseView.initialize(1);
9 | }
10 |
11 | // Update the view
12 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
13 | if (data.position == null) {
14 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
15 | dc.drawText(W / 2, H / 8.2, Graphics.FONT_MEDIUM, "Updating GPS\nLocation..", Graphics.TEXT_JUSTIFY_CENTER);
16 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
17 | dc.drawText(W / 2, H / 2.1, Graphics.FONT_TINY, "Or press MENU\nto manually select\na location.", Graphics.TEXT_JUSTIFY_CENTER);
18 | return;
19 | }
20 |
21 | if (data.symbols.size() < 1) {
22 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
23 | dc.drawText(W / 2, H / 6.5, Graphics.FONT_LARGE, "Loading..", Graphics.TEXT_JUSTIFY_CENTER);
24 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
25 | dc.drawText(W / 2, H / 2.6, Graphics.FONT_TINY, "Phone Bluetooth\nconnection required\nto load Weather.", Graphics.TEXT_JUSTIFY_CENTER);
26 | return;
27 | }
28 |
29 | // Location
30 | drawHeader(dc, W, H, data.location);
31 |
32 | // Temperature
33 | var sumM = H / 13; // Summary margin
34 | dc.drawBitmap(sumM, sumM * 2.7, res.getSymbol(data.symbols.size() == 0 ? 2018941991 : data.symbols[0]));
35 |
36 | dc.drawText(sumM + 50, sumM * 2.5, Graphics.FONT_NUMBER_MILD, degrees(data.temperatures[0], data.tempUnits) + "°", Graphics.TEXT_JUSTIFY_LEFT);
37 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
38 | var apTemp = calcApparentTemperature(data.temperatures[0], data.humidity[0], data.windSpeeds[0]);
39 | dc.drawText(sumM, sumM * 5, Graphics.FONT_XTINY, "Feels Like " + degrees(apTemp, data.tempUnits) + "°" + (data.tempUnits == 1 ? "F" : "C"), Graphics.TEXT_JUSTIFY_LEFT);
40 |
41 | // Wind
42 | dc.drawText(W - sumM * 3.1, sumM * 2.5, Graphics.FONT_NUMBER_MILD, wind(data.windSpeeds[0], data.windUnits), Graphics.TEXT_JUSTIFY_RIGHT);
43 | dc.drawText(W - sumM * 1.1, sumM * 5, Graphics.FONT_XTINY,
44 | SettingsDelegate.WIND_UNITS[data.windUnits], Graphics.TEXT_JUSTIFY_RIGHT);
45 | dc.fillPolygon(generateArrow([ W - sumM * 2.9, sumM * 2.9 ], data.windDirections[0] + 180, (sumM * 1.8).toNumber()));
46 | dc.setColor(Graphics.COLOR_BLUE, Graphics.COLOR_TRANSPARENT);
47 |
48 | // Rain chart
49 | var mw = W / 8.5; // Rain chart width margin
50 | var mh = H / 6.7; // Rain chart height margin
51 | var lh = H / 14; // Rain chart line height
52 | var rainPrimary = data.nowRainfall != null && data.nowRainfall.size() > 0;
53 | var rainBackup = data.rainfall.size() >= 6;
54 |
55 | var rainCount = rainPrimary ? data.nowRainfall.size() : rainBackup ? 6 : 0;
56 | var rainPolygon = new [rainCount + 2];
57 | rainPolygon[0] = [ W - mw, H - mh ];
58 | rainPolygon[1] = [ mw, H - mh ];
59 | for (var i = 0; i < rainCount; i++) {
60 | var r = rainPrimary ? data.nowRainfall[i] : data.rainfall[i];
61 | rainPolygon[i + 2] = [ mw + ((W - (mw * 2)) / (rainCount - 1)) * i, H - mh - (r <= 0 ? 0 : r > 5 ? lh * 3.25 : ((r + 0.3) * lh * 0.6)) ];
62 | }
63 |
64 | dc.fillPolygon(rainPolygon);
65 |
66 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
67 | dc.drawText(W * 0.27, H - mh + 2, Graphics.FONT_XTINY, "Now", Graphics.TEXT_JUSTIFY_CENTER);
68 | dc.drawText(W / 2, H - mh + 2, Graphics.FONT_XTINY, !rainPrimary && rainBackup ? "3hr" : "45", Graphics.TEXT_JUSTIFY_CENTER);
69 | dc.drawText(W * 0.73, H - mh + 2, Graphics.FONT_XTINY, !rainPrimary && rainBackup ? "6hr" : "90", Graphics.TEXT_JUSTIFY_CENTER);
70 |
71 | dc.drawLine(mw, H - mh, W - mw, H - mh);
72 | dc.setColor(Graphics.COLOR_DK_GRAY, Graphics.COLOR_TRANSPARENT);
73 | dc.drawLine(mw, H - mh - lh, W - mw, H - mh - lh);
74 | dc.drawLine(mw, H - mh - lh * 2, W - mw, H - mh - lh * 2);
75 | dc.drawLine(mw, H - mh - lh * 3, W - mw, H - mh - lh * 3);
76 |
77 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
78 | dc.drawText(W / 2, H - mh - lh * 3 - FONT_HEIGHT, Graphics.FONT_XTINY,
79 | rainPrimary ? "Rainfall next 90 min." : rainBackup ? "Rainfall next 6 hr." : "90 Min. Rainfall Unavailable.", Graphics.TEXT_JUSTIFY_CENTER);
80 |
81 | // Page Indicator
82 | drawIndicator(dc, 0);
83 | }
84 |
85 | // thanks Mr. Gpt (may or may not actually calculate the right values)
86 | function calcApparentTemperature(temp as Float, humidity as Float, wind as Float) as Float {
87 | if (temp > 27.0) {
88 | // Calculate Heat Index
89 | var tempFahrenheit = (temp * 9 / 5) + 32;
90 | var heatIndex = 0.5 * (tempFahrenheit + 61.0 + ((tempFahrenheit - 68.0) * 1.2) + (humidity * 0.094));
91 |
92 | // Ensure the result is in Celsius
93 | return (heatIndex - 32) * 5 / 9;
94 | } else if (temp < 10.0) {
95 | var windMph = wind * 2.237; // meters/s to miles/h
96 | var windChill = 13.12 + 0.6215 * temp - 11.37 * Math.pow(windMph, 0.16) + 0.3965 * temp * Math.pow(windMph, 0.16);
97 |
98 | return windChill;
99 | }
100 |
101 | return temp + (humidity / 100.0) * 5;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/source/view/UvView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 |
5 | class UvView extends BaseView {
6 |
7 | function initialize() {
8 | BaseView.initialize(1);
9 | }
10 |
11 | // Update the view
12 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
13 | drawHeader(dc, W, H, "UV / Air");
14 |
15 | var mw = W * 0.15; // Margin Width
16 | var mh = H * 0.23; // Margin Height
17 | var cw = W - mw * 2.0; // Chart Width
18 | var ch = (H - mh * 2.0) * 0.4; // Chart Height
19 |
20 | // UV guidelines
21 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
22 | dc.drawLine(mw, H - mh - ch, mw + cw, H - mh - ch);
23 | dc.drawLine(mw, H - mh - ch * 0.65, mw + cw, H - mh - ch * 0.65);
24 | dc.drawLine(mw, H - mh - ch * 0.3, mw + cw, H - mh - ch * 0.3);
25 | dc.drawText(mw + cw + 3, H - mh - ch - H / 26, Graphics.FONT_XTINY, "10", Graphics.TEXT_JUSTIFY_LEFT);
26 | dc.drawText(mw + cw + 3, H - mh - ch * 0.65 - H / 26, Graphics.FONT_XTINY, "6", Graphics.TEXT_JUSTIFY_LEFT);
27 | dc.drawText(mw + cw + 3, H - mh - ch * 0.3 - H / 26, Graphics.FONT_XTINY, "3", Graphics.TEXT_JUSTIFY_LEFT);
28 |
29 | // UV chart
30 | var len = data.hourlyEntries() > 25 ? 25 : data.hourlyEntries();
31 | var hour = Time.Gregorian.info(Time.now(), Time.FORMAT_SHORT).hour;
32 | for (var i = 0; i < len; i++) {
33 | var x = mw + (cw / len * i);
34 | var h = Math.floor(data.uv[i] < 0.3 ? ch / 20 : data.uv[i] * ch / 10);
35 |
36 | colorUv(dc, data.uv[i]);
37 | dc.drawRectangle(x, H - mh - h, cw / len * 0.9, h);
38 |
39 | if (i % 4 == 0) {
40 | dc.drawText(x, H - mh, Graphics.FONT_XTINY, ((hour + i) % 24).format("%02d"), Graphics.TEXT_JUSTIFY_CENTER);
41 | }
42 | }
43 |
44 | // UV Text
45 | colorUv(dc, data.uv[0]);
46 | dc.drawText(mw, mh * 0.8, Graphics.FONT_NUMBER_MEDIUM, data.uv[0].format("%d"), Graphics.TEXT_JUSTIFY_LEFT);
47 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
48 | dc.drawText(mw, mh * 1.85, Graphics.FONT_XTINY,
49 | data.uv[0] >= 11 ? "Extreme" : data.uv[0] >= 8 ? "Strong" : data.uv[0] >= 6 ? "High" :
50 | data.uv[0] >= 3 ? "Medium" : data.uv[0] >= 0.3 ? "Low" : "No UV", Graphics.TEXT_JUSTIFY_LEFT);
51 |
52 | // yep
53 | var temp = data.temperatures[0];
54 | var hum = data.humidity[0];
55 | var dew = 243.04 * (Math.ln(hum / 100) + ((17.625 * temp) / (243.04 + temp))) / (17.625 - Math.ln(hum / 100) - ((17.625 * temp) / (243.04 + temp)));
56 |
57 | // Humidity Text
58 | dc.drawText(mw + cw, mh, Graphics.FONT_XTINY, "Humidity " + hum.format("%d") + "%", Graphics.TEXT_JUSTIFY_RIGHT);
59 | dc.drawText(mw + cw, mh + FONT_HEIGHT, Graphics.FONT_XTINY, "Dew " + degrees(dew, data.tempUnits) + "°", Graphics.TEXT_JUSTIFY_RIGHT);
60 | dc.setColor(dew < 15 ? Graphics.COLOR_GREEN :
61 | dew < 20 ? Graphics.COLOR_YELLOW :
62 | dew < 24 ? Graphics.COLOR_ORANGE : Graphics.COLOR_RED, Graphics.COLOR_TRANSPARENT);
63 | dc.drawText(mw + cw, mh + FONT_HEIGHT * 2, Graphics.FONT_XTINY,
64 | dew < 15 ? "Pleasant" : dew < 20 ? "Sticky" : dew < 24 ? "Uncomfortable" : "Unbearable", Graphics.TEXT_JUSTIFY_RIGHT);
65 |
66 | // Page Indicator
67 | drawIndicator(dc, 5);
68 | }
69 |
70 | function colorUv(dc, uv) {
71 | dc.setColor(uv >= 11 ? Graphics.COLOR_PURPLE :
72 | uv >= 8 ? Graphics.COLOR_RED :
73 | uv >= 6 ? Graphics.COLOR_ORANGE :
74 | uv >= 3 ? Graphics.COLOR_YELLOW :
75 | uv >= 0.3 ? Graphics.COLOR_GREEN : Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/source/view/WaterView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 | import Toybox.Time;
5 |
6 | class WaterView extends BaseView {
7 |
8 | function initialize() {
9 | BaseView.initialize(1);
10 | }
11 |
12 | // Update the view
13 | function onDraw(dc as Dc, W as Number, H as Number, FONT_HEIGHT as Number) as Void {
14 | var mw = W * 0.085; // Margin Width
15 | var mh = H * 0.22; // Margin Height
16 |
17 | drawHeader(dc, W, H, "Water");
18 | if (data.waterNames.size() == 0) {
19 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
20 | dc.drawText(W / 2, H / 2.5, Graphics.FONT_TINY, "No Nearby Water\nTemperatures Found.", Graphics.TEXT_JUSTIFY_CENTER);
21 | } else {
22 | for (var i = 0; i < data.waterNames.size() && i < 3; i++) {
23 | var offset = mh + i * (H / 4.5);
24 | var small = data.waterNames[i].length() > 13;
25 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
26 | dc.drawText(mw, offset, small ? Graphics.FONT_XTINY : Graphics.FONT_TINY, data.waterNames[i], Graphics.TEXT_JUSTIFY_LEFT);
27 |
28 | dc.setColor(Graphics.COLOR_DK_GRAY, Graphics.COLOR_TRANSPARENT);
29 | dc.drawText(W - mw - H / 4.25, offset + H / (small ? 11 : 10), Graphics.FONT_XTINY,
30 | (data.waterDistances[i] / 1000.0).format(data.waterDistances[i] > 10000 ? "%d" : "%.1f") + "km", Graphics.TEXT_JUSTIFY_RIGHT);
31 |
32 | var time = Time.Gregorian.info(new Moment(data.waterTimestamps[i]), Time.FORMAT_MEDIUM);
33 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
34 | dc.drawText(mw, offset + H / (small ? 11 : 10), Graphics.FONT_XTINY,
35 | time.month + " " + time.day.format("%02d") + " " + time.hour.format("%02d") + ":" + time.min.format("%02d"), Graphics.TEXT_JUSTIFY_LEFT);
36 |
37 |
38 | dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_TRANSPARENT);
39 | dc.drawText(W - mw * 0.8, offset + H / 40, Graphics.FONT_SMALL,
40 | (data.tempUnits == 1 ? degrees(data.waterTemperatures[i], data.tempUnits) : data.waterTemperatures[i].format("%.1f")) + "°", Graphics.TEXT_JUSTIFY_RIGHT);
41 | }
42 | }
43 |
44 | // Page Indicator
45 | drawIndicator(dc, 7);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/source/view/special/AppGlanceView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 |
5 | (:glance)
6 | class AppGlanceView extends WatchUi.GlanceView {
7 |
8 | private var data as BaseData;
9 |
10 | function initialize(data as BaseData) {
11 | GlanceView.initialize();
12 |
13 | System.println("Init Glance");
14 | self.data = data;
15 | }
16 |
17 | // Update the view
18 | function onUpdate(dc as Dc) as Void {
19 | var W = dc.getWidth();
20 | var H = dc.getHeight();
21 | var loaded = data.temperatures.size() > 0;
22 |
23 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
24 | dc.drawText(0, H * 0.15, Graphics.FONT_GLANCE, data.location, Graphics.TEXT_JUSTIFY_LEFT);
25 | dc.drawText(0, H * 0.4, Graphics.FONT_GLANCE_NUMBER, (loaded ? degrees(data.temperatures[0], data.tempUnits) : "--") + "°", Graphics.TEXT_JUSTIFY_LEFT);
26 |
27 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
28 | dc.fillPolygon(generateArrow([ W * 0.22, H * 0.52 ], loaded ? data.windDirections[0] + 180 : 0, W / 8));
29 | dc.drawText(W * 0.37, H * 0.4, Graphics.FONT_GLANCE_NUMBER, loaded ? wind(data.windSpeeds[0], data.windUnits) : "--", Graphics.TEXT_JUSTIFY_LEFT);
30 |
31 | var mw = W * 0.55; // Rain chart width margin (left)
32 | var mh = H / 5.5; // Rain chart height margin (bottom)
33 | var lh = (H - mh * 3) / 3; // Rain chart line height
34 | var chartWidth = W - mw;
35 |
36 | var rainPrimary = data.nowRainfall != null && data.nowRainfall.size() > 0;
37 | var rainBackup = data.rainfall.size() >= 6;
38 |
39 | if (rainPrimary || rainBackup) {
40 | var rainCount = rainPrimary ? data.nowRainfall.size() : rainBackup ? 6 : 0;
41 | var rainPolygon = new [rainCount + 2];
42 | rainPolygon[0] = [ mw + chartWidth, H - mh ];
43 | rainPolygon[1] = [ mw, H - mh ];
44 | for (var i = 0; i < rainCount; i++) {
45 | var r = rainPrimary ? data.nowRainfall[i] : data.rainfall[i];
46 | rainPolygon[i + 2] = [ mw + (chartWidth / (rainCount - 1)) * i, H - mh - (r <= 0 ? 0 : r > 5 ? lh * 3 : ((r + 0.3) * lh * 0.6)) ];
47 | }
48 |
49 | dc.setColor(Graphics.COLOR_BLUE, Graphics.COLOR_TRANSPARENT);
50 | dc.fillPolygon(rainPolygon);
51 |
52 | if (!rainPrimary && data.nowRainfall != null) {
53 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
54 | dc.drawText(W, H * 0.2, Graphics.FONT_GLANCE, "6hr", Graphics.TEXT_JUSTIFY_RIGHT);
55 | }
56 | } else {
57 | dc.drawText(W * 0.8, H * 0.3, Graphics.FONT_GLANCE, "Rain\nUnavailable", Graphics.TEXT_JUSTIFY_CENTER);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/source/view/special/HintDelegate.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Lang;
2 | import Toybox.WatchUi;
3 |
4 | class HintDelegate extends WatchUi.BehaviorDelegate {
5 |
6 | private var buttons;
7 |
8 | function initialize(buttons) {
9 | BehaviorDelegate.initialize();
10 | self.buttons = buttons;
11 | }
12 |
13 | public function onSelect() as Boolean {
14 | if (buttons.indexOf(0) != -1) {
15 | WatchUi.popView(WatchUi.SLIDE_BLINK);
16 | return true;
17 | }
18 |
19 | return false;
20 | }
21 |
22 | //! Handle going to the previous view
23 | //! @return true if handled, false otherwise
24 | public function onPreviousPage() as Boolean {
25 | if (buttons.indexOf(1) != -1) {
26 | WatchUi.popView(WatchUi.SLIDE_BLINK);
27 | return true;
28 | }
29 | return false;
30 | }
31 | }
--------------------------------------------------------------------------------
/source/view/special/HintView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 |
5 | class HintView extends WatchUi.View {
6 |
7 | private var text;
8 | private var buttons;
9 |
10 | function initialize(text, buttons) {
11 | View.initialize();
12 | self.text = text;
13 | self.buttons = buttons;
14 | }
15 |
16 | // Update the view
17 | function onUpdate(dc as Dc) as Void {
18 | // Call the parent onUpdate function to redraw the layout
19 | View.onUpdate(dc);
20 |
21 | var W = dc.getWidth();
22 | var H = dc.getHeight();
23 |
24 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
25 | dc.drawText(W / 2,
26 | H / 8, Graphics.FONT_LARGE, "HINT", Graphics.TEXT_JUSTIFY_CENTER);
27 | dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
28 | dc.drawText(W / 2, H / 2.5, Graphics.FONT_TINY, text, Graphics.TEXT_JUSTIFY_CENTER);
29 |
30 | if (buttons.indexOf(0) != -1) {
31 | BaseView.drawDots(dc, 5, -1, 5.73, 0.06);
32 | }
33 | /*if (buttons.indexOf(1) != -1) {
34 | BaseView.drawDots(dc, 5, -1, 3.14, 0.06);
35 | }*/
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/source/view/special/RegisterDelegate.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Lang;
2 | import Toybox.WatchUi;
3 |
4 | class RegisterDelegate extends WatchUi.BehaviorDelegate {
5 |
6 | function initialize() {
7 | BehaviorDelegate.initialize();
8 | }
9 |
10 | public function onSelect() as Boolean {
11 | WatchUi.popView(WatchUi.SLIDE_BLINK);
12 | return true;
13 | }
14 | }
--------------------------------------------------------------------------------
/source/view/special/RegisterView.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Graphics;
2 | import Toybox.WatchUi;
3 | import Toybox.Lang;
4 |
5 | class RegisterView extends WatchUi.View {
6 |
7 | private var days;
8 |
9 | function initialize(days) {
10 | View.initialize();
11 | self.days = days;
12 | }
13 |
14 | // Update the view
15 | function onUpdate(dc as Dc) as Void {
16 | // Call the parent onUpdate function to redraw the layout
17 | View.onUpdate(dc);
18 |
19 | var W = dc.getWidth();
20 | var H = dc.getHeight();
21 |
22 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
23 | dc.drawText(W / 2, H / 12, Graphics.FONT_LARGE, "TRIAL", Graphics.TEXT_JUSTIFY_CENTER);
24 | dc.setColor(data.blocked ? Graphics.COLOR_RED : Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
25 | dc.drawText(W / 2, H / 4.8, Graphics.FONT_TINY, days + " Days Left", Graphics.TEXT_JUSTIFY_CENTER);
26 |
27 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
28 | dc.drawText(W / 2, H / 2.55, Graphics.FONT_TINY, "To Activate: Go to", Graphics.TEXT_JUSTIFY_CENTER);
29 | dc.setColor(Graphics.COLOR_BLUE, Graphics.COLOR_TRANSPARENT);
30 | dc.drawText(W / 2, H / 2, Graphics.FONT_MEDIUM, "rainy.bleach.dev", Graphics.TEXT_JUSTIFY_CENTER);
31 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
32 | dc.drawText(W / 2, H / 1.55, Graphics.FONT_TINY, "and enter code", Graphics.TEXT_JUSTIFY_CENTER);
33 | dc.setColor(Graphics.COLOR_BLUE, Graphics.COLOR_TRANSPARENT);
34 | dc.drawText(W / 2, H / 1.35, Graphics.FONT_MEDIUM, data.DEVICE_ID, Graphics.TEXT_JUSTIFY_CENTER);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/source/view/special/SettingsDelegate.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Application;
2 | import Toybox.Lang;
3 | import Toybox.WatchUi;
4 |
5 | class SettingsDelegate extends Menu2InputDelegate {
6 |
7 | public static var WIND_UNITS = [ "m/s", "km/h", "mph", "Bft.", "Knots" ];
8 |
9 | function initialize() {
10 | Menu2InputDelegate.initialize();
11 | }
12 |
13 | function onSelect(item) {
14 | System.println(item.getId());
15 | if (item.getId() == 0) {
16 | if (!(WatchUi has :TextPicker)) {
17 | item.setSubLabel("See Mobile Settings!");
18 | return;
19 | }
20 |
21 | if (data.autoLocation) {
22 | WatchUi.pushView(
23 | new TextPicker(""),
24 | new SpellSearchDelegate(),
25 | WatchUi.SLIDE_LEFT
26 | );
27 | } else {
28 | item.setSubLabel("Automatic (GPS)");
29 | data.autoLocation = true;
30 | Properties.setValue("autoLocation", data.autoLocation);
31 | }
32 | } else if (item.getId() == 1) {
33 | data.pageOrder = !data.pageOrder;
34 | Properties.setValue("pageOrder", data.pageOrder);
35 | item.setSubLabel(data.pageOrder ? "Yes" : "No");
36 | } else if (item.getId() == 2) {
37 | data.tempUnits = (data.tempUnits + 1) % 2;
38 | Properties.setValue("tempUnits", data.tempUnits);
39 | item.setSubLabel(data.tempUnits == 0 ? "Celsius" : "Fahrenheit");
40 | } else if (item.getId() == 3) {
41 | data.windUnits = (data.windUnits + 1) % WIND_UNITS.size();
42 | Properties.setValue("windUnits", data.windUnits);
43 | item.setSubLabel(WIND_UNITS[data.windUnits]);
44 | } else if (item.getId() == 4) {
45 | data.update(data.position);
46 | WatchUi.popView(WatchUi.SLIDE_BLINK);
47 | }
48 |
49 | }
50 | }
--------------------------------------------------------------------------------
/source/view/special/SpellSearchDelegate.mc:
--------------------------------------------------------------------------------
1 | import Toybox.Application;
2 | import Toybox.Lang;
3 | import Toybox.WatchUi;
4 |
5 | class SpellSearchDelegate extends TextPickerDelegate {
6 |
7 | function initialize() {
8 | TextPickerDelegate.initialize();
9 | }
10 |
11 | function onTextEntered(text, changed) {
12 | if (changed) {
13 | WatchUi.popView(WatchUi.SLIDE_IMMEDIATE);
14 | WatchUi.popView(WatchUi.SLIDE_IMMEDIATE);
15 | data.enterText(text);
16 | WatchUi.pushView(new View(), null, WatchUi.SLIDE_IMMEDIATE); // Not good but onTextEntered pops the last view after returning
17 | return true;
18 | }
19 |
20 | return false;
21 | }
22 | }
23 |
24 | class SpellListDelegate extends Menu2InputDelegate {
25 |
26 | private var dt as Dictionary?;
27 |
28 | function initialize(dt as Dictionary?) {
29 | Menu2InputDelegate.initialize();
30 | self.dt = dt;
31 | }
32 |
33 | function onSelect(item) {
34 | data.autoLocation = false;
35 | Properties.setValue("autoLocation", data.autoLocation);
36 | data.update(dt[item.getId()]["position"]);
37 | WatchUi.popView(WatchUi.SLIDE_BLINK);
38 | }
39 | }
--------------------------------------------------------------------------------