z_mirror/TaskList

git clone https://git.raiguard.me/z_mirror/TaskList

Caleb HeuerRename global to storage4a85a42

austinrobichaux18/Twiggy/AddPriorityAndArea
6.7 KiB219 linesraw
1--[[
2  DESIGN GOALS:
3  - Extremely simple to-do list
4  - Compact and full versions of the UI
5    - Compact for reference, full for manipulation
6  - Opt-in advanced features
7    - Timed reminders (interval, absolute time)
8    - Notifications for reminders
9    - Task assignment
10    - Maybe projects?
11  - Current task must be easily visible in some way
12    - Consider using the bottom-right of the screen for this
13  - "Private" and "public" tasks
14    - Private is visible only to you, public is visible to your force
15  - An infinite amount of subtask nesting
16  - Import and export TODOs
17
18  DESIGN NOTES:
19  - Each task will have an entirely unique ID
20    - Store the next ID in the root of `storage`
21  - Tasks will be stored in a one-dimensional table keyed by task ID
22  - Tasks can be owned by the force, or by the player
23    - Player tasks will be shown separately from force tasks
24  - A task can have infinite subtasks
25    - Subtasks are just pointers to other tasks, so they support the full feature suite, including more subtasks
26    - Subtasks may have a different assignee from their parent
27  - Import and export will use the standard method
28  - Each owner (force, player, or task) will have a `tasks` array containing the task IDs to show, in order
29    - Subtasks are also stored in the same manner, but are in a `subtasks` table instead
30  - When a task is completed, it is added to its owners `completed_tasks` array at the front
31    - Completed tasks will be listed after active tasks, in the order that they were completed
32    - Store completion time?
33]]
34
35local gui = require("gui")
36local migration = require("__flib__.migration")
37
38local active_task_button = require("scripts.gui.active-task-button")
39local migrations = require("scripts.migrations")
40local edit_task_gui = require("scripts.gui.edit-task.index")
41local player_data = require("scripts.player-data")
42local task = require("scripts.task")
43local tasks_gui = require("scripts.gui.tasks.index")
44local util = require("scripts.util")
45
46--- @param force LuaForce
47local function init_force(force)
48  --- @class ForceTable
49  storage.forces[force.index] = {
50    --- @type number[]
51    completed_tasks = {},
52    --- @type number[]
53    tasks = {},
54  }
55end
56
57-- BOOTSTRAP
58
59script.on_init(function()
60  --- @type table<uint, ForceTable>
61  storage.forces = {}
62  storage.next_task_id = 1
63  --- @type table<uint, PlayerTable>
64  storage.players = {}
65  --- @type table<number, Task>
66  storage.tasks = {}
67
68  for _, force in pairs(game.forces) do
69    init_force(force)
70  end
71  for _, player in pairs(game.players) do
72    player_data.init(player)
73  end
74
75  migrations.generic()
76end)
77
78script.on_load(function()
79  for _, Task in pairs(storage.tasks) do
80    task.load(Task)
81  end
82
83  for _, player_table in pairs(storage.players) do
84    tasks_gui.load(player_table.guis.tasks)
85    if player_table.guis.edit_task then
86      edit_task_gui.load(player_table.guis.edit_task)
87    end
88  end
89end)
90
91script.on_configuration_changed(function(e)
92  if migration.on_config_changed(e, migrations.versions) then
93    migrations.generic()
94  end
95end)
96
97-- FORCE
98
99script.on_event(defines.events.on_force_created, function(e)
100  init_force(e.force)
101end)
102
103-- INTERACTION
104
105gui.hook_events(function(e)
106  local msg = gui.read_action(e)
107  if msg then
108    local Gui = util.get_gui(e.player_index, msg.gui)
109    if Gui then
110      Gui:dispatch(msg, e)
111    end
112  end
113end)
114
115script.on_event("tlst-linked-confirm-gui", function(e)
116  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
117  local EditTaskGui = util.get_gui(e.player_index, "edit_task")
118  if EditTaskGui then
119    EditTaskGui:dispatch({ action = "confirm" })
120    player.play_sound({ path = "utility/confirm" })
121  elseif player.mod_settings["tlst-new-task-on-confirm"].value then
122    local TasksGui = util.get_gui(e.player_index, "tasks")
123    if TasksGui and TasksGui.state.visible and not TasksGui.state.pinned then
124      TasksGui:dispatch({ action = "edit_task", confirmed = true })
125    end
126  end
127end)
128
129--- @param player_index uint
130local function toggle_new_task(player_index)
131  local EditTaskGui = util.get_gui(player_index, "edit_task")
132  if EditTaskGui then
133    EditTaskGui:destroy()
134  else
135    local player = game.get_player(player_index) --[[@as LuaPlayer]]
136    local player_table = storage.players[player_index]
137    edit_task_gui.new(player, player_table, { standalone = true })
138  end
139end
140
141script.on_event("tlst-new-task", function(e)
142  toggle_new_task(e.player_index)
143end)
144
145script.on_event({ "tlst-toggle-gui", defines.events.on_lua_shortcut }, function(e)
146  if (e.input_name or e.prototype_name) == "tlst-toggle-gui" then
147    local player_table = storage.players[e.player_index]
148    local Gui = util.get_gui(e.player_index, "tasks")
149    if Gui then
150      Gui:toggle()
151    else
152      local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
153      player_data.refresh(player, player_table)
154    end
155  elseif e.prototype_name == "tlst-new-task" then
156    toggle_new_task(e.player_index)
157  end
158end)
159
160-- PLAYER
161
162script.on_event(defines.events.on_player_created, function(e)
163  local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
164
165  player_data.init(player)
166  player_data.refresh(player, storage.players[e.player_index])
167end)
168
169script.on_event(defines.events.on_player_changed_force, function(e)
170  local player = game.get_player(e.player_index)
171  if not player then
172    return
173  end
174
175  local player_table = storage.players[e.player_index]
176  if not player_table then
177    return
178  end
179
180  player_data.refresh(player, player_table)
181end)
182
183script.on_event(defines.events.on_player_removed, function(e)
184  -- Remove all player tasks
185  local player_table = storage.players[e.player_index]
186  for _, task_ids in pairs({ player_table.completed_tasks, player_table.tasks }) do
187    for _, task_id in pairs(task_ids) do
188      local Task = storage.tasks[task_id]
189      if Task then
190        Task:delete()
191      end
192    end
193  end
194
195  storage.players[e.player_index] = nil
196end)
197
198script.on_event(defines.events.on_runtime_mod_setting_changed, function(e)
199  if e.setting == "tlst-new-task-on-confirm" then
200    local TasksGui = util.get_gui(e.player_index, "tasks")
201    if TasksGui then
202      local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
203      local tooltip = { "gui.tlst-new-task" }
204      if player.mod_settings[e.setting].value then
205        tooltip[1] = tooltip[1] .. "-instruction"
206      end
207      TasksGui.refs.new_task_button.tooltip = tooltip
208    end
209  elseif e.setting == "tlst-show-active-task" or e.setting == "tlst-active-filter-assigned" then
210    local player = game.get_player(e.player_index) --[[@as LuaPlayer]]
211    local player_table = storage.players[e.player_index]
212    local value = player.mod_settings["tlst-show-active-task"].value
213    if value == "off" then
214      active_task_button.destroy(player_table)
215    else
216      active_task_button.build(player, player_table)
217    end
218  end
219end)