|
| 1 | +local utils = require('utils') |
| 2 | +local loadedData ---@type AppInfo[]|string|true|nil |
| 3 | + |
| 4 | +---@param app AppInfo |
| 5 | +---@return boolean |
| 6 | +local function appDetails(app) |
| 7 | + ui.offsetCursor(4) |
| 8 | + ui.image(app.meta.icon, 32) |
| 9 | + ui.sameLine(0, 16) |
| 10 | + ui.offsetCursorY(-4) |
| 11 | + ui.beginGroup() |
| 12 | + ui.textWrapped(app.meta.description) |
| 13 | + ui.offsetCursorY(8) |
| 14 | + ui.pushFont(ui.Font.Small) |
| 15 | + if app.meta.author ~= 'x4fab' then |
| 16 | + ui.text('Author: %s' % app.meta.author) |
| 17 | + end |
| 18 | + ui.text('Version: %s' % app.meta.version) |
| 19 | + ui.text('Size: %s' % app.displaySize) |
| 20 | + if app.domainName then |
| 21 | + ui.text('More: ') |
| 22 | + ui.sameLine(0, 0) |
| 23 | + if ui.textHyperlink(app.domainName) then |
| 24 | + os.openURL(app.meta.detailsURL) |
| 25 | + end |
| 26 | + if ui.itemHovered() then |
| 27 | + ui.setTooltip(app.meta.detailsURL) |
| 28 | + end |
| 29 | + end |
| 30 | + if app.installed then |
| 31 | + ui.text('Location: ') |
| 32 | + ui.sameLine(0, 0) |
| 33 | + local shortLocation = app.location:regmatch('apps\\\\lua.+') |
| 34 | + if ui.textHyperlink(shortLocation) then |
| 35 | + os.openInExplorer(app.location) |
| 36 | + end |
| 37 | + if ui.itemHovered() then |
| 38 | + ui.setTooltip(app.location) |
| 39 | + end |
| 40 | + end |
| 41 | + ui.popFont() |
| 42 | + ui.endGroup() |
| 43 | + |
| 44 | + ui.offsetCursorY(12) |
| 45 | + local w = ui.availableSpaceX() |
| 46 | + if app.installing == true then |
| 47 | + w = w / 2 - 4 |
| 48 | + ui.modernButton('Installing…', vec2(w, 40), ui.ButtonFlags.Disabled, ui.Icons.LoadingSpinner) |
| 49 | + elseif app.installing then |
| 50 | + w = w / 2 - 4 |
| 51 | + ui.modernButton('Failed to install', vec2(w, 40), ui.ButtonFlags.Disabled, ui.Icons.Warning) |
| 52 | + elseif app.installed == app.meta.version then |
| 53 | + w = w / 3 - 8 |
| 54 | + if ui.modernButton('Open', vec2(w, 40), ui.ButtonFlags.None, ui.Icons.AppWindow) then |
| 55 | + ac.setAppOpen(app.meta.id) |
| 56 | + return true |
| 57 | + end |
| 58 | + ui.sameLine(0, 4) |
| 59 | + if ui.modernButton('Uninstall', vec2(w, 40), ui.ButtonFlags.None, ui.Icons.Trash) then |
| 60 | + utils.uninstallApp(app) |
| 61 | + return true |
| 62 | + end |
| 63 | + elseif app.installed then |
| 64 | + w = w / 3 - 8 |
| 65 | + if ui.modernButton('Update', vec2(w, 40), ui.ButtonFlags.Confirm, ui.Icons.Download) then |
| 66 | + utils.installApp(app) |
| 67 | + return true |
| 68 | + end |
| 69 | + ui.sameLine(0, 4) |
| 70 | + if ui.modernButton('Uninstall', vec2(w, 40), ui.ButtonFlags.None, ui.Icons.Trash) then |
| 71 | + utils.uninstallApp(app) |
| 72 | + return true |
| 73 | + end |
| 74 | + else |
| 75 | + w = w / 2 - 4 |
| 76 | + if ui.modernButton('Install', vec2(w, 40), ui.ButtonFlags.Confirm, ui.Icons.Download) then |
| 77 | + utils.installApp(app) |
| 78 | + return true |
| 79 | + end |
| 80 | + end |
| 81 | + ui.sameLine(0, 4) |
| 82 | + if ui.modernButton('Close', vec2(w, 40), ui.ButtonFlags.None, ui.Icons.Cancel) then |
| 83 | + return true |
| 84 | + end |
| 85 | + |
| 86 | + return false |
| 87 | +end |
| 88 | + |
| 89 | +function script.windowMain(dt) |
| 90 | + local cfg = utils.config() |
| 91 | + if not loadedData then |
| 92 | + loadedData = true |
| 93 | + utils.loadApps(function (err, data) |
| 94 | + loadedData = err and tostring(err) or data |
| 95 | + if data then |
| 96 | + local cfg = utils.config() |
| 97 | + local knownApps = stringify.tryParse(cfg.knownApps, nil, {}) |
| 98 | + local newApps = table.map(data, function (item) |
| 99 | + if not table.contains(knownApps, item.meta.id) then |
| 100 | + if cfg.notifyAboutNewApps then |
| 101 | + item.newApp = true |
| 102 | + end |
| 103 | + return item.meta.id |
| 104 | + else |
| 105 | + return nil |
| 106 | + end |
| 107 | + end) |
| 108 | + if #newApps > 0 then |
| 109 | + cfg.knownApps = stringify(table.chain(knownApps, newApps), true) |
| 110 | + end |
| 111 | + end |
| 112 | + end) |
| 113 | + end |
| 114 | + |
| 115 | + if loadedData == true then |
| 116 | + ui.drawLoadingSpinner(ui.windowSize() / 2 - 20, ui.windowSize() / 2 + 20) |
| 117 | + elseif type(loadedData) == 'table' then |
| 118 | + ac.setWindowNotificationCounter('main', 0) |
| 119 | + |
| 120 | + for i, app in ipairs(loadedData) do |
| 121 | + ui.pushID(i) |
| 122 | + local s = ui.getCursorY() |
| 123 | + ui.pushStyleVar(ui.StyleVar.FrameRounding, 2) |
| 124 | + if ui.button('##btn', vec2(-0.01, 48)) then |
| 125 | + ui.modalDialog(app.meta.name, function () return appDetails(app) end, true) |
| 126 | + end |
| 127 | + if ui.itemHovered() then |
| 128 | + ui.setTooltip(app.meta.description) |
| 129 | + end |
| 130 | + |
| 131 | + if app.newApp then |
| 132 | + ui.notificationCounter() |
| 133 | + end |
| 134 | + |
| 135 | + ui.setCursorY(s + 8) |
| 136 | + ui.offsetCursorX(16) |
| 137 | + ui.image(app.meta.icon, 32) |
| 138 | + ui.sameLine(0, 16) |
| 139 | + ui.beginGroup() |
| 140 | + ui.textAligned(app.meta.name, 0, vec2(-0.01, 0), true) |
| 141 | + ui.pushFont(ui.Font.Small) |
| 142 | + ui.drawRectFilled(ui.getCursor():add(vec2(0, -2)), ui.getCursor():add(vec2(56, 13)), rgbm(0, 0, 0, 0.3), 2) |
| 143 | + ui.beginScale() |
| 144 | + ui.drawTextClipped(app.meta.category, ui.getCursor():add(vec2(0, -3)), ui.getCursor():add(vec2(56, 14)), rgbm.colors.white, 0.5, true) |
| 145 | + ui.endScale(0.9) |
| 146 | + ui.offsetCursorX(64) |
| 147 | + ui.offsetCursorY(2) |
| 148 | + if app.installed == app.meta.version then |
| 149 | + ui.image(ui.Icons.Confirm, 8, rgbm.colors.lime) |
| 150 | + if ui.itemHovered() then |
| 151 | + ui.setTooltip('Latest version installed') |
| 152 | + end |
| 153 | + ui.sameLine(0, 4) |
| 154 | + elseif app.installed then |
| 155 | + ui.image(ui.Icons.ArrowUp, 8, rgbm.colors.yellow) |
| 156 | + if ui.itemHovered() then |
| 157 | + ui.setTooltip('Update is available (installed version: v%s)' % app.installed) |
| 158 | + end |
| 159 | + ui.sameLine(0, 4) |
| 160 | + elseif app.installing == true then |
| 161 | + ui.drawLoadingSpinner(ui.getCursor(), ui.getCursor() + 8, rgbm.colors.white) |
| 162 | + ui.dummy(8) |
| 163 | + if ui.itemHovered() then |
| 164 | + ui.setTooltip('Installing…') |
| 165 | + end |
| 166 | + ui.sameLine(0, 4) |
| 167 | + elseif app.installing then |
| 168 | + ui.image(ui.Icons.Warning, 8, rgbm.colors.orange) |
| 169 | + if ui.itemHovered() then |
| 170 | + ui.setTooltip('Failed to install: %s' % tostring(app.installing)) |
| 171 | + end |
| 172 | + ui.sameLine(0, 4) |
| 173 | + else |
| 174 | + ui.image(ui.Icons.Skip, 8, rgbm.colors.white) |
| 175 | + if ui.itemHovered() then |
| 176 | + ui.setTooltip('Available to install (%s)' % app.displaySize) |
| 177 | + end |
| 178 | + ui.sameLine(0, 4) |
| 179 | + end |
| 180 | + ui.offsetCursorY(-2) |
| 181 | + ui.text('v'..app.meta.version) |
| 182 | + if app.meta.author ~= 'x4fab' then |
| 183 | + ui.sameLine(60, 0) |
| 184 | + ui.text('by '..app.meta.author) |
| 185 | + end |
| 186 | + ui.popFont() |
| 187 | + ui.endGroup() |
| 188 | + |
| 189 | + ui.setCursorY(s + 56) |
| 190 | + ui.popStyleVar() |
| 191 | + ui.popID() |
| 192 | + end |
| 193 | + if not cfg.settingsOpenedOnce then |
| 194 | + ui.pushFont(ui.Font.Small) |
| 195 | + ui.textWrapped('More apps are coming soon. Check App Shelf settings if you want to get a notification when a new app would be available.') |
| 196 | + ui.popFont() |
| 197 | + end |
| 198 | + else |
| 199 | + ui.offsetCursorY(12) |
| 200 | + ui.header('Error') |
| 201 | + ui.textWrapped('Failed to load list of apps:\n%s' % (loadedData or 'unknown error')) |
| 202 | + end |
| 203 | +end |
| 204 | + |
| 205 | +function script.windowMainSettings() |
| 206 | + local cfg = utils.config() |
| 207 | + cfg.settingsOpenedOnce = true |
| 208 | + |
| 209 | + if ui.checkbox('Notify about new apps', cfg.notifyAboutNewApps) then |
| 210 | + cfg.notifyAboutNewApps = not cfg.notifyAboutNewApps |
| 211 | + end |
| 212 | + if ui.itemHovered() then |
| 213 | + ui.setTooltip('Show notification mark in taskbar if there are new apps on the shelf ready to be installed') |
| 214 | + end |
| 215 | + |
| 216 | + if cfg.automaticallyInstallUpdates then ui.pushDisabled() end |
| 217 | + if ui.checkbox('Notify about updates', cfg.notifyAboutUpdates) then |
| 218 | + cfg.notifyAboutUpdates = not cfg.notifyAboutUpdates |
| 219 | + end |
| 220 | + if cfg.automaticallyInstallUpdates then ui.popDisabled() end |
| 221 | + if ui.itemHovered() then |
| 222 | + ui.setTooltip('Show notification mark in taskbar if there are new updates to be installed') |
| 223 | + end |
| 224 | + if ui.checkbox('Install updates automatically', cfg.automaticallyInstallUpdates) then |
| 225 | + cfg.automaticallyInstallUpdates = not cfg.automaticallyInstallUpdates |
| 226 | + end |
| 227 | + if ui.itemHovered() then |
| 228 | + ui.setTooltip('Automatically install new apps when possible') |
| 229 | + end |
| 230 | + |
| 231 | + if ui.checkbox('Open new apps immediately', cfg.openOnceInstalled) then |
| 232 | + cfg.openOnceInstalled = not cfg.openOnceInstalled |
| 233 | + end |
| 234 | + if ui.itemHovered() then |
| 235 | + ui.setTooltip('Automatically open new apps after installing') |
| 236 | + end |
| 237 | +end |
| 238 | + |
| 239 | +local rescanning = false |
| 240 | +ac.onFolderChanged(ac.getFolder(ac.FolderID.ACApps)..'\\lua', '?', false, function (files) |
| 241 | + if rescanning then return end |
| 242 | + rescanning = true |
| 243 | + setTimeout(function () |
| 244 | + rescanning = false |
| 245 | + if type(loadedData) == 'table' then |
| 246 | + for _, v in ipairs(loadedData) do |
| 247 | + utils.refreshApp(v) |
| 248 | + end |
| 249 | + end |
| 250 | + end, 0.5) |
| 251 | +end) |
0 commit comments