Skip to content

Commit

Permalink
start date per habit
Browse files Browse the repository at this point in the history
  • Loading branch information
waozixyz committed Jan 23, 2025
1 parent 3db5e90 commit 5cc2404
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 55 deletions.
1 change: 1 addition & 0 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extern uint32_t ACTIVE_RENDERER_INDEX;
extern const float BREAKPOINT_LARGE;
extern const float BREAKPOINT_MEDIUM;
extern const float BREAKPOINT_SMALL;
extern const float BREAKPOINT_XSMALL;

// Font IDs
extern const uint32_t FONT_ID_BODY_16;
Expand Down
7 changes: 6 additions & 1 deletion include/platforms/sdl/renderer_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ void RenderRoundedRectangle(
SDL_Renderer* renderer,
SDL_FRect rect,
Clay_CornerRadius cornerRadius,
Clay_Color color
Clay_Color color,
bool shadowEnabled,
Clay_Color shadowColor,
Clay_Vector2 shadowOffset,
float shadowBlurRadius,
float shadowSpread
);

void RenderScrollbar(
Expand Down
2 changes: 1 addition & 1 deletion include/state/habits_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef struct {
Clay_Color color;
HabitDay calendar_days[MAX_CALENDAR_DAYS];
size_t days_count;
time_t start_date;
} Habit;

// Collection of all habits
Expand All @@ -39,7 +40,6 @@ typedef struct {
uint32_t active_habit_id;
bool is_editing_new_habit;
TextInput* habit_name_input;
time_t calendar_start_date;
} HabitCollection;


Expand Down
24 changes: 15 additions & 9 deletions src/components/nav.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,16 @@ void CleanupNavIcons() {
}
}
#endif

void RenderNavItem(const char* text, uint32_t pageId) {
bool isActive = ACTIVE_PAGE == pageId;
bool isSmallScreen = windowWidth < BREAKPOINT_SMALL; // Check if the screen is small
bool isXSmallScreen = windowWidth < BREAKPOINT_XSMALL; // Check if the screen is very small
bool isSmallScreen = windowWidth >= BREAKPOINT_XSMALL && windowWidth < BREAKPOINT_MEDIUM; // Check if the screen is small
bool isMediumScreen = windowWidth >= BREAKPOINT_MEDIUM; // Check if the screen is medium or larger

// Adjust button width based on screen size
float buttonWidth = isSmallScreen ? 80.0f : 120.0f; // Wider buttons on larger screens
// Adjust button width and padding based on screen size
float buttonWidth = isXSmallScreen ? 60.0f : (isSmallScreen ? 80.0f : 120.0f); // Wider buttons on larger screens
float padding = isXSmallScreen ? 4.0f : 8.0f; // Smaller padding on very small screens

Clay_TextElementConfig *text_config = CLAY_TEXT_CONFIG({
.fontSize = 14, // Smaller text for compact design
Expand All @@ -60,7 +64,7 @@ void RenderNavItem(const char* text, uint32_t pageId) {

CLAY(CLAY_IDI("Nav", pageId),
CLAY_LAYOUT({
.padding = {8, 8}, // Compact padding
.padding = {padding, padding}, // Dynamic padding
.childGap = 4, // Smaller gap between icon and text
.childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
.sizing = { CLAY_SIZING_FIXED(buttonWidth), CLAY_SIZING_FIXED(60) } // Dynamic width for each nav item
Expand Down Expand Up @@ -92,19 +96,22 @@ void RenderNavItem(const char* text, uint32_t pageId) {
#endif
) {}

// Show text below the icon only if the screen is not small
if (!isSmallScreen) {
// Show text below the icon only if the screen is medium or larger
if (isMediumScreen) {
Clay_String nav_text = { .chars = text, .length = strlen(text) };
CLAY_TEXT(nav_text, text_config);
}
}
}

void RenderNavigationMenu() {
bool isXSmallScreen = windowWidth < BREAKPOINT_XSMALL; // Check if the screen is very small

CLAY(CLAY_ID("BottomNavigation"),
CLAY_LAYOUT({
.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(80) }, // Taller bar
.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(isXSmallScreen ? 60.0f : 80.0f) }, // Shorter bar on very small screens
.childGap = 0, // No gap between items
.padding = { 8, 8, 8, 8 }, // Compact padding
.padding = { isXSmallScreen ? 4.0f : 8.0f, isXSmallScreen ? 4.0f : 8.0f }, // Smaller padding on very small screens
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT // Horizontal layout
}),
Expand All @@ -120,7 +127,6 @@ void RenderNavigationMenu() {
RenderNavItem("Habits", 1);
RenderNavItem("Todos", 2);
RenderNavItem("Home", 0);

RenderNavItem("Timeline", 3);
RenderNavItem("Routine", 4);
}
Expand Down
1 change: 1 addition & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ uint32_t ACTIVE_RENDERER_INDEX = 0;
const float BREAKPOINT_LARGE = 1024.0f;
const float BREAKPOINT_MEDIUM = 640.0f;
const float BREAKPOINT_SMALL = 480.0f;
const float BREAKPOINT_XSMALL = 420.0f;

// Font IDs
const uint32_t FONT_ID_BODY_16 = 0;
Expand Down
26 changes: 19 additions & 7 deletions src/pages/habits.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,21 +521,32 @@ void CleanupHabitTabBar(void) {
}

void HandleDateChange(time_t new_date) {
habits.calendar_start_date = new_date;
SaveHabits(&habits);
Habit* active_habit = GetActiveHabit(&habits);
if (active_habit) {
active_habit->start_date = new_date;
SaveHabits(&habits);
}
}

#ifdef __EMSCRIPTEN__
void InitializeHabitsPage() {
LoadHabits(&habits);
habits.habit_name_input = CreateTextInput(NULL, HandleHabitNameSubmit);
InitializeDatePicker(habits.calendar_start_date, HandleDateChange, &date_picker_modal);

Habit* active_habit = GetActiveHabit(&habits);
if (active_habit) {
InitializeDatePicker(active_habit->start_date, HandleDateChange, &date_picker_modal);
}
}
#else
void InitializeHabitsPage(SDL_Renderer* renderer) {
LoadHabits(&habits);
habits.habit_name_input = CreateTextInput(NULL, HandleHabitNameSubmit);
InitializeDatePicker(habits.calendar_start_date, HandleDateChange, &date_picker_modal);

Habit* active_habit = GetActiveHabit(&habits);
if (active_habit) {
InitializeDatePicker(active_habit->start_date, HandleDateChange, &date_picker_modal);
}

InitializeHabitTabBar(renderer);
}
#endif
Expand Down Expand Up @@ -595,7 +606,8 @@ void RenderHabitsPage() {
today_midnight.tm_sec = 0;
time_t today_timestamp = mktime(&today_midnight);

struct tm *start_tm = localtime(&habits.calendar_start_date);
// Use the active habit's start_date
struct tm *start_tm = localtime(&active_habit->start_date);
struct tm start_date = *start_tm;

const int WEEKS_TO_DISPLAY = 10;
Expand Down Expand Up @@ -632,7 +644,7 @@ void RenderHabitsPage() {
})
) {
RenderColorPicker(active_habit->color, HandleColorChange, &color_picker_modal);
RenderDatePicker(habits.calendar_start_date, HandleDateChange, &date_picker_modal);
RenderDatePicker(active_habit->start_date, HandleDateChange, &date_picker_modal); // Use active habit's start_date
RenderDeleteHabitModal();
}

Expand Down
15 changes: 13 additions & 2 deletions src/platforms/sdl/renderer_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,25 @@ void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray renderComm
fprintf(stderr, "Error: Rectangle config is NULL\n");
continue;
}

if (config->cursorPointer &&
mouseX >= boundingBox.x && mouseX <= boundingBox.x + boundingBox.width &&
mouseY >= boundingBox.y && mouseY <= boundingBox.y + boundingBox.height) {
hasPointerElement = true;
}

RenderRoundedRectangle(renderer, scaledBox, config->cornerRadius, config->color);
// Pass shadow parameters to RenderRoundedRectangle
RenderRoundedRectangle(
renderer,
scaledBox,
config->cornerRadius,
config->color,
config->shadowEnabled, // Shadow enabled
config->shadowColor, // Shadow color
config->shadowOffset, // Shadow offset
config->shadowBlurRadius, // Shadow blur radius
config->shadowSpread // Shadow spread
);
break;
}
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
Expand Down
33 changes: 28 additions & 5 deletions src/platforms/sdl/renderer_shape.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,44 @@ void RenderBorder(
SDL_RenderFillRectF(renderer, &rightRect);
}
}

void RenderRoundedRectangle(
SDL_Renderer* renderer,
SDL_FRect rect,
Clay_CornerRadius cornerRadius,
Clay_Color color
Clay_Color color,
bool shadowEnabled,
Clay_Color shadowColor,
Clay_Vector2 shadowOffset,
float shadowBlurRadius,
float shadowSpread
) {
float radius = cornerRadius.topLeft * renderScaleFactor;

// Render the shadow if enabled
if (shadowEnabled) {
// Calculate the shadow rectangle dimensions
SDL_FRect shadowRect = {
.x = rect.x + shadowOffset.x - shadowBlurRadius - shadowSpread,
.y = rect.y + shadowOffset.y - shadowBlurRadius - shadowSpread,
.w = rect.w + (shadowBlurRadius + shadowSpread) * 2,
.h = rect.h + (shadowBlurRadius + shadowSpread) * 2
};

// Render the shadow as a rounded rectangle
roundedBoxRGBA(renderer,
shadowRect.x,
shadowRect.y,
shadowRect.x + shadowRect.w,
shadowRect.y + shadowRect.h,
cornerRadius.topLeft * renderScaleFactor, // Use the same corner radius as the rectangle
shadowColor.r, shadowColor.g, shadowColor.b, shadowColor.a);
}

// Render the main rectangle
roundedBoxRGBA(renderer,
rect.x,
rect.y,
rect.x + rect.w,
rect.y + rect.h,
radius,
cornerRadius.topLeft * renderScaleFactor,
color.r, color.g, color.b, color.a);
}

Expand Down
55 changes: 25 additions & 30 deletions src/state/habits_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ static cJSON* HabitToJSON(const Habit* habit) {
cJSON_AddNumberToObject(color, "a", habit->color.a);
cJSON_AddItemToObject(habitObj, "color", color);

cJSON_AddNumberToObject(habitObj, "start_date", (double)habit->start_date); // Add start_date

cJSON* days = cJSON_CreateArray();
for (size_t i = 0; i < habit->days_count; i++) {
cJSON* day = cJSON_CreateObject();
Expand All @@ -42,7 +44,6 @@ static cJSON* HabitToJSON(const Habit* habit) {

return habitObj;
}

static void SaveHabitsJSON(const HabitCollection* collection) {
if (!collection) return;

Expand All @@ -51,7 +52,6 @@ static void SaveHabitsJSON(const HabitCollection* collection) {

cJSON* root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "active_habit_id", collection->active_habit_id);
cJSON_AddNumberToObject(root, "calendar_start_date", (double)collection->calendar_start_date);

cJSON* habits = cJSON_CreateArray();
for (size_t i = 0; i < collection->habits_count; i++) {
Expand All @@ -77,6 +77,14 @@ static void LoadHabitFromJSON(Habit* habit, cJSON* habitObj) {
habit->color.b = cJSON_GetObjectItem(color, "b")->valuedouble;
habit->color.a = cJSON_GetObjectItem(color, "a")->valuedouble;

// Load start_date if it exists, otherwise set to current time
cJSON* start_date = cJSON_GetObjectItem(habitObj, "start_date");
if (start_date) {
habit->start_date = (time_t)start_date->valuedouble;
} else {
habit->start_date = time(NULL);
}

cJSON* days = cJSON_GetObjectItem(habitObj, "calendar_days");
habit->days_count = 0;
cJSON* day;
Expand All @@ -89,17 +97,14 @@ static void LoadHabitFromJSON(Habit* habit, cJSON* habitObj) {
habitDay->completed = cJSON_IsTrue(cJSON_GetObjectItem(day, "completed"));
}
}

static void CreateDefaultHabitsJSON(HabitCollection* defaultCollection) {
Habit* default_habit = &defaultCollection->habits[0];
strncpy(default_habit->name, "Meditation", MAX_HABIT_NAME - 1);
default_habit->id = 0;
default_habit->color = COLOR_PRIMARY;
default_habit->days_count = 0;
defaultCollection->habits_count = 1;
defaultCollection->active_habit_id = 0;

// Set calendar start date to the most recent past Monday
// Set the start date to the most recent past Monday
time_t now = time(NULL);
struct tm *local_time = localtime(&now);
struct tm start_date = *local_time;
Expand All @@ -108,11 +113,13 @@ static void CreateDefaultHabitsJSON(HabitCollection* defaultCollection) {
start_date.tm_sec = 0;
int days_to_monday = start_date.tm_wday == 0 ? 6 : start_date.tm_wday - 1;
start_date.tm_mday -= days_to_monday;
defaultCollection->calendar_start_date = mktime(&start_date);
default_habit->start_date = mktime(&start_date);

defaultCollection->habits_count = 1;
defaultCollection->active_habit_id = 0;

SaveHabitsJSON(defaultCollection);
}

static void LoadHabitsJSON(HabitCollection* collection) {
StorageConfig storage_config;
determine_storage_directory(&storage_config);
Expand Down Expand Up @@ -147,25 +154,9 @@ static void LoadHabitsJSON(HabitCollection* collection) {
LoadHabitFromJSON(&collection->habits[collection->habits_count++], habit);
}

// Check if calendar_start_date exists in the JSON
cJSON* start_date = cJSON_GetObjectItem(root, "calendar_start_date");
if (start_date) {
collection->calendar_start_date = (time_t)start_date->valuedouble;
} else {
// If not present, set it to the most recent past Monday
time_t now = time(NULL);
struct tm *local_time = localtime(&now);
struct tm start_tm = *local_time;
start_tm.tm_hour = 0;
start_tm.tm_min = 0;
start_tm.tm_sec = 0;
int days_to_monday = start_tm.tm_wday == 0 ? 6 : start_tm.tm_wday - 1;
start_tm.tm_mday -= days_to_monday;
collection->calendar_start_date = mktime(&start_tm);
}

cJSON_Delete(root);
}

#endif
void DeleteHabit(HabitCollection* collection, uint32_t habit_id) {
if (!collection) return;
Expand Down Expand Up @@ -210,7 +201,6 @@ void DeleteHabit(HabitCollection* collection, uint32_t habit_id) {
SaveHabits(collection);
#endif
}

void AddNewHabit(HabitCollection* collection) {
if (!collection || collection->habits_count >= MAX_HABITS) return;

Expand All @@ -223,6 +213,9 @@ void AddNewHabit(HabitCollection* collection) {
new_habit->id = collection->habits_count; // ID matches position
new_habit->color = COLOR_PRIMARY;
new_habit->days_count = 0;

// Set the start date to the current time
new_habit->start_date = time(NULL);

collection->habits_count++;
collection->active_habit_id = new_habit->id;
Expand Down Expand Up @@ -272,8 +265,6 @@ void LoadHabits(HabitCollection* collection) {
collection->active_habit_id = 0;
}
}


bool ToggleHabitDay(HabitCollection* collection, uint32_t day_index) {
if (!collection) return false;

Expand Down Expand Up @@ -310,8 +301,12 @@ bool ToggleHabitDay(HabitCollection* collection, uint32_t day_index) {

void UpdateCalendarStartDate(HabitCollection* collection, time_t new_start_date) {
if (!collection) return;
collection->calendar_start_date = new_start_date;
SaveHabits(collection);

Habit* habit = GetActiveHabit(collection);
if (habit) {
habit->start_date = new_start_date;
SaveHabits(collection);
}
}

void UpdateHabitColor(HabitCollection* collection, Clay_Color color) {
Expand Down

0 comments on commit 5cc2404

Please sign in to comment.