Skip to content

Commit 0605e85

Browse files
committed
Update
Forgot I even had this repo, how silly of me
1 parent 933c422 commit 0605e85

File tree

152 files changed

+15704
-386
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+15704
-386
lines changed

.gitignore

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
.vscode
22
*.kn5
3-
data.zip
3+
*.psd
4+
*.compiled
5+
*.off
6+
*.luac
7+
data.zip
8+
9+
bin
10+
obj
11+
deps
12+
*.xsd

included-apps/AppShelf/AppShelf.lua

+251
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
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)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
local app = worker.input ---@type AppInfo
2+
web.get(app.meta.downloadURL, function (err, response)
3+
if err then error(err) end
4+
5+
local data = io.loadFromZip(response.body, app.meta.id..'/manifest.ini')
6+
if not data then error('Package is damaged') end
7+
8+
local manifest = ac.INIConfig.parse(data, ac.INIFormat.Extended)
9+
local version = manifest:get('ABOUT', 'VERSION', '')
10+
if version == '' then error('Package manifest is damaged') end
11+
if app.installed == version then error('Package is obsolete') end
12+
13+
io.createDir(app.location)
14+
if not io.dirExists(app.location) then error('Failed to create directory') end
15+
16+
local destinationPrefix = io.getParentPath(app.location)..'/'
17+
for _, e in ipairs(io.scanZip(response.body)) do
18+
local content = io.loadFromZip(response.body, e)
19+
if content then
20+
local fileDestination = destinationPrefix..e
21+
io.createFileDir(fileDestination)
22+
io.save(fileDestination, content)
23+
end
24+
end
25+
worker.result = version
26+
end)

included-apps/AppShelf/Service.lua

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
local utils = require('utils')
2+
local cfg = utils.config()
3+
local shelfRunning = ac.isLuaAppRunning('AppShelf')
4+
if not cfg.automaticallyInstallUpdates and not cfg.notifyAboutNewApps and not cfg.notifyAboutUpdates or shelfRunning then
5+
return
6+
end
7+
utils.loadApps(function (err, data)
8+
if not data then
9+
ac.log('AppShelf: failed to load list of apps', err)
10+
return
11+
end
12+
local counter = 0
13+
local knownApps = stringify.tryParse(cfg.knownApps, nil, {})
14+
for _, app in ipairs(data) do
15+
if app.installed and string.versionCompare(app.meta.version, app.installed) > 0 then
16+
if cfg.automaticallyInstallUpdates and not ac.isLuaAppRunning(app.meta.id) then
17+
utils.installApp(app)
18+
elseif cfg.notifyAboutUpdates then
19+
counter = counter + 1
20+
end
21+
elseif cfg.notifyAboutNewApps and not app.installed and not table.contains(knownApps, app.meta.id) then
22+
counter = counter + 1
23+
end
24+
end
25+
ac.setWindowNotificationCounter('main', counter)
26+
end, function (meta)
27+
local location = ac.getFolder(ac.FolderID.ExtInternal)..'\\lua-apps\\AppShelf'
28+
local installedManifest = ac.INIConfig.load(location..'\\manifest.ini', ac.INIFormat.Extended)
29+
local installedVersion = installedManifest:get('ABOUT', 'VERSION', '')
30+
if string.versionCompare(meta.version, installedVersion) > 0 then
31+
ac.log('AppShelf update found: %s (installed: %s)' % {meta.version, installedVersion})
32+
web.get(meta.downloadURL, function (err, response)
33+
if err then
34+
ac.warn(err)
35+
return
36+
end
37+
38+
local data = io.loadFromZip(response.body, 'AppShelf/manifest.ini')
39+
if not data then error('Package is damaged') end
40+
41+
local manifest = ac.INIConfig.parse(data, ac.INIFormat.Extended)
42+
local version = manifest:get('ABOUT', 'VERSION', '')
43+
if version == '' then error('Package manifest is damaged') end
44+
if installedVersion == version then error('Package is obsolete') end
45+
if not io.dirExists(location) then error('Corrupted state') end
46+
47+
local destinationPrefix = io.getParentPath(location)..'/'
48+
for _, e in ipairs(io.scanZip(response.body)) do
49+
local content = io.loadFromZip(response.body, e)
50+
if content then
51+
local fileDestination = destinationPrefix..e
52+
io.createFileDir(fileDestination)
53+
io.save(fileDestination, content)
54+
end
55+
end
56+
end)
57+
end
58+
end)

included-apps/AppShelf/icon.png

1.06 KB
Loading

included-apps/AppShelf/manifest.ini

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[ABOUT]
2+
NAME = App Shelf
3+
AUTHOR = x4fab
4+
VERSION = 1.0
5+
DESCRIPTION = Install more apps.
6+
7+
[CORE]
8+
LAZY = FULL ; Possible values:
9+
; • NONE (or 0, default value): load script when Assetto Corsa is loading, run it until it’s closed
10+
; • PARTIAL (or 1): load script only when app is first opened, after that keep it running until Assetto Corsa is closed.
11+
; • FULL (or 2): load script when app is opened, when all windows are closed, unload an app completely.
12+
; Note: when app unloads, all of its internal state (apart from stored with things like `ac.connect()`,
13+
; `ac.storage()` or `ac.store()`) is completely lost. That’s why sometimes it might make more sense to
14+
; use partial laziness and unload app manually on closing (for example, if your app has manual saving
15+
; and a user closed or hid window without saving).
16+
17+
[WINDOW_...]
18+
ID = main
19+
NAME = App Shelf
20+
ICON = icon.png
21+
FUNCTION_MAIN = windowMain
22+
FUNCTION_SETTINGS = windowMainSettings
23+
FLAGS = SETTINGS
24+
MIN_SIZE = 160, 120
25+
SIZE = 240, 400
26+
27+
[SERVICE]
28+
SCRIPT = Service
29+
PERIOD = 12h

0 commit comments

Comments
 (0)