This commit is contained in:
Your Name
2026-08-23 11:43:31 +03:00
parent 3ca84a252d
commit 7d54e9e6f9
6 changed files with 74 additions and 541 deletions
+2 -2
View File
@@ -3,6 +3,7 @@
This is source code for "Percentage" pebble app. It tracks success/fail rates of 9 items. It was designed in cloudpebble.
<img src="screenshots/pic1.png" height=400>
<img src="screenshots/pic2.png" height=400>
## Features
@@ -20,5 +21,4 @@ This is source code for "Percentage" pebble app. It tracks success/fail rates of
## Resources
* Pixelorama project files (Blue/Red/Green)
* C code
* Silkscreen font
* C code
+6
View File
@@ -0,0 +1,6 @@
# TODO
* Configurable ORANGE/RED limits
* RED & GREEN theme
* Automatic smaller font to allow more characters?
* add "fail/success" display system (red/green)
+5 -36
View File
@@ -12,42 +12,11 @@
"displayName": "Percentage",
"enableMultiJS": true,
"messageKeys": [
"ITEM_1",
"ITEM_2",
"ITEM_3",
"ITEM_4",
"ITEM_5",
"ITEM_6",
"ITEM_7",
"ITEM_8",
"ITEM_9",
"ITEM_1_SUCCESS",
"ITEM_1_FAIL",
"ITEM_1_PERCENTAGE",
"ITEM_2_SUCCESS",
"ITEM_2_FAIL",
"ITEM_2_PERCENTAGE",
"ITEM_3_SUCCESS",
"ITEM_3_FAIL",
"ITEM_3_PERCENTAGE",
"ITEM_4_SUCCESS",
"ITEM_4_FAIL",
"ITEM_4_PERCENTAGE",
"ITEM_5_SUCCESS",
"ITEM_5_FAIL",
"ITEM_5_PERCENTAGE",
"ITEM_6_SUCCESS",
"ITEM_6_FAIL",
"ITEM_6_PERCENTAGE",
"ITEM_7_SUCCESS",
"ITEM_7_FAIL",
"ITEM_7_PERCENTAGE",
"ITEM_8_SUCCESS",
"ITEM_8_FAIL",
"ITEM_8_PERCENTAGE",
"ITEM_9_SUCCESS",
"ITEM_9_FAIL",
"ITEM_9_PERCENTAGE"
"ITEM_NAME",
"ITEM_SUCCESS",
"ITEM_FAIL",
"ITEM_PERCENTAGE",
"ITEM_REMOVE"
],
"projectType": "native",
"resources": {
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

+53 -237
View File
@@ -1,4 +1,6 @@
#include <pebble.h>
#include <ctype.h>
#include "items.h"
#include "src/c/scrolllayer.h"
@@ -41,281 +43,95 @@ item_list_t *items_get() {
return &s_items;
}
// ------------ HELPERS ------------
static int str_case_cmp(const char *a, const char *b, size_t n) {
for (size_t i = 0; i < n; i++) {
unsigned char ca = (unsigned char)a[i];
unsigned char cb = (unsigned char)b[i];
int lca = tolower(ca);
int lcb = tolower(cb);
if (lca != lcb) {
return lca - lcb;
}
if (ca == '\0') {
return 0;
}
}
return 0;
}
// ------------ PHONE ------------
static void update_items(item_list_t *items, const item_list_t *buffer) {
if (!items || !buffer) {
static void update_items(item_list_t *items, const item_t *item, bool remove) {
if (!items || !item || item->name[0] == '\0') {
return;
}
// Check existing items
// Find existing item
for (int i = 0; i < MAX_ITEMS; i++) {
if (items->items[i].name[0] == '\0') {
continue;
}
bool found = false;
for (int j = 0; j < MAX_ITEMS; j++) {
if (buffer->items[j].name[0] != '\0' && strcmp(items->items[i].name, buffer->items[j].name) == 0) {
// Item still exists
items->items[i].show_percentage = buffer->items[j].show_percentage;
found = true;
break;
if (items->items[i].name[0] != '\0' && str_case_cmp(items->items[i].name, item->name, MAX_CHARACTERS) == 0) {
if (remove) {
memset(&items->items[i], 0, sizeof(items->items[i]));
}
else {
items->items[i].show_percentage = item->show_percentage;
}
}
// Item no longer exists
if (!found) {
memset(&items->items[i], 0, sizeof(items->items[i]));
return;
}
}
// Add items
for (int i = 0; i < MAX_ITEMS; i++) {
if (buffer->items[i].name[0] == '\0') {
continue;
}
bool found = false;
for (int j = 0; j < MAX_ITEMS; j++) {
if (items->items[j].name[0] != '\0' && strcmp(items->items[j].name, buffer->items[i].name) == 0) {
found = true;
// Not found
if (!remove) {
for (int i = 0; i < MAX_ITEMS; i++) {
if (items->items[i].name[0] == '\0') {
items->items[i] = *item;
break;
}
}
if (!found) {
for (int j = 0; j < MAX_ITEMS; j++) {
if (items->items[j].name[0] == '\0') {
memcpy(&items->items[j], &buffer->items[i], sizeof(items->items[j]));
break;
}
}
}
}
items_organize(items);
}
static void inbox_received_handler(DictionaryIterator *iter, void *context) {
// Remove scroll layer items
scroll_layer_remove_items();
Tuple *tuple;
item_list_t item_buffer;
Tuple *tuple;;
item_t item;
memset(&item, 0, sizeof(item));
bool remove = false;
// Get the item 1
tuple = dict_find(iter, MESSAGE_KEY_ITEM_1);
tuple = dict_find(iter, MESSAGE_KEY_ITEM_NAME);
if (tuple) {
strncpy(item_buffer.items[0].name, tuple->value->cstring, MAX_CHARACTERS);
strncpy(item.name, tuple->value->cstring, MAX_CHARACTERS);
item.name[MAX_CHARACTERS - 1] = '\0';
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_1_SUCCESS);
tuple = dict_find(iter, MESSAGE_KEY_ITEM_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[0].successes = success;
item.successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_1_FAIL);
tuple = dict_find(iter, MESSAGE_KEY_ITEM_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[0].fails = fail;
item.fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_1_PERCENTAGE);
tuple = dict_find(iter, MESSAGE_KEY_ITEM_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[0].show_percentage = show_percentage;
item.show_percentage = show_percentage;
}
// Get the item 2
tuple = dict_find(iter, MESSAGE_KEY_ITEM_2);
// Add or remove
tuple = dict_find(iter, MESSAGE_KEY_ITEM_REMOVE);
if (tuple) {
strncpy(item_buffer.items[1].name, tuple->value->cstring, MAX_CHARACTERS);
remove = tuple->value->int32 != 0;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_2_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[1].successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_2_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[1].fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_2_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[1].show_percentage = show_percentage;
}
// Get the item 3
tuple = dict_find(iter, MESSAGE_KEY_ITEM_3);
if (tuple) {
strncpy(item_buffer.items[2].name, tuple->value->cstring, MAX_CHARACTERS);
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_3_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[2].successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_3_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[2].fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_3_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[2].show_percentage = show_percentage;
}
// Get the item 4
tuple = dict_find(iter, MESSAGE_KEY_ITEM_4);
if (tuple) {
strncpy(item_buffer.items[3].name, tuple->value->cstring, MAX_CHARACTERS);
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_4_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[3].successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_4_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[3].fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_4_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[3].show_percentage = show_percentage;
}
// Get the item 5
tuple = dict_find(iter, MESSAGE_KEY_ITEM_5);
if (tuple) {
strncpy(item_buffer.items[4].name, tuple->value->cstring, MAX_CHARACTERS);
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_5_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[4].successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_5_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[4].fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_5_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[4].show_percentage = show_percentage;
}
// Get the item 6
tuple = dict_find(iter, MESSAGE_KEY_ITEM_6);
if (tuple) {
strncpy(item_buffer.items[5].name, tuple->value->cstring, MAX_CHARACTERS);
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_6_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[5].successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_6_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[5].fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_6_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[5].show_percentage = show_percentage;
}
// Get the item 7
tuple = dict_find(iter, MESSAGE_KEY_ITEM_7);
if (tuple) {
strncpy(item_buffer.items[6].name, tuple->value->cstring, MAX_CHARACTERS);
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_7_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[6].successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_7_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[6].fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_7_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[6].show_percentage = show_percentage;
}
// Get the item 8
tuple = dict_find(iter, MESSAGE_KEY_ITEM_8);
if (tuple) {
strncpy(item_buffer.items[7].name, tuple->value->cstring, MAX_CHARACTERS);
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_8_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[7].successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_8_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[7].fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_8_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[7].show_percentage = show_percentage;
}
// Get the item 9
tuple = dict_find(iter, MESSAGE_KEY_ITEM_9);
if (tuple) {
strncpy(item_buffer.items[8].name, tuple->value->cstring, MAX_CHARACTERS);
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_9_SUCCESS);
if (tuple) {
int success = atoi(tuple->value->cstring);
if (success < 0) { success = 0; }
item_buffer.items[8].successes = success;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_9_FAIL);
if (tuple) {
int fail = atoi(tuple->value->cstring);
if (fail < 0) { fail = 0; }
item_buffer.items[8].fails = fail;
}
tuple = dict_find(iter, MESSAGE_KEY_ITEM_9_PERCENTAGE);
if (tuple) {
bool show_percentage = tuple->value->int32 != 0;
item_buffer.items[8].show_percentage = show_percentage;
}
// Organize buffer
items_organize(&item_buffer);
// Update list from buffer
update_items(&s_items, &item_buffer);
update_items(&s_items, &item, remove);
// Save the items to NVM
items_organize(&s_items);
+8 -266
View File
@@ -5,7 +5,7 @@ module.exports = [
},
{
"type": "text",
"defaultValue": "Character limit is 10. If numbers go higher than 1000, use percentage."
"defaultValue": "Add/remove up to 9 items. Character limit is 10. If numbers go higher than 1000, use percentage."
},
{
@@ -13,293 +13,35 @@ module.exports = [
"items": [
{
"type": "heading",
"defaultValue": "Item 1"
"defaultValue": "Item"
},
{
"type": "input",
"messageKey": "ITEM_1",
"messageKey": "ITEM_NAME",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_1_SUCCESS",
"messageKey": "ITEM_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_1_FAIL",
"messageKey": "ITEM_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_1_PERCENTAGE",
"messageKey": "ITEM_PERCENTAGE",
"label": "Show percentage",
"defaultValue": false
}
]
},
{
"type": "section",
"items": [
{
"type": "heading",
"defaultValue": "Item 2"
},
{
"type": "input",
"messageKey": "ITEM_2",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_2_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_2_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_2_PERCENTAGE",
"label": "Show percentage",
"defaultValue": false
}
]
},
{
"type": "section",
"items": [
{
"type": "heading",
"defaultValue": "Item 3"
},
{
"type": "input",
"messageKey": "ITEM_3",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_3_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_3_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_3_PERCENTAGE",
"label": "Show percentage",
"defaultValue": false
}
]
},
{
"type": "section",
"items": [
{
"type": "heading",
"defaultValue": "Item 4"
},
{
"type": "input",
"messageKey": "ITEM_4",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_4_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_4_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_4_PERCENTAGE",
"label": "Show percentage",
"defaultValue": false
}
]
},
{
"type": "section",
"items": [
{
"type": "heading",
"defaultValue": "Item 5"
},
{
"type": "input",
"messageKey": "ITEM_5",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_5_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_5_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_5_PERCENTAGE",
"label": "Show percentage",
"defaultValue": false
}
]
},
{
"type": "section",
"items": [
{
"type": "heading",
"defaultValue": "Item 6"
},
{
"type": "input",
"messageKey": "ITEM_6",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_6_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_6_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_6_PERCENTAGE",
"label": "Show percentage",
"defaultValue": false
}
]
},
{
"type": "section",
"items": [
{
"type": "heading",
"defaultValue": "Item 7"
},
{
"type": "input",
"messageKey": "ITEM_7",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_7_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_7_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_7_PERCENTAGE",
"label": "Show percentage",
"defaultValue": false
}
]
},
{
"type": "section",
"items": [
{
"type": "heading",
"defaultValue": "Item 8"
},
{
"type": "input",
"messageKey": "ITEM_8",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_8_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_8_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_8_PERCENTAGE",
"label": "Show percentage",
"defaultValue": false
}
]
},
{
"type": "section",
"items": [
{
"type": "heading",
"defaultValue": "Item 9"
},
{
"type": "input",
"messageKey": "ITEM_9",
"defaultValue": ""
},
{
"type": "input",
"messageKey": "ITEM_9_SUCCESS",
"label": "Success",
"defaultValue": "0"
},
{
"type": "input",
"messageKey": "ITEM_9_FAIL",
"label": "Fail",
"defaultValue": "0"
},
{
"type": "toggle",
"messageKey": "ITEM_9_PERCENTAGE",
"label": "Show percentage",
"messageKey": "ITEM_REMOVE",
"label": "Remove item",
"defaultValue": false
}
]