Skip to content

Commit 5e0369b

Browse files
authored
Merge pull request #51 from ZFordDev/41-startup-mode-selector-popup-cli-flags
41 startup mode selector popup cli flags
2 parents 98cb16a + 49724c8 commit 5e0369b

12 files changed

Lines changed: 623 additions & 410 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ schedplus/
143143
│ ├── assets/ # Icons and UI assets
144144
│ ├── data/ # Local task storage
145145
│ ├── logic/ # Core scheduling logic
146+
│ ├── startup/ # NEW — startup
146147
│ ├── ui/ # Tkinter + PyQt interfaces
147148
│ └── main.py # Application entry point
148149

src/logic/scheduler.py

Lines changed: 96 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,96 @@
1-
"""
2-
scheduler.py (v0.4)
3-
-------------------
4-
Core scheduler logic for SchedPlus (v0.4).
5-
6-
This module provides the `Task` dataclass and the `Scheduler` class.
7-
The `Scheduler` is responsible for in-memory task management and
8-
exposes small wrapper methods to persist/load tasks via the storage
9-
layer so UIs (Tkinter/PyQt) do not need to know storage paths.
10-
"""
11-
12-
import uuid
13-
from dataclasses import dataclass, field
14-
from typing import List
15-
from datetime import datetime
16-
17-
@dataclass
18-
class Task:
19-
id: str = field(default_factory=lambda: str(uuid.uuid4()))
20-
date: str = ""
21-
time: str = ""
22-
text: str = ""
23-
createdAt: str = field(default_factory=lambda: datetime.utcnow().isoformat())
24-
updatedAt: str = field(default_factory=lambda: datetime.utcnow().isoformat())
25-
26-
def to_dict(self):
27-
return {
28-
"id": self.id,
29-
"date": self.date,
30-
"time": self.time,
31-
"text": self.text,
32-
"createdAt": self.createdAt,
33-
"updatedAt": self.updatedAt,
34-
}
35-
36-
@classmethod
37-
def from_dict(cls, data: dict):
38-
return cls(
39-
id=data.get("id", str(uuid.uuid4())),
40-
date=data.get("date", ""),
41-
time=data.get("time", ""),
42-
text=data.get("text", ""),
43-
createdAt=data.get("createdAt", datetime.utcnow().isoformat()),
44-
updatedAt=data.get("updatedAt", datetime.utcnow().isoformat()),
45-
)
46-
class Scheduler:
47-
"""
48-
The Scheduler class manages a list of tasks.
49-
In v0.4, tasks are stored in memory and the class exposes
50-
simple `save_tasks`/`load_tasks` helpers that delegate to the
51-
storage layer. This keeps UIs decoupled from storage details.
52-
"""
53-
54-
def __init__(self):
55-
self.tasks: List[Task] = []
56-
57-
def add_task(self, date: str, time: str, text: str):
58-
"""
59-
Add a new task to the scheduler.
60-
No validation yet — this will be added in v0.2+.
61-
"""
62-
task = Task(date=date, time=time, text=text)
63-
self.tasks.append(task)
64-
65-
def save_tasks(self, filepath: str = None):
66-
"""
67-
Persist current tasks using the storage layer.
68-
69-
This method performs a local import to avoid import cycles
70-
between `logic.storage` and `logic.scheduler`.
71-
"""
72-
try:
73-
from . import storage as _storage
74-
75-
_storage.save_tasks(self.tasks, filepath) if filepath else _storage.save_tasks(self.tasks)
76-
except Exception:
77-
# Intentionally swallow errors here; storage will log on failure.
78-
pass
79-
80-
def load_tasks(self, filepath: str = None):
81-
"""
82-
Load tasks from the storage layer into `self.tasks`.
83-
Returns the loaded list of tasks.
84-
"""
85-
try:
86-
from . import storage as _storage
87-
88-
self.tasks = _storage.load_tasks(filepath)
89-
except Exception:
90-
self.tasks = []
91-
92-
return self.tasks
93-
94-
def get_tasks(self) -> List[Task]:
95-
"""Return the list of tasks."""
96-
return self.tasks
1+
"""
2+
scheduler.py (v0.4)
3+
-------------------
4+
Core scheduler logic for SchedPlus (v0.4).
5+
6+
This module provides the `Task` dataclass and the `Scheduler` class.
7+
The `Scheduler` is responsible for in-memory task management and
8+
exposes small wrapper methods to persist/load tasks via the storage
9+
layer so UIs (Tkinter/PyQt) do not need to know storage paths.
10+
"""
11+
12+
import uuid
13+
from dataclasses import dataclass, field
14+
from typing import List
15+
from datetime import datetime
16+
17+
@dataclass
18+
class Task:
19+
id: str = field(default_factory=lambda: str(uuid.uuid4()))
20+
date: str = ""
21+
time: str = ""
22+
text: str = ""
23+
createdAt: str = field(default_factory=lambda: datetime.utcnow().isoformat())
24+
updatedAt: str = field(default_factory=lambda: datetime.utcnow().isoformat())
25+
26+
def to_dict(self):
27+
return {
28+
"id": self.id,
29+
"date": self.date,
30+
"time": self.time,
31+
"text": self.text,
32+
"createdAt": self.createdAt,
33+
"updatedAt": self.updatedAt,
34+
}
35+
36+
@classmethod
37+
def from_dict(cls, data: dict):
38+
return cls(
39+
id=data.get("id", str(uuid.uuid4())),
40+
date=data.get("date", ""),
41+
time=data.get("time", ""),
42+
text=data.get("text", ""),
43+
createdAt=data.get("createdAt", datetime.utcnow().isoformat()),
44+
updatedAt=data.get("updatedAt", datetime.utcnow().isoformat()),
45+
)
46+
class Scheduler:
47+
"""
48+
The Scheduler class manages a list of tasks.
49+
In v0.4, tasks are stored in memory and the class exposes
50+
simple `save_tasks`/`load_tasks` helpers that delegate to the
51+
storage layer. This keeps UIs decoupled from storage details.
52+
"""
53+
54+
def __init__(self):
55+
self.tasks: List[Task] = []
56+
57+
def add_task(self, date: str, time: str, text: str):
58+
"""
59+
Add a new task to the scheduler.
60+
No validation yet — this will be added in v0.2+.
61+
"""
62+
task = Task(date=date, time=time, text=text)
63+
self.tasks.append(task)
64+
65+
def save_tasks(self, filepath: str = None):
66+
"""
67+
Persist current tasks using the storage layer.
68+
69+
This method performs a local import to avoid import cycles
70+
between `logic.storage` and `logic.scheduler`.
71+
"""
72+
try:
73+
from . import storage as _storage
74+
75+
_storage.save_tasks(self.tasks, filepath) if filepath else _storage.save_tasks(self.tasks)
76+
except Exception:
77+
# Intentionally swallow errors here; storage will log on failure.
78+
pass
79+
80+
def load_tasks(self, filepath: str = None):
81+
"""
82+
Load tasks from the storage layer into `self.tasks`.
83+
Returns the loaded list of tasks.
84+
"""
85+
try:
86+
from . import storage as _storage
87+
88+
self.tasks = _storage.load_tasks(filepath)
89+
except Exception:
90+
self.tasks = []
91+
92+
return self.tasks
93+
94+
def get_tasks(self) -> List[Task]:
95+
"""Return the list of tasks."""
96+
return self.tasks

src/logic/storage.py

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,48 @@
1-
import json
2-
import os
3-
from .scheduler import Task # import the dataclass Task
4-
5-
SCHEMA_VERSION = 1
6-
7-
# Absolute / robust path relative to this file
8-
DATA_FILE = os.path.join(os.path.dirname(__file__), "..", "data", "tasks.json")
9-
os.makedirs(os.path.dirname(DATA_FILE), exist_ok=True)
10-
11-
12-
13-
def save_tasks(tasks, filepath=DATA_FILE):
14-
"""
15-
Save list of Task objects to JSON file
16-
"""
17-
data = {
18-
"version": SCHEMA_VERSION,
19-
"tasks": [t.to_dict() for t in tasks], # convert each Task → dict
20-
}
21-
22-
try:
23-
directory = os.path.dirname(filepath)
24-
if directory:
25-
os.makedirs(directory, exist_ok=True)
26-
27-
with open(filepath, "w", encoding="utf-8") as f:
28-
json.dump(data, f, indent=2, ensure_ascii=False)
29-
except Exception as e:
30-
print(f"[ERROR] Failed to save tasks: {e}")
31-
32-
33-
def load_tasks(filepath=DATA_FILE):
34-
"""
35-
Load JSON file → return list of Task objects
36-
"""
37-
if not os.path.exists(filepath):
38-
return []
39-
40-
try:
41-
with open(filepath, "r", encoding="utf-8") as f:
42-
data = json.load(f)
43-
44-
tasks_data = data.get("tasks", [])
45-
return [Task.from_dict(t) for t in tasks_data] # convert dict → Task
46-
except Exception as e:
47-
print(f"[ERROR] Failed to load tasks: {e}")
1+
import json
2+
import os
3+
from .scheduler import Task # import the dataclass Task
4+
5+
SCHEMA_VERSION = 1
6+
7+
# Absolute / robust path relative to this file
8+
DATA_FILE = os.path.join(os.path.dirname(__file__), "..", "data", "tasks.json")
9+
os.makedirs(os.path.dirname(DATA_FILE), exist_ok=True)
10+
11+
12+
13+
def save_tasks(tasks, filepath=DATA_FILE):
14+
"""
15+
Save list of Task objects to JSON file
16+
"""
17+
data = {
18+
"version": SCHEMA_VERSION,
19+
"tasks": [t.to_dict() for t in tasks], # convert each Task → dict
20+
}
21+
22+
try:
23+
directory = os.path.dirname(filepath)
24+
if directory:
25+
os.makedirs(directory, exist_ok=True)
26+
27+
with open(filepath, "w", encoding="utf-8") as f:
28+
json.dump(data, f, indent=2, ensure_ascii=False)
29+
except Exception as e:
30+
print(f"[ERROR] Failed to save tasks: {e}")
31+
32+
33+
def load_tasks(filepath=DATA_FILE):
34+
"""
35+
Load JSON file → return list of Task objects
36+
"""
37+
if not os.path.exists(filepath):
38+
return []
39+
40+
try:
41+
with open(filepath, "r", encoding="utf-8") as f:
42+
data = json.load(f)
43+
44+
tasks_data = data.get("tasks", [])
45+
return [Task.from_dict(t) for t in tasks_data] # convert dict → Task
46+
except Exception as e:
47+
print(f"[ERROR] Failed to load tasks: {e}")
4848
return []

src/main.py

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,13 @@
1-
"""
2-
main.py (v0.4)
3-
--------------
4-
Entry point for SchedPlus (v0.4).
5-
6-
This module creates the `Scheduler`, asks it to load persisted tasks,
7-
and launches the selected UI. UIs interact only with the scheduler API.
8-
"""
9-
10-
from logic.scheduler import Scheduler
11-
from ui.tkinter_ui import run_ui
12-
from ui.pyqt_ui import run_pyqt_ui
13-
14-
15-
def choose_ui():
16-
prompt = "Choose UI: [1] Tkinter, [2] PyQt (experimental)\nSelection [1]: "
17-
choice = input(prompt).strip()
18-
return choice == "2"
19-
20-
21-
def main():
22-
scheduler = Scheduler()
23-
# Load tasks from storage via Scheduler helper
24-
scheduler.load_tasks()
25-
26-
if choose_ui():
27-
run_pyqt_ui(scheduler)
28-
else:
29-
run_ui(scheduler)
30-
31-
32-
if __name__ == "__main__":
33-
main()
1+
"""
2+
main.py (v0.4)
3+
--------------
4+
Entry point for SchedPlus (v0.4).
5+
6+
This module creates the `Scheduler`, asks it to load persisted tasks,
7+
and launches the selected UI. UIs interact only with the scheduler API.
8+
"""
9+
10+
from startup.controller import boot
11+
12+
if __name__ == "__main__":
13+
boot()

src/startup/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)