From 3490cceb6b94ffbc947b699c8495cf8500e65b98 Mon Sep 17 00:00:00 2001 From: ailurux Date: Fri, 27 Sep 2024 16:59:59 +1000 Subject: [PATCH] Added listened indicator for audiobooks and podcasts --- lua/browser.lua | 95 +++++++++++++++++++------------ lua/images.lua | 2 + lua/img/listened.png | Bin 0 -> 595 bytes lua/img/unlistened.png | Bin 0 -> 6532 bytes lua/main_menu.lua | 1 + lua/theme_dark.lua | 6 ++ lua/theme_hicon.lua | 8 +++ lua/theme_light.lua | 10 +++- lua/widgets.lua | 6 +- luals-stubs/database.lua | 3 + src/tangara/database/index.cpp | 2 +- src/tangara/lua/lua_database.cpp | 18 ++++++ 12 files changed, 113 insertions(+), 38 deletions(-) create mode 100644 lua/img/listened.png create mode 100644 lua/img/unlistened.png diff --git a/lua/browser.lua b/lua/browser.lua index 48c3895f..ce89d5ab 100644 --- a/lua/browser.lua +++ b/lua/browser.lua @@ -9,6 +9,7 @@ local playback = require("playback") local theme = require("theme") local screen = require("screen") local database = require("database") +local img = require("images") return screen:new{ create_ui = function(self) @@ -54,43 +55,66 @@ return screen:new{ } end - local buttons = header:Object({ - flex = { - flex_direction = "row", - flex_wrap = "wrap", - justify_content = "space-between", - align_items = "center", - align_content = "center" - }, - w = lvgl.PCT(100), - h = lvgl.SIZE_CONTENT, - pad_column = 4 - }) - local original_iterator = self.iterator:clone() - local enqueue = widgets.IconBtn(buttons, "//lua/img/enqueue.png", "Enqueue") - enqueue:onClicked(function() - queue.add(original_iterator) - playback.playing:set(true) - end) - local shuffle_play = widgets.IconBtn(buttons, "//lua/img/shuffleplay.png", "Shuffle") - shuffle_play:onClicked(function() - queue.clear() - queue.random:set(true) - queue.add(original_iterator) - playback.playing:set(true) - backstack.push(playing:new()) - end) - -- enqueue:add_flag(lvgl.FLAG.HIDDEN) - local play = widgets.IconBtn(buttons, "//lua/img/play_small.png", "Play") - play:onClicked(function() - queue.clear() - queue.random:set(false) - queue.add(original_iterator) - playback.playing:set(true) - backstack.push(playing:new()) - end) + if (self.mediatype == database.MediaTypes.Music) then + local buttons = header:Object({ + flex = { + flex_direction = "row", + flex_wrap = "wrap", + justify_content = "space-between", + align_items = "center", + align_content = "center" + }, + w = lvgl.PCT(100), + h = lvgl.SIZE_CONTENT, + pad_column = 4 + }) + local original_iterator = self.iterator:clone() + local enqueue = widgets.IconBtn(buttons, "//lua/img/enqueue.png", "Enqueue") + enqueue:onClicked(function() + queue.add(original_iterator) + playback.playing:set(true) + end) + local shuffle_play = widgets.IconBtn(buttons, "//lua/img/shuffleplay.png", "Shuffle") + shuffle_play:onClicked(function() + queue.clear() + queue.random:set(true) + queue.add(original_iterator) + playback.playing:set(true) + backstack.push(playing:new()) + end) + -- enqueue:add_flag(lvgl.FLAG.HIDDEN) + local play = widgets.IconBtn(buttons, "//lua/img/play_small.png", "Play") + play:onClicked(function() + queue.clear() + queue.random:set(false) + queue.add(original_iterator) + playback.playing:set(true) + backstack.push(playing:new()) + end) + end + + local get_icon_func = nil + local show_listened = self.mediatype == database.MediaTypes.Audiobook or self.mediatype == database.MediaTypes.Podcast + if show_listened then + get_icon_func = function (item) + local contents = item:contents() + if type(contents) == "userdata" then + return + else + local track = database.track_by_id(contents) + if not track then return end + if (track.play_count > 0) then + return img.listened + else + return img.unlistened + end + end + + end + end widgets.InfiniteList(self.root, self.iterator, { + get_icon = get_icon_func, callback = function(item) return function() local contents = item:contents() @@ -98,6 +122,7 @@ return screen:new{ backstack.push(require("browser"):new{ title = self.title, iterator = contents, + mediatype = self.mediatype, breadcrumb = tostring(item) }) else diff --git a/lua/images.lua b/lua/images.lua index 84853a52..42a4a3fd 100644 --- a/lua/images.lua +++ b/lua/images.lua @@ -17,6 +17,8 @@ local img = { settings = lvgl.ImgData("//lua/img/settings.png"), chevron = lvgl.ImgData("//lua/img/chevron.png"), usb = lvgl.ImgData("//lua/img/usb.png"), + listened = lvgl.ImgData("//lua/img/listened.png"), + unlistened = lvgl.ImgData("//lua/img/unlistened.png"), } return img diff --git a/lua/img/listened.png b/lua/img/listened.png new file mode 100644 index 0000000000000000000000000000000000000000..6c23423ef78205b5bc6d50f25b368799ca0e70d5 GIT binary patch literal 595 zcmV-Z0<8UsP)EX>4Tx04R}tkv&MmKp2MKrj}NzIM_kNAwzYtAS&XhRVYG*P%E_RU~=gnG%+M8 zE{=k0!NH%!s)LKOt`4q(Aov5~?BJy6A|-y86k5c1$8itueecWNcYx5SGR^8512o+> zGpVGQ%dd#xS9BwU2u)FDmN6?yY50z>dj$A?m*83cb$^atwO}zIAQI0o!?cOliKjMg zgY!OdjFn}T_?&puqze*1a$WKGjdRImfoI0dY-Wx)Ml6;(Sm|I^HZ|f&;<&2mlrQ8w zRyl8R)~Yqux+i~Ow4g69ah=u>QdqzuB#2N@Lj_gXNYJj6Vj)B4Ngw~9>zBx-kgEbl zj(KcAgY5dj|KN9Tt>VPEmlRC`p%=&b7zV<-K(p>R-^Y&AJOP5wz?I(iZ#01EPtxmc zEq(;_Z37qAZB5w&E_Z-|Cqp)6R|?V+ibdf4jJ_!k^xpzKt6tw)=Qw=;vec{e4RCM> zjFc#Q&F9^b&c6Ly)9T+34;ONO0jX_y00009a7bBm001r{001r{0eGc9b^rhX2XskI zMF;2!8wMRPVe_G)0000PbVXQnLvL+uWo~o;Lvm$dbY)~9cWHEJAV*0}P*;Ht7XSbN zJxN4CR2b7^WPpPI|NsAIKm&}7jEoHU6rhOXQh=G4G_n&vI-}k@HT4&CAp1t>H@BMl9dDec`B-@fLCB@f^ zLm&`IqLrCF_*}`q#YDj0(F_q82t-^m+`)xwPvJoW*(^H4AAoYh0s$xx%Ai9ap+lvv zjI247_^10CFT_l0)6TuCt7%k<7JqiV^8Fu?M4o?pg^+x{$@vcrUlB{vhL3A^85St* zOchb~h%8^Tb#Th2+XLqwy>LOvvYvTiF2Ve0Q`g4Nue%Jp(l~}??dX*rOQ!`lZrvNS zwmzUIyz1KU`w$7AxzEOlLTL+k=}OW{g8C6w&lZA>)DCUFu%Xw&i2mMk_m`yw#GoQ< zYq|%EWL-XLu;;1Vl)hPKZ|VBPTez2lfi?Bqt4G?%x9^Si;~NUOv(x)p%18Ten7wR8 zOvYn{vwLPlY)yo$!eh#d^$&+JbCDbB7C%{(Hj#QH$vyYVr$0S4sO6+Pq=#G^ZV)*% z{#K-K=k~HS#d#ihA|-#)s|M zp@TxBiS2HKRIw^8H>JFe0!`euLb#z%R7p&`2t z)(9S?hzjkZDd<%Y`?k;r(1NGM+hn=b=-?MJQ!$x++Z9$worQ3oo@gHG7pcw7AgnMm zrfo4k&?@BeSoFHhtku<){?RyTmF6QRQk#2To;7nx)v#V)*0%Yy$svuxJnP~?;IwI) z{`0(@Wi4wht-8-ZH|<0e_8cN=S(Js|IBQwjf$NW41+VU5Yn6svw^<;}5A42QH;kA9rt+Q%5sXSIsKMPMNO}} zI@H|SXg5vH$MqJp*g=NHcIPU4nD5zA666 z;n9G*sOuxf`vt*A?OB|(7jN_8`9g!0Qd=j}6l25)G?1ovK^+ zzU5PTcXz~`5!q(CByZObCN5d;5)S zY?5c&_WZNW39lwUI{dNgRP$l9weY!sfNjmB4~V@Is*Ln)yBv3h= zHKX2Fsu^~+OyaYgKTXhKeppi}hZa>P_#im1^|-pham3bW{A>&~=efCf$E;8RFNfE< zZ~9y)f$s#Q&)5LvHFO4RYwy06+&|M+@MuLpjTjAX= z>dTaj)4OWUvF)fZW_!$+wdoOhqxhMKr`Z{6ga;KTRX&_^=z$(zyGmr&8`?&(o2E-C zO0EhCd0QgoR@N~pgo!S_h-YLygIUc{7J>Z9Trc{tOG%6Km3s#z;n)(tbQ*7?K1U==Iw>>mZ#sGOh!{q3o2DCC^xT?N$(M3!PvD`$cU66Tp5jyk>{3!4 z$|K3$)Q6gVbh@T?^$_LAsHFUoe$oq9Gcckt=r$Bv6OJm1MPH18+B zYrf!OYvEIs*T@se+S)E$xH>OiAkC z$fu2?N|z@y3}ZjJ1uY59`n62RwMNTUMK1*Z7+qd-!3O#@c>ZfkKPdY)vh0d3`EKaZ z^+mBNI_(Rudjp|&Z;vB}{{G6Xzi{0`%5swozbyOxaWNMs-K((`A@|6N5AQf8z0WHB zZ17Madh=k`pioG6fA5y!F9+&1!z7D5uN?TZ+EDaMX6?Nv^qQ&CPQQHN%vFU>^%|LO z6Z8_hXUWBzwy%*E3|lpGtQ6Ruk`=thm*j|yHp-mo^N(M@I!ViyTy2zM6k-aT}rNFV%AIOsD>O3A4c4vu{i*BA?VvzG#8;i0+LRPmQj*$gU(Udc`5 z=~gN|6suC&kz%q|V*m5a!$s%L;l^)Ocqb3xM|vXNCcA>$K9OeieCdO-1G#i($I8CD z^Hn}k7mxQ^^K|CyimiK7?T@(;e0x7ud`Pzpcg3-8Zt{Ck>GilJqI0ZHINS|0;&@j< zi=Nf7b5v^&hE#1#8@U`>WJkO+S+DDA?<%AEM!-8nK`xGhT^VgRID8w(Dw_0S0NIdRt_QN_pnZO+)!kaYylq4#FC{ z8A%8K*mr1l9Ft8}&+~s}H0{#lKJq5_0gyNzG-t`FdwKO?&CdDoqe-VyqqJ{bi@4@& z+WispP>MX=9;hWyhiobpo3EF+2J8HY$#=h;NB5Ah(ZIqhjtv{Aeaux>Quqof%N%e*`gI1?2}K_2?22#)yeT+ zBs_ZEH(Rx)j;h>EGfJFF5S4m<-TGAR%v!aLgD$0NyAgX9oc5O9-kwx9;r4C|=FG#t zNc$~k;e^Mr^iv5#Q99f|*WFUP|5(y-&&%w~2~h?Qo|dTCy)DSJRxfPXx7fbQg2+QA z=3R=Mk6zX8S-F<>YA*z`;vmD+)Rt&!`lB%f+rhm383d~)W5tA#^I1+sdILL}RZN2` zpqgVB9o0?ZZMCW=Y&C`PiQXQ8!-jK#Fe5kiYm*`uys zf}_*iuX>`P(AD=*O;ySL$ro_U19OH!smFk0i+Q0v1*=vYvG=`QJj`hWV!i*m>rYS9 zv)Gn}cbV{X!s(0=$F3JoWFns#IO(&3`igb>ZfuRFROKU)K_~lU>|Jic)RJs%O@$o? ztUAk%da0O>6P3T_zshbcJW?WHkrw7}d|+y+@#`p$RXWyuJzJh6a7N+w2St%vwZ@fi z^hR!{bsMaRyMOc8?bZr9+%AgTo&N?I%DbN(~ zVOWK;f!*O`2Wq$EUo^Q4`afj-5*uH# zoX*dIfaZVW{-XUO_hn^Ji$ubkv8ciP@Q7vv7~emh#-cK4_~lm}915qehth^?Yf~w3 ztS+Dr*Q4uD;W(NO1w+GNu~@3^Pf)}F4wn)@1^7@PID!Gb*C;{S70d?*?SMZ@Uo(Y?I1;W#u(502ILqQSlN z(Ry$U4GU;f&{(=I8n+BZqv9=CY$gRNh7GN(ew(b_Cje6H$FA0p0-kfq$>4AM=d=wpswii;mIN zg;TxgG&okDj)8mOaCA6DR~Jk7!s%jZ+SFgsIV?JtM_~gyyunPtY`_Xy&IYRfjZ2MR z)pO*U{BNqwpvc4Ea4{B>%hqk+K2u|Bzy^tnkxD0NQ<< z12-6Oze4`KVSOi!&*T5_`o0+dLk}SIZzunX-`{lort4oZ@UN7ASJ!X4{uKlNO8Iwn z{lC#A{?CyI2msq49(bUUs`~O6JPfT2v~uM@AP80dy&|;GC(lU+*3P7B0D$f~pW^4xyAw+YsS(%Av+ last_index then last_index = index end - local btn = infinite_list.root:add_btn(nil, tostring(item)) + local icon = nil + if opts.get_icon then + icon = opts.get_icon(item) + end + local btn = infinite_list.root:add_btn(icon, tostring(item)) if add_to_top then btn:move_to_index(0) end diff --git a/luals-stubs/database.lua b/luals-stubs/database.lua index a21f61be..9d6c4c48 100644 --- a/luals-stubs/database.lua +++ b/luals-stubs/database.lua @@ -67,6 +67,9 @@ local Index = {} --- @return string function Index:name() end +--- Returns the media type of this index +function Index:type() end + --- Returns a new iterator that can be used to access every record within the --- first level of this index. --- @return Iterator it An iterator that yields `Record`s. diff --git a/src/tangara/database/index.cpp b/src/tangara/database/index.cpp index 0ced27ed..1cdc0d07 100644 --- a/src/tangara/database/index.cpp +++ b/src/tangara/database/index.cpp @@ -60,7 +60,7 @@ const IndexInfo kPodcasts{ .id = 5, .type = MediaType::kPodcast, .name = "Podcasts", - .components = {Tag::kTitle}, + .components = {Tag::kAlbum, Tag::kTitle}, }; const IndexInfo kAudiobooks{ diff --git a/src/tangara/lua/lua_database.cpp b/src/tangara/lua/lua_database.cpp index 39179bf3..2a3ab59d 100644 --- a/src/tangara/lua/lua_database.cpp +++ b/src/tangara/lua/lua_database.cpp @@ -388,6 +388,24 @@ static auto lua_database(lua_State* state) -> int { luaL_setfuncs(state, kDbRecordFuncs, 0); luaL_newlib(state, kDatabaseFuncs); + + lua_pushliteral(state, "MediaTypes"); + lua_newtable(state); + lua_pushliteral(state, "Unknown"); + lua_pushinteger(state, (int)database::MediaType::kUnknown); + lua_rawset(state, -3); + lua_pushliteral(state, "Music"); + lua_pushinteger(state, (int)database::MediaType::kMusic); + lua_rawset(state, -3); + lua_pushliteral(state, "Podcast"); + lua_pushinteger(state, (int)database::MediaType::kPodcast); + lua_rawset(state, -3); + lua_pushliteral(state, "Audiobook"); + lua_pushinteger(state, (int)database::MediaType::kAudiobook); + lua_rawset(state, -3); + lua_rawset(state, -3); + + return 1; }