Workbook Load Sequence
1HTML loads in WebView
2Flutter channel ready
3Check if response exists
4Load saved data if found
5Populate form fields
6Enable auto-save listeners
Auto-Save Mechanism
All form changes trigger a 2-second debounced auto-save. The collectWorkbookData() function gathers ALL form elements, and triggerAutoSave() is attached to ALL interactive elements.
Responses are auto-saved
Editing...
Saving...
Saved
Save failed - will retry
Flutter only handles saving/loading JSON. All form interactions and auto-save logic are managed by the HTML workbook itself.
Flutter Channel Messages
| Action | Direction | Purpose |
|---|---|---|
saveWorkbookResponse | JS → Flutter | Save workbook data to JSON file |
loadWorkbookResponse | JS → Flutter | Load previously saved responses |
checkResponseExists | JS → Flutter | Check if a response file exists |
saveResult | Flutter → JS | Confirm save success/failure |
loadResult | Flutter → JS | Return loaded data or empty result |
responseExistsResult | Flutter → JS | Return whether file exists |
Note: When loading data, access nested fields with data.data.data — the response wraps actual workbook data inside a data property.
File Naming Convention
Format: {course_code}{workbook_number}_response.json — All journals use workbook number 1
| Example | Course |
|---|---|
C14ENB1_response.json | Confidence, English |
H23ENB1_response.json | Smoking cessation, English |
S66ENB1_response.json | Weight loss, English |
P11ENM1_response.json | Productivity, English, Male |
Storage: AppData/JSONs/User_Workbook_Responses/
JSON Response Structure
| Field | Type | Description |
|---|---|---|
workbook_id | String | Unique identifier for the workbook type |
created_at | ISO8601 | First save timestamp (preserved across updates) |
updated_at | ISO8601 | Most recent save timestamp |
ai_prompt | String | Context prompt for AI analysis of journal data |
data | Object | Workbook-specific response data (entries, tracking, etc.) |
Supported Input Types
TextgetElementById().value
TextareagetElementById().value
RadioquerySelector(:checked).value
CheckboxquerySelectorAll(:checked).map
SelectgetElementById().value
NumberparseInt(value)
DategetElementById().value
RangegetElementById().value
Calendar.calendar-day.checked
EditablegetElementById().innerText