File size: 3,907 Bytes
d0f7ae6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
import uuid

# ---------- Helpers ----------
def new_item(text):
    return {"id": str(uuid.uuid4()), "text": text.strip(), "done": False}

def build_choices(items):
    return [f"{i}:{'βœ… ' if it['done'] else '◻️ '}{it['text']}" for i, it in enumerate(items)]

def parse_idx(choice):
    return int(choice.split(":", 1)[0]) if choice else None

def progress_html(done, total):
    pct = int(done / total * 100) if total else 0
    return f"<progress value='{done}' max='{total}' style='width:100%'></progress><br>{done}/{total} done ({pct}%)"

def render_ui(state):
    """Returns CheckboxGroup + HTML for a given state"""
    ch = build_choices(state)
    html = "<ul>"
    for it in state:
        t = f"<s>{it['text']}</s>" if it["done"] else it["text"]
        html += f"<li>{t}</li>"
    html += "</ul>" if state else "<i>No items yet</i>"
    done = sum(i["done"] for i in state)
    prog = progress_html(done, len(state))
    return gr.update(choices=ch, value=[]), gr.update(value=html + "<br>" + prog)

# ---------- Actions ----------
def add_item(txt, state):
    if txt.strip():
        state.append(new_item(txt))
    cbx_update, html_update = render_ui(state)
    return cbx_update, html_update, gr.update(value=""), state

def toggle_item(selected, state):
    for s in selected:
        idx = parse_idx(s)
        if 0 <= idx < len(state):
            state[idx]["done"] = not state[idx]["done"]
    cbx_update, html_update = render_ui(state)
    return cbx_update, html_update, state

def delete_item(selected, state):
    idxs = sorted([parse_idx(s) for s in selected], reverse=True)
    for i in idxs:
        if 0 <= i < len(state):
            state.pop(i)
    cbx_update, html_update = render_ui(state)
    return cbx_update, html_update, state


# ---------- Build Gradio Interface ----------
with gr.Blocks(title="To-Do & Habit Tracker") as demo:
    gr.Markdown("# βœ… To-Do & Habit Tracker\nKeep your daily routine organized!")

    with gr.Row():
        # --- To-Do Section ---
        with gr.Column():
            gr.Markdown("### πŸ“ To-Do Tasks")
            task_input = gr.Textbox(label="Add a new task")
            add_task_btn = gr.Button("βž• Add Task")
            todo_box = gr.CheckboxGroup(label="Tasks")
            toggle_task_btn = gr.Button("βœ”οΈ Toggle Complete")
            del_task_btn = gr.Button("πŸ—‘οΈ Delete Selected")
            todo_html = gr.HTML()
            todo_state = gr.State([])

        # --- Habits Section ---
        with gr.Column():
            gr.Markdown("### πŸ” Daily Habits")
            habit_input = gr.Textbox(label="Add a new habit")
            add_habit_btn = gr.Button("βž• Add Habit")
            habit_box = gr.CheckboxGroup(label="Habits")
            toggle_habit_btn = gr.Button("βœ”οΈ Toggle Complete")
            del_habit_btn = gr.Button("πŸ—‘οΈ Delete Selected")
            habit_html = gr.HTML()
            habit_state = gr.State([])

    # Connect To-Do events
    add_task_btn.click(add_item, [task_input, todo_state], [todo_box, todo_html, task_input, todo_state])
    toggle_task_btn.click(toggle_item, [todo_box, todo_state], [todo_box, todo_html, todo_state])
    del_task_btn.click(delete_item, [todo_box, todo_state], [todo_box, todo_html, todo_state])

    # Connect Habit events
    add_habit_btn.click(add_item, [habit_input, habit_state], [habit_box, habit_html, habit_input, habit_state])
    toggle_habit_btn.click(toggle_item, [habit_box, habit_state], [habit_box, habit_html, habit_state])
    del_habit_btn.click(delete_item, [habit_box, habit_state], [habit_box, habit_html, habit_state])

    # Initialize UI
    def init():
        cbx1, html1 = render_ui([])
        cbx2, html2 = render_ui([])
        return cbx1, html1, cbx2, html2, [], []

    demo.load(init, None, [todo_box, todo_html, habit_box, habit_html, todo_state, habit_state])

demo.launch()