main.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. #!/usr/bin/env python3
  2. from dataclasses import dataclass, field
  3. from typing import Any, Callable, List
  4. from nicegui import ui
  5. @dataclass
  6. class TodoItem:
  7. name: str
  8. on_change: Callable
  9. done: bool = False
  10. def rename(self, new_name: str) -> None:
  11. self.name = new_name
  12. def __setattr__(self, name: str, value: Any) -> None:
  13. super().__setattr__(name, value)
  14. if hasattr(self, 'on_change'):
  15. self.on_change()
  16. @dataclass
  17. class ToDoList:
  18. title: str
  19. on_change: Callable
  20. items: List[TodoItem] = field(default_factory=list)
  21. def add(self, name: str, done: bool = False) -> None:
  22. self.items.append(TodoItem(name, self.on_change, done))
  23. self.on_change()
  24. def remove(self, item: TodoItem) -> None:
  25. self.items.remove(item)
  26. self.on_change()
  27. @ui.refreshable
  28. def todo_ui():
  29. if not todos.items:
  30. ui.label('List is empty.').classes('mx-auto')
  31. return
  32. ui.linear_progress(sum(item.done for item in todos.items) / len(todos.items), show_value=False)
  33. with ui.row().classes('justify-center w-full'):
  34. ui.label(f'Completed: {sum(item.done for item in todos.items)}')
  35. ui.label(f'Remaining: {sum(not item.done for item in todos.items)}')
  36. for item in todos.items:
  37. with ui.row().classes('items-center'):
  38. ui.checkbox().bind_value(item, 'done')
  39. input = ui.input(value=item.name).classes('flex-grow')
  40. input.on('keydown.enter', lambda _, item=item, input=input: item.rename(input.value))
  41. ui.button(on_click=lambda _, item=item: todos.remove(item)).props('flat fab-mini icon=delete color=grey')
  42. todos = ToDoList('My Weekend', on_change=todo_ui.refresh)
  43. todos.add('Order pizza', done=True)
  44. todos.add('New NiceGUI Release')
  45. todos.add('Clean the house')
  46. todos.add('Call mom')
  47. with ui.card().classes('w-80 items-stretch'):
  48. ui.label().bind_text_from(todos, 'title').classes('text-semibold text-2xl')
  49. todo_ui()
  50. add_input = ui.input('New item').classes('mx-12')
  51. add_input.on('keydown.enter', lambda: (todos.add(add_input.value), add_input.set_value('')))
  52. ui.run()