diff --git a/chatcommands.lua b/chatcommands.lua index 284c49c..c77ba33 100644 --- a/chatcommands.lua +++ b/chatcommands.lua @@ -1,6 +1,6 @@ minetest.register_chatcommand("mail",{ description = "Open the mail interface", func = function(name) - mail.show_inbox(name, "3", "1", "") + mail.show_mail_menu(name) end }) diff --git a/init.lua b/init.lua index cf25a92..2646f98 100644 --- a/init.lua +++ b/init.lua @@ -21,7 +21,9 @@ mail = { to = {}, cc = {}, bcc = {}, - boxtab = {} + boxtab = {}, + sortfield = {}, + sortdirection = {} }, message_drafts = {} diff --git a/storage.lua b/storage.lua index a3e6488..a853299 100644 --- a/storage.lua +++ b/storage.lua @@ -43,75 +43,33 @@ function mail.get_message(playername, msg_id) end end -function mail.sort_messages(unsorted_messages, sortfield, sortdirection) - local messages = {} - if not sortfield or sortfield == "" then - sortfield = "3" - end - if not sortdirection or sortdirection == "" then - sortdirection = "1" - end - - if unsorted_messages[1] then - -- add first message - table.insert(messages, unsorted_messages[1]) - table.remove(unsorted_messages, 1) - -- sort messages - for _, unsorted_msg in ipairs(unsorted_messages) do - local is_message_sorted = false - for j, sorted_msg in ipairs(messages) do - if sortfield == "1" and unsorted_msg.from >= sorted_msg.from then -- for inbox - table.insert(messages, j, unsorted_msg) - is_message_sorted = true - break - elseif sortfield == "1" and unsorted_msg.to >= sorted_msg.to then -- for outbox - table.insert(messages, j, unsorted_msg) - is_message_sorted = true - break - elseif sortfield == "2" and unsorted_msg.subject >= sorted_msg.subject then - table.insert(messages, j, unsorted_msg) - is_message_sorted = true - break - elseif sortfield == "3" and unsorted_msg.time >= sorted_msg.time then - table.insert(messages, j, unsorted_msg) - is_message_sorted = true - break - end - end - if not is_message_sorted then - table.insert(messages, 1, unsorted_msg) - end - end - end - - -- reverse for descending - - local sorted_messages = messages - - if sortdirection == "2" then - sorted_messages = {} - for i=#messages, 1, -1 do - sorted_messages[#sorted_messages+1] = messages[i] - end - end - - return sorted_messages +local function safe_find(str, sub) + return str and sub and str:find(sub, 1, true) or nil end -function mail.filter_messages(unfiltered_messages, filter) - if not filter or filter == "" then - return unfiltered_messages - end - - local filtered_messages = {} - - for _, msg in ipairs(unfiltered_messages) do - if string.find(msg.from, filter) or string.find(msg.to, filter) or string.find(msg.subject, filter) then - table.insert(filtered_messages, msg) +function mail.sort_messages(messages, sortfield, descending, filter) + local results = {} + -- Filtering + if filter and filter ~= "" then + for _, msg in ipairs(messages) do + if safe_find(msg.from, filter) or safe_find(msg.to, filter) or safe_find(msg.subject, filter) then + table.insert(results, msg) + end + end + else + for i = 1, #messages do + results[i] = messages[i] end end - - return filtered_messages + -- Sorting + if sortfield ~= nil then + if descending then + table.sort(results, function(a, b) return a[sortfield] > b[sortfield] end) + else + table.sort(results, function(a, b) return a[sortfield] < b[sortfield] end) + end + end + return results end -- marks a mail read by its id diff --git a/ui/events.lua b/ui/events.lua index 8722ad4..6ff24bc 100644 --- a/ui/events.lua +++ b/ui/events.lua @@ -1,46 +1,44 @@ + +-- Getter to filter and sort messages on demand +local function messageGetter(messages, sortfield, ascending, filter) + local results + return function() + if not results then + results = mail.sort_messages(messages, sortfield, ascending, filter) + end + return results + end +end + minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "mail:inbox" and formname ~= "mail:sent" and formname ~= "mail:drafts" then return end + -- Get player name and handle / convert common input fields local name = player:get_player_name() + local filter = fields.filter or "" + local sortfieldindex = tonumber(fields.sortfield or mail.selected_idxs.sortfield[name]) or 3 + local sortdirection = fields.sortdirection or mail.selected_idxs.sortdirection[name] or "1" + local inboxsortfield = ({"from","subject","time"})[sortfieldindex] + local outboxsortfield = ({"to","subject","time"})[sortfieldindex] + + -- Store common player configuration for reuse + mail.selected_idxs.sortfield[name] = sortfieldindex + mail.selected_idxs.sortdirection[name] = sortdirection -- split inbox and sent msgs for different tests local entry = mail.get_storage_entry(name) - - local messagesInboxUnAnalyzed = entry.inbox - local messagesOutBoxUnAnalyzed = entry.outbox local messagesDrafts = entry.drafts + local getInbox = messageGetter(entry.inbox, inboxsortfield, sortdirection == "2", filter) + local getOutbox = messageGetter(entry.outbox, outboxsortfield, sortdirection == "2", filter) - -- filter inbox/outbox messages - - local filter = fields.filter - if not filter then - filter = "" - end - - local messagesInboxFiltered = mail.filter_messages(messagesInboxUnAnalyzed, filter) - local messagesOutboxFiltered = mail.filter_messages(messagesOutBoxUnAnalyzed, filter) - - -- then sort them - - local sortfield = tostring(fields.sortfield) - local sortdirection = tostring(fields.sortdirection) - if not sortfield or sortfield == "" or sortfield == "0" then - sortfield = "3" - end - if not sortdirection or sortdirection == "" or sortdirection == "0" then - sortdirection = "1" - end - - local messagesInbox = mail.sort_messages(messagesInboxFiltered, sortfield, sortdirection, filter) - local messagesSent = mail.sort_messages(messagesOutboxFiltered, sortfield, sortdirection, filter) - + -- Hanmdle formspec event if fields.inbox then -- inbox table local evt = minetest.explode_table_event(fields.inbox) mail.selected_idxs.inbox[name] = evt.row - 1 - if evt.type == "DCL" and messagesInbox[mail.selected_idxs.inbox[name]] then - mail.show_message(name, messagesInbox[mail.selected_idxs.inbox[name]].id) + if evt.type == "DCL" and getInbox()[mail.selected_idxs.inbox[name]] then + mail.show_message(name, getInbox()[mail.selected_idxs.inbox[name]].id) end return true end @@ -48,8 +46,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if fields.sent then -- sent table local evt = minetest.explode_table_event(fields.sent) mail.selected_idxs.sent[name] = evt.row - 1 - if evt.type == "DCL" and messagesSent[mail.selected_idxs.sent[name]] then - mail.show_message(name, messagesSent[mail.selected_idxs.sent[name]].id) + if evt.type == "DCL" and getOutbox()[mail.selected_idxs.sent[name]] then + mail.show_message(name, getOutbox()[mail.selected_idxs.sent[name]].id) end return true end @@ -72,21 +70,21 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if fields.boxtab == "1" then mail.selected_idxs.boxtab[name] = 1 - mail.show_inbox(name, sortfield, sortdirection, filter) + mail.show_inbox(name, sortfieldindex, sortdirection, filter) elseif fields.boxtab == "2" then mail.selected_idxs.boxtab[name] = 2 - mail.show_sent(name, sortfield, sortdirection, filter) + mail.show_sent(name, sortfieldindex, sortdirection, filter) elseif fields.boxtab == "3" then mail.selected_idxs.boxtab[name] = 3 mail.show_drafts(name) elseif fields.read then - if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then -- inbox table - mail.show_message(name, messagesInbox[mail.selected_idxs.inbox[name]].id) - elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then -- sent table - mail.show_message(name, messagesSent[mail.selected_idxs.sent[name]].id) + if formname == "mail:inbox" and getInbox()[mail.selected_idxs.inbox[name]] then -- inbox table + mail.show_message(name, getInbox()[mail.selected_idxs.inbox[name]].id) + elseif formname == "mail:sent" and getOutbox()[mail.selected_idxs.sent[name]] then -- sent table + mail.show_message(name, getOutbox()[mail.selected_idxs.sent[name]].id) end elseif fields.edit then @@ -102,60 +100,60 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end elseif fields.delete then - if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then -- inbox table - mail.delete_mail(name, messagesInbox[mail.selected_idxs.inbox[name]].id) - elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then -- sent table - mail.delete_mail(name, messagesSent[mail.selected_idxs.sent[name]].id) + if formname == "mail:inbox" and getInbox()[mail.selected_idxs.inbox[name]] then -- inbox table + mail.delete_mail(name, getInbox()[mail.selected_idxs.inbox[name]].id) + elseif formname == "mail:sent" and getOutbox()[mail.selected_idxs.sent[name]] then -- sent table + mail.delete_mail(name, getOutbox()[mail.selected_idxs.sent[name]].id) elseif formname == "mail:drafts" and messagesDrafts[mail.selected_idxs.drafts[name]] then -- drafts table mail.delete_mail(name, messagesDrafts[mail.selected_idxs.drafts[name]].id) end - mail.show_mail_menu(name, sortfield, sortdirection, filter) + mail.show_mail_menu(name, sortfieldindex, sortdirection, filter) elseif fields.reply then - if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then - local message = messagesInbox[mail.selected_idxs.inbox[name]] + if formname == "mail:inbox" and getInbox()[mail.selected_idxs.inbox[name]] then + local message = getInbox()[mail.selected_idxs.inbox[name]] mail.reply(name, message) - elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then - local message = messagesSent[mail.selected_idxs.sent[name]] + elseif formname == "mail:sent" and getOutbox()[mail.selected_idxs.sent[name]] then + local message = getOutbox()[mail.selected_idxs.sent[name]] mail.reply(name, message) end elseif fields.replyall then - if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then - local message = messagesInbox[mail.selected_idxs.inbox[name]] + if formname == "mail:inbox" and getInbox()[mail.selected_idxs.inbox[name]] then + local message = getInbox()[mail.selected_idxs.inbox[name]] mail.replyall(name, message) - elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then - local message = messagesSent[mail.selected_idxs.sent[name]] + elseif formname == "mail:sent" and getOutbox()[mail.selected_idxs.sent[name]] then + local message = getOutbox()[mail.selected_idxs.sent[name]] mail.replyall(name, message) end elseif fields.forward then - if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then - local message = messagesInbox[mail.selected_idxs.inbox[name]] + if formname == "mail:inbox" and getInbox()[mail.selected_idxs.inbox[name]] then + local message = getInbox()[mail.selected_idxs.inbox[name]] mail.forward(name, message) - elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then - local message = messagesSent[mail.selected_idxs.sent[name]] + elseif formname == "mail:sent" and getOutbox()[mail.selected_idxs.sent[name]] then + local message = getOutbox()[mail.selected_idxs.sent[name]] mail.forward(name, message) end elseif fields.markread then - if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then - mail.mark_read(name, messagesInbox[mail.selected_idxs.inbox[name]].id) - elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then - mail.mark_read(name, messagesSent[mail.selected_idxs.sent[name]].id) + if formname == "mail:inbox" and getInbox()[mail.selected_idxs.inbox[name]] then + mail.mark_read(name, getInbox()[mail.selected_idxs.inbox[name]].id) + elseif formname == "mail:sent" and getOutbox()[mail.selected_idxs.sent[name]] then + mail.mark_read(name, getOutbox()[mail.selected_idxs.sent[name]].id) end - mail.show_mail_menu(name, sortfield, sortdirection, filter) + mail.show_mail_menu(name, sortfieldindex, sortdirection, filter) elseif fields.markunread then - if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then - mail.mark_unread(name, messagesInbox[mail.selected_idxs.inbox[name]].id) - elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then - mail.mark_unread(name, messagesSent[mail.selected_idxs.sent[name]].id) + if formname == "mail:inbox" and getInbox()[mail.selected_idxs.inbox[name]] then + mail.mark_unread(name, getInbox()[mail.selected_idxs.inbox[name]].id) + elseif formname == "mail:sent" and getOutbox()[mail.selected_idxs.sent[name]] then + mail.mark_unread(name, getOutbox()[mail.selected_idxs.sent[name]].id) end - mail.show_mail_menu(name, sortfield, sortdirection, filter) + mail.show_mail_menu(name, sortfieldindex, sortdirection, filter) elseif fields.new then mail.show_compose(name) @@ -170,7 +168,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) mail.show_about(name) elseif fields.sortfield or fields.sortdirection or fields.filter then - mail.show_mail_menu(name, sortfield, sortdirection, filter) + mail.show_mail_menu(name, sortfieldindex, sortdirection, filter) end return true diff --git a/ui/inbox.lua b/ui/inbox.lua index 1d76b14..554ce85 100644 --- a/ui/inbox.lua +++ b/ui/inbox.lua @@ -2,20 +2,10 @@ local S = minetest.get_translator("mail") -function mail.show_inbox(name, sortfield, sortdirection, filter) - if not sortfield or sortfield == "" or sortfield == "0" then - sortfield = 3 - end - if not sortdirection or sortdirection == "" or sortdirection == "0" then - sortdirection = 1 - end - - sortfield = tostring(sortfield) - sortdirection = tostring(sortdirection) - - if not filter then - filter = "" - end +function mail.show_inbox(name, sortfieldindex, sortdirection, filter) + sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name]) or 3 + sortdirection = sortdirection or mail.selected_idxs.sortdirection[name] or "1" + filter = filter or "" local inbox_formspec = "size[8.5,10;]" .. mail.theme .. [[ tabheader[0.3,1;boxtab;]] .. S("Inbox") .. "," .. S("Sent messages").. "," .. S("Drafts") .. [[;1;false;false] @@ -34,9 +24,9 @@ function mail.show_inbox(name, sortfield, sortdirection, filter) button_exit[6,9.5;2.5,0.5;quit;]] .. S("Close") .. [[] dropdown[0,9.4;2,0.5;sortfield;]] .. - S("From") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. tostring(sortfield) .. [[;1] + S("From") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. sortfieldindex .. [[;true] dropdown[2.0,9.4;2,0.5;sortdirection;]] .. - S("Ascending") .. "," .. S("Descending") .. [[;]] .. tostring(sortdirection) .. [[;1] + S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;true] field[4.25,9.85;1.4,0.5;filter;]] .. S("Filter") .. [[:;]] .. filter .. [[] button[5.14,9.52;0.85,0.5;search;Q] @@ -44,11 +34,12 @@ function mail.show_inbox(name, sortfield, sortdirection, filter) table[0,0.7;5.75,8.35;inbox;#999,]] .. S("From") .. "," .. S("Subject") local formspec = { inbox_formspec } local entry = mail.get_storage_entry(name) - local messages = mail.sort_messages(mail.filter_messages(entry.inbox, filter), sortfield, sortdirection) + local sortfield = ({"from","subject","time"})[sortfieldindex] + local messages = mail.sort_messages(entry.inbox, sortfield, sortdirection == "2", filter) mail.message_drafts[name] = nil - if messages[1] then + if #messages > 0 then for _, message in ipairs(messages) do if not message.read then if not mail.player_in_list(name, message.to) then diff --git a/ui/outbox.lua b/ui/outbox.lua index 3466e5e..97e6a2f 100644 --- a/ui/outbox.lua +++ b/ui/outbox.lua @@ -2,20 +2,10 @@ local S = minetest.get_translator("mail") -function mail.show_sent(name, sortfield, sortdirection, filter) - if not sortfield or sortfield == "" or sortfield == "0" then - sortfield = 3 - end - if not sortdirection or sortdirection == "" or sortdirection == "0" then - sortdirection = 1 - end - - sortfield = tostring(sortfield) - sortdirection = tostring(sortdirection) - - if not filter then - filter = "" - end +function mail.show_sent(name, sortfieldindex, sortdirection, filter) + sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name]) or 3 + sortdirection = sortdirection or mail.selected_idxs.sortdirection[name] or "1" + filter = filter or "" local sent_formspec = "size[8.5,10;]" .. mail.theme .. [[ tabheader[0.3,1;boxtab;]] .. S("Inbox") .. "," .. S("Sent messages").. "," .. S("Drafts") .. [[;2;false;false] @@ -32,9 +22,9 @@ function mail.show_sent(name, sortfield, sortdirection, filter) button_exit[6,9.5;2.5,0.5;quit;]] .. S("Close") .. [[] dropdown[0,9.4;2,0.5;sortfield;]] - .. S("To") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. tostring(sortfield) .. [[;1] + .. S("To") .. "," .. S("Subject") .. "," .. S("Date") .. [[;]] .. sortfieldindex .. [[;1] dropdown[2.0,9.4;2,0.5;sortdirection;]] - .. S("Ascending") .. "," .. S("Descending") .. [[;]] .. tostring(sortdirection) .. [[;1] + .. S("Ascending") .. "," .. S("Descending") .. [[;]] .. sortdirection .. [[;1] field[4.25,9.85;1.4,0.5;filter;]].. S("Filter") .. [[:;]] .. filter .. [[] button[5.14,9.52;0.85,0.5;search;Q] @@ -42,11 +32,12 @@ function mail.show_sent(name, sortfield, sortdirection, filter) table[0,0.7;5.75,8.35;sent;#999,]] .. S("To") .. "," .. S("Subject") local formspec = { sent_formspec } local entry = mail.get_storage_entry(name) - local messages = mail.sort_messages(mail.filter_messages(entry.outbox, filter), sortfield, sortdirection) + local sortfield = ({"to","subject","time"})[sortfieldindex] + local messages = mail.sort_messages(entry.outbox, sortfield, sortdirection == "2", filter) mail.message_drafts[name] = nil - if messages[1] then + if #messages > 0 then for _, message in ipairs(messages) do formspec[#formspec + 1] = "," formspec[#formspec + 1] = ","