Skip to content

Commit

Permalink
Merge pull request #91 from suchmememanyskill/dev
Browse files Browse the repository at this point in the history
Release v1.8.0
  • Loading branch information
beebls authored Jul 22, 2023
2 parents 378efc4 + d4dffeb commit e801cf3
Show file tree
Hide file tree
Showing 37 changed files with 961 additions and 495 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ jobs:
pip install -r requirements.txt
- name: Build Python Backend
run: pyinstaller --noconfirm --onefile --name "CssLoader-Standalone" ./main.py
run: pyinstaller --noconfirm --onefile --add-data "./assets;/assets" --name "CssLoader-Standalone" ./main.py ./css_win_tray.py

- name: Build Python Backend Headless
run: pyinstaller --noconfirm --noconsole --onefile --name "CssLoader-Standalone-Headless" ./main.py
run: pyinstaller --noconfirm --noconsole --onefile --add-data "./assets;/assets" --name "CssLoader-Standalone-Headless" ./main.py ./css_win_tray.py

- name: Upload package artifact
uses: actions/upload-artifact@v3
Expand Down
Binary file removed assets/logo.png
Binary file not shown.
Binary file added assets/paint-roller-solid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions css_inject.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,16 @@ async def remove(self) -> Result:
return Result(True)

DEFAULT_MAPPINGS = {
"desktop": ["Steam.*", ".*Supernav"],
"desktop": ["Steam.*"],
"desktopchat": ["!friendsui-container"],
"desktoppopup": ["OverlayBrowser_Browser", "SP Overlay:.*", ".*Menu", "notificationtoasts_.*", "SteamBrowser_Find", "OverlayTab\\d+_Find", "!ModalDialogPopup", "!FullModalOverlay"],
"desktoppopup": ["OverlayBrowser_Browser", "SP Overlay:.*", "notificationtoasts_.*", "SteamBrowser_Find", "OverlayTab\\d+_Find", "!ModalDialogPopup", "!FullModalOverlay"],
"desktopoverlay": ["desktoppopup"],
"desktopcontextmenu": [".*Menu", ".*Supernav"],
"bigpicture": ["~Valve Steam Gamepad/default~"],
"bigpictureoverlay": ["QuickAccess", "MainMenu"],
"store": ["~https://store.steampowered.com~", "~https://steamcommunity.com~"],

# Legacy
"SP": ["bigpicture"],
"Steam Big Picture Mode": ["bigpicture"],
"MainMenu": ["MainMenu.*"],
Expand All @@ -125,7 +128,7 @@ def extend_tabs(tabs : list, theme) -> list:
new_tabs = []

if len(tabs) <= 0:
return theme.tab_mappings["default"] if ("default" in theme.tab_mappings) else []
return extend_tabs(theme.tab_mappings["default"], theme) if ("default" in theme.tab_mappings) else []

for x in tabs:
if x in theme.tab_mappings:
Expand All @@ -140,9 +143,6 @@ def extend_tabs(tabs : list, theme) -> list:
def to_inject(key : str, tabs : list, basePath : str, theme) -> Inject:
if key.startswith("--"):
value = tabs[0]
if (";" in value or ";" in key):
raise Exception("Multiple css statements are unsupported in a variable")

inject = Inject("", extend_tabs(tabs[1:], theme), theme)
inject.css = f":root {{ {key}: {value}; }}"
else:
Expand Down
2 changes: 1 addition & 1 deletion css_sfp_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from css_inject import Inject, to_inject

SFP_DEFAULT_FILES = {
"libraryroot.custom.css": ["desktop", "desktopoverlay"],
"libraryroot.custom.css": ["desktop", "desktopoverlay", "desktopcontextmenu"],
"bigpicture.custom.css": ["bigpicture", "bigpictureoverlay"],
"friends.custom.css": ["desktopchat"],
"webkit.css": ["store"]
Expand Down
69 changes: 69 additions & 0 deletions css_win_tray.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import pystray, css_theme, css_utils, os, webbrowser, subprocess
from PIL import Image, ImageDraw

ICON = None
MAIN = None
LOOP = None
DEV_MODE_STATE = False

def reset():
LOOP.create_task(MAIN.reset(MAIN))

def open_theme_dir():
theme_dir = css_utils.get_theme_path()
os.startfile(theme_dir)

def exit():
LOOP.create_task(MAIN.exit(MAIN))

def get_dev_mode_state(x) -> bool:
return DEV_MODE_STATE

def toggle_dev_mode_state():
global DEV_MODE_STATE
DEV_MODE_STATE = not DEV_MODE_STATE
LOOP.create_task(MAIN.toggle_watch_state(MAIN, get_dev_mode_state(None)))

def check_if_symlink_exists():
return os.path.exists(os.path.join(css_utils.get_steam_path(), "steamui", "themes_custom"))

def open_install_docs():
webbrowser.open_new_tab("https://docs.deckthemes.com/CSSLoader/Install/#windows")

def get_desktop_install_path() -> str|None:
if os.path.exists("C:/Program Files/CSSLoader Desktop/CSSLoader Desktop.exe"):
return "C:/Program Files/CSSLoader Desktop/CSSLoader Desktop.exe"

return None

def open_desktop():
path = get_desktop_install_path()
if path != None:
subprocess.Popen([path])

def start_icon(main, loop):
global ICON, MAIN, LOOP, DEV_MODE_STATE
MAIN = main
LOOP = loop
DEV_MODE_STATE = MAIN.observer != None
symlink = check_if_symlink_exists()

ICON = pystray.Icon(
'CSS Loader',
title='CSS Loader',
icon=Image.open(os.path.join(os.path.dirname(__file__), "assets", "paint-roller-solid.png")),
menu=pystray.Menu(
pystray.MenuItem(f"CSS Loader v{css_theme.CSS_LOADER_VER}", action=None, enabled=False),
pystray.MenuItem("Local Images/Fonts: Enabled" if symlink else "Local Images/Fonts: Disabled", action=None, enabled=None),
pystray.MenuItem("Please enable Windows Developer Mode", action=open_install_docs, visible=not symlink),
pystray.MenuItem("Open Desktop App", action=open_desktop, enabled=get_desktop_install_path() != None, default=True),
pystray.MenuItem("Live CSS Editing", toggle_dev_mode_state, checked=get_dev_mode_state),
pystray.MenuItem("Open Themes Folder", open_theme_dir),
pystray.MenuItem("Reload Themes", reset),
pystray.MenuItem("Exit", exit)
))
ICON.run_detached()

def stop_icon():
if ICON != None:
ICON.stop()
62 changes: 49 additions & 13 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,27 +277,41 @@ async def store_write(self, key : str, val : str) -> dict:
return Result(True).to_dict()

async def generate_preset_theme(self, name : str) -> dict:
Log("Generating theme preset...")

try:
result = await self._generate_preset_theme_internal(self, name)
deps = {}

for x in self.themes:
if x.enabled and FLAG_PRESET not in x.flags:
deps[x.name] = {}
for y in x.patches:
deps[x.name][y.name] = y.get_value()

result = await self._generate_preset_theme_internal(self, name, deps)
return result.to_dict()
except Exception as e:
return Result(False, str(e))

async def generate_preset_theme_from_theme_names(self, name : str, themeNames : list) -> dict:
try:
deps = {}

async def _generate_preset_theme_internal(self, name : str) -> Result:
for x in self.themes:
if x.name in themeNames and FLAG_PRESET not in x.flags:
deps[x.name] = {}
for y in x.patches:
deps[x.name][y.name] = y.get_value()

result = await self._generate_preset_theme_internal(self, name, deps)
return result.to_dict()
except Exception as e:
return Result(False, str(e))

async def _generate_preset_theme_internal(self, name : str, deps : dict) -> Result:
Log(f"Generating theme preset '{name}'...")
a = await self._get_theme(self, name)
if a != None and FLAG_PRESET not in a.flags:
return Result(False, f"Theme '{name}' already exists")

deps = {}

for x in self.themes:
if x.enabled and FLAG_PRESET not in x.flags:
deps[x.name] = {}
for y in x.patches:
deps[x.name][y.name] = y.get_value()

theme_path = path.join(get_theme_path(), name)

if not path.exists(theme_path):
Expand All @@ -310,6 +324,12 @@ async def _generate_preset_theme_internal(self, name : str) -> Result:
"flags": [FLAG_PRESET],
"dependencies": deps
}, fp)

for x in self.themes:
if x.name == name: # Hotpatch preset in memory
Log(f"Updating dependencies for {name}: {deps}")
x.dependencies = deps
break

return Result(True)

Expand Down Expand Up @@ -387,6 +407,12 @@ async def _load_stage_2(self, inject_now : bool = True):
self.themes.sort(key=lambda d: d.name)

async def exit(self):
try:
import css_win_tray
css_win_tray.stop_icon()
except:
pass

sys.exit(0)

async def _main(self):
Expand Down Expand Up @@ -456,4 +482,14 @@ async def run(self):
count += 1

asyncio.get_event_loop().run_until_complete(A().run())
asyncio.get_event_loop().run_forever()

import css_win_tray

css_win_tray.start_icon(Plugin, asyncio.get_event_loop())

try:
asyncio.get_event_loop().run_forever()
except KeyboardInterrupt:
pass

css_win_tray.stop_icon()
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "SDH-CssLoader",
"version": "1.7.1",
"version": "1.8.0",
"description": "A css loader",
"scripts": {
"build": "shx rm -rf dist && rollup -c",
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ aiohttp==3.8.1
aiohttp-jinja2==1.5.0
aiohttp_cors==0.7.0
watchdog==2.1.7
certifi==2022.12.7
certifi==2022.12.7
pystray
5 changes: 5 additions & 0 deletions src/ThemeTypes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { MinimalCSSThemeInfo } from "./apiTypes";

export interface Theme {
id: string;
enabled: boolean; // used to be called checked
Expand Down Expand Up @@ -32,3 +34,6 @@ export enum Flags {
"dontDisableDeps" = "KEEP_DEPENDENCIES",
"optionalDeps" = "OPTIONAL_DEPENDENCIES",
}

export type LocalThemeStatus = "installed" | "outdated" | "local";
export type UpdateStatus = [string, LocalThemeStatus, false | MinimalCSSThemeInfo];
19 changes: 13 additions & 6 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ServerAPI } from "decky-frontend-lib";
import { CssLoaderState } from "./state";
import { toast, storeWrite } from "./python";
import { ThemeQueryRequest, ThemeQueryResponse } from "./apiTypes";
import { toast, storeWrite, downloadThemeFromUrl, reloadBackend } from "./python";
import { ThemeQueryRequest } from "./apiTypes";
import { generateParamStr } from "./logic";

var server: ServerAPI | undefined = undefined;
Expand Down Expand Up @@ -84,6 +84,7 @@ export function refreshToken(): Promise<string | undefined> {
if (apiTokenExpireDate === undefined) {
return Promise.resolve(apiFullToken);
}
// @ts-ignore
if (new Date().valueOf() < apiTokenExpireDate) {
return Promise.resolve(apiFullToken);
}
Expand Down Expand Up @@ -199,14 +200,11 @@ export function getThemes(
// If there are other filters after the prepend, add a ".", otherwise don't
(searchOpts.filters !== "All" ? "." : "");

console.log("prepend", prependString);
console.log("full", prependString + (searchOpts.filters === "All" ? "" : searchOpts.filters));

const queryStr = generateParamStr(
searchOpts.filters !== "All" ? searchOpts : { ...searchOpts, filters: "" },
prependString
);
genericGET(`${apiPath}${queryStr}`, requiresAuth).then((data: ThemeQueryResponse) => {
genericGET(`${apiPath}${queryStr}`, requiresAuth).then((data) => {
if (data.total > 0) {
setGlobalState(globalStateVarName, data);
} else {
Expand Down Expand Up @@ -241,3 +239,12 @@ export function toggleStar(themeId: string, isStarred: boolean, authToken: strin
console.error(`Error starring theme`, err);
});
}

export async function installTheme(themeId: string) {
const setGlobalState = globalState!.setGlobalState.bind(globalState);
setGlobalState("isInstalling", true);
await downloadThemeFromUrl(themeId);
await reloadBackend();
setGlobalState("isInstalling", false);
return;
}
Loading

0 comments on commit e801cf3

Please sign in to comment.