├── .gitignore
├── monkey.jungle
├── .settings
└── IQ_IDE.prefs
├── resources
├── drawables
│ ├── drawables.xml
│ └── launcher_icon.png
├── fonts
│ ├── qrcode-1.png
│ ├── qrcode-10.png
│ ├── qrcode-11.png
│ ├── qrcode-12.png
│ ├── qrcode-13.png
│ ├── qrcode-14.png
│ ├── qrcode-15.png
│ ├── qrcode-16.png
│ ├── qrcode-2.png
│ ├── qrcode-3.png
│ ├── qrcode-4.png
│ ├── qrcode-5.png
│ ├── qrcode-6.png
│ ├── qrcode-7.png
│ ├── qrcode-8.png
│ ├── qrcode-9.png
│ ├── fonts.xml
│ ├── qrcode-9.fnt
│ ├── qrcode-1.fnt
│ ├── qrcode-2.fnt
│ ├── qrcode-3.fnt
│ ├── qrcode-4.fnt
│ ├── qrcode-5.fnt
│ ├── qrcode-6.fnt
│ ├── qrcode-8.fnt
│ ├── qrcode-15.fnt
│ ├── qrcode-16.fnt
│ ├── qrcode-10.fnt
│ ├── qrcode-11.fnt
│ ├── qrcode-12.fnt
│ ├── qrcode-13.fnt
│ ├── qrcode-14.fnt
│ └── qrcode-7.fnt
├── strings.xml
├── properties.xml
└── settings.xml
├── README.md
├── source
├── Utils.mc
├── menu
│ ├── QrCodeViewerMenuDelegate.mc
│ └── DMenu.mc
├── Settings.mc
├── QRCodeViewerDelegate.mc
├── Code.mc
├── QRCodeViewerApp.mc
└── QRCodeViewerView.mc
├── .project
├── resources-eng
└── strings.xml
├── resources-tha
└── strings.xml
├── resources-ces
└── strings.xml
├── resources-fre
└── strings.xml
├── resources-deu
└── strings.xml
└── manifest.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 |
--------------------------------------------------------------------------------
/monkey.jungle:
--------------------------------------------------------------------------------
1 | project.manifest = manifest.xml
2 |
3 |
--------------------------------------------------------------------------------
/.settings/IQ_IDE.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | project_manifest=manifest.xml
3 |
--------------------------------------------------------------------------------
/resources/drawables/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/resources/fonts/qrcode-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-1.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-10.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-11.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-12.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-13.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-14.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-15.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-16.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-2.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-3.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-4.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-5.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-6.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-7.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-8.png
--------------------------------------------------------------------------------
/resources/fonts/qrcode-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/fonts/qrcode-9.png
--------------------------------------------------------------------------------
/resources/drawables/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macherel/Connect-IQ-QR-Code-Viewer/HEAD/resources/drawables/launcher_icon.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QR Code Viewer
2 | [QR Code Viewer on the Connect IQ App Store](https://apps.garmin.com/en-US/apps/3a83fd85-0c2c-49a3-b46e-69869d6ea3bc)
3 |
4 | A widget that can display QR Code on Garmin watch
5 |
--------------------------------------------------------------------------------
/source/Utils.mc:
--------------------------------------------------------------------------------
1 | function join(array, char) {
2 | var result = array[0];
3 | for(var i=1; i
2 |
3 | QR Code Viewer
4 |
5 |
6 |
7 |
8 |
9 | connectiq.builder
10 |
11 |
12 |
13 |
14 |
15 | connectiq.projectNature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/source/menu/QrCodeViewerMenuDelegate.mc:
--------------------------------------------------------------------------------
1 | using Toybox.WatchUi as Ui;
2 | using Toybox.Application as App;
3 |
4 | class QrCodeViewerMenuDelegate extends Ui.MenuInputDelegate {
5 |
6 | function initialize () {
7 | MenuInputDelegate.initialize ();
8 | }
9 |
10 | function onMenuItem (item) {
11 | System.println("Select code #" + item.userData);
12 | Settings.setCurrentId(item.userData);
13 | Ui.popView(Ui.SLIDE_IMMEDIATE);
14 | }
15 | }
--------------------------------------------------------------------------------
/source/Settings.mc:
--------------------------------------------------------------------------------
1 | using Toybox.Application as App;
2 | using Toybox.WatchUi as Ui;
3 |
4 | module Settings {
5 |
6 | var barcodeHeight;
7 | var cacheEnabled;
8 | var currentId;
9 | var displayLabel;
10 | var offsetY;
11 | var retainMenuIndex;
12 | var size;
13 |
14 | function load() {
15 | var app = App.getApp();
16 |
17 | // Force default value for old version
18 | if(app.getProperty("liVersion")==null) {
19 | app.setProperty("liVersion", 0);
20 | app.setProperty("cacheEnabled", true);
21 | }
22 |
23 | barcodeHeight = app.getProperty("barcodeHeight");
24 | cacheEnabled = app.getProperty("cacheEnabled");
25 | currentId = app.getProperty("currentId");
26 | displayLabel = app.getProperty("displayLabel");
27 | offsetY = app.getProperty("offsetY");
28 | retainMenuIndex = app.getProperty("retainMenuIndex");
29 | size = app.getProperty("size");
30 | }
31 |
32 | function setCurrentId(id) {
33 | currentId = id;
34 | App.getApp().setProperty("currentId", currentId);
35 | }
36 | }
--------------------------------------------------------------------------------
/resources/fonts/fonts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/source/QRCodeViewerDelegate.mc:
--------------------------------------------------------------------------------
1 | using Toybox.WatchUi as Ui;
2 | using Toybox.Application as App;
3 |
4 | class QRCodeViewerDelegate extends Ui.BehaviorDelegate {
5 |
6 | function initialize() {
7 | BehaviorDelegate.initialize();
8 | }
9 |
10 | function onSelect() {
11 | var app = App.getApp();
12 |
13 | if(app.enabledCodes.size() > 0) {
14 | var qrCodesMenu = [];
15 | var menuIndex = 0;
16 | for(var i=0; i
2 | QR Code Viewer
3 |
4 | No QR code
5 | Select QR code
6 |
7 | Select QR Code
8 |
9 |
10 | Size
11 | Barcode height
12 | Offset Y
13 | Enable offline mode
14 | Error
15 | Please
contact
developer
16 |
17 | Display label
18 | Enable
19 | Label 1
20 | Value 1
21 | Type 1
22 | Enable
23 | Label 2
24 | Value 2
25 | Type 2
26 | Enable
27 | Label 3
28 | Value 3
29 | Type 3
30 | Enable
31 | Label 4
32 | Value 4
33 | Type 4
34 | Enable
35 | Label 5
36 | Value 5
37 | Type 5
38 | Enable
39 | Label 6
40 | Value 6
41 | Type 6
42 | Enable
43 | Label 7
44 | Value 7
45 | Type 7
46 | Enable
47 | Label 8
48 | Value 8
49 | Type 8
50 |
51 |
52 |
--------------------------------------------------------------------------------
/resources-eng/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | QR Code Viewer
3 |
4 | No QR code
5 | Select QR code
6 |
7 | Select QR Code
8 |
9 |
10 | Size
11 | Barcode height
12 | Offset Y
13 | Enable offline mode
14 | Error
15 | Please
contact
developer
16 |
17 | Display label
18 | Enable
19 | Label 1
20 | Value 1
21 | Type 1
22 | Enable
23 | Label 2
24 | Value 2
25 | Type 2
26 | Enable
27 | Label 3
28 | Value 3
29 | Type 3
30 | Enable
31 | Label 4
32 | Value 4
33 | Type 4
34 | Enable
35 | Label 5
36 | Value 5
37 | Type 5
38 | Enable
39 | Label 6
40 | Value 6
41 | Type 6
42 | Enable
43 | Label 7
44 | Value 7
45 | Type 7
46 | Enable
47 | Label 8
48 | Value 8
49 | Type 8
50 |
51 |
52 |
--------------------------------------------------------------------------------
/resources-tha/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | QR Code Viewer
3 |
4 | ไม่พบ QR code
5 | เลือก QR code
6 |
7 | เลือก QR Code
8 |
9 |
10 | ขนาด
11 | ค่าสูงของ Barcode
12 | เลื่อนภาพในแนวตั้ง
13 | ใช้งานแบบออฟไลน์
14 | พบข้อผิดพลาด
15 | โทเคน หรือ ประเภทของโค้ดไม่ถูกต้อง
16 |
17 | แสดงชื่อ
18 | เปิดใช้งาน
19 | ชื่อ 1
20 | ค่า 1
21 | ประเภท 1
22 | เปิดใช้งาน
23 | ชื่อ 2
24 | ค่า 2
25 | ประเภท 2
26 | เปิดใช้งาน
27 | ชื่อ 3
28 | ค่า 3
29 | ประเภท 3
30 | เปิดใช้งาน
31 | ชื่อ 4
32 | ค่า 4
33 | ประเภท 4
34 | เปิดใช้งาน
35 | ชื่อ 5
36 | ค่า 5
37 | ประเภท 5
38 | เปิดใช้งาน
39 | ชื่อ 6
40 | ค่า 6
41 | ประเภท 6
42 | เปิดใช้งาน
43 | ชื่อ 7
44 | ค่า 7
45 | ประเภท 7
46 | เปิดใช้งาน
47 | ชื่อ 8
48 | ค่า 8
49 | ประเภท 8
50 |
51 |
52 |
--------------------------------------------------------------------------------
/resources-ces/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | QR Code Viewer
3 |
4 | Žádný QR kód
5 | Vyberte QR kód
6 |
7 | Vyberte QR kód
8 |
9 |
10 | Velikost
11 | Výška èárového kódu
12 | Ofset Y
13 | Zapnout offline mód
14 | Chyba
15 | Prosím
kontatujte
vývojáøe
16 |
17 | Zobrazit popis
18 | Aktivovat
19 | Popis 1
20 | Hodnota 1
21 | Typ 1
22 | Aktivovat
23 | Popis 2
24 | Hodnota 2
25 | Typ 2
26 | Aktivovat
27 | Popis 3
28 | Hodnota 3
29 | Typ 3
30 | Aktivovat
31 | Popis 4
32 | Hodnota 4
33 | Typ 4
34 | Aktivovat
35 | Popis 5
36 | Hodnota 5
37 | Typ 5
38 | Aktivovat
39 | Popis 6
40 | Hodnota 6
41 | Typ 6
42 | Aktivovat
43 | Popis 7
44 | Hodnota 7
45 | Typ 7
46 | Aktivovat
47 | Popis 8
48 | Hodnota 8
49 | Typ 8
50 |
51 |
--------------------------------------------------------------------------------
/resources-fre/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | QR Code Viewer
3 |
4 | Pas de QR code
5 | Sélectionnez un QR code
6 |
7 | QR Code
8 |
9 |
10 | Taille
11 | Hauteur des codes-barres
12 | Offset Y
13 | Mode déconnecté
14 | Erreur
15 | Veuillez
contacter
le développeur
16 |
17 | Affiche les libellés
18 | Actif
19 | Libellé 1
20 | Valeur 1
21 | Type 1
22 | Actif
23 | Libellé 2
24 | Valeur 2
25 | Type 2
26 | Actif
27 | Libellé 3
28 | Valeur 3
29 | Type 3
30 | Actif
31 | Libellé 4
32 | Valeur 4
33 | Type 4
34 | Actif
35 | Libellé 5
36 | Valeur 5
37 | Type 5
38 | Actif
39 | Libellé 6
40 | Valeur 6
41 | Type 6
42 | Actif
43 | Libellé 7
44 | Valeur 7
45 | Type 7
46 | Actif
47 | Libellé 8
48 | Valeur 8
49 | Type 8
50 |
51 |
52 |
--------------------------------------------------------------------------------
/resources-deu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | QR-Code Viewer
3 |
4 | Kein QR-code
5 | Wähle QR-Code
6 |
7 | Wähle QR-Code
8 |
9 |
10 | Grösse
11 | Barcode-Höhe
12 | Offset Y
13 | Offline-Modus aktivieren
14 | Fehler
15 | Bitte
Entwickler
kontaktieren
16 |
17 | Displaybezeichnung
18 | Aktiv
19 | Bezeichnung 1
20 | Wert 1
21 | Typ 1
22 | Aktiv
23 | Bezeichnung 2
24 | Wert 2
25 | Typ 2
26 | Aktiv
27 | Bezeichnung 3
28 | Wert 3
29 | Typ 3
30 | Aktiv
31 | Bezeichnung 4
32 | Wert 4
33 | Typ 4
34 | Aktiv
35 | Bezeichnung 5
36 | Wert 5
37 | Typ 5
38 | Aktiv
39 | Bezeichnung 6
40 | Wert 6
41 | Typ 6
42 | Aktiv
43 | Bezeichnung 7
44 | Wert 7
45 | Typ 7
46 | Aktiv
47 | Bezeichnung 8
48 | Wert 8
49 | Typ 8
50 |
51 |
52 |
--------------------------------------------------------------------------------
/resources/properties.xml:
--------------------------------------------------------------------------------
1 |
2 | false
3 | false
4 |
5 |
6 | qrcode
7 | false
8 |
9 |
10 | qrcode
11 | false
12 |
13 |
14 | qrcode
15 | false
16 |
17 |
18 | qrcode
19 | false
20 |
21 |
22 | qrcode
23 | false
24 |
25 |
26 | qrcode
27 | false
28 |
29 |
30 | qrcode
31 | false
32 |
33 |
34 | qrcode
35 |
36 | 0
37 | 0
38 | 0
39 | true
40 |
--------------------------------------------------------------------------------
/source/Code.mc:
--------------------------------------------------------------------------------
1 | using Toybox.Application as App;
2 |
3 | class Code {
4 | var id;
5 | var enabled;
6 | var label;
7 | var type;
8 | var value;
9 | var cache;
10 | var lat;
11 | var lng;
12 |
13 | function initialize(id, enabled, label, type, value, cache, lat, lng) {
14 | self.id = id;
15 | self.enabled = enabled;
16 | self.label = label;
17 | self.type = type;
18 | self.value = value;
19 | self.cache = cache;
20 | self.lat = lat;
21 | self.lng = lng;
22 | if(isNullOrEmpty(self.type)) {
23 | self.type = "qrcode";
24 | }
25 | }
26 |
27 | function store() {
28 | var app = App.getApp();
29 | var id = self.id;
30 | System.println("Store code #" + id);
31 | System.println("Store code " + self);
32 | app.setProperty("codeEnable"+ id, self.enabled);
33 | app.setProperty("codeType" + id, self.type);
34 | app.setProperty("codeLabel" + id, self.label);
35 | app.setProperty("codeValue" + id, self.value);
36 | app.setProperty("cacheValue"+ id, self.value);
37 | app.setProperty("cacheData" + id, self.cache);
38 | app.setProperty("codeLat" + id, self.lat);
39 | app.setProperty("codeLng" + id, self.lng);
40 | }
41 |
42 | function fromSettings(id) {
43 | var app = App.getApp();
44 | var value = app.getProperty("codeValue" + id);
45 | var cacheValue = app.getProperty("cacheValue"+ id);
46 | if(value == null || !value.equals(cacheValue)) {
47 | app.setProperty("cacheData"+ id, null);
48 | }
49 | System.println("Load code #" + id + " : " + app.getProperty("codeEnable"+ id));
50 | return new Code(
51 | id,
52 | app.getProperty("codeEnable"+ id),
53 | app.getProperty("codeLabel" + id),
54 | app.getProperty("codeType" + id),
55 | app.getProperty("codeValue" + id),
56 | app.getProperty("cacheData" + id),
57 | app.getProperty("codeLat" + id),
58 | app.getProperty("codeLng" + id)
59 | );
60 | }
61 |
62 | function fromResponseData(id, data) {
63 | return new Code(
64 | id,
65 | true,
66 | data["name"],
67 | data["type"],
68 | data["value"],
69 | data["encodedData"],
70 | data["latlng"]["lat"],
71 | data["latlng"]["lng"]
72 | );
73 | }
74 |
75 | function toString() {
76 | return "Code{"
77 | + "id: " + self.id
78 | + ", enabled: " + self.enabled
79 | + ", label: " + self.label
80 | + ", type: " + self.type
81 | + ", value: " + self.value
82 | + ", cache: " + self.cache
83 | + "}";
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/manifest.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 | ces
87 | deu
88 | eng
89 | fre
90 | tha
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/source/QRCodeViewerApp.mc:
--------------------------------------------------------------------------------
1 | using Toybox.WatchUi as Ui;
2 | using Toybox.Application as App;
3 | using Toybox.Communications as Comm;
4 |
5 | class QRCodeViewerApp extends App.AppBase {
6 |
7 | var enabledCodes = [];
8 | var loadingCache = 0;
9 | var latlng = null;
10 | var status = :UNKNOWN;
11 |
12 | ////////////////////////////////////////////////////////////////
13 | // Callbacks
14 | ////////////////////////////////////////////////////////////////
15 |
16 | function onReceive(responseCode, data) {
17 | System.println("Receiving data (" + responseCode + "): " + data);
18 | var app = App.getApp();
19 | loadingCache--;
20 | if (responseCode == 200) {
21 | var id = data["id"];
22 | app.setProperty("cacheValue" + id, data["data"]);
23 | app.setProperty("cacheData" + id, data["response"]);
24 | System.println("Cache data #" + id + " loaded");
25 | } else {
26 | System.println("Error while loading data : " + responseCode);
27 | // nothing to do, data will be store next time
28 | }
29 | if(loadingCache==0) {
30 | Ui.requestUpdate();
31 | }
32 | }
33 |
34 | ////////////////////////////////////////////////////////////////
35 | // Private methods
36 | ////////////////////////////////////////////////////////////////
37 |
38 | function getCodeIndex(id) {
39 | for(var i=0; i Comm.HTTP_REQUEST_METHOD_GET,
63 | :headers => {
64 | "Content-Type" => Comm.REQUEST_CONTENT_TYPE_JSON
65 | },
66 | :responseType => Comm.HTTP_RESPONSE_CONTENT_TYPE_JSON
67 | },
68 | method(:onReceive)
69 | );
70 | }
71 | }
72 |
73 | function initQRCodeSettings(id) {
74 | var app = App.getApp();
75 | var code = Code.fromSettings(id);
76 | System.println("Initialize code " + code);
77 | var cacheValue = code.cache;
78 | if(code.enabled && !isNullOrEmpty(code.label) && !isNullOrEmpty(code.value)) {
79 | // The QR Code exist, we have to handle with it
80 | if(code.value != null && code.cache == null) {
81 | loadQRCodeData(code);
82 | }
83 | System.println("Add QR code #" + id);
84 | enabledCodes.add(code);
85 | } else if(Settings.currentId == id) {
86 | System.println("Reset currentId");
87 | Settings.setCurrentId(null);
88 | } else {
89 | System.println("Code not loaded");
90 | }
91 | }
92 |
93 | function initQRCodes() {
94 | System.println("init QR codes...");
95 | enabledCodes = [];
96 | for(var i=1; i<=8; i++) {
97 | initQRCodeSettings(i);
98 | }
99 | if(loadingCache==0) {
100 | setStatus(:READY);
101 | Ui.requestUpdate();
102 | }
103 | }
104 |
105 | function handleSettings() {
106 | System.println("Handle settings...");
107 | Settings.load();
108 | System.println(
109 | "Settings = {"
110 | + "barcodeHeight: " + Settings.barcodeHeight
111 | + ", cacheEnabled: " + Settings.cacheEnabled
112 | + ", currentId: " + Settings.currentId
113 | + ", displayLabel: " + Settings.displayLabel
114 | + ", offsetY: " + Settings.offsetY
115 | + ", retainMenuIndex: " + Settings.retainMenuIndex
116 | + ", size: " + Settings.size
117 | + "}"
118 | );
119 |
120 | var app = App.getApp();
121 | initQRCodes();
122 | }
123 |
124 | function setStatus(newStatus) {
125 | if(status == newStatus) {
126 | return;
127 | }
128 | System.println("set status : " + newStatus);
129 | status = newStatus;
130 | Ui.requestUpdate();
131 | }
132 |
133 | function orderCodes() {
134 | }
135 |
136 | ////////////////////////////////////////////////////////////////
137 | // Public methods
138 | ////////////////////////////////////////////////////////////////
139 |
140 | function initialize() {
141 | System.println("App initialization...");
142 | AppBase.initialize();
143 | handleSettings();
144 | System.println("App initialized.");
145 | }
146 |
147 | function onSettingsChanged() {
148 | AppBase.onSettingsChanged();
149 | handleSettings();
150 | }
151 |
152 | // onStart() is called on application start up
153 | function onStart(state) {
154 | System.println("onStart : " + state);
155 | }
156 |
157 | // onStop() is called when your application is exiting
158 | function onStop(state) {
159 | System.println("onStop : " + state);
160 | }
161 |
162 | // Return the initial view of your application here
163 | function getInitialView() {
164 | return [ new QRCodeViewerView(), new QRCodeViewerDelegate() ];
165 | }
166 |
167 | }
--------------------------------------------------------------------------------
/resources/settings.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 |
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 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/source/menu/DMenu.mc:
--------------------------------------------------------------------------------
1 | using Toybox.WatchUi as Ui;
2 | using Toybox.Graphics as Gfx;
3 |
4 | var SCALE = 100;
5 |
6 | // Inherit from this if you want to store additional information in the menu entry and/or change how
7 | // the menu is drawn - for example adding in a status icon.
8 | // Any overridden drawing should be constrained within the items boundaries, i.e. y .. y + height / 3.
9 | class DMenuItem
10 | {
11 | const LABEL_FONT = Gfx.FONT_SMALL;
12 | const SELECTED_LABEL_FONT = Gfx.FONT_LARGE;
13 | const VALUE_FONT = Gfx.FONT_MEDIUM;
14 | const PAD = 0;
15 |
16 | var id, label, value, userData;
17 | var index; // filled in with its index, if selected
18 |
19 | // _id is typically a symbol but can be anything and is just used in menu delegate to identify
20 | // which item has been selected.
21 | // _label the text to show as the item name. Can be any object responding to toString ().
22 | // _value the text to show when the item is in the selectable position. Use null for no text
23 | // otherwise any object responding to toString () can be used.
24 | // _userData optional.
25 | function initialize (_id, _label, _value, _userData)
26 | {
27 | id = _id;
28 | label = _label;
29 | value = _value;
30 | userData = _userData;
31 | }
32 |
33 | function draw (dc, y, highlight)
34 | {
35 |
36 | if (highlight)
37 | {
38 | setHighlightColor (dc);
39 | drawHighlightedLabel (dc, y);
40 | }
41 | else
42 | {
43 | setColor (dc);
44 | drawLabel (dc, y);
45 | }
46 | }
47 |
48 | function setHighlightColor (dc)
49 | {
50 | dc.setColor (Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
51 | }
52 |
53 | function setColor (dc)
54 | {
55 | dc.setColor (Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
56 | }
57 |
58 | function drawLabel (dc, y)
59 | {
60 | var width = dc.getWidth ();
61 | var h3 = dc.getHeight () / 3;
62 | var lab = label.toString ();
63 | var labDims = dc.getTextDimensions (lab, LABEL_FONT);
64 | var yL = y + (h3 - labDims[1]) / 2;
65 |
66 | dc.drawText (width / 2, yL, LABEL_FONT, lab, Gfx.TEXT_JUSTIFY_CENTER);
67 | }
68 |
69 | function drawHighlightedLabel (dc, y)
70 | {
71 | var width = dc.getWidth ();
72 | var h3 = dc.getHeight () / 3;
73 | var lab = label.toString ();
74 | var labDims = dc.getTextDimensions (lab, SELECTED_LABEL_FONT);
75 | var yL, yV, h;
76 |
77 | if (value != null)
78 | {
79 | // Show label and value.
80 | var val = value.toString ();
81 | var index = val.find("\n");
82 | if(index != null) {
83 | val = val.substring(0, index);
84 | }
85 | var valDims = dc.getTextDimensions (val, VALUE_FONT);
86 |
87 | h = labDims[1] + valDims[1] + PAD;
88 | yL = y + (h3 - h) / 2;
89 | yV = yL + labDims[1] + PAD;
90 | dc.drawText (width / 2, yV, VALUE_FONT, val, Gfx.TEXT_JUSTIFY_CENTER);
91 | }
92 | else
93 | {
94 | yL = y + (h3 - labDims[1]) / 2;
95 | }
96 | dc.drawText (width / 2, yL, SELECTED_LABEL_FONT, lab, Gfx.TEXT_JUSTIFY_CENTER);
97 | }
98 | }
99 |
100 | class DMenu extends Ui.View
101 | {
102 | var menuArray;
103 | var title;
104 | var index;
105 |
106 | var nextIndex;
107 | hidden var drawMenu;
108 |
109 | function initialize (_menuArray, _menuTitle)
110 | {
111 | menuArray = _menuArray;
112 | title = _menuTitle;
113 | index = 0;
114 | nextIndex = 0;
115 |
116 | View.initialize ();
117 | }
118 |
119 | function onShow ()
120 | {
121 | drawMenu = new DrawMenu ();
122 | }
123 |
124 | function onHide ()
125 | {
126 | drawMenu = null;
127 | }
128 |
129 | // Return the menuItem with the matching id. The menu item has its index field updated
130 | // with the index it was found at. Returns null if not found.
131 | function itemWithId (id)
132 | {
133 | for (var idx = 0; idx < menuArray.size (); idx++)
134 | {
135 | if (menuArray[idx].id == id)
136 | {
137 | menuArray[idx].index = idx;
138 | return menuArray[idx];
139 | }
140 | }
141 | return null;
142 | }
143 |
144 | const ANIM_TIME = 0.3;
145 | function updateIndex (offset)
146 | {
147 | if (menuArray.size () <= 1)
148 | {
149 | return;
150 | }
151 |
152 | /*
153 | if (offset == 1)
154 | {
155 | // Scroll down. Use 1000 as end value as cannot use 1. Scale as necessary in draw call.
156 | Ui.animate (drawMenu, :t, Ui.ANIM_TYPE_LINEAR, SCALE, 0, ANIM_TIME, null);
157 | }
158 | else
159 | {
160 | // Scroll up.
161 | Ui.animate (drawMenu, :t, Ui.ANIM_TYPE_LINEAR, -SCALE, 0, ANIM_TIME, null);
162 | }
163 | //*/
164 | nextIndex = index + offset;
165 |
166 | // Cope with a 'feature' in modulo operator not handling -ve numbers as desired.
167 | nextIndex = nextIndex < 0 ? menuArray.size () + nextIndex : nextIndex;
168 |
169 | nextIndex = nextIndex % menuArray.size ();
170 |
171 | Ui.requestUpdate();
172 | index = nextIndex;
173 | }
174 |
175 | function selectedItem ()
176 | {
177 | menuArray[index].index = index;
178 | return menuArray[index];
179 | }
180 |
181 | function onUpdate (dc)
182 | {
183 | if(drawMenu == null) {
184 | return;
185 | }
186 | var width = dc.getWidth ();
187 | var height = dc.getHeight ();
188 |
189 | dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
190 | dc.fillRectangle(0, 0, width, height);
191 |
192 | // Draw the menu items.
193 | drawMenu.index = index;
194 | drawMenu.nextIndex = nextIndex;
195 | drawMenu.menu = self;
196 |
197 | drawMenu.draw (dc);
198 |
199 | // Draw the decorations.
200 | var h3 = height / 3;
201 | dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
202 | dc.setPenWidth (2);
203 | dc.drawLine (0, h3, width, h3);
204 | dc.drawLine (0, h3 * 2, width, h3 * 2);
205 |
206 | drawArrows (dc);
207 | }
208 |
209 | const GAP = 5;
210 | const TS = 5;
211 |
212 | // The arrows are drawn with lines as polygons don't give different sized triangles depending
213 | // on their orientation.
214 | function drawArrows (dc)
215 | {
216 | var x = dc.getWidth () / 2;
217 | var y;
218 |
219 | dc.setPenWidth (1);
220 | dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
221 |
222 | if (nextIndex != 0)
223 | {
224 | y = GAP;
225 |
226 | for (var i = 0; i < TS; i++)
227 | {
228 | dc.drawLine (x - i, y + i, x + i + 1, y + i);
229 | }
230 | }
231 |
232 | if (nextIndex != menuArray.size () - 1)
233 | {
234 | y = dc.getHeight () - TS - GAP;
235 |
236 | var d;
237 | for (var i = 0; i < TS; i++)
238 | {
239 | d = TS - 1 - i;
240 | dc.drawLine (x - d, y + i, x + d + 1, y + i);
241 | }
242 | }
243 | }
244 | }
245 |
246 | // Done as a class so it can be animated.
247 | class DrawMenu extends Ui.Drawable
248 | {
249 | const TITLE_FONT = Gfx.FONT_SMALL;
250 |
251 | var t = 0; // 'time' in the animation cycle 0...1000 or -1000...0.
252 | var index, nextIndex, menu;
253 |
254 | function initialize ()
255 | {
256 | Drawable.initialize ({});
257 | }
258 |
259 | function draw (dc)
260 | {
261 | var width = dc.getWidth ();
262 | var height = dc.getHeight ();
263 | var h3 = height / 3;
264 | var items = menu.menuArray.size ();
265 |
266 | nextIndex = menu.nextIndex;
267 |
268 | // y for the middle of the three items.
269 | var y = h3 + (t / SCALE) * h3;
270 |
271 | // Depending on where we are in the menu and in the animation some of
272 | // these will be unnecessary but it is easier to draw everything and
273 | // rely on clipping to avoid unnecessary drawing calls.
274 | drawTitle (dc, y - nextIndex * h3 - h3);
275 | for (var i = -2; i < 3; i++)
276 | {
277 | drawItem (dc, nextIndex + i, y + h3 * i, i == 0);
278 | }
279 | }
280 |
281 | function drawTitle (dc, y)
282 | {
283 | var width = dc.getWidth ();
284 | var h3 = dc.getHeight () / 3;
285 |
286 | // Check if any of the title is visible.,
287 | if (y < -h3)
288 | {
289 | return;
290 | }
291 |
292 | dc.setColor (Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
293 | dc.fillRectangle (0, y, width, h3);
294 |
295 | if (menu.title != null)
296 | {
297 | var dims = dc.getTextDimensions (menu.title, TITLE_FONT);
298 | var h = (h3 - dims[1]) / 2;
299 | dc.setColor (Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
300 | dc.drawText (width / 2, y + h, TITLE_FONT, menu.title, Gfx.TEXT_JUSTIFY_CENTER);
301 | }
302 | }
303 |
304 | // highlight is the selected menu item that can optionally show a value.
305 | function drawItem (dc, idx, y, highlight)
306 | {
307 | var h3 = dc.getHeight () / 3;
308 |
309 | // Cannot see item if it doesn't exist or will not be visible.
310 | if (idx < 0 || idx >= menu.menuArray.size () ||
311 | menu.menuArray[idx] == null || y > dc.getHeight () || y < -h3)
312 | {
313 | return;
314 | }
315 |
316 | menu.menuArray[idx].draw (dc, y, highlight);
317 | }
318 | }
319 |
320 | class DMenuDelegate extends Ui.BehaviorDelegate
321 | {
322 | hidden var menu;
323 | hidden var userMenuDelegate;
324 |
325 | function initialize (_menu, _userMenuInputDelegate)
326 | {
327 | menu = _menu;
328 | userMenuDelegate = _userMenuInputDelegate;
329 | BehaviorDelegate.initialize ();
330 | }
331 |
332 | function onNextPage ()
333 | {
334 | menu.updateIndex (1);
335 | return true;
336 | }
337 |
338 | function onPreviousPage ()
339 | {
340 | menu.updateIndex (-1);
341 | return true;
342 | }
343 |
344 | function onKey(e) {
345 | switch(e.getKey()) {
346 | case KEY_ENTER:
347 | case KEY_START:
348 | case KEY_MENU:
349 | return onNextPage();
350 | case KEY_LAP:
351 | return onPreviousPage();
352 | }
353 | return false;
354 | }
355 |
356 | function onSelect ()
357 | {
358 | userMenuDelegate.onMenuItem (menu.selectedItem ());
359 | Ui.requestUpdate();
360 | return true;
361 | }
362 |
363 | function onBack ()
364 | {
365 | Ui.popView (Ui.SLIDE_RIGHT);
366 | return true;
367 | }
368 | }
--------------------------------------------------------------------------------
/source/QRCodeViewerView.mc:
--------------------------------------------------------------------------------
1 | using Toybox.WatchUi as Ui;
2 | using Toybox.Application as App;
3 | using Toybox.Communications as Comm;
4 | using Toybox.Graphics as Gfx;
5 |
6 | class QRCodeViewerView extends Ui.View {
7 |
8 | var qrCodeFont = [];
9 | var dcWidth = 0;
10 | var dcHeight = 0;
11 | var maxWidth = 0;
12 | var maxHeight = 0;
13 | var offsetHeight = 0;
14 | var size = 0;
15 |
16 | var requestCounter = 0;
17 | var image = null;
18 | var message = null;
19 |
20 | // Set up the responseCallback function to return an image or null
21 | function onReceiveImage(responseCode, data) {
22 | requestCounter--;
23 | System.println("Receiving image data (" + responseCode + "). Remaining " + requestCounter);
24 | if(requestCounter==0) { // handle only the last request
25 | if (responseCode == 200) {
26 | App.getApp().setStatus(:READY);
27 | System.println("QR code image loaded");
28 | image = data;
29 | } else {
30 | App.getApp().setStatus(:ERROR);
31 | image = null;
32 | var app = App.getApp();
33 | message = Ui.loadResource(Rez.Strings.error) +": " + responseCode
34 | + "\n" + Ui.loadResource(Rez.Strings.errorImage);
35 | System.println(message);
36 | }
37 | Ui.requestUpdate();
38 | }
39 | }
40 |
41 | function initialize() {
42 | System.println("View initialization...");
43 | View.initialize();
44 | }
45 |
46 | // Load your resources here
47 | function onLayout(dc) {
48 | System.println("Loading resources...");
49 | dcWidth = dc.getWidth();
50 | dcHeight = dc.getHeight();
51 |
52 | qrCodeFont = [
53 | Ui.loadResource(Rez.Fonts.qrcode1),
54 | Ui.loadResource(Rez.Fonts.qrcode2),
55 | Ui.loadResource(Rez.Fonts.qrcode3),
56 | Ui.loadResource(Rez.Fonts.qrcode4),
57 | Ui.loadResource(Rez.Fonts.qrcode5),
58 | Ui.loadResource(Rez.Fonts.qrcode6),
59 | Ui.loadResource(Rez.Fonts.qrcode7),
60 | Ui.loadResource(Rez.Fonts.qrcode8),
61 | Ui.loadResource(Rez.Fonts.qrcode9),
62 | Ui.loadResource(Rez.Fonts.qrcode10),
63 | Ui.loadResource(Rez.Fonts.qrcode11),
64 | Ui.loadResource(Rez.Fonts.qrcode12),
65 | Ui.loadResource(Rez.Fonts.qrcode13),
66 | Ui.loadResource(Rez.Fonts.qrcode14),
67 | Ui.loadResource(Rez.Fonts.qrcode15),
68 | Ui.loadResource(Rez.Fonts.qrcode16)
69 | ];
70 | System.println("resources loaded.");
71 | }
72 |
73 | // Called when this View is brought to the foreground. Restore
74 | // the state of this View and prepare it to be shown. This includes
75 | // loading resources into memory.
76 | function onShow() {
77 | System.println("View.onShow");
78 | var app = App.getApp();
79 | var id = Settings.currentId;
80 | if(id == null) {
81 | // nothing to show...
82 | System.println("View.onShow - nothing to show");
83 | return;
84 | }
85 |
86 | maxWidth = dcWidth * 0.8;
87 | maxHeight= dcHeight * 0.8;
88 | if(maxWidth == maxHeight) {
89 | // For round device... Otherwise image is hidden in corner
90 | maxWidth = maxWidth * 0.8;
91 | maxHeight = maxHeight * 0.8;
92 | }
93 |
94 | if(Settings.displayLabel) {
95 | var fontHeight = Gfx.getFontHeight(Gfx.FONT_MEDIUM);
96 | var marginTop = (dcHeight - maxHeight) / 2;
97 | if(marginTop < fontHeight) {
98 | offsetHeight = fontHeight - marginTop;
99 | maxHeight = maxHeight - offsetHeight;
100 | }
101 | }
102 |
103 | size = Settings.size;
104 | if(size == 0) {
105 | size = maxWidth size,
130 | :maxHeight=> size
131 | },
132 | method(:onReceiveImage)
133 | );
134 | app.setStatus(:WAITING_CODES);
135 | }
136 | System.println("View.onShow - end");
137 | }
138 |
139 | // Update the view
140 | function onUpdate(dc) {
141 | System.println("View.onUpdate");
142 | // Call the parent onUpdate function to redraw the layout
143 | View.onUpdate(dc);
144 |
145 | var app = App.getApp();
146 | var id = Settings.currentId;
147 | var data = getCachedData(id);
148 | if(id == null || message == null) {
149 | if(app.enabledCodes.size() == 0) {
150 | message = Ui.loadResource(Rez.Strings.errorNoQRCode);
151 | } else {
152 | message = Ui.loadResource(Rez.Strings.selectQRCode);
153 | }
154 | }
155 | dc.setColor (Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
156 | dc.clear();
157 | dc.drawText(
158 | (dc.getWidth()) / 2,
159 | (dc.getHeight()) / 2,
160 | Gfx.FONT_MEDIUM,
161 | message,
162 | Gfx.TEXT_JUSTIFY_CENTER | Gfx.TEXT_JUSTIFY_VCENTER
163 | );
164 | if(id != null && (data != null || image != null)) {
165 | System.println("Display QR code");
166 | var error = null;
167 | var imageFontSize = 1;
168 | if(data != null) {
169 | // On round watch barcode can be bigger
170 | var factor = (maxHeight==maxWidth && data.size()==1) ? 0.8 : 1;
171 | for(imageFontSize = 1;
172 | imageFontSize < qrCodeFont.size() &&
173 | (imageFontSize+1) * data[0].length() <= size/factor+0.001;
174 | imageFontSize++
175 | ) {
176 | }
177 | System.println("Code will be displayed using font size " + imageFontSize);
178 | }
179 | dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_WHITE);
180 | dc.clear();
181 | if(Settings.displayLabel) {
182 | System.println("Display label");
183 | dc.setColor (Gfx.COLOR_BLACK, Gfx.COLOR_WHITE);
184 | dc.drawText(
185 | (dc.getWidth()) / 2,
186 | offsetHeight + app.getProperty("offsetY") - 3,
187 | Gfx.FONT_MEDIUM,
188 | app.getProperty("codeLabel" + id),
189 | Gfx.TEXT_JUSTIFY_CENTER
190 | );
191 | }
192 | if(data != null) {
193 | System.println("Display cached code");
194 | dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
195 | drawQRCode(dc, data, imageFontSize);
196 | app.setStatus(:READY);
197 | } else {
198 | System.println("Display code image");
199 | dc.drawBitmap(
200 | (dc.getWidth() - image.getWidth() ) / 2,
201 | (dc.getHeight() - image.getHeight()) / 2 + offsetHeight + app.getProperty("offsetY"),
202 | image
203 | );
204 | }
205 | } else {
206 | switch(app.status) {
207 | case :READY:
208 | app.setStatus(:ERROR);
209 | case :WAITING_CODES:
210 | case :ERROR:
211 | case :UNKNOWN:
212 | break;
213 | default:
214 | System.println("Unknown status : " + app.status);
215 | app.setStatus(:UNKNOWN);
216 | }
217 | }
218 | updateStatus(dc);
219 | System.println("View updated.");
220 | }
221 |
222 | // Called when this View is removed from the screen. Save the
223 | // state of this View here. This includes freeing resources from
224 | // memory.
225 | function onHide() {
226 | }
227 |
228 | function updateStatus(dc) {
229 | var status = App.getApp().status;
230 | var color = Gfx.COLOR_RED;
231 | switch(status) {
232 | case :READY:
233 | System.println("status READY");
234 | return false;
235 | case :WAITING_CODES:
236 | System.println("status WAITING_CODES");
237 | color = Gfx.COLOR_BLUE;
238 | break;
239 | case :UNKNOWN:
240 | System.println("status UNKNOWN");
241 | color = Gfx.COLOR_ORANGE;
242 | break;
243 | case :ERROR:
244 | System.println("status ERROR");
245 | color = Gfx.COLOR_RED;
246 | break;
247 | default:
248 | System.println("Other status : " + status);
249 | color = COLOR_LT_GRAY;
250 | }
251 | dc.setColor(color, Gfx.COLOR_BLACK);
252 | dc.setPenWidth(dcHeight * 0.05);
253 | dc.drawRectangle(0, 0, dcWidth, dcHeight);
254 | return true;
255 | }
256 |
257 | function drawQRCode(dc, datas, moduleSize) {
258 | if(!(datas instanceof Toybox.Lang.Array)) {
259 | return;
260 | }
261 | var app = App.getApp();
262 | var nbLines = datas.size();
263 | if(nbLines == 1) {
264 | var barcodeHeight = Settings.barcodeHeight;
265 | if(barcodeHeight == 0) {
266 | barcodeHeight = dc.getHeight()/10;
267 | }
268 | nbLines = barcodeHeight / moduleSize;
269 | }
270 | var offsetY = (dc.getHeight() - (nbLines-1) * 4 * moduleSize) / 2 + offsetHeight + Settings.offsetY;
271 | for(var i=0; i