diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index 68b9b65..0000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a004a1f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,234 @@
+# ---> C
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+# ---> Python
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# UV
+# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+#uv.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
+.pdm.toml
+.pdm-python
+.pdm-build/
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+# Ruff stuff:
+.ruff_cache/
+
+# PyPI configuration file
+.pypirc
+
+*DS_Store*
+.git-credentials
+developer_key
+bin
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index a37aa84..e3a3d8b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,20 +2,17 @@ MIT License
Copyright (c) 2025 noobun
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all copies or substantial
+portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
+EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index fdf0076..477993d 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
-# ROcalendar 2025
-> [!IMPORTANT]
-> This works only for the 2025 year
+[](README.ro.md)
+
+
+# ROcalendar
ROcalendar is an app made for garmin watches (with 5 buttons).
@@ -11,7 +12,7 @@ This will display all the events that are part of the Cristian Ortodox Calendar
The app supports 3 event types:
* Public Holidays
-* Blue Cross Cristian Ortodox
+* Red Cross Cristian Ortodox
* Black Cross Cristian Ortodox
> [!TIP]
@@ -20,9 +21,7 @@ The app supports 3 event types:
# Implementation
### Database
-Due to limitations for Connect IQ and memory on device the database needs to be splitted in 2 -> Main one and Glance one
-
-Database consists in a json file for Main and 12 json for glance
+Each year has his own json file inside resources/db/[YEAR]
### Month View
@@ -52,7 +51,6 @@ Menu View -> Where you can set colors for each event type
# Improvements that could be done
-* Multi-Year
* More details on event
* Notifications/Alerts
diff --git a/README.ro.md b/README.ro.md
new file mode 100644
index 0000000..3abffcc
--- /dev/null
+++ b/README.ro.md
@@ -0,0 +1,59 @@
+
+
+[](README.md)
+
+
+# ROcalendar
+
+ROcalendar este o aplicatie pentru ceasurile garmin (cu 5 butoane).
+
+Aceasta va afisa toate evenimentele care sunt parte din Calendarul Ortotox si Sarbatorile Publice din Romania
+
+Aplicatia suports 3 tipuri de evenimente
+* Sarbatori publice
+* Sarbatori cu cruce neagra
+* Sarbatori cu cruce rosie
+
+> [!TIP]
+> Poti incarca aplicatia prin sideloading
+
+# Implementare
+
+### Baza de date
+
+Datorita limitarilor legate de memorie, baza de date este impartita per an. Fiecare an are propria fila json in : resources/db/[AN]
+
+# Screenshots
+Glance View -> Unde poti vedea urmatorul eveniment
+
+
+
+Main View -> Unde poti sa vezi intreaga luna
+
+
+
+Month View -> Unde poti sa vezi o lista de evenimente din luna curenta, cu detalii
+
+
+
+Menu View -> Unde poti sa definesti culorile pentru evenimente
+
+
+
+# Imbunatatirii
+
+* Mai multe detalii
+* Notificari si Alerte
+
+# Disclaimer
+
+Nu sunt promise imbunatariti/rectificari.
+
+> [!CAUTION]
+>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/manifest.xml b/manifest.xml
index c8e545d..6f686d5 100644
--- a/manifest.xml
+++ b/manifest.xml
@@ -5,7 +5,7 @@
Use "Monkey C: Edit Application" from the Visual Studio Code command palette
to update the application attributes.
-->
-
+
-
+ /> -->
now.year+i, :month => mo, :day => d_key}).subtract(Gregorian.moment({:year => now.year, :month => now.month, :day => now.day})).value()/Gregorian.SECONDS_PER_DAY;
+ event = res[mo-1][d_key.toString()]; // Event found
+ break;
+
+ }
+ if(event){break;}
+ }
+ res = null;
+ if(event){break;}
}
- var now = Gregorian.info(Time.now(), Time.FORMAT_SHORT);
- var now_day = now.day;
-
- free_day_color = Properties.getValue("free_day_color") as Number;
- black_cross_color = Properties.getValue("black_cross_color") as Number;
- red_cross_color = Properties.getValue("red_cross_color") as Number;
-
- var payload = getNextEvent(now_day, db);
- var days_untill = payload[1];
- event= payload[2];
- var current_day_crawl = payload[0];
-
- var untill_days = days_untill+current_day_crawl-now_day;
- if(untill_days == 0){
- untill_prompt = "astazi";
- }else if(untill_days == 1){
- untill_prompt = "maine";
+ if(event != null){
+ if(days_untill == 0){
+ event["untill_prompt"] = "astazi";
+ }else if(days_untill == 1){
+ event["untill_prompt"] = "maine";
+ }else{
+ event["untill_prompt"] = "in "+days_untill.toString()+" zile";
+ }
+ Storage.setValue("glance_event", event);
}else{
- untill_prompt = "in "+untill_days.toString()+" zile";
+ Storage.setValue("glance_event", null);
}
+
+ writeLog("GlanceView:onUpdate", event.toString(), 100);
}
function onHide() as Void {
writeLog("glanceView:onHide", "Cleanup", 100);
- db = [];
}
function onUpdate(dc) {
- dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
+ var free_day_color = Properties.getValue("free_day_color") as Number;
+ var black_cross_color = Properties.getValue("black_cross_color") as Number;
+ var red_cross_color = Properties.getValue("red_cross_color") as Number;
+
var font_h_XTINY = dc.getFontHeight(Graphics.FONT_XTINY);
var font_h_TINY = dc.getFontHeight(Graphics.FONT_TINY);
- dc.drawText(0, 0.5*dc.getHeight()-font_h_TINY/2, Graphics.FONT_SYSTEM_TINY, untill_prompt, Graphics.TEXT_JUSTIFY_LEFT);
+ var event = Storage.getValue("glance_event") as Dictionary;
+ if(event != null){
+ var free = event["opt"].substring(0, 1);
+ var color = event["opt"].substring(1, 2);
- if("black".equals(event["cross"])){
- dc.setColor(black_cross_color, Graphics.COLOR_TRANSPARENT);
- dc.fillCircle(dc.getWidth()-3*font_h_XTINY, 0.5*dc.getHeight(), font_h_XTINY/2);
- }
+ dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
+ dc.drawText(0, 0.5*dc.getHeight()-font_h_TINY/2, Graphics.FONT_SYSTEM_TINY, event["untill_prompt"], Graphics.TEXT_JUSTIFY_LEFT);
- if(event["free"]==true){
- dc.setColor(free_day_color, Graphics.COLOR_TRANSPARENT);
- dc.fillCircle(dc.getWidth()-2*font_h_XTINY, 0.5*dc.getHeight(), font_h_XTINY/2);
- }
+ if("b".equals(color)){
+ dc.setColor(black_cross_color, Graphics.COLOR_TRANSPARENT);
+ dc.fillCircle(dc.getWidth()-3*font_h_XTINY, 0.5*dc.getHeight(), font_h_XTINY/2);
+ }
- if("red".equals(event["cross"])){
- dc.setColor(red_cross_color, Graphics.COLOR_TRANSPARENT);
- dc.fillCircle(dc.getWidth()-font_h_XTINY, 0.5*dc.getHeight(), font_h_XTINY/2);
+ if("t".equals(free)){
+ dc.setColor(free_day_color, Graphics.COLOR_TRANSPARENT);
+ dc.fillCircle(dc.getWidth()-2*font_h_XTINY, 0.5*dc.getHeight(), font_h_XTINY/2);
+ }
+
+ if("r".equals(color)){
+ dc.setColor(red_cross_color, Graphics.COLOR_TRANSPARENT);
+ dc.fillCircle(dc.getWidth()-font_h_XTINY, 0.5*dc.getHeight(), font_h_XTINY/2);
+ }
+ }else{
+ dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
+ dc.drawText(0, 0.5*dc.getHeight()-font_h_TINY/2, Graphics.FONT_SYSTEM_TINY, "no event", Graphics.TEXT_JUSTIFY_LEFT);
}
}
}
\ No newline at end of file
diff --git a/source/misc/generic.mc b/source/misc/generic.mc
index 881dcd2..d93f75c 100644
--- a/source/misc/generic.mc
+++ b/source/misc/generic.mc
@@ -9,6 +9,67 @@ import Toybox.Communications;
import Toybox.Attention;
using Toybox.Math;
+(:glance )
+function getSupportedYears(){
+ return {
+ "2025" => Rez.JsonData.year_2025,
+ "2026" => Rez.JsonData.year_2026
+ };
+}
+
+(:glance)
+function getRelativeYears(current as Number, direction as Number){
+ var sup_years = getSupportedYears().keys();
+ var years_array = [];
+ for (var i = 0; i < sup_years.size(); i++){
+ years_array.add(sup_years[i].toNumber());
+ }
+ years_array.sort(null);
+ var current_index = years_array.indexOf(current);
+ var next_index = current_index+direction;
+
+ //writeLog("generic:getRelativeYear", years_array.slice(next_index%years_array.size(), next_index%years_array.size()).toString(), 100);
+ //return years_array.slice(next_index%years_array.size(), next_index%years_array.size())[0];
+ return years_array[(next_index%years_array.size()).abs()];
+}
+
+var weekdayname = ["Lu", "Ma", "Mi", "Jo", "Vi", "Sm", "Du"];
+
+var monthname = ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie",
+ "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"];
+
+(:glance )
+function getDaysInMonth(year as Number, month as Number) as Number {
+
+ // Create a moment for the 1st day of the current month
+ var start = Gregorian.moment({
+ :year => year,
+ :month => month,
+ :day => 1
+ });
+
+ // Create a moment for the 1st day of the next month
+ var nextStart;
+ if (month == 12) {
+ nextStart = Gregorian.moment({
+ :year => year + 1,
+ :month => 1,
+ :day => 1
+ });
+ } else {
+ nextStart = Gregorian.moment({
+ :year => year,
+ :month => month + 1,
+ :day => 1
+ });
+ }
+
+ // Duration between them in seconds
+ var diff = nextStart.subtract(start);
+
+ // Convert seconds → days
+ return diff.value() / Gregorian.SECONDS_PER_DAY;
+}
(:glance )
function vibrateAttention() {
@@ -26,26 +87,6 @@ function getDeadSpace(diameter, height) as Float {
return radius-tmp;
}
-// (:glance )
-// function returnColorBasedOnString(color_str as String) as Graphics.ColorValue{
-// if(color_str.equals("verde")){
-// return Graphics.COLOR_GREEN;
-// }else if(color_str.equals("rosu")){
-// return Graphics.COLOR_RED;
-// }else if(color_str.equals("galben")){
-// return Graphics.COLOR_YELLOW;
-// }else if(color_str.equals("albastru")){
-// return Graphics.COLOR_BLUE;
-// }else if(color_str.equals("alb")){
-// return Graphics.COLOR_WHITE;
-// }else if(color_str.equals("nimic")){
-// return Graphics.COLOR_TRANSPARENT;
-// }else{
-// writeLog("returnColorBasedOnString", "Unknow render color", 100);
-// return Graphics.COLOR_TRANSPARENT;
-// }
-// }
-
(:glance )
function getNextEvent(now_day as Number, db as Array) as Array{
var days_untill = 0;
diff --git a/source/misc/logging.mc b/source/misc/logging.mc
index c07e712..a21496c 100644
--- a/source/misc/logging.mc
+++ b/source/misc/logging.mc
@@ -27,7 +27,7 @@ public function getNow() as Lang.String {
(:glance)
public function writeLog(component as String, message as String, level as Number) as Void {
- if(level<=Properties.getValue("logging")){
+ //if(level<=Properties.getValue("logging")){
System.println(level.toString() + " | " + getNow()+" "+component+" | "+message.toString());
- }
+ //}
}
diff --git a/source/pages/.DS_Store b/source/pages/.DS_Store
deleted file mode 100644
index 6a74e84..0000000
Binary files a/source/pages/.DS_Store and /dev/null differ
diff --git a/source/pages/month/MonthDelegate.mc b/source/pages/month/MonthDelegate.mc
index 573059c..6e03132 100644
--- a/source/pages/month/MonthDelegate.mc
+++ b/source/pages/month/MonthDelegate.mc
@@ -13,6 +13,7 @@ class MonthDelegate extends WatchUi.BehaviorDelegate {
var db as Dictionary= Storage.getValue("db");
var month as Number = Storage.getValue("now_month");
+ var year as Number = Storage.getValue("now_year");
function initialize(manager) {
BehaviorDelegate.initialize();
diff --git a/source/pages/month/MonthView.mc b/source/pages/month/MonthView.mc
index 3a9bf27..eff6bd9 100644
--- a/source/pages/month/MonthView.mc
+++ b/source/pages/month/MonthView.mc
@@ -13,7 +13,8 @@ class MonthView extends WatchUi.View {
var month_draw = new Rez.Drawables.month_draw();
- var current_month;
+ var selected_mount;
+ var selected_year;
var db = {};
var scrolled_h;
@@ -34,30 +35,16 @@ class MonthView extends WatchUi.View {
var eventList;
var selected = 0;
-
+ var selected_set = false;
var canvas;
- var main_res_dict = [
- Rez.JsonData.main_ianuarie,
- Rez.JsonData.main_februarie,
- Rez.JsonData.main_martie,
- Rez.JsonData.main_aprilie,
- Rez.JsonData.main_mai,
- Rez.JsonData.main_iunie,
- Rez.JsonData.main_iulie,
- Rez.JsonData.main_august,
- Rez.JsonData.main_septembrie,
- Rez.JsonData.main_octombrie,
- Rez.JsonData.main_noiembrie,
- Rez.JsonData.main_decembrie
- ];
-
function anim_finish() as Void{
during_anim = false;
}
function initialize(){
View.initialize();
+ selected_set=false;
}
function drawBackground(dc as Dc) as Void {
@@ -67,10 +54,11 @@ class MonthView extends WatchUi.View {
function onLayout(dc) as Void {
setLayout(Rez.Layouts.view_month(dc));
- current_month = Storage.getValue("current_month");
- db = Application.loadResource(main_res_dict[current_month-1]);
+ selected_mount = Storage.getValue("selected_mount");
+ selected_year = Storage.getValue("selected_year");
+ db=Application.loadResource(getSupportedYears()[selected_year.toString()])[selected_mount-1];
- drawMonth = new DrawMonth (db, dc);
+ drawMonth = new DrawMonth (dc);
render_h = drawMonth.local_h;
diameter = dc.getHeight(); // Diameter of the screen, round only
@@ -84,8 +72,6 @@ class MonthView extends WatchUi.View {
width = Math.round(diameter*3/5); // Width of the calendar
scrolled_h = Math.round(diameter/3+1); //- font_h_TINY/2;
-
- current_month = Storage.getValue("current_month");
writeLog("MonthView:onLayout", "Executed...", 100);
}
@@ -94,7 +80,7 @@ class MonthView extends WatchUi.View {
// the state of this View and prepare it to be shown. This includes
// loading resources into memory.
function onShow() as Void {
- writeLog("MonthView:onShow", "Current Working Month NR:"+current_month.toString(), 100);
+ writeLog("MonthView:onShow", "Current Working Month NR:"+selected_mount.toString(), 100);
writeLog("MonthView:onShow", "Current Working Month:"+db, 100);
}
@@ -107,7 +93,7 @@ class MonthView extends WatchUi.View {
writeLog("font_h_SMALL:", font_h_SMALL, 100);
if(drawMonth==null){
- drawMonth = new DrawMonth (db, dc);
+ drawMonth = new DrawMonth (dc);
render_h = drawMonth.local_h;
}
@@ -115,14 +101,32 @@ class MonthView extends WatchUi.View {
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
dc.drawLine(0, rootHight - font_h_SMALL, diameter, rootHight - font_h_SMALL);
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
- dc.drawText(diameter/2, rootHight-2*font_h_SMALL, Graphics.FONT_SYSTEM_SMALL, db["month"], Graphics.TEXT_JUSTIFY_CENTER);
-
+ dc.drawText(diameter/2, rootHight-2*font_h_SMALL, Graphics.FONT_SYSTEM_SMALL, monthname[selected_mount-1], Graphics.TEXT_JUSTIFY_CENTER);
+ dc.drawText(diameter/2, rootHight-3*font_h_SMALL, Graphics.FONT_XTINY, selected_year.toString(), Graphics.TEXT_JUSTIFY_CENTER);
+
+
dc.setClip(0, Math.round(rootHight - font_h_SMALL), diameter, diameter);
- eventList = drawMonth.drawData(dc);
+ eventList = drawMonth.drawData(selected_year, selected_mount, db, dc);
+
+ dc.clearClip();
+ if(!selected_set and selected_year == Storage.getValue("now_year") and selected_mount == Storage.getValue("now_month")){
+ writeLog("MonthView:onUpdate", "Auto scroll enabled, move to next event", 100);
+ for(var day=1; day<= getDaysInMonth(selected_year, selected_mount); day+=1){
+ if(db.hasKey(day.toString())==true){
+ scroll(-1);
+ if(day >= Storage.getValue("now_day")){
+ selected_set=true;
+ break;
+ }
+ }
+ }
+ selected_set=true;
+ }
+
writeLog("MonthView:onUpdate:eventList", eventList, 100);
writeLog("MonthView:onUpdate", "executed", 100);
- dc.clearClip();
+
}
// Called when this View is removed from the screen. Save the
@@ -134,7 +138,7 @@ class MonthView extends WatchUi.View {
drawMonth = null;
}
- public function scroll(direction as Number) as Void {
+ public function scroll(direction as Number) as Number {
// direction 1 -> Down, -1 -> Up
if((drawMonth.local_h >= rootHight - font_h_SMALL && direction == 1 ) || (direction == -1 && scrolled_h <= drawMonth.abs_h * -1 + diameter/2 + drawMonth.itemH)){
writeLog("MonthView:scroll", "Stop Scroll due to max placement", 10);
@@ -149,6 +153,8 @@ class MonthView extends WatchUi.View {
}
writeLog("MonthView:scroll", "Selected Event:"+selected, 100);
writeLog("MonthView:scroll", "scrolled_h: "+scrolled_h.toString()+"| local_h: "+drawMonth.abs_h+" | delta: "+(drawMonth.local_h * -1 + 150).toString(), 10);
+
+ return selected;
}
function getCurrentEvent() as Lang.String {
@@ -167,10 +173,13 @@ class MonthView extends WatchUi.View {
// Done as a class so it can be animated.
class DrawMonth extends WatchUi.Drawable
{
- var month_data;
+ var db;
var local_h;
var abs_h;
+ var selected_year;
+ var selected_mount;
+
var free_day_color;
var black_cross_color;
var red_cross_color;
@@ -181,7 +190,7 @@ class DrawMonth extends WatchUi.Drawable
var font_h_TINY; // H or the Tiny font
var itemH;
- function initialize (month_data_inner, dc)
+ function initialize (dc)
{
abs_h = 0;
@@ -192,7 +201,7 @@ class DrawMonth extends WatchUi.Drawable
itemH = Math.round(1.2 * font_h_TINY + font_h_XTINY);
local_h = diameter/2-itemH/2;
- month_data = month_data_inner;
+ db = db;
writeLog("MonthView:DrawMonth", "Initialize", 100);
@@ -201,9 +210,11 @@ class DrawMonth extends WatchUi.Drawable
red_cross_color = Properties.getValue("red_cross_color") as Number;
}
- function drawData (dc) as Array
+ function drawData (year, month, db, dc) as Array
{
- var weeknr = month_data["nr_weeks"];
+ selected_year = year;
+ selected_mount = month;
+
var eventList = [];
writeLog("MonthView:draw", local_h, 100);
@@ -216,15 +227,13 @@ class DrawMonth extends WatchUi.Drawable
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
dc.drawLine(5, Math.round(dc.getHeight()/2-0.4*itemH), 5, Math.round(dc.getHeight()/2+0.4*itemH));
- for(var week_pass=1; week_pass<=weeknr; week_pass+=1){
- var week_days = month_data["weeks"][week_pass.toString()]["end"];
- for(var day=1; day<= week_days; day+=1){
- if(month_data["weeks"][week_pass.toString()]["days"].hasKey(day.toString())==true){
- var event = month_data["weeks"][week_pass.toString()]["days"][day.toString()];
- render_h = drawEventItem(dc, render_h, event, day);
- eventList.add(event["name"]);
- items += 1;
- }
+
+ for(var day=1; day<= getDaysInMonth(selected_year, selected_mount); day+=1){
+ if(db.hasKey(day.toString())==true){
+ var event = db[day.toString()];
+ render_h = drawEventItem(dc, render_h, event, day);
+ eventList.add(event["name"]);
+ items += 1;
}
}
@@ -240,17 +249,20 @@ class DrawMonth extends WatchUi.Drawable
// highlight is the selected menu item that can optionally show a value.
function drawEventItem (dc, render_h, event, day) as Number
{
- if("black".equals(event["cross"])){
+ var free = event["opt"].substring(0, 1);
+ var color = event["opt"].substring(1, 2);
+
+ if("b".equals(color)){
dc.setColor(black_cross_color, Graphics.COLOR_TRANSPARENT);
dc.fillCircle(diameter/20*4, render_h+itemH*1/4, itemH/5/2);
}
- if(event["free"]==true){
+ if("t".equals(free)){
dc.setColor(free_day_color, Graphics.COLOR_TRANSPARENT);
dc.fillCircle(diameter/20*4, render_h+itemH*2/4, itemH/5/2);
}
- if("red".equals(event["cross"])){
+ if("r".equals(color)){
dc.setColor(red_cross_color, Graphics.COLOR_TRANSPARENT);
dc.fillCircle(diameter/20*4, render_h+itemH*3/4, itemH/5/2);
}
diff --git a/source/pages/overview/OverviewDelegate.mc b/source/pages/overview/OverviewDelegate.mc
index 5698eae..44842f8 100644
--- a/source/pages/overview/OverviewDelegate.mc
+++ b/source/pages/overview/OverviewDelegate.mc
@@ -6,6 +6,8 @@ import Toybox.System;
import Toybox.Communications;
using Toybox.Graphics;
using Toybox.Attention;
+using Toybox.Time.Gregorian;
+using Toybox.Time;
class OverviewDelegate extends WatchUi.BehaviorDelegate {
var httpreq;
@@ -16,7 +18,13 @@ class OverviewDelegate extends WatchUi.BehaviorDelegate {
var db = Storage.getValue("db");
var now_month = Storage.getValue("now_month");
+ var now_year = Storage.getValue("now_year");
+ var now_day = Storage.getValue("now_day");
+
+ var supported_years = Properties.getValue("supportedyears") as Number;
+
var month = Storage.getValue("now_month");
+ var year = Storage.getValue("now_year");
function initialize(manager) {
BehaviorDelegate.initialize();
@@ -41,7 +49,8 @@ class OverviewDelegate extends WatchUi.BehaviorDelegate {
function eventHandling(code){
if(code==4 || code==3){ // Forward
- Storage.setValue("current_month", month);
+ Storage.setValue("selected_mount", month);
+ Storage.setValue("selected_year", year);
if(_manager.moveSubPage(1)){
var page = _manager.getCurrentPage();
@@ -52,9 +61,10 @@ class OverviewDelegate extends WatchUi.BehaviorDelegate {
var currentSubLevel = _manager.getSubViewIndex();
var currentLevel = _manager.getViewIndex();
- if(month!=now_month){
- _view.onDataReceived(now_month);
+ if(month!=now_month or year!=now_year){
+ _view.onDataReceived(now_month, now_year);
month = now_month;
+ year = now_year;
}else{
if(currentSubLevel==0){
if(currentLevel==0){
@@ -76,15 +86,20 @@ class OverviewDelegate extends WatchUi.BehaviorDelegate {
month = month + 1;
if(month > 12){
month = 1;
+ year = getRelativeYears(year, 1);
}
}
if(code==13 || code==2){ // Up
month = month - 1;
if(month < 1){
month = 12;
+ year = getRelativeYears(year, -1);
}
}
- _view.onDataReceived(month);
+
+ Storage.setValue("selected_month", month);
+ Storage.setValue("selected_year", year);
+ _view.onDataReceived(month, year);
}
function vibrateAttention() {
diff --git a/source/pages/overview/OverviewView.mc b/source/pages/overview/OverviewView.mc
index 6dd13ff..22298e4 100644
--- a/source/pages/overview/OverviewView.mc
+++ b/source/pages/overview/OverviewView.mc
@@ -6,6 +6,8 @@ import Toybox.Lang;
import Toybox.Application;
import Toybox.System;
import Toybox.Communications;
+using Toybox.Time.Gregorian;
+using Toybox.Time;
class OverviewView extends WatchUi.View {
@@ -13,9 +15,12 @@ class OverviewView extends WatchUi.View {
var db as Dictionary = {};
var now_month = Storage.getValue("now_month") as Number;
- var current_month = now_month;
+ var now_year = Storage.getValue("now_year") as Number;
var now_day = Storage.getValue("now_day") as Number;
- var current_day = now_day;
+
+ var selected_mount = now_month;
+ var selected_year = now_year;
+ var selected_day = now_day;
var free_day_color as Number = 0;
var black_cross_color as Number = 0;
@@ -31,20 +36,7 @@ class OverviewView extends WatchUi.View {
var rootWidth as Number = 0; // Starting point for horizonal alligment
var width as Number = 0; // Width of the calendar
- var main_res_dict = [
- Rez.JsonData.main_ianuarie,
- Rez.JsonData.main_februarie,
- Rez.JsonData.main_martie,
- Rez.JsonData.main_aprilie,
- Rez.JsonData.main_mai,
- Rez.JsonData.main_iunie,
- Rez.JsonData.main_iulie,
- Rez.JsonData.main_august,
- Rez.JsonData.main_septembrie,
- Rez.JsonData.main_octombrie,
- Rez.JsonData.main_noiembrie,
- Rez.JsonData.main_decembrie
- ];
+ var index_arr = [-5, 1, 0, -1, -2, -3, -4]; // Used to determine when week starts
function initialize() {
View.initialize();
@@ -59,7 +51,7 @@ class OverviewView extends WatchUi.View {
setLayout(Rez.Layouts.view_overview(dc));
// _month = findDrawableById("month") as WatchUi.Text;
- // _month.setText(db[current_month-1]["month"]);
+ // _month.setText(db[selected_mount-1]["month"]);
diameter = dc.getHeight(); // Diameter of the screen, round only
font_h_XTINY = dc.getFontHeight(Graphics.FONT_XTINY); // H of the TINY font
@@ -76,7 +68,7 @@ class OverviewView extends WatchUi.View {
// the state of this View and prepare it to be shown. This includes
// loading resources into memory.
function onShow() as Void {
- db=Application.loadResource(main_res_dict[current_month-1]);
+ db=Application.loadResource(getSupportedYears()[selected_year.toString()]);
free_day_color = Properties.getValue("free_day_color") as Number;
black_cross_color = Properties.getValue("black_cross_color") as Number;
@@ -88,28 +80,45 @@ class OverviewView extends WatchUi.View {
dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
dc.drawLine(deadSpace, rootHight+font_h_XTINY, (diameter-deadSpace)*0.9, rootHight+font_h_XTINY);
+
+ dc.drawText(
+ diameter/2, // gets the width of the device and divides by 2
+ 0.90*diameter, // gets the height of the device and divides by 2
+ Graphics.FONT_XTINY, // sets the font size
+ selected_year.toString(), // the String to display TODO: Use name not index
+ Graphics.TEXT_JUSTIFY_CENTER // sets the justification for the text
+ );
+
overview_draw.draw( dc );
}
function drawForeground(dc as Dc, month as Dictionary) as Void {
+ var options = {
+ :year => selected_year,
+ :month => selected_mount,
+ :day => 1,
+ :hour => 0
+ };
+ var date = Gregorian.moment(options);
+ writeLog("OverviewDelegate:eventHandling", "First day in mount:"+Gregorian.info(date, Time.FORMAT_SHORT).day_of_week, 100);
+ writeLog("OverviewView:onUpdate", "End day in mount:"+getDaysInMonth(2025, selected_mount).toString(), 100);
+
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
- var index = 2-month["weeks"]["1"]["start_day_index"]; // Force on negative if start day not monday
- var last = month["last"]; // Last day or the month
-
+ var index = index_arr[Gregorian.info(date, Time.FORMAT_SHORT).day_of_week-1]; // -1 for week start saturday, Force on negative if start day not monday
+ var last = getDaysInMonth(selected_year, selected_mount); // Last day or the month
dc.drawText(
diameter/2, // gets the width of the device and divides by 2
0.03*diameter, // gets the height of the device and divides by 2
Graphics.FONT_XTINY, // sets the font size
- month["month"], // the String to display
+ monthname[selected_mount-1], // the String to display TODO: Use name not index
Graphics.TEXT_JUSTIFY_CENTER // sets the justification for the text
);
//////////////////////////
// Draw week days
//////////////////////////
- var weekdayname = ["Lu", "Ma", "Mi", "Jo", "Vi", "Sm", "Du"];
for (var i = 1; i <= 7; i += 1){
dc.drawText(
@@ -125,6 +134,7 @@ class OverviewView extends WatchUi.View {
// Draw dates
//////////////////////////
var weeks_nr = 1;
+ var day_nr = 0;
for (var i = 1; i <= 6; i += 1){ // Weeks
for (var j = 0; j <= 6; j+=1){ // Days
@@ -132,7 +142,8 @@ class OverviewView extends WatchUi.View {
index += 1;
continue;
}
-
+ day_nr++;
+ //writeLog("OverviewView:drawForeground", "Idenx day:"+day_nr.toString(), 100);
// Set Color for Day
if((j+1)%6==0){
dc.setColor(Graphics.COLOR_BLUE, Graphics.COLOR_TRANSPARENT);
@@ -153,18 +164,21 @@ class OverviewView extends WatchUi.View {
// Determine of an event exists in the current drawing day
var mark_radius = font_h_XTINY/5;
var mark_diameter = mark_radius * 2;
- if(month["weeks"][weeks_nr.toString()]["days"].hasKey(index.toString())==true){
- if("black".equals(month["weeks"][weeks_nr.toString()]["days"][index.toString()]["cross"])){
+ if(month.hasKey(day_nr.toString())==true){
+ var free = month[day_nr.toString()]["opt"].substring(0, 1);
+ var color = month[day_nr.toString()]["opt"].substring(1, 2);
+
+ if("b".equals(color)){
dc.setColor(black_cross_color, Graphics.COLOR_TRANSPARENT);
dc.fillCircle(rootWidth + j * width/6 + font_h_XTINY/2 - mark_diameter, rootHight + i * hight/6 + 1.1*font_h_XTINY, mark_radius);
}
- if(month["weeks"][weeks_nr.toString()]["days"][index.toString()]["free"]==true){
+ if("t".equals(free)){
dc.setColor(free_day_color, Graphics.COLOR_TRANSPARENT);
dc.fillCircle(rootWidth + j * width/6 + font_h_XTINY/2, rootHight + i * hight/6 + 1.1*font_h_XTINY, mark_radius);
}
- if("red".equals(month["weeks"][weeks_nr.toString()]["days"][index.toString()]["cross"])){
+ if("r".equals(color)){
dc.setColor(red_cross_color, Graphics.COLOR_TRANSPARENT);
dc.fillCircle(rootWidth + j * width/6 + font_h_XTINY/2 + mark_diameter, rootHight + i * hight/6 + 1.1*font_h_XTINY, mark_radius);
}
@@ -173,7 +187,7 @@ class OverviewView extends WatchUi.View {
///////////////////////////////
// Draw circle for current day
///////////////////////////////
- if(now_month == current_month && now_day == index){
+ if(now_month == selected_mount && now_day == index){
dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_TRANSPARENT);
dc.setPenWidth(3);
dc.drawArc(rootWidth + j * width/6 + font_h_XTINY/2,
@@ -200,10 +214,9 @@ class OverviewView extends WatchUi.View {
// Update the view
function onUpdate(dc as Dc) as Void {
// Call the parent onUpdate function to redraw the layout
- Storage.setValue("current_month", current_month);
- db=Application.loadResource(main_res_dict[current_month-1]);
-
- writeLog("OverviewView:onUpdate", db["month"]+" loaded.", 100);
+ //Storage.setValue("selected_mount", selected_mount); // Done in delegate
+
+ db=Application.loadResource(getSupportedYears()[selected_year.toString()])[selected_mount-1];
View.onUpdate(dc);
drawBackground(dc);
@@ -217,8 +230,9 @@ class OverviewView extends WatchUi.View {
db = {};
}
- function onDataReceived(data) as Lang.Boolean {
- current_month = data;
+ function onDataReceived(month, year) as Lang.Boolean {
+ selected_mount = month;
+ selected_year = year;
WatchUi.requestUpdate();
return true;
}