goalsbreakdown/database.py
Yuyao Huang 6b05ba3e2c Improve tasks UI: scroll-to-focus picker, landscape layout, height alignment
- Complete tasks now displayed in scroll view alongside unfinished tasks
- Priority order: completed tasks first (by finished_time desc), then unfinished (by order asc)
- Time picker-style scroll: wheel scroll snaps per task, center item gets visual focus
- Landscape mode (>=1024px): scroll view + edit panel side by side, panel always visible
- Portrait mode: edit panel slides in from right on tap
- Fixed flex layout so scroll view and edit panel align perfectly in height
2026-05-08 15:47:25 +08:00

138 lines
3.4 KiB
Python

import os
from tinydb import TinyDB, Query
from tinydb.operations import increment
import config
os.makedirs(os.path.dirname(config.DB_PATH), exist_ok=True)
db = TinyDB(config.DB_PATH)
users_table = db.table("users")
goals_table = db.table("goals")
tasks_table = db.table("tasks")
User = Query()
Goal = Query()
Task = Query()
def init_db():
if users_table.count(User.role == "admin") == 0:
import bcrypt
password_hash = bcrypt.hashpw(
config.DEFAULT_ADMIN_PASSWORD.encode("utf-8"),
bcrypt.gensalt()
).decode("utf-8")
users_table.insert({
"username": config.DEFAULT_ADMIN_USERNAME,
"password_hash": password_hash,
"role": "admin",
"max_goals": 100
})
def get_user_by_username(username):
result = users_table.search(User.username == username)
return result[0] if result else None
def get_user_by_id(user_id):
return users_table.get(doc_id=user_id)
def create_user(username, password_hash, role="user", max_goals=None):
if max_goals is None:
max_goals = config.DEFAULT_MAX_GOALS
doc_id = users_table.insert({
"username": username,
"password_hash": password_hash,
"role": role,
"max_goals": max_goals
})
return users_table.get(doc_id=doc_id)
def update_user(user_id, **kwargs):
users_table.update(kwargs, doc_ids=[user_id])
def get_all_users():
return users_table.all()
def get_goals_by_user(user_id):
return goals_table.search(Goal.user_id == user_id)
def get_goal_by_id(goal_id):
return goals_table.get(doc_id=goal_id)
def create_goal(user_id, title):
doc_id = goals_table.insert({
"user_id": user_id,
"title": title,
"activated": True
})
return goals_table.get(doc_id=doc_id)
def update_goal(goal_id, **kwargs):
goals_table.update(kwargs, doc_ids=[goal_id])
def delete_goal(goal_id):
tasks = tasks_table.search(Task.goal_id == goal_id)
for task in tasks:
tasks_table.remove(doc_ids=[task.doc_id])
goals_table.remove(doc_ids=[goal_id])
def count_goals_by_user(user_id):
return len(goals_table.search(Goal.user_id == user_id))
def get_tasks_by_goal(goal_id):
return tasks_table.search(Task.goal_id == goal_id)
def get_task_by_id(task_id):
return tasks_table.get(doc_id=task_id)
def create_task(goal_id, title, desc="", status="todo", order=None):
if order is None:
existing_tasks = tasks_table.search(Task.goal_id == goal_id)
unfinished = [t for t in existing_tasks if t.get("status") != "done"]
order = max([t.get("order", 0) for t in unfinished], default=0) + 1.0
doc_id = tasks_table.insert({
"goal_id": goal_id,
"title": title,
"desc": desc,
"status": status,
"start_time": None,
"finished_time": None,
"order": order
})
return tasks_table.get(doc_id=doc_id)
def update_task(task_id, **kwargs):
tasks_table.update(kwargs, doc_ids=[task_id])
def delete_task(task_id):
tasks_table.remove(doc_ids=[task_id])
def get_tasks_sorted(goal_id):
all_tasks = tasks_table.search(Task.goal_id == goal_id)
unfinished = [t for t in all_tasks if t.get("status") != "done"]
finished = [t for t in all_tasks if t.get("status") == "done"]
unfinished.sort(key=lambda t: t.get("order", 0))
finished.sort(key=lambda t: t.get("finished_time", ""), reverse=True)
return finished + unfinished