Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson
2024-12-12 16:43:03 -08:00
committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "applib/app.h"
#include "applib/rockyjs/rocky.h"
#include "applib/ui/app_window_stack.h"
#include "resource/resource_ids.auto.h"
void tictoc_main(void) {
// Push a window so we don't exit
Window *window = window_create();
app_window_stack_push(window, false/*animated*/);
#if CAPABILITY_HAS_JAVASCRIPT
rocky_event_loop_with_system_resource(RESOURCE_ID_JS_TICTOC);
#else
app_event_loop();
#endif
}

View File

@@ -0,0 +1,258 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "watch_model.h"
#include "applib/app.h"
#include "applib/fonts/fonts.h"
#include "applib/graphics/gpath.h"
#include "applib/graphics/graphics_circle.h"
#include "applib/graphics/text.h"
#include "util/trig.h"
#include "applib/ui/app_window_stack.h"
#include "applib/ui/ui.h"
#include "kernel/pbl_malloc.h"
#include "process_state/app_state/app_state.h"
#include "resource/resource_ids.auto.h"
#include "services/common/clock.h"
#include "util/time/time.h"
typedef struct {
Window window;
GFont text_font;
ClockModel clock_model;
GBitmap *bg_bitmap;
GPath *hour_path;
GPath *minute_path;
} MultiWatchData;
static const GPathInfo HOUR_PATH_INFO = {
.num_points = 9,
.points = (GPoint[]) {
{-5, 10}, {-2, 10}, {-2, 15}, {2, 15}, {2, 10}, {5, 10}, {5, -51}, {0, -56}, {-5, -51},
},
};
static const GPathInfo MINUTE_PATH_INFO = {
.num_points = 5,
.points = (GPoint[]) {
{-5, 10}, {5, 10}, {5, -61}, {0, -66}, {-5, -61},
},
};
void watch_model_handle_change(ClockModel *model) {
MultiWatchData *data = app_state_get_user_data();
data->clock_model = *model;
layer_mark_dirty(window_get_root_layer(&data->window));
}
static GPointPrecise prv_gpoint_from_polar(const GPointPrecise *center, uint32_t distance,
int32_t angle) {
return gpoint_from_polar_precise(center, distance << GPOINT_PRECISE_PRECISION, angle);
}
static void prv_graphics_draw_centered_text(GContext *ctx, const GSize *max_size,
const GPoint *center, const GFont font,
const GColor color, const char *text) {
GSize text_size = app_graphics_text_layout_get_content_size(
text, font, (GRect) { .size = *max_size }, GTextOverflowModeFill, GTextAlignmentCenter);
GPoint text_center = *center;
text_center.x -= text_size.w / 2 + 1;
text_center.y -= text_size.h * 2 / 3;
graphics_context_set_text_color(ctx, color);
graphics_draw_text(ctx, text, font, (GRect) { .origin = text_center, .size = text_size },
GTextOverflowModeFill, GTextAlignmentCenter, NULL);
}
static void prv_draw_watch_hand_rounded(GContext *ctx, ClockHand *hand, GPointPrecise center) {
GPointPrecise watch_hand_end = prv_gpoint_from_polar(&center, hand->length, hand->angle);
if (hand->style == CLOCK_HAND_STYLE_ROUNDED_WITH_HIGHLIGHT) {
graphics_context_set_stroke_color(ctx, GColorWhite);
graphics_line_draw_precise_stroked_aa(ctx, center, watch_hand_end, hand->thickness + 2);
}
graphics_context_set_stroke_color(ctx, hand->color);
graphics_line_draw_precise_stroked_aa(ctx, center, watch_hand_end, hand->thickness);
}
static void prv_draw_watch_hand_pointed(GContext *ctx, ClockHand *hand, GPoint center,
GPath *path) {
graphics_context_set_fill_color(ctx, hand->color);
gpath_rotate_to(path, hand->angle);
gpath_move_to(path, center);
gpath_draw_filled(ctx, path);
}
static void prv_draw_watch_hand(GContext *ctx, ClockHand *hand, GPointPrecise center, GPath *path) {
switch (hand->style) {
case CLOCK_HAND_STYLE_POINTED:
prv_draw_watch_hand_pointed(ctx, hand, GPointFromGPointPrecise(center), path);
case CLOCK_HAND_STYLE_ROUNDED:
case CLOCK_HAND_STYLE_ROUNDED_WITH_HIGHLIGHT:
default:
prv_draw_watch_hand_rounded(ctx, hand, center);
break;
}
}
static GPointPrecise prv_get_clock_center_point(ClockLocation location, const GRect *bounds) {
GPoint imprecise_center_point = {0};
switch (location) {
case CLOCK_LOCATION_TOP:
imprecise_center_point = (GPoint) {
.x = bounds->size.w / 2,
.y = bounds->size.h / 4,
};
case CLOCK_LOCATION_RIGHT:
imprecise_center_point = (GPoint) {
.x = bounds->size.w * 3 / 4 - 5,
.y = bounds->size.h / 2,
};
case CLOCK_LOCATION_BOTTOM:
imprecise_center_point = (GPoint) {
.x = bounds->size.w / 2,
.y = bounds->size.h * 3 / 4 + 6,
};
case CLOCK_LOCATION_LEFT:
imprecise_center_point = (GPoint) {
.x = bounds->size.w / 4 + 4,
.y = bounds->size.h / 2,
};
default:
// aiming for width / 2 - 0.5 to get the true center
return (GPointPrecise) {
.x = { .integer = bounds->size.w / 2 - 1, .fraction = 3 },
.y = { .integer = bounds->size.h / 2 - 1, .fraction = 3 }
};
}
return GPointPreciseFromGPoint(imprecise_center_point);
}
static void prv_draw_clock_face(GContext *ctx, ClockFace *face) {
MultiWatchData *data = app_state_get_user_data();
const GRect *bounds = &window_get_root_layer(&data->window)->bounds;
const GPointPrecise center = prv_get_clock_center_point(face->location, bounds);
// Draw hands.
// TODO: Need to do something about the static GPaths used for watchands. This is very inflexible.
prv_draw_watch_hand(ctx, &face->hour_hand, center, data->hour_path);
prv_draw_watch_hand(ctx, &face->minute_hand, center, data->minute_path);
// Draw bob.
GRect bob_rect = (GRect) {
.size = GSize(face->bob_radius * 2, face->bob_radius * 2)
};
GRect bob_center_rect = (GRect) {
.size = GSize(face->bob_center_radius * 2, face->bob_center_radius * 2)
};
grect_align(&bob_rect, bounds, GAlignCenter, false /* clips */);
grect_align(&bob_center_rect, bounds, GAlignCenter, false /* clips */);
graphics_context_set_fill_color(ctx, face->bob_color);
graphics_fill_oval(ctx, bob_rect, GOvalScaleModeFitCircle);
graphics_context_set_fill_color(ctx, face->bob_center_color);
graphics_fill_oval(ctx, bob_center_rect, GOvalScaleModeFitCircle);
}
static void prv_draw_non_local_clock(GContext *ctx, NonLocalClockFace *clock) {
// TODO: The non-local clock text is currently baked into the background image.
prv_draw_clock_face(ctx, &clock->face);
}
static void prv_update_proc(Layer *layer, GContext *ctx) {
MultiWatchData *data = app_state_get_user_data();
const GRect *bounds = &layer->bounds;
// Background.
graphics_draw_bitmap_in_rect(ctx, data->bg_bitmap, bounds);
ClockModel *clock_model = &data->clock_model;
// Watch text. TODO: Locate the text properly, rather than hard-coding.
if (clock_model->text.location == CLOCK_TEXT_LOCATION_BOTTOM) {
const GPoint point = (GPoint) { 90, 140 };
prv_graphics_draw_centered_text(ctx, &bounds->size, &point, data->text_font,
clock_model->text.color, clock_model->text.buffer);
} else if (clock_model->text.location == CLOCK_TEXT_LOCATION_LEFT) {
const GRect box = (GRect) { .origin = GPoint(25, 78), .size = bounds->size };
graphics_draw_text(ctx, clock_model->text.buffer, data->text_font, box,
GTextOverflowModeFill, GTextAlignmentLeft, NULL);
}
// Draw the clocks.
for (uint32_t i = 0; i < clock_model->num_non_local_clocks; ++i) {
prv_draw_non_local_clock(ctx, &clock_model->non_local_clock[i]);
}
prv_draw_clock_face(ctx, &clock_model->local_clock);
}
static void prv_window_load(Window *window) {
MultiWatchData *data = app_state_get_user_data();
layer_set_update_proc(window_get_root_layer(window), prv_update_proc);
watch_model_init();
data->hour_path = gpath_create(&HOUR_PATH_INFO);
data->minute_path = gpath_create(&MINUTE_PATH_INFO);
data->bg_bitmap = gbitmap_create_with_resource(data->clock_model.bg_bitmap_id);
}
static void prv_window_unload(Window *window) {
MultiWatchData *data = app_state_get_user_data();
gpath_destroy(data->hour_path);
gpath_destroy(data->minute_path);
gbitmap_destroy(data->bg_bitmap);
}
static void prv_app_did_focus(bool did_focus) {
if (!did_focus) {
return;
}
app_focus_service_unsubscribe();
watch_model_start_intro();
}
static void prv_init(void) {
MultiWatchData *data = app_zalloc_check(sizeof(*data));
app_state_set_user_data(data);
data->text_font = fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD);
window_init(&data->window, "TicToc");
window_set_window_handlers(&data->window, &(WindowHandlers) {
.load = prv_window_load,
.unload = prv_window_unload,
});
const bool animated = true;
app_window_stack_push(&data->window, animated);
app_focus_service_subscribe_handlers((AppFocusHandlers) {
.did_focus = prv_app_did_focus,
});
}
static void prv_deinit(void) {
MultiWatchData *data = app_state_get_user_data();
window_destroy(&data->window);
watch_model_cleanup();
}
void tictoc_main(void) {
prv_init();
app_event_loop();
prv_deinit();
}

View File

@@ -0,0 +1,212 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "watch_model.h"
#include "util/trig.h"
#include "applib/app_watch_info.h"
#include "applib/pbl_std/pbl_std.h"
#include "applib/tick_timer_service.h"
#include "resource/resource_ids.auto.h"
#include "syscall/syscall.h"
#include "util/time/time.h"
#include <ctype.h>
static void prv_calculate_hand_angles(struct tm *tick_time, int32_t *hour_angle,
int32_t *minute_angle) {
*hour_angle = (tick_time->tm_hour % 12) * TRIG_MAX_ANGLE / 12
+ tick_time->tm_min * TRIG_MAX_ANGLE / 60 / 12;
*minute_angle = tick_time->tm_min * TRIG_MAX_ANGLE / 60;
}
static ClockFace prv_local_clock_face_default(struct tm *tick_time) {
int32_t hour_angle, minute_angle;
prv_calculate_hand_angles(tick_time, &hour_angle, &minute_angle);
// TODO: Don't return by value. This thing is massive.
return (ClockFace) {
.hour_hand = {
.angle = hour_angle,
.backwards_extension = LOCAL_HOUR_HAND_BACK_EXT_DEFAULT,
.color = LOCAL_HOUR_HAND_COLOR_DEFAULT,
.length = LOCAL_HOUR_HAND_LENGTH_DEFAULT,
.style = CLOCK_HAND_STYLE_ROUNDED,
.thickness = LOCAL_HOUR_HAND_THICKNESS_DEFAULT,
},
.minute_hand = {
.angle = minute_angle,
.backwards_extension = LOCAL_MINUTE_HAND_BACK_EXT_DEFAULT,
.color = LOCAL_MINUTE_HAND_COLOR_DEFAULT,
.length = LOCAL_MINUTE_HAND_LENGTH_DEFAULT,
.style = CLOCK_HAND_STYLE_ROUNDED,
.thickness = LOCAL_MINUTE_HAND_THICKNESS_DEFAULT,
},
.bob_radius = LOCAL_BOB_RADIUS_DEFAULT,
.bob_color = LOCAL_BOB_COLOR_DEFAULT,
.location = CLOCK_LOCATION_CENTER,
};
}
static NonLocalClockFace prv_configure_non_local_clock_face(int32_t utc_offset, const char *text,
GColor text_color, GColor hand_color,
ClockTextLocation location) {
time_t t = rtc_get_time();
struct tm* tick_time = pbl_override_gmtime(&t);
tick_time->tm_hour += utc_offset; // TODO check if this works properly
int32_t hour_angle, minute_angle;
prv_calculate_hand_angles(tick_time, &hour_angle, &minute_angle);
// TODO: Don't return by value. This thing is massive.
NonLocalClockFace non_local_clock = (NonLocalClockFace) {
.face = {
.hour_hand = {
.length = NON_LOCAL_HOUR_HAND_LENGTH_DEFAULT,
.thickness = NON_LOCAL_HOUR_HAND_WIDTH_DEFAULT,
.backwards_extension = 0,
.angle = hour_angle,
.color = hand_color,
.style = CLOCK_HAND_STYLE_ROUNDED,
},
.minute_hand = {
.length = NON_LOCAL_MINUTE_HAND_LENGTH_DEFAULT,
.thickness = NON_LOCAL_MINUTE_HAND_WIDTH_DEFAULT,
.backwards_extension = 0,
.angle = minute_angle,
.color = hand_color,
.style = CLOCK_HAND_STYLE_ROUNDED,
},
.location = location,
},
.text_color = text_color,
};
strncpy(non_local_clock.buffer, text, sizeof(non_local_clock.buffer));
return non_local_clock;
}
// Configure the text displayed on the clock.
static ClockText prv_configure_clock_text(ClockTextType type, ClockTextLocation location,
GColor color, struct tm *tick_time) {
ClockText text = (ClockText) {
.location = location,
.color = color,
};
if (type == CLOCK_TEXT_TYPE_DATE) {
strftime(text.buffer, sizeof(text.buffer), "%a %d", tick_time);
} else if (type == CLOCK_TEXT_TYPE_TIME) {
strftime(text.buffer, sizeof(text.buffer), "$l:%M%P", tick_time);
}
for (uint32_t i = 0; i < sizeof(text.buffer); i++) {
text.buffer[i] = toupper((unsigned char)text.buffer[i]);
}
// TODO: Don't return a struct
return text;
}
static ClockModel prv_clock_model_default(struct tm *tick_time) {
// Create a generic model and configure a default clock.
ClockModel model;
model.local_clock = prv_local_clock_face_default(tick_time);
// Add watch-specific details.
const WatchInfoColor watch_color = sys_watch_info_get_color();
switch (watch_color) {
case WATCH_INFO_COLOR_TIME_ROUND_BLACK_14:
model.local_clock.minute_hand.color = GColorBlue;
model.text = prv_configure_clock_text(CLOCK_TEXT_TYPE_DATE, CLOCK_TEXT_LOCATION_LEFT,
GColorWhite, tick_time);
model.bg_bitmap_id = RESOURCE_ID_MULTIWATCH_BACKGROUND_14MM_BLACK_RED;
break;
case WATCH_INFO_COLOR_TIME_ROUND_BLACK_20:
model.num_non_local_clocks = 2;
model.non_local_clock[0] = prv_configure_non_local_clock_face(-7, "LA", GColorDarkGray,
GColorWhite,
CLOCK_LOCATION_LEFT);
model.non_local_clock[1] = prv_configure_non_local_clock_face(2, "PAR", GColorDarkGray,
GColorWhite,
CLOCK_LOCATION_RIGHT);
model.text = prv_configure_clock_text(CLOCK_TEXT_TYPE_DATE, CLOCK_TEXT_LOCATION_BOTTOM,
GColorWhite, tick_time);
model.bg_bitmap_id = RESOURCE_ID_MULTIWATCH_BACKGROUND_20MM_BLACK;
break;
case WATCH_INFO_COLOR_TIME_ROUND_SILVER_14:
model.local_clock.hour_hand.style = CLOCK_HAND_STYLE_POINTED;
model.local_clock.hour_hand.color = GColorBlack;
model.local_clock.minute_hand.style = CLOCK_HAND_STYLE_POINTED;
model.local_clock.minute_hand.color = GColorCadetBlue;
model.text = prv_configure_clock_text(CLOCK_TEXT_TYPE_DATE, CLOCK_TEXT_LOCATION_BOTTOM,
GColorDarkGray, tick_time);
model.bg_bitmap_id = RESOURCE_ID_MULTIWATCH_BACKGROUND_14MM_SILVER;
break;
case WATCH_INFO_COLOR_TIME_ROUND_SILVER_20:
model.local_clock.hour_hand.style = CLOCK_HAND_STYLE_POINTED;
model.local_clock.minute_hand.style = CLOCK_HAND_STYLE_POINTED;
model.local_clock.minute_hand.color = GColorRed;
model.local_clock.bob_color = GColorBlack;
model.bg_bitmap_id = RESOURCE_ID_MULTIWATCH_BACKGROUND_20MM_SILVER_BROWN;
break;
case WATCH_INFO_COLOR_TIME_ROUND_ROSE_GOLD_14:
default:
model.local_clock.bob_center_color = GColorOrange;
model.local_clock.minute_hand.color = GColorWhite;
model.local_clock.minute_hand.thickness = 2;
model.local_clock.minute_hand.length = 54;
model.local_clock.hour_hand.color = GColorBlack;
model.local_clock.hour_hand.thickness = 8;
model.local_clock.hour_hand.length = 39;
model.local_clock.bob_radius = 7;
model.local_clock.bob_center_radius = 3;
model.local_clock.bob_color = GColorWhite;
model.bg_bitmap_id = RESOURCE_ID_MULTIWATCH_BACKGROUND_14MM_ROSE_GOLD;
break;
}
// disable timezones until they can be configured by the user
model.num_non_local_clocks = 0;
// TODO: Don't return a struct here
return model;
}
static void prv_handle_time_update(struct tm *tick_time, TimeUnits units_changed) {
ClockModel model = prv_clock_model_default(tick_time);
watch_model_handle_change(&model);
}
void watch_model_cleanup() {
tick_timer_service_unsubscribe();
}
static void prv_intro_animation_finished(Animation *animation) {
const time_t t = rtc_get_time();
prv_handle_time_update(pbl_override_localtime(&t), (TimeUnits)0xff);
tick_timer_service_subscribe(MINUTE_UNIT, prv_handle_time_update);
}
void watch_model_start_intro() {
prv_intro_animation_finished(NULL);
}
void watch_model_init(void) {
const time_t t = rtc_get_time();
struct tm *tick_time = pbl_override_localtime(&t);
ClockModel model = prv_clock_model_default(tick_time);
watch_model_handle_change(&model);
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "applib/graphics/gtypes.h"
#include <inttypes.h>
#define LOCAL_HOUR_HAND_LENGTH_DEFAULT 51
#define LOCAL_HOUR_HAND_THICKNESS_DEFAULT 6
#define LOCAL_HOUR_HAND_COLOR_DEFAULT GColorWhite
#define LOCAL_HOUR_HAND_BACK_EXT_DEFAULT 0
#define LOCAL_MINUTE_HAND_LENGTH_DEFAULT 58
#define LOCAL_MINUTE_HAND_THICKNESS_DEFAULT 6
#define LOCAL_MINUTE_HAND_COLOR_DEFAULT GColorWhite
#define LOCAL_MINUTE_HAND_BACK_EXT_DEFAULT 0
#define LOCAL_BOB_RADIUS_DEFAULT 6
#define LOCAL_BOB_COLOR_DEFAULT GColorRed
#define NON_LOCAL_HOUR_HAND_LENGTH_DEFAULT 11
#define NON_LOCAL_HOUR_HAND_WIDTH_DEFAULT 3
#define NON_LOCAL_MINUTE_HAND_LENGTH_DEFAULT 21
#define NON_LOCAL_MINUTE_HAND_WIDTH_DEFAULT 3
#define NUM_NON_LOCAL_CLOCKS 3
#define GLANCE_TIME_OUT_MS 8000
typedef enum {
CLOCK_TEXT_TYPE_NONE = 0,
CLOCK_TEXT_TYPE_TIME,
CLOCK_TEXT_TYPE_DATE,
} ClockTextType;
typedef enum {
CLOCK_TEXT_LOCATION_NONE = 0,
CLOCK_TEXT_LOCATION_BOTTOM,
CLOCK_TEXT_LOCATION_LEFT,
} ClockTextLocation;
typedef enum {
CLOCK_HAND_STYLE_ROUNDED = 0,
CLOCK_HAND_STYLE_ROUNDED_WITH_HIGHLIGHT,
CLOCK_HAND_STYLE_POINTED,
} ClockHandStyle;
typedef enum {
CLOCK_LOCATION_CENTER,
CLOCK_LOCATION_LEFT,
CLOCK_LOCATION_BOTTOM,
CLOCK_LOCATION_RIGHT,
CLOCK_LOCATION_TOP,
} ClockLocation;
typedef struct {
uint16_t length;
uint16_t thickness;
uint16_t backwards_extension;
int32_t angle;
GColor color;
ClockHandStyle style;
} ClockHand;
typedef struct {
ClockHand hour_hand;
ClockHand minute_hand;
uint16_t bob_radius;
uint16_t bob_center_radius;
GColor bob_color;
GColor bob_center_color;
ClockLocation location;
} ClockFace;
typedef struct {
ClockFace face;
char buffer[4];
int32_t utc_offest;
GColor text_color;
} NonLocalClockFace;
typedef struct {
ClockTextType type;
ClockTextLocation location;
char buffer[10]; // FIXME magic number
GColor color;
} ClockText;
typedef struct {
ClockFace local_clock;
uint32_t num_non_local_clocks;
NonLocalClockFace non_local_clock[NUM_NON_LOCAL_CLOCKS];
ClockText text;
uint32_t bg_bitmap_id;
} ClockModel;
void watch_model_init(void);
void watch_model_handle_change(ClockModel *model);
void watch_model_start_intro(void);
void watch_model_cleanup(void);

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "tictoc.h"
#include "resource/resource_ids.auto.h"
const PebbleProcessMd* tictoc_get_app_info(void) {
static const PebbleProcessMdSystem s_app_md = {
.common = {
// UUID: 8f3c8686-31a1-4f5f-91f5-01600c9bdc59
.uuid = { 0x8f, 0x3c, 0x86, 0x86, 0x31, 0xa1, 0x4f, 0x5f,
0x91, 0xf5, 0x01, 0x60, 0x0c, 0x9b, 0xdc, 0x59 },
.main_func = tictoc_main,
.process_type = ProcessTypeWatchface,
#if CAPABILITY_HAS_JAVASCRIPT && !defined(PLATFORM_SPALDING)
.is_rocky_app = true,
#endif
},
.icon_resource_id = RESOURCE_ID_MENU_ICON_TICTOC_WATCH,
.name = "TicToc",
};
return (const PebbleProcessMd*) &s_app_md;
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "process_management/pebble_process_md.h"
void tictoc_main(void);
const PebbleProcessMd* tictoc_get_app_info(void);