mail_app.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. -- based on https://github.com/cheapie/mail
  2. laptop.register_app("mail", {
  3. app_name = "Mail",
  4. app_icon = "laptop_email_letter.png",
  5. app_info = "Send Electronic Mail",
  6. formspec_func = function(app, mtos)
  7. local cloud = mtos.bdev:get_app_storage('cloud', 'mail')
  8. if not cloud then
  9. mtos:set_app("mail:nonet")
  10. return false
  11. end
  12. if not mtos.sysram.current_player then
  13. mtos:set_app() -- no player. Back to launcher
  14. return false
  15. end
  16. if not cloud[mtos.sysram.current_player] then
  17. mtos:set_app("mail:newplayer")
  18. return false
  19. end
  20. local account = cloud[mtos.sysram.current_player]
  21. account.selected_box = account.selected_box or "inbox"
  22. account.selected_index = nil -- will be new determinated by selectedmessage
  23. local box = account[account.selected_box] -- inbox or outbox
  24. app.app_info = app.app_info.." - Welcome "..mtos.sysram.current_player
  25. local formspec =
  26. mtos.theme:get_tableoptions()..
  27. "tablecolumns[" ..
  28. "image,align=center,1="..mtos.theme:get_texture('laptop_mail.png')..",2="..mtos.theme:get_texture('laptop_mail_read.png')..";".. --icon column
  29. "color;".. -- subject and date color
  30. "text;".. -- subject
  31. "text,padding=1.5;".. -- sender
  32. "text,padding=1.5,align=right]".. -- date
  33. "table[0,0.5;7.5,8.2;message;"
  34. if box and box[1] then
  35. for idx,message in ipairs(box) do
  36. if idx > 1 then
  37. formspec = formspec..','
  38. end
  39. -- set read/unread status
  40. if account.selected_box == "sentbox" then
  41. formspec = formspec .. "2,"..mtos.theme.muted_textcolor.."," -- sent are always read
  42. elseif not message.is_read then
  43. formspec = formspec .. "1,"..mtos.theme.table_textcolor.."," -- unread
  44. else
  45. formspec = formspec .. "2,"..mtos.theme.muted_textcolor.."," -- read
  46. end
  47. -- set subject
  48. if not message.subject or message.subject == "" then
  49. formspec = formspec .. "(No Subject),"
  50. elseif string.len(message.subject) > 30 then
  51. formspec = formspec .. minetest.formspec_escape(string.sub(message.subject,1,27)) .. "...,"
  52. else
  53. formspec = formspec .. minetest.formspec_escape(message.subject) .. ","
  54. end
  55. -- set sender or receiver
  56. if account.selected_box == "inbox" then
  57. formspec = formspec..minetest.formspec_escape(message.sender or "") .."," -- body
  58. else
  59. formspec = formspec..minetest.formspec_escape(message.receiver or "") .."," -- body
  60. end
  61. -- set date
  62. formspec = formspec .. os.date("%c", message.time) -- timestamp
  63. -- handle marked line
  64. if account.selectedmessage and
  65. message.sender == account.selectedmessage.sender and
  66. message.subject == account.selectedmessage.subject and
  67. message.time == account.selectedmessage.time and
  68. message.body == account.selectedmessage.body then
  69. account.selected_index = idx
  70. end
  71. end
  72. formspec = formspec .. ";"..(account.selected_index or "").."]"
  73. else
  74. formspec = formspec .. ",,No Mail :(]"
  75. end
  76. -- toggle inbox/sentbox
  77. if account.selected_box == "inbox" then
  78. formspec = formspec .. mtos.theme:get_image_button('0,9;1,1', 'minor', 'switch_sentbox', 'laptop_mail_sentbox.png', '', 'Show Sent Messages')
  79. else
  80. formspec = formspec .. mtos.theme:get_image_button('0,9;1,1', 'minor', 'switch_inbox', 'laptop_mail_received.png', '', 'Show Received Messages')
  81. end
  82. formspec = formspec .. mtos.theme:get_image_button('1.7,9;1,1', 'minor', 'new', 'laptop_email_new.png', '', 'New Message')
  83. if account.newmessage then
  84. formspec = formspec .. mtos.theme:get_image_button('2.7,9;1,1', 'minor', 'continue', 'laptop_email_edit.png', '', 'Continue Last Message')
  85. end
  86. if account.selectedmessage then
  87. formspec = formspec ..
  88. mtos.theme:get_image_button('3.7,9;1,1', 'minor', 'reply', 'laptop_email_reply.png', '', 'Reply')..
  89. mtos.theme:get_image_button('4.7,9;1,1', 'minor', 'forward', 'laptop_email_forward.png', '', 'Forward')..
  90. mtos.theme:get_image_button('5.7,9;1,1', 'minor', 'delete', 'laptop_email_trash.png', '', 'Delete')
  91. if account.selected_box == "inbox" then
  92. if not account.selectedmessage.is_read then
  93. formspec = formspec .. mtos.theme:get_image_button('6.7,9;1,1', 'minor', 'markread', 'laptop_mail_read_button.png', '', 'Mark Message as Read')
  94. else
  95. formspec = formspec .. mtos.theme:get_image_button('6.7,9;1,1', 'minor', 'markunread', 'laptop_mail_button.png', '', 'Mark Message as Unread')
  96. end
  97. end
  98. formspec = formspec .. mtos.theme:get_image_button('8,9;1,1', 'minor', 'print', 'laptop_printer_button.png', '', 'Print Email')
  99. if account.selected_box == "inbox" then
  100. formspec = formspec .. mtos.theme:get_label('8,0.5', "From: "..(account.selectedmessage.sender or ""))
  101. else
  102. formspec = formspec .. mtos.theme:get_label('8,0.5', "To: "..(account.selectedmessage.receiver or ""))
  103. end
  104. formspec = formspec .. mtos.theme:get_label('8,1', "Subject: "..(account.selectedmessage.subject or ""))..
  105. mtos.theme:get_tableoptions(false).."tablecolumns[text]table[8,1.55;6.85,7.15;preview_bg;]"..
  106. "textarea[8.35,1.6;6.8,8.25;;"..minetest.colorize(mtos.theme.table_textcolor, minetest.formspec_escape(account.selectedmessage.body) or "")..";]"
  107. end
  108. return formspec
  109. end,
  110. receive_fields_func = function(app, mtos, sender, fields)
  111. if mtos.sysram.current_player ~= mtos.sysram.last_player then
  112. mtos:set_app() -- wrong player. Back to launcher
  113. return
  114. end
  115. local cloud = mtos.bdev:get_app_storage('cloud', 'mail')
  116. local account = cloud[mtos.sysram.current_player]
  117. if not account then
  118. mtos:set_app() -- wrong player. Back to launcher
  119. return
  120. end
  121. account.selected_box = account.selected_box or "inbox"
  122. local box = account[account.selected_box] -- inbox or outbox
  123. -- Set read status if 2 seconds selected
  124. if account.selected_index and account.selectedmessage and account.selected_box == "inbox" and
  125. account.selected_timestamp and (os.time() - account.selected_timestamp) > 1 then
  126. account.selectedmessage.is_read = true
  127. end
  128. -- process input
  129. if fields.message then
  130. local event = minetest.explode_table_event(fields.message)
  131. account.selectedmessage = box[event.row]
  132. if account.selectedmessage then
  133. account.selected_index = event.row
  134. account.selected_timestamp = os.time()
  135. else
  136. account.selected_index = nil
  137. end
  138. elseif fields.new then
  139. account.newmessage = {}
  140. mtos:set_app("mail:compose")
  141. elseif fields.continue then
  142. mtos:set_app("mail:compose")
  143. elseif fields.switch_sentbox then
  144. account.selected_box = "sentbox"
  145. account.selectedmessage = nil
  146. elseif fields.switch_inbox then
  147. account.selected_box = "inbox"
  148. account.selectedmessage = nil
  149. elseif account.selected_index then
  150. if fields.delete then
  151. table.remove(box, account.selected_index)
  152. account.selectedmessage = nil
  153. elseif fields.reply then
  154. account.newmessage = {}
  155. account.newmessage.receiver = account.selectedmessage.sender
  156. account.newmessage.subject = "Re: "..(account.selectedmessage.subject or "")
  157. account.newmessage.body = "Type your reply here."..string.char(10)..string.char(10).."--Original message follows--"..string.char(10)..(account.selectedmessage.body or "")
  158. mtos:set_app("mail:compose")
  159. elseif fields.forward then
  160. account.newmessage = {}
  161. account.newmessage.subject = "Fw: "..(account.selectedmessage.subject or "")
  162. account.newmessage.body = "Type your reply here."..string.char(10)..string.char(10).."--Original message follows--"..string.char(10)..(account.selectedmessage.body or "")
  163. mtos:set_app("mail:compose")
  164. elseif fields.markread then
  165. account.selectedmessage.is_read = true
  166. elseif fields.markunread then
  167. account.selectedmessage.is_read = false
  168. account.selected_timestamp = nil
  169. elseif fields.print then
  170. mtos:print_file_dialog({
  171. label = account.selectedmessage.subject,
  172. author = account.selectedmessage.sender,
  173. timestamp = account.selectedmessage.time,
  174. text = account.selectedmessage.body,
  175. })
  176. end
  177. end
  178. end
  179. })
  180. laptop.register_view("mail:newplayer", {
  181. formspec_func = function(app, mtos)
  182. return mtos.theme:get_label('1,3', "No mail account for player "..mtos.sysram.current_player.. " found. Do you like to create a new account?")..
  183. mtos.theme:get_button('1,4;3,1', 'major', 'create', 'Create Account')
  184. end,
  185. receive_fields_func = function(app, mtos, sender, fields)
  186. if mtos.sysram.current_player ~= mtos.sysram.last_player then
  187. mtos:set_app() -- wrong player. Back to launcher
  188. return
  189. end
  190. if fields.create then
  191. local cloud = mtos.bdev:get_app_storage('cloud', 'mail')
  192. cloud[mtos.sysram.current_player] = {
  193. inbox = {},
  194. sentbox = {}
  195. }
  196. app:back_app()
  197. elseif fields.os_back then
  198. app:exit_app()
  199. end
  200. end
  201. })
  202. laptop.register_view("mail:nonet", {
  203. formspec_func = function(app, mtos)
  204. return mtos.theme:get_label('1,3', "NO NETWORK CONNECTION")
  205. end,
  206. receive_fields_func = function(app, mtos, sender, fields)
  207. app:exit_app()
  208. end
  209. })
  210. -- Write new mail
  211. laptop.register_view("mail:compose", {
  212. formspec_func = function(app, mtos)
  213. local cloud = mtos.bdev:get_app_storage('cloud', 'mail')
  214. local account = cloud[mtos.sysram.current_player]
  215. account.newmessage = account.newmessage or {}
  216. local message = account.newmessage
  217. local formspec = "background[0,0.4;8,2.4;"..mtos.theme.contrast_background.."]"..
  218. mtos.theme:get_label("0.25,2", "Subject:", "contrast").."field[2.7,2;5,1;subject;;"..minetest.formspec_escape(message.subject or "").."]"..
  219. "background[0,3.05;7.95,3.44;"..mtos.theme.contrast_background.."]"..
  220. "textarea[0.25,3;8,4;body;;"..minetest.formspec_escape(message.body or "").."]"..
  221. mtos.theme:get_button("0,8;2,1", "major", "send", "Send message")..
  222. mtos.theme:get_label("0.25,0.75", "Receiver:", "contrast").."dropdown[2.4,0.75;5.2,1;receiver;"
  223. local sortedtab = {}
  224. for playername,_ in pairs(cloud) do
  225. table.insert(sortedtab, playername)
  226. end
  227. table.sort(sortedtab)
  228. local selected_idx
  229. for idx, playername in ipairs(sortedtab) do
  230. formspec = formspec..',' .. minetest.formspec_escape(playername)
  231. if playername == message.receiver then
  232. selected_idx = idx+1 -- +1 because of empty entry
  233. end
  234. end
  235. formspec = formspec .. ";"..(selected_idx or "").."]"
  236. if message.receiver and not cloud[message.receiver] then
  237. formspec = formspec..mtos.theme:get_label('2.3,8', "invalid receiver player")
  238. end
  239. return formspec
  240. end,
  241. receive_fields_func = function(app, mtos, sender, fields)
  242. if mtos.sysram.current_player ~= mtos.sysram.last_player then
  243. mtos:set_app() -- wrong player. Back to launcher
  244. return
  245. end
  246. local cloud = mtos.bdev:get_app_storage('cloud', 'mail')
  247. local account = cloud[mtos.sysram.current_player]
  248. account.newmessage = account.newmessage or {}
  249. local message = account.newmessage
  250. message.receiver = fields.receiver or message.receiver
  251. message.sender = mtos.sysram.current_player
  252. message.time = os.time()
  253. message.subject = fields.subject or message.subject
  254. message.body = fields.body or message.body
  255. if fields.send and message.receiver and cloud[message.receiver] then
  256. table.insert(cloud[message.receiver].inbox, message)
  257. table.insert(account.sentbox, table.copy(message))
  258. account.newmessage = nil
  259. app:back_app()
  260. end
  261. end
  262. })