Beispiel #1
0
static void window_load(Window *window) {
  SprinklesAppData *data = window_get_user_data(window);

  Layer *root_layer = window_get_root_layer(window);
  const GRect root_layer_bounds = layer_get_bounds(root_layer);

  data->homer_bitmap = gbitmap_create_with_resource(RESOURCE_ID_HOMER);

  GRect homer_bitmap_layer_frame = root_layer_bounds;
  homer_bitmap_layer_frame.size = gbitmap_get_bounds(data->homer_bitmap).size;
  grect_align(&homer_bitmap_layer_frame, &root_layer_bounds, GAlignBottom, true /* clip */);

  data->homer_layer = bitmap_layer_create(homer_bitmap_layer_frame);
  bitmap_layer_set_bitmap(data->homer_layer, data->homer_bitmap);
  bitmap_layer_set_compositing_mode(data->homer_layer, GCompOpSet);
  layer_add_child(root_layer, bitmap_layer_get_layer(data->homer_layer));

  const int16_t date_layer_width = PBL_IF_RECT_ELSE(41, 58);
  const int16_t date_layer_height = 17;
  GRect date_layer_frame = (GRect) { .size = GSize(date_layer_width, date_layer_height) };
  grect_align(&date_layer_frame, &root_layer_bounds, GAlignRight, true /* clip */);
  data->date_layer = layer_create(date_layer_frame);
  layer_set_update_proc(data->date_layer, prv_date_layer_update_proc);
  layer_add_child(root_layer, data->date_layer);

  data->homer_eyes_layer = layer_create(homer_bitmap_layer_frame);
  layer_set_update_proc(data->homer_eyes_layer, prv_homer_eyes_layer_update_proc);
  layer_add_child(root_layer, data->homer_eyes_layer);

  data->donut_bitmap = gbitmap_create_with_resource(RESOURCE_ID_DONUT);

  data->hands_layer = layer_create(root_layer_bounds);
  layer_set_update_proc(data->hands_layer, prv_hands_layer_update_proc);
  layer_add_child(root_layer, data->hands_layer);

  const time_t current_time = time(NULL);
  struct tm *current_time_tm = localtime(&current_time);
  prv_tick_timer_service_handler(current_time_tm, SECOND_UNIT);
}

static void window_unload(Window *window) {
  SprinklesAppData *data = window_get_user_data(window);

  layer_destroy(data->hands_layer);
  layer_destroy(data->homer_eyes_layer);
  layer_destroy(data->date_layer);

  gbitmap_destroy(data->donut_bitmap);

  bitmap_layer_destroy(data->homer_layer);
  gbitmap_destroy(data->homer_bitmap);

  window_destroy(window);
}
Beispiel #2
0
//loading
static void load(Window* window) {    
  previous_question = -1;

  Layer *window_layer = window_get_root_layer(ui.window);
  GRect window_bounds = layer_get_bounds(window_layer);
  #ifdef PBL_COLOR
    layer_set_update_proc(window_layer, bg_update_proc);
  #endif

  // init text layers
  for(int i=0; i < 3; i++) {
    GRect answerBounds = GRect(144 - 34, 84 - 58 + i * 49, 30, 18);

    ui.romajiAnswer[i] = text_layer_create(answerBounds);    
    text_layer_set_text_alignment(ui.romajiAnswer[i], GTextAlignmentRight);
    text_layer_set_font(ui.romajiAnswer[i], fonts_get_system_font(FONT_KEY_GOTHIC_18));
    text_layer_set_text(ui.romajiAnswer[i], "");

    #ifdef PBL_COLOR
      text_layer_set_background_color(ui.romajiAnswer[i], GColorClear);
      text_layer_set_text_color(ui.romajiAnswer[i], SEC_FG_COLOR);
    #endif
  }

  for(int i=0; i < 3; i++) 
    ui.bitmaps[i] = NULL;

  GRect statsBounds = GRect(0, 0, 144, 18);
  ui.stats = text_layer_create(statsBounds);
  text_layer_set_text_alignment(ui.stats, GTextAlignmentCenter);
  text_layer_set_font(ui.stats, fonts_get_system_font(FONT_KEY_GOTHIC_18));
  #ifdef PBL_COLOR
    text_layer_set_background_color(ui.stats, GColorClear);
    text_layer_set_text_color(ui.stats, SEC_FG_COLOR);
  #endif

  total_question_num = 0;
  correct_anserted_questions = 0;
  update_stats_disp();

  // init icons
  GRect icon_rect = GRect(0, 0, window_bounds.size.w, window_bounds.size.h);
  grect_align(&icon_rect, &window_bounds, GAlignCenter, false);
  ui.glyph_layer = layer_create(icon_rect);
  layer_set_update_proc(ui.glyph_layer, glyph_layer_update_proc);
  layer_set_clips(ui.glyph_layer, true);

  // init layers
  layer_add_child(window_layer, ui.glyph_layer);  
  layer_add_child(window_layer, text_layer_get_layer(ui.stats));
  for(int i=0; i<3; i++) 
    layer_add_child(window_layer, text_layer_get_layer(ui.romajiAnswer[i])); 

  window_set_click_config_provider(ui.window, (ClickConfigProvider) config_provider);

  load_new_question();
}
Beispiel #3
0
void bitmap_layer_update_func (Layer* l,GContext* ctx) {
    BITMAP_GET;
    GRect rect=GRect(0,0,l->frame.size.w,l->frame.size.h);
    graphics_context_set_fill_color(ctx,bitmap->background_color);
    graphics_fill_rect (ctx,rect,0,0);
    rect.origin=l->frame.origin;
    grect_align (&rect,&l->frame,bitmap->alignment,l->clips);
    rect.origin.x-=l->frame.origin.x;
    rect.origin.y-=l->frame.origin.y;
    graphics_context_set_compositing_mode (ctx,bitmap->compositing_mode);
    graphics_draw_bitmap_in_rect (ctx,bitmap->bitmap,rect);
}
Beispiel #4
0
void bitmap_layer_update_func (Layer* me,GContext* ctx) {
    GRect rect=GRect(0,0,me->frame.size.w,me->frame.size.h);
    BitmapLayer* bitmapLayer=(BitmapLayer*)me;
    graphics_context_set_fill_color(ctx,bitmapLayer->background_color);
    graphics_fill_rect (ctx,rect,0,0);
    rect.origin=me->frame.origin;
    grect_align (&rect,&me->frame,bitmapLayer->alignment,me->clips);
    rect.origin.x-=me->frame.origin.x;
    rect.origin.y-=me->frame.origin.y;
    graphics_context_set_compositing_mode (ctx,bitmapLayer->compositing_mode);
    graphics_draw_bitmap_in_rect (ctx,bitmapLayer->bitmap,rect);
}
Beispiel #5
0
static void prv_date_layer_update_proc(Layer *layer, GContext *ctx) {
  const SprinklesConfiguration *configuration = sprinkles_configuration_get_configuration();
  if (!configuration->date_enabled) {
    return;
  }

  const GRect layer_bounds = layer_get_bounds(layer);
  GRect date_rect = (GRect) { .size = GSize(24, layer_bounds.size.h) };
  grect_align(&date_rect, &layer_bounds, GAlignCenter, true /* clip */);

  graphics_context_set_fill_color(ctx, configuration->date_background_color);
  graphics_fill_rect(ctx, date_rect, 3, GCornersAll);

  // Push the date_rect up a little bit to account for the font cap offset
  date_rect.origin.y -= 4;

  graphics_context_set_text_color(ctx, configuration->date_text_color);
  const GFont font = fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD);
  char date_string[3] = {0};
  const time_t current_time = time(NULL);
  struct tm *current_time_tm = localtime(&current_time);
  strftime(date_string, ARRAY_LENGTH(date_string), "%d", current_time_tm);
  graphics_draw_text(ctx, date_string, font, date_rect, GTextOverflowModeTrailingEllipsis,
                     GTextAlignmentCenter, NULL);
}

static void prv_homer_eyes_layer_update_proc(Layer *layer, GContext *ctx) {
  const GRect layer_bounds = layer_get_bounds(layer);

  const GPoint donut_orbit_perimeter_point = prv_get_donut_orbit_perimeter_point(&layer_bounds);

  const GEdgeInsets eye_rect_insets = GEdgeInsets(1);

  const GRect right_eye_rect = grect_inset(PBL_IF_ROUND_ELSE(GRect(53, 49, 33, 33),
                                                             GRect(52, 45, 35, 32)),
                                           eye_rect_insets);
  prv_draw_pupil(ctx, &right_eye_rect, &donut_orbit_perimeter_point);

  const GRect left_eye_rect = grect_inset(PBL_IF_ROUND_ELSE(GRect(22, 48, 32, 31),
                                                            GRect(22, 45, 32, 29)),
                                          eye_rect_insets);
  prv_draw_pupil(ctx, &left_eye_rect, &donut_orbit_perimeter_point);
}

static void prv_tick_timer_service_handler(struct tm *tick_time, TimeUnits units_changed) {
  s_app_data->current_hours = tick_time->tm_hour;
  s_app_data->current_minutes = tick_time->tm_min;
  s_app_data->current_seconds = tick_time->tm_sec;
  layer_mark_dirty(s_app_data->homer_eyes_layer);
  layer_mark_dirty(s_app_data->hands_layer);
}
static void prv_goal_reached_sequence_layer_update_proc(Layer *layer, GContext *ctx) {
  GoalStarGoalEventWindowData *data = window_get_user_data(layer_get_window(layer));
  const GRect layer_bounds = layer_get_bounds(layer);

  GRect sequence_frame = (GRect) {
    .size = gdraw_command_sequence_get_bounds_size(data->goal_reached_sequence),
  };
  grect_align(&sequence_frame, &layer_bounds, GAlignCenter, true /* clip */);
  sequence_frame.origin.y -= sequence_frame.origin.y / 4;

  GDrawCommandFrame *frame = gdraw_command_sequence_get_frame_by_index(
    data->goal_reached_sequence, data->goal_reached_sequence_frame_index);
  if (frame) {
    gdraw_command_frame_draw(ctx, data->goal_reached_sequence, frame, sequence_frame.origin);
  }

  const uint32_t num_frames = gdraw_command_sequence_get_num_frames(data->goal_reached_sequence);
  if (++data->goal_reached_sequence_frame_index >= num_frames) {
    app_timer_cancel(data->goal_reached_sequence_timer);
    const uint32_t timeout_ms = goal_star_configuration_get_goal_event_timeout_ms();
    if (timeout_ms) {
      data->goal_reached_sequence_timer = app_timer_register(timeout_ms,
                                                             prv_goal_reached_wait_timer_handler,
                                                             data);
    }
  }

  char text[GOAL_STAR_CONFIGURATION_STRING_BUFFER_LENGTH] = {0};
  goal_star_configuration_get_goal_summary_string(text);
  graphics_context_set_text_color(ctx, GColorBlack);
  const GFont font = fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD);
  const int16_t font_height = 24;
  const GRect text_frame = GRect(0, sequence_frame.origin.y + sequence_frame.size.h,
                                 layer_bounds.size.w, font_height);
  graphics_draw_text(ctx, text, font, text_frame, GTextOverflowModeTrailingEllipsis,
                     GTextAlignmentCenter, NULL);
}

static void prv_goal_reached_sequence_timer_handler(void *context) {
  GoalStarGoalEventWindowData *data = context;
  if (data) {
    layer_mark_dirty(data->goal_reached_sequence_layer);
    data->goal_reached_sequence_timer = app_timer_register(ANIMATION_FRAME_INTERVAL_MS,
                                                           prv_goal_reached_sequence_timer_handler,
                                                           data);
  }
}
Beispiel #7
0
void handle_init() {
  time_t clock = time(NULL);
  now = localtime(&clock);
  window = window_create();
  window_stack_push(window, true /* Animated */);
  window_set_background_color(window, BG_COLOR);

  date_layer = layer_create(GRect(0, EXTENT, EXTENT, 24));
  layer_set_update_proc(date_layer, &date_layer_update_callback);
  layer_add_child(window_get_root_layer(window), date_layer);

  background_layer = layer_create(GRect(0, 0, EXTENT, EXTENT));
  layer_set_update_proc(background_layer, &background_layer_update_callback);
  layer_add_child(window_get_root_layer(window), background_layer);

  logo = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_LOGO);
  gbitmap_set_palette(logo, bw_palette, false);
  GRect frame = gbitmap_get_bounds(logo);
  grect_align(&frame, &GRect(0, 0, EXTENT, CENTER_Y), GAlignCenter, false);
  logo_layer = bitmap_layer_create(frame);
  bitmap_layer_set_bitmap	(logo_layer, logo);
  layer_add_child(background_layer, bitmap_layer_get_layer(logo_layer));

  hands_layer = layer_create(layer_get_frame(background_layer));
  layer_set_update_proc(hands_layer, &hands_layer_update_callback);
  layer_add_child(background_layer, hands_layer);

  battery_layer = layer_create(GRect(EXTENT-22-3, 3, 22, 10));
  layer_set_update_proc(battery_layer, &battery_layer_update_callback);
  layer_add_child(window_get_root_layer(window), battery_layer);

  for (int i = 0; i < 2; i++) {
    bluetooth_images[i] = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_BLUETOOTH_OFF + i);  
    gbitmap_set_palette(bluetooth_images[i], bw_palette, false);
  }
  bluetooth_layer = bitmap_layer_create(GRect(CENTER_X - 6, CENTER_Y - DOTS_RADIUS - 4, 13, 13));
  layer_add_child(background_layer, bitmap_layer_get_layer(bluetooth_layer));

#if DEBUG
  debug_layer = text_layer_create(GRect(0, 0, 32, 16));
  strcpy(debug_buffer, "");
  text_layer_set_text(debug_layer, debug_buffer);
  text_layer_set_text_color(debug_layer, FG_COLOR);
  text_layer_set_background_color(debug_layer, BG_COLOR);
  layer_add_child(window_get_root_layer(window), text_layer_get_layer(debug_layer));
#endif
  
  hour_path = gpath_create(&HOUR_POINTS);
  gpath_move_to(hour_path, GPoint(CENTER_X, CENTER_Y));
  min_path = gpath_create(&MIN_POINTS);
  gpath_move_to(min_path, GPoint(CENTER_X, CENTER_Y));
  sec_path = gpath_create(&SEC_POINTS);
  gpath_move_to(sec_path, GPoint(CENTER_X, CENTER_Y));
  battery_path = gpath_create(&BATTERY_POINTS);
  charge_path = gpath_create(&CHARGE_POINTS);

  startup_animation = animation_create();
  animation_set_curve(startup_animation, AnimationCurveEaseOut);
  animation_set_implementation(startup_animation, &startup_animation_implementation);
  startup_animation_init();
  app_focus_service_subscribe_handlers((AppFocusHandlers){
    .did_focus = handle_app_did_focus,
  });
static void prv_window_load(Window *window) {
  GoalStarNumberWindow *number_window = window_get_user_data(window);
  if (!number_window) {
    return;
  }

  Layer *window_root_layer = window_get_root_layer(window);
  const GRect window_root_layer_bounds = layer_get_bounds(window_root_layer);

  number_window->checkmark_icon = gbitmap_create_with_resource(RESOURCE_ID_CHECKMARK);
  number_window->up_icon = gbitmap_create_with_resource(RESOURCE_ID_UP);
  number_window->down_icon = gbitmap_create_with_resource(RESOURCE_ID_DOWN);

  const GTextAlignment text_layer_alignment = GTextAlignmentRight;
  const GTextOverflowMode text_layer_overflow_mode = GTextOverflowModeTrailingEllipsis;

  const GFont label_text_font = fonts_get_system_font(FONT_KEY_GOTHIC_14);
  const int16_t label_text_font_height = 14;

  const int16_t value_text_max_font_height = 36;

  const int16_t horizontal_padding = 5;
  GRect text_container_frame = grect_inset(window_root_layer_bounds,
                                           GEdgeInsets(0, ACTION_BAR_WIDTH + horizontal_padding,
                                                       0, horizontal_padding));
  text_container_frame.size.h = label_text_font_height + value_text_max_font_height;
  grect_align(&text_container_frame, &window_root_layer_bounds, GAlignLeft, true /* clip */);
  text_container_frame.origin.y -= gbitmap_get_bounds(number_window->checkmark_icon).size.h / 2;

  GRect label_text_layer_frame = (GRect) {
    .size = GSize(text_container_frame.size.w, label_text_font_height),
  };
  grect_align(&label_text_layer_frame, &text_container_frame, GAlignTop, true /* clip */);
  number_window->label_text_layer = text_layer_create(label_text_layer_frame);
  TextLayer *label_text_layer = number_window->label_text_layer;
  text_layer_set_text(label_text_layer, number_window->label);
  text_layer_set_text_color(label_text_layer, GColorBlack);
  text_layer_set_background_color(label_text_layer, GColorClear);
  text_layer_set_font(label_text_layer, label_text_font);
  text_layer_set_overflow_mode(label_text_layer, text_layer_overflow_mode);
  text_layer_set_text_alignment(label_text_layer, text_layer_alignment);
  layer_add_child(window_root_layer, text_layer_get_layer(label_text_layer));

  GRect value_text_layer_frame = (GRect) {
    .size = GSize(text_container_frame.size.w, value_text_max_font_height),
  };
  grect_align(&value_text_layer_frame, &text_container_frame, GAlignBottom, true /* clip */);
  number_window->value_text_layer = text_layer_create(value_text_layer_frame);
  TextLayer *value_text_layer = number_window->value_text_layer;
  prv_update_value_text_layer(number_window);
  text_layer_set_text_color(value_text_layer, GColorBlack);
  text_layer_set_background_color(value_text_layer, GColorClear);
  text_layer_set_overflow_mode(value_text_layer, text_layer_overflow_mode);
  text_layer_set_text_alignment(value_text_layer, text_layer_alignment);
  layer_add_child(window_root_layer, text_layer_get_layer(value_text_layer));

  number_window->action_bar_layer = action_bar_layer_create();
  ActionBarLayer *action_bar_layer = number_window->action_bar_layer;
  action_bar_layer_set_click_config_provider(action_bar_layer, prv_click_config_provider);
  action_bar_layer_set_context(action_bar_layer, number_window);
  action_bar_layer_set_icon(action_bar_layer, BUTTON_ID_SELECT, number_window->checkmark_icon);
  action_bar_layer_set_icon(action_bar_layer, BUTTON_ID_UP, number_window->up_icon);
  action_bar_layer_set_icon(action_bar_layer, BUTTON_ID_DOWN, number_window->down_icon);
  action_bar_layer_add_to_window(action_bar_layer, window);
}

static void prv_window_unload(Window *window) {
  GoalStarNumberWindow *number_window = window_get_user_data(window);
  if (number_window) {
    text_layer_destroy(number_window->label_text_layer);
    text_layer_destroy(number_window->value_text_layer);
    action_bar_layer_destroy(number_window->action_bar_layer);
    gbitmap_destroy(number_window->checkmark_icon);
    gbitmap_destroy(number_window->up_icon);
    gbitmap_destroy(number_window->down_icon);
  }
}

static void prv_goal_star_number_window_init(GoalStarNumberWindow *number_window, const char *label,
                                             GoalStarNumberWindowCallbacks callbacks,
                                             void *callback_context) {
  if (!number_window) {
    return;
  }

  *number_window = (GoalStarNumberWindow) {
    .label = label,
    .value = 0,
    .min = GOAL_STAR_NUMBER_WINDOW_MIN,
    .max = GOAL_STAR_NUMBER_WINDOW_MAX,
    .step_size = 1,
    .callbacks = callbacks,
    .callback_context = callback_context,
  };

  number_window->window = window_create();
  Window *window = number_window->window;
  window_set_window_handlers(window, (WindowHandlers) {
    .load = prv_window_load,
    .unload = prv_window_unload,
  });
  window_set_background_color(window, GColorLightGray);
  window_set_user_data(window, number_window);
}

GoalStarNumberWindow *goal_star_number_window_create(const char *label,
                                                     GoalStarNumberWindowCallbacks callbacks,
                                                     void *callback_context) {
  GoalStarNumberWindow *number_window = calloc(1, sizeof(*number_window));
  prv_goal_star_number_window_init(number_window, label, callbacks, callback_context);
  return number_window;
}
Beispiel #9
0
void draw_marine_layer(Layer *layer, GContext *ctx) {
  int next_x = 0;
  int next_y = 5 - ceil(anim_data.current_battery_state.charge_percent / 20.0);
  
  next_y = next_y > MAX_SPRITE_Y ? MAX_SPRITE_Y : next_y; 
  
  bool destroy_new_sprite = false;
  GBitmap* new_sprite = NULL;
  
  if (!anim_data.current_battery_state.is_charging && !anim_data.current_battery_state.is_plugged) {
      switch (anim_data.current_x) {
        case 2:
          next_x = 1;
          break;
        case 1:
          switch (anim_data.previous_x) {
            case 2:
             next_x = 0;
             break;
            case 0:
             next_x = 2;
             break;
            case 1:
             next_x = 0;
             break;
            default:
              return;
          }
          break;
       case 0:
        next_x = 1;
        break;
       default:
        return;
     }
      
     anim_data.previous_x = anim_data.current_x;
     anim_data.current_x = next_x;
     
     new_sprite  = get_sprite_by_index(marine_spritesheet, next_x, next_y);
     
     if (!new_sprite) {
       APP_LOG(APP_LOG_LEVEL_ERROR, "Error getting new sprite! x:%d y:%d", next_x, next_y);
       return;
     }
     
     destroy_new_sprite = true; 
  } else {
    new_sprite = marine_charging;
  }
   
#ifdef PBL_PLATFORM_BASALT
   GRect image_size = gbitmap_get_bounds(new_sprite);
#else 
   GRect image_size = new_sprite->bounds;
#endif  
  
  GRect bounds = layer_get_bounds(layer);
  
  grect_align(&image_size, &bounds, GAlignCenter, true);

  graphics_context_set_compositing_mode(ctx, GCompOpAssign);
  graphics_draw_bitmap_in_rect(ctx, new_sprite, image_size);
  
  if (destroy_new_sprite) {
    gbitmap_destroy(new_sprite);
  }
}
Beispiel #10
0
void handle_init() {
  time_t clock = time(NULL);
  now = localtime(&clock);
  window = window_create();
  window_stack_push(window, true /* Animated */);
  window_set_background_color(window, GColorBlack);

  date_layer = layer_create(GRect(0, 144, 144, 24));
  layer_set_update_proc(date_layer, &date_layer_update_callback);
  layer_add_child(window_get_root_layer(window), date_layer);

  background_layer = layer_create(GRect(0, 0, 144, 144));
  layer_set_update_proc(background_layer, &background_layer_update_callback);
  layer_add_child(window_get_root_layer(window), background_layer);

  logo = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_LOGO);  
  GRect frame = logo->bounds;
  grect_align(&frame, &GRect(0, 0, 144, 72), GAlignCenter, false);
  logo_layer = bitmap_layer_create(frame);
  bitmap_layer_set_bitmap	(logo_layer, logo);
  layer_add_child(background_layer, bitmap_layer_get_layer(logo_layer));

  hands_layer = layer_create(layer_get_frame(background_layer));
  layer_set_update_proc(hands_layer, &hands_layer_update_callback);
  layer_add_child(background_layer, hands_layer);

  for (int i = 0; i < 22; i++)
    battery_images[i] = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_BATTERY_0 + i);  
  battery_layer = bitmap_layer_create(GRect(144-16-3, 3, 16, 10));
  layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(battery_layer));

  for (int i = 0; i < 2; i++)
    bluetooth_images[i] = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_BLUETOOTH_OFF + i);  
  bluetooth_layer = bitmap_layer_create(GRect(66, 0, 13, 13));
  layer_add_child(background_layer, bitmap_layer_get_layer(bluetooth_layer));

#if DEBUG
  debug_layer = text_layer_create(GRect(0, 0, 32, 16));
  strcpy(debug_buffer, "");
  text_layer_set_text(debug_layer, debug_buffer);
  text_layer_set_text_color(debug_layer, GColorWhite);
  text_layer_set_background_color(debug_layer, GColorBlack);
  layer_add_child(window_get_root_layer(window), text_layer_get_layer(debug_layer));
#endif
  
  inverter_layer = inverter_layer_create(GRect(0, 0, 144, 168));
  layer_add_child(window_get_root_layer(window), inverter_layer_get_layer(inverter_layer));

  hour_path = gpath_create(&HOUR_POINTS);
  gpath_move_to(hour_path, GPoint(CENTER_X, CENTER_Y));
  min_path = gpath_create(&MIN_POINTS);
  gpath_move_to(min_path, GPoint(CENTER_X, CENTER_Y));
  sec_path = gpath_create(&SEC_POINTS);
  gpath_move_to(sec_path, GPoint(CENTER_X, CENTER_Y));

  font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_30));

  has_config = true;
  if (persist_exists(SECONDS_MODE)) seconds_mode = persist_read_int(SECONDS_MODE); else has_config = false;
  if (persist_exists(BATTERY_MODE)) battery_mode = persist_read_int(BATTERY_MODE); else has_config = false;
  if (persist_exists(DATE_MODE)) date_mode = persist_read_int(DATE_MODE); else has_config = false;
  if (persist_exists(BLUETOOTH_MODE)) bluetooth_mode = persist_read_int(BLUETOOTH_MODE); else has_config = false;
  if (has_config) APP_LOG(APP_LOG_LEVEL_DEBUG, "Loaded config");
  tick_timer_service_subscribe(hide_seconds ? MINUTE_UNIT : SECOND_UNIT, &handle_tick);
  battery_state_service_subscribe(&handle_battery);
  handle_battery(battery_state_service_peek());
  bluetooth_connection_service_subscribe(&handle_bluetooth);
  handle_bluetooth(bluetooth_connection_service_peek());
  handle_inverter();
  app_message_register_inbox_received(&handle_appmessage_receive);
  app_message_open(INBOX_SIZE, OUTBOX_SIZE);
  if (!has_config) request_config();
}