Add project files
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/subprojects/blueprint-compiler
|
||||||
|
/src/__pycache__
|
||||||
8
data/hu.kramo.GameShelf.desktop.in
Normal file
8
data/hu.kramo.GameShelf.desktop.in
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=Game Shelf
|
||||||
|
Exec=gameshelf
|
||||||
|
Icon=hu.kramo.GameShelf
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Game;
|
||||||
|
StartupNotify=true
|
||||||
21
data/hu.kramo.GameShelf.gschema.xml
Normal file
21
data/hu.kramo.GameShelf.gschema.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<schemalist gettext-domain="gameshelf">
|
||||||
|
<schema id="hu.kramo.GameShelf" path="/hu/kramo/GameShelf/">
|
||||||
|
<key name="exit-after-launch" type="b">
|
||||||
|
<default>false</default>
|
||||||
|
</key>
|
||||||
|
<key name="steam-location" type="s">
|
||||||
|
<default>"~/.steam/"</default>
|
||||||
|
</key>
|
||||||
|
<key name="sort-mode" type="s">
|
||||||
|
<choices>
|
||||||
|
<choice value="a-z"/>
|
||||||
|
<choice value="z-a"/>
|
||||||
|
<choice value="newest"/>
|
||||||
|
<choice value="oldest"/>
|
||||||
|
<choice value="last_played"/>
|
||||||
|
</choices>
|
||||||
|
<default>"a-z"</default>
|
||||||
|
</key>
|
||||||
|
</schema>
|
||||||
|
</schemalist>
|
||||||
13
data/hu.kramo.GameShelf.metainfo.xml.in
Normal file
13
data/hu.kramo.GameShelf.metainfo.xml.in
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop-application">
|
||||||
|
<id>hu.kramo.GameShelf.desktop</id>
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>GPL-3.0-or-later</project_license>
|
||||||
|
<name>Game Shelf</name>
|
||||||
|
<summary>Launch all your games</summary>
|
||||||
|
<description>
|
||||||
|
<p>Game Shelf is a simple game launcher. It has support for importing your games from Steam with organizational features such as hiding and sorting by date added or last played.</p>
|
||||||
|
</description>
|
||||||
|
<launchable type="desktop-id">hu.kramo.GameShelf.desktop</launchable>
|
||||||
|
<developer_name>kramo</developer_name>
|
||||||
|
</component>
|
||||||
22
data/icons/hicolor/scalable/apps/hu.kramo.GameShelf.svg
Normal file
22
data/icons/hicolor/scalable/apps/hu.kramo.GameShelf.svg
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="20" y="8" width="88" height="112" rx="9" fill="#C64600"/>
|
||||||
|
<rect x="20" y="8" width="88" height="95" rx="9" fill="#FF7800"/>
|
||||||
|
<rect x="26" y="14" width="76" height="50" rx="4" fill="black"/>
|
||||||
|
<rect x="38" y="20" width="52" height="38" rx="4" fill="url(#paint0_linear_5_31)"/>
|
||||||
|
<rect x="54" y="107" width="9" height="9" rx="4.5" fill="#241F31"/>
|
||||||
|
<rect x="70" y="109" width="5" height="5" rx="2.5" fill="#241F31"/>
|
||||||
|
<rect x="40" y="73" width="7" height="21" rx="3.5" fill="black"/>
|
||||||
|
<rect x="54" y="80" width="7" height="21" rx="3.5" transform="rotate(90 54 80)" fill="black"/>
|
||||||
|
<rect x="40" y="72" width="7" height="21" rx="3.5" fill="#241F31"/>
|
||||||
|
<rect x="54" y="79" width="7" height="21" rx="3.5" transform="rotate(90 54 79)" fill="#241F31"/>
|
||||||
|
<rect x="80" y="80" width="11" height="11" rx="5.5" transform="rotate(90 80 80)" fill="black"/>
|
||||||
|
<rect x="94" y="73" width="11" height="11" rx="5.5" transform="rotate(90 94 73)" fill="black"/>
|
||||||
|
<rect x="80" y="79" width="11" height="11" rx="5.5" transform="rotate(90 80 79)" fill="#241F31"/>
|
||||||
|
<rect x="94" y="72" width="11" height="11" rx="5.5" transform="rotate(90 94 72)" fill="#241F31"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_5_31" x1="38" y1="20" x2="38" y2="58" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#597E53"/>
|
||||||
|
<stop offset="1" stop-color="#97AE79"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 1C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1H3ZM5 2C4.44772 2 4 2.44772 4 3V6C4 6.55228 4.44772 7 5 7H11C11.5523 7 12 6.55228 12 6V3C12 2.44772 11.5523 2 11 2H5ZM4 10.5C4 9.67157 4.67157 9 5.5 9C6.32843 9 7 9.67157 7 10.5C7 11.3284 6.32843 12 5.5 12C4.67157 12 4 11.3284 4 10.5ZM10 9C9.44772 9 9 9.44771 9 10C9 10.5523 9.44771 11 10 11H11C11.5523 11 12 10.5523 12 10C12 9.44771 11.5523 9 11 9H10Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 637 B |
13
data/icons/meson.build
Normal file
13
data/icons/meson.build
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
application_id = 'hu.kramo.GameShelf'
|
||||||
|
|
||||||
|
scalable_dir = join_paths('hicolor', 'scalable', 'apps')
|
||||||
|
install_data(
|
||||||
|
join_paths(scalable_dir, ('@0@.svg').format(application_id)),
|
||||||
|
install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir)
|
||||||
|
)
|
||||||
|
|
||||||
|
symbolic_dir = join_paths('hicolor', 'symbolic', 'apps')
|
||||||
|
install_data(
|
||||||
|
join_paths(symbolic_dir, ('@0@-symbolic.svg').format(application_id)),
|
||||||
|
install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir)
|
||||||
|
)
|
||||||
39
data/meson.build
Normal file
39
data/meson.build
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
desktop_file = i18n.merge_file(
|
||||||
|
input: 'hu.kramo.GameShelf.desktop.in',
|
||||||
|
output: 'hu.kramo.GameShelf.desktop',
|
||||||
|
type: 'desktop',
|
||||||
|
po_dir: '../po',
|
||||||
|
install: true,
|
||||||
|
install_dir: join_paths(get_option('datadir'), 'applications')
|
||||||
|
)
|
||||||
|
|
||||||
|
desktop_utils = find_program('desktop-file-validate', required: false)
|
||||||
|
if desktop_utils.found()
|
||||||
|
test('Validate desktop file', desktop_utils, args: [desktop_file])
|
||||||
|
endif
|
||||||
|
|
||||||
|
appstream_file = i18n.merge_file(
|
||||||
|
input: 'hu.kramo.GameShelf.metainfo.xml.in',
|
||||||
|
output: 'hu.kramo.GameShelf.metainfo.xml',
|
||||||
|
po_dir: '../po',
|
||||||
|
install: true,
|
||||||
|
install_dir: join_paths(get_option('datadir'), 'metainfo')
|
||||||
|
)
|
||||||
|
|
||||||
|
appstream_util = find_program('appstream-util', required: false)
|
||||||
|
if appstream_util.found()
|
||||||
|
test('Validate appstream file', appstream_util, args: ['validate', appstream_file])
|
||||||
|
endif
|
||||||
|
|
||||||
|
install_data('hu.kramo.GameShelf.gschema.xml',
|
||||||
|
install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
|
||||||
|
)
|
||||||
|
|
||||||
|
compile_schemas = find_program('glib-compile-schemas', required: false)
|
||||||
|
if compile_schemas.found()
|
||||||
|
test('Validate schema file',
|
||||||
|
compile_schemas,
|
||||||
|
args: ['--strict', '--dry-run', meson.current_source_dir()])
|
||||||
|
endif
|
||||||
|
|
||||||
|
subdir('icons')
|
||||||
40
hu.kramo.GameShelf.json
Normal file
40
hu.kramo.GameShelf.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"app-id" : "hu.kramo.GameShelf",
|
||||||
|
"runtime" : "org.gnome.Platform",
|
||||||
|
"runtime-version" : "master",
|
||||||
|
"sdk" : "org.gnome.Sdk",
|
||||||
|
"command" : "gameshelf",
|
||||||
|
"finish-args" : [
|
||||||
|
"--share=ipc",
|
||||||
|
"--socket=fallback-x11",
|
||||||
|
"--device=dri",
|
||||||
|
"--socket=wayland",
|
||||||
|
"--socket=session-bus",
|
||||||
|
"--filesystem=xdg-run/gvfsd",
|
||||||
|
"--filesystem=~/.steam/steam/"
|
||||||
|
],
|
||||||
|
"cleanup" : [
|
||||||
|
"/include",
|
||||||
|
"/lib/pkgconfig",
|
||||||
|
"/man",
|
||||||
|
"/share/doc",
|
||||||
|
"/share/gtk-doc",
|
||||||
|
"/share/man",
|
||||||
|
"/share/pkgconfig",
|
||||||
|
"*.la",
|
||||||
|
"*.a"
|
||||||
|
],
|
||||||
|
"modules" : [
|
||||||
|
{
|
||||||
|
"name" : "gameshelf",
|
||||||
|
"builddir" : true,
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "file:///home/kramo/Projects"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
20
meson.build
Normal file
20
meson.build
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
project('gameshelf',
|
||||||
|
version: '0.1.0',
|
||||||
|
meson_version: '>= 0.59.0',
|
||||||
|
default_options: [ 'warning_level=2', 'werror=false', ],
|
||||||
|
)
|
||||||
|
|
||||||
|
i18n = import('i18n')
|
||||||
|
gnome = import('gnome')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
subdir('data')
|
||||||
|
subdir('src')
|
||||||
|
subdir('po')
|
||||||
|
|
||||||
|
gnome.post_install(
|
||||||
|
glib_compile_schemas: true,
|
||||||
|
gtk_update_icon_cache: true,
|
||||||
|
update_desktop_database: true,
|
||||||
|
)
|
||||||
1
po/LINGUAS
Normal file
1
po/LINGUAS
Normal file
@@ -0,0 +1 @@
|
|||||||
|
hu
|
||||||
14
po/POTFILES
Normal file
14
po/POTFILES
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
data/hu.kramo.GameShelf.desktop.in
|
||||||
|
data/hu.kramo.GameShelf.metainfo.xml.in
|
||||||
|
|
||||||
|
src/main.py
|
||||||
|
src/window.py
|
||||||
|
src/window.blp
|
||||||
|
src/game.py
|
||||||
|
src/preferences.py
|
||||||
|
|
||||||
|
src/gtk/game.blp
|
||||||
|
src/gtk/preferences.blp
|
||||||
|
|
||||||
|
src/utils/create_details_window.py
|
||||||
|
src/utils/create_dialog.py
|
||||||
259
po/gameshelf.pot
Normal file
259
po/gameshelf.pot
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2022-12-26 14:29+0100\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=CHARSET\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#: game.blp:32 ../utils/create_details_window.py:72
|
||||||
|
msgid "Title"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: game.blp:62 game.blp:88 ../window.blp:132
|
||||||
|
msgid "Play"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: game.blp:69 game.blp:95 ../window.blp:374 ../window.blp:393
|
||||||
|
msgid "Edit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: game.blp:74 ../window.blp:379
|
||||||
|
msgid "Hide"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: game.blp:79 game.blp:105 ../window.blp:384 ../window.blp:403
|
||||||
|
msgid "Remove"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: game.blp:100 ../window.blp:398
|
||||||
|
msgid "Unhide"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: preferences.blp:10
|
||||||
|
msgid "General"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: preferences.blp:13
|
||||||
|
msgid "Exit after launching a game"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: preferences.blp:25
|
||||||
|
msgid "Steam install location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: preferences.blp:26
|
||||||
|
msgid "Directory to use when importing games"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:6 ../window.blp:14 ../utils/steam_parser.py:98
|
||||||
|
msgid "No Games Found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:7
|
||||||
|
msgid "Try a different search."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:15
|
||||||
|
msgid "Use the + button to add games."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:22
|
||||||
|
msgid "No Hidden Games"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:23
|
||||||
|
msgid "Games you hide will appear here."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:29
|
||||||
|
msgid "Game Shelf"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:52
|
||||||
|
msgid "Game Details"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:90
|
||||||
|
msgid "Game Title"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:241
|
||||||
|
msgid "Hidden Games"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:299
|
||||||
|
msgid "Sort"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:302
|
||||||
|
msgid "A-Z"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:308
|
||||||
|
msgid "Z-A"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:314
|
||||||
|
msgid "Newest"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:320
|
||||||
|
msgid "Oldest"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:326
|
||||||
|
msgid "Last Played"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:333
|
||||||
|
msgid "Show Hidden"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:341
|
||||||
|
msgid "Preferences"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:346
|
||||||
|
msgid "Keyboard Shortcuts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:351
|
||||||
|
msgid "About Game Shelf"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:360
|
||||||
|
msgid "Add Game"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.blp:365
|
||||||
|
msgid "Import From Steam"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. Create toast for undoing the remove action
|
||||||
|
#: ../main.py:126
|
||||||
|
msgid " removed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../main.py:127
|
||||||
|
msgid "Undo"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.py:196
|
||||||
|
msgid "Today"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.py:198
|
||||||
|
msgid "Yesterday"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.py:222
|
||||||
|
msgid "Added: "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.py:223
|
||||||
|
msgid "Last played: "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../window.py:223
|
||||||
|
msgid "Last played: Never"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:33
|
||||||
|
msgid "Add New Game"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:37
|
||||||
|
msgid "Confirm"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:39
|
||||||
|
msgid "Edit Game Details"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:43
|
||||||
|
msgid "Apply"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:46
|
||||||
|
msgid "Images"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:73
|
||||||
|
msgid "The title of the game"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:77
|
||||||
|
msgid "Executable"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:78
|
||||||
|
msgid "File to open or command to run when launching the game"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:86
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:133 ../utils/create_details_window.py:137
|
||||||
|
msgid "Couldn't Add Game"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:133 ../utils/create_details_window.py:158
|
||||||
|
msgid "Game title cannot be empty."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:137 ../utils/create_details_window.py:162
|
||||||
|
msgid "Executable cannot be empty."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:158 ../utils/create_details_window.py:162
|
||||||
|
msgid "Couldn't Apply Preferences"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/create_dialog.py:24
|
||||||
|
msgid "Dismiss"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:49
|
||||||
|
msgid "Couldn't Import Games"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:49
|
||||||
|
msgid "Steam directory cannot be found."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:49
|
||||||
|
msgid "Set Steam Location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:98
|
||||||
|
msgid "No new games found in Steam library."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:100 ../utils/steam_parser.py:102
|
||||||
|
msgid "Steam Games Imported"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:100
|
||||||
|
msgid "Successfully imported 1 game."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:102
|
||||||
|
msgid "Successfully imported "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:102
|
||||||
|
msgid " games."
|
||||||
|
msgstr ""
|
||||||
260
po/hu.po
Normal file
260
po/hu.po
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2022-12-26 14:29+0100\n"
|
||||||
|
"PO-Revision-Date: 2022-12-26 14:33+0100\n"
|
||||||
|
"Last-Translator: kramo <contact@kramo.hu>\n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"Language: hu\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Generator: Poedit 3.2.2\n"
|
||||||
|
|
||||||
|
#: game.blp:32 ../utils/create_details_window.py:72
|
||||||
|
msgid "Title"
|
||||||
|
msgstr "Cím"
|
||||||
|
|
||||||
|
#: game.blp:62 game.blp:88 ../window.blp:132
|
||||||
|
msgid "Play"
|
||||||
|
msgstr "Játék"
|
||||||
|
|
||||||
|
#: game.blp:69 game.blp:95 ../window.blp:374 ../window.blp:393
|
||||||
|
msgid "Edit"
|
||||||
|
msgstr "Szerkeszt"
|
||||||
|
|
||||||
|
#: game.blp:74 ../window.blp:379
|
||||||
|
msgid "Hide"
|
||||||
|
msgstr "Elrejt"
|
||||||
|
|
||||||
|
#: game.blp:79 game.blp:105 ../window.blp:384 ../window.blp:403
|
||||||
|
msgid "Remove"
|
||||||
|
msgstr "Eltávolít"
|
||||||
|
|
||||||
|
#: game.blp:100 ../window.blp:398
|
||||||
|
msgid "Unhide"
|
||||||
|
msgstr "Mutat"
|
||||||
|
|
||||||
|
#: preferences.blp:10
|
||||||
|
msgid "General"
|
||||||
|
msgstr "Általános"
|
||||||
|
|
||||||
|
#: preferences.blp:13
|
||||||
|
msgid "Exit after launching a game"
|
||||||
|
msgstr "Kilépés játék indítása után"
|
||||||
|
|
||||||
|
#: preferences.blp:25
|
||||||
|
msgid "Steam install location"
|
||||||
|
msgstr "Steam telepítés helye"
|
||||||
|
|
||||||
|
#: preferences.blp:26
|
||||||
|
msgid "Directory to use when importing games"
|
||||||
|
msgstr "Az importáláskor használatos mappa"
|
||||||
|
|
||||||
|
#: ../window.blp:6 ../window.blp:14 ../utils/steam_parser.py:98
|
||||||
|
msgid "No Games Found"
|
||||||
|
msgstr "Nem Találhatóak Játékok"
|
||||||
|
|
||||||
|
#: ../window.blp:7
|
||||||
|
msgid "Try a different search."
|
||||||
|
msgstr "Próbálkozz más kereséssel."
|
||||||
|
|
||||||
|
#: ../window.blp:15
|
||||||
|
msgid "Use the + button to add games."
|
||||||
|
msgstr "Használd a + gombot a játékok hozzáadásához."
|
||||||
|
|
||||||
|
#: ../window.blp:22
|
||||||
|
msgid "No Hidden Games"
|
||||||
|
msgstr "Nincsenek Rejtett Játékok"
|
||||||
|
|
||||||
|
#: ../window.blp:23
|
||||||
|
msgid "Games you hide will appear here."
|
||||||
|
msgstr "A rejtett játékaid itt lesznek megtalálhatók."
|
||||||
|
|
||||||
|
#: ../window.blp:29
|
||||||
|
msgid "Game Shelf"
|
||||||
|
msgstr "Játékpolc"
|
||||||
|
|
||||||
|
#: ../window.blp:52
|
||||||
|
msgid "Game Details"
|
||||||
|
msgstr "Játék Részletei"
|
||||||
|
|
||||||
|
#: ../window.blp:90
|
||||||
|
msgid "Game Title"
|
||||||
|
msgstr "Cím"
|
||||||
|
|
||||||
|
#: ../window.blp:241
|
||||||
|
msgid "Hidden Games"
|
||||||
|
msgstr "Rejtett Játékok"
|
||||||
|
|
||||||
|
#: ../window.blp:299
|
||||||
|
msgid "Sort"
|
||||||
|
msgstr "Rendezés"
|
||||||
|
|
||||||
|
#: ../window.blp:302
|
||||||
|
msgid "A-Z"
|
||||||
|
msgstr "A-Z"
|
||||||
|
|
||||||
|
#: ../window.blp:308
|
||||||
|
msgid "Z-A"
|
||||||
|
msgstr "Z-A"
|
||||||
|
|
||||||
|
#: ../window.blp:314
|
||||||
|
msgid "Newest"
|
||||||
|
msgstr "Legújabb"
|
||||||
|
|
||||||
|
#: ../window.blp:320
|
||||||
|
msgid "Oldest"
|
||||||
|
msgstr "Legrégebbi"
|
||||||
|
|
||||||
|
#: ../window.blp:326
|
||||||
|
msgid "Last Played"
|
||||||
|
msgstr "Legutóbb játszott"
|
||||||
|
|
||||||
|
#: ../window.blp:333
|
||||||
|
msgid "Show Hidden"
|
||||||
|
msgstr "Rejtett Játékok"
|
||||||
|
|
||||||
|
#: ../window.blp:341
|
||||||
|
msgid "Preferences"
|
||||||
|
msgstr "Beállítások"
|
||||||
|
|
||||||
|
#: ../window.blp:346
|
||||||
|
msgid "Keyboard Shortcuts"
|
||||||
|
msgstr "Billentyűparancsok"
|
||||||
|
|
||||||
|
#: ../window.blp:351
|
||||||
|
msgid "About Game Shelf"
|
||||||
|
msgstr "A Játékpolcról"
|
||||||
|
|
||||||
|
#: ../window.blp:360
|
||||||
|
msgid "Add Game"
|
||||||
|
msgstr "Játék Hozzáadása"
|
||||||
|
|
||||||
|
#: ../window.blp:365
|
||||||
|
msgid "Import From Steam"
|
||||||
|
msgstr "Importálás Steam-ből"
|
||||||
|
|
||||||
|
#. Create toast for undoing the remove action
|
||||||
|
#: ../main.py:126
|
||||||
|
msgid " removed"
|
||||||
|
msgstr " eltávolítva"
|
||||||
|
|
||||||
|
#: ../main.py:127
|
||||||
|
msgid "Undo"
|
||||||
|
msgstr "Visszavonás"
|
||||||
|
|
||||||
|
#: ../window.py:196
|
||||||
|
msgid "Today"
|
||||||
|
msgstr "Ma"
|
||||||
|
|
||||||
|
#: ../window.py:198
|
||||||
|
msgid "Yesterday"
|
||||||
|
msgstr "Tegnap"
|
||||||
|
|
||||||
|
#: ../window.py:222
|
||||||
|
msgid "Added: "
|
||||||
|
msgstr "Hozzáadva: "
|
||||||
|
|
||||||
|
#: ../window.py:223
|
||||||
|
msgid "Last played: "
|
||||||
|
msgstr "Legutóbb játszva: "
|
||||||
|
|
||||||
|
#: ../window.py:223
|
||||||
|
msgid "Last played: Never"
|
||||||
|
msgstr "Legutóbb játszva: Soha"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:33
|
||||||
|
msgid "Add New Game"
|
||||||
|
msgstr "Új Játék Hozzáadása"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:37
|
||||||
|
msgid "Confirm"
|
||||||
|
msgstr "Megerősít"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:39
|
||||||
|
msgid "Edit Game Details"
|
||||||
|
msgstr "Játék Részleteinek Szerkesztése"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:43
|
||||||
|
msgid "Apply"
|
||||||
|
msgstr "Alkalmaz"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:46
|
||||||
|
msgid "Images"
|
||||||
|
msgstr "Képek"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:73
|
||||||
|
msgid "The title of the game"
|
||||||
|
msgstr "A játék címe"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:77
|
||||||
|
msgid "Executable"
|
||||||
|
msgstr "Program"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:78
|
||||||
|
msgid "File to open or command to run when launching the game"
|
||||||
|
msgstr "Fájl megnyitása vagy parancs futtatása a játék indításakor"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:86
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr "Mégse"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:133 ../utils/create_details_window.py:137
|
||||||
|
msgid "Couldn't Add Game"
|
||||||
|
msgstr "Nem Lehet Hozzáadni a Játékot"
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:133 ../utils/create_details_window.py:158
|
||||||
|
msgid "Game title cannot be empty."
|
||||||
|
msgstr "A cím nem lehet üres."
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:137 ../utils/create_details_window.py:162
|
||||||
|
msgid "Executable cannot be empty."
|
||||||
|
msgstr "A program nem lehet üres."
|
||||||
|
|
||||||
|
#: ../utils/create_details_window.py:158 ../utils/create_details_window.py:162
|
||||||
|
msgid "Couldn't Apply Preferences"
|
||||||
|
msgstr "Nem Lehet Menteni a Beállításokat"
|
||||||
|
|
||||||
|
#: ../utils/create_dialog.py:24
|
||||||
|
msgid "Dismiss"
|
||||||
|
msgstr "Rendben"
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:49
|
||||||
|
msgid "Couldn't Import Games"
|
||||||
|
msgstr "Nem Lehet Importálni a Játékot"
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:49
|
||||||
|
msgid "Steam directory cannot be found."
|
||||||
|
msgstr "A Steam mappa nem található."
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:49
|
||||||
|
msgid "Set Steam Location"
|
||||||
|
msgstr "Steam Mappa Kiválasztása"
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:98
|
||||||
|
msgid "No new games found in Steam library."
|
||||||
|
msgstr "Nem találhatók új játékok a Steam könyvtárban."
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:100 ../utils/steam_parser.py:102
|
||||||
|
msgid "Steam Games Imported"
|
||||||
|
msgstr "Steam Játékok Importálva"
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:100
|
||||||
|
msgid "Successfully imported 1 game."
|
||||||
|
msgstr "1 játék sikeresen importálva."
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:102
|
||||||
|
msgid "Successfully imported "
|
||||||
|
msgstr "Sikeresen importálva "
|
||||||
|
|
||||||
|
#: ../utils/steam_parser.py:102
|
||||||
|
msgid " games."
|
||||||
|
msgstr " játék."
|
||||||
1
po/meson.build
Normal file
1
po/meson.build
Normal file
@@ -0,0 +1 @@
|
|||||||
|
i18n.gettext('gameshelf', preset: 'glib')
|
||||||
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
16
src/assets/library_placeholder.svg
Normal file
16
src/assets/library_placeholder.svg
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<svg width="200" height="300" viewBox="0 0 200 300" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="200" height="300" fill="url(#paint0_linear_1_2)"/>
|
||||||
|
<g clip-path="url(#clip0_1_2)">
|
||||||
|
<path d="M49 169.125V185.062C49 193.853 56.147 201 64.9375 201H68.125C75.1724 201 80.875 195.297 80.875 188.25C80.875 181.203 86.5776 175.5 93.625 175.5C100.672 175.5 106.375 181.203 106.375 188.25C107.247 196.169 114.394 201.872 122.312 201C131.103 201 138.25 193.878 138.25 185.062V169.125C138.25 155.03 126.845 143.625 112.75 143.625H74.5C60.4053 143.625 49 155.03 49 169.125ZM69.7188 156.375H72.9062C73.7778 156.375 74.5 157.097 74.5 157.969V162.75H79.2812C80.1528 162.75 80.875 163.472 80.875 164.344V167.531C80.875 168.428 80.1528 169.125 79.2812 169.125H74.5V173.906C74.5 174.803 73.7778 175.5 72.9062 175.5H69.7188C68.8223 175.5 68.125 174.803 68.125 173.906V169.125H63.3438C62.4473 169.125 61.75 168.428 61.75 167.531V164.344C61.75 163.472 62.4473 162.75 63.3438 162.75H68.125V157.969C68.125 157.097 68.8223 156.375 69.7188 156.375ZM109.562 161.156C112.202 161.156 114.344 163.298 114.344 165.938C114.344 168.577 112.202 170.719 109.562 170.719C106.923 170.719 104.781 168.577 104.781 165.938C104.781 163.298 106.923 161.156 109.562 161.156ZM122.312 167.531C124.952 167.531 127.094 169.673 127.094 172.312C127.094 174.952 124.952 177.094 122.312 177.094C119.673 177.094 117.531 174.952 117.531 172.312C117.531 169.673 119.673 167.531 122.312 167.531Z" fill="#241F31"/>
|
||||||
|
<path d="M61.75 118.225C61.7998 128.783 70.416 137.3 80.9746 137.25H131.775C142.384 137.25 151 128.634 151 118.025C150.95 107.467 142.334 98.9502 131.775 99H80.9746C70.3662 99 61.75 107.616 61.75 118.225ZM82.2695 105.375H85.457C86.3286 105.375 87.0508 106.097 87.0508 106.969V111.75H91.832C92.7036 111.75 93.4258 112.472 93.4258 113.344V116.531C93.4258 117.428 92.7036 118.125 91.832 118.125H87.0508V122.906C87.0508 123.803 86.3286 124.5 85.457 124.5H82.2695C81.373 124.5 80.6758 123.803 80.6758 122.906V118.125H75.8945C74.998 118.125 74.3008 117.428 74.3008 116.531V113.344C74.3008 112.472 74.998 111.75 75.8945 111.75H80.6758V106.969C80.6758 106.097 81.373 105.375 82.2695 105.375ZM122.113 110.156C124.753 110.156 126.895 112.298 126.895 114.938C126.895 117.577 124.753 119.719 122.113 119.719C119.474 119.719 117.332 117.577 117.332 114.938C117.332 112.298 119.474 110.156 122.113 110.156ZM134.863 110.355C137.503 110.355 139.645 112.497 139.645 115.137C139.645 117.776 137.503 119.918 134.863 119.918C132.224 119.918 130.082 117.776 130.082 115.137C130.082 112.497 132.224 110.355 134.863 110.355Z" fill="#241F31"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_1_2" x1="100" y1="0" x2="100" y2="300" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#DEDDDA"/>
|
||||||
|
<stop offset="1" stop-color="#9A9996"/>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="clip0_1_2">
|
||||||
|
<rect width="102" height="102" fill="white" transform="translate(49 99)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
40
src/game.py
Normal file
40
src/game.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# game.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
@Gtk.Template(resource_path='/hu/kramo/GameShelf/gtk/game.ui')
|
||||||
|
class game(Gtk.Box):
|
||||||
|
__gtype_name__ = 'game'
|
||||||
|
|
||||||
|
title = Gtk.Template.Child()
|
||||||
|
cover = Gtk.Template.Child()
|
||||||
|
cover_button = Gtk.Template.Child()
|
||||||
|
menu_button = Gtk.Template.Child()
|
||||||
|
hidden_game_options = Gtk.Template.Child()
|
||||||
|
|
||||||
|
def __init__(self, title, pixbuf, game_id, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
self.name = title
|
||||||
|
self.pixbuf = pixbuf
|
||||||
|
self.game_id = game_id
|
||||||
|
|
||||||
|
self.title.set_label(title)
|
||||||
|
self.cover.set_pixbuf(pixbuf)
|
||||||
10
src/gameshelf.gresource.xml
Normal file
10
src/gameshelf.gresource.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/hu/kramo/GameShelf">
|
||||||
|
<file preprocess="xml-stripblanks">window.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">gtk/game.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">gtk/preferences.ui</file>
|
||||||
|
<file>assets/library_placeholder.svg</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
||||||
46
src/gameshelf.in
Executable file
46
src/gameshelf.in
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!@PYTHON@
|
||||||
|
|
||||||
|
# gameshelf.in
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
import locale
|
||||||
|
import gettext
|
||||||
|
|
||||||
|
VERSION = '@VERSION@'
|
||||||
|
pkgdatadir = '@pkgdatadir@'
|
||||||
|
localedir = '@localedir@'
|
||||||
|
|
||||||
|
sys.path.insert(1, pkgdatadir)
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
locale.bindtextdomain('gameshelf', localedir)
|
||||||
|
locale.textdomain('gameshelf')
|
||||||
|
gettext.install('gameshelf', localedir)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import gi
|
||||||
|
|
||||||
|
from gi.repository import Gio
|
||||||
|
resource = Gio.Resource.load(os.path.join(pkgdatadir, 'gameshelf.gresource'))
|
||||||
|
resource._register()
|
||||||
|
|
||||||
|
from gameshelf import main
|
||||||
|
sys.exit(main.main(VERSION))
|
||||||
109
src/gtk/game.blp
Normal file
109
src/gtk/game.blp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
template game : Box {
|
||||||
|
orientation: vertical;
|
||||||
|
halign: center;
|
||||||
|
valign: start;
|
||||||
|
|
||||||
|
Button cover_button {
|
||||||
|
Picture cover {
|
||||||
|
width-request: 200;
|
||||||
|
height-request: 300;
|
||||||
|
hexpand: true;
|
||||||
|
vexpand: true;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"card",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"card",
|
||||||
|
"flat",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.Clamp {
|
||||||
|
maximum-size: 200;
|
||||||
|
|
||||||
|
Box {
|
||||||
|
Label title {
|
||||||
|
label: _("Title");
|
||||||
|
ellipsize: end;
|
||||||
|
hexpand: true;
|
||||||
|
halign: start;
|
||||||
|
margin-start: 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuButton menu_button {
|
||||||
|
icon-name: "view-more-symbolic";
|
||||||
|
margin-top: 6;
|
||||||
|
margin-bottom: 6;
|
||||||
|
margin-end: 6;
|
||||||
|
margin-start: 6;
|
||||||
|
menu-model: game_options;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"flat",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"card",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
menu game_options {
|
||||||
|
section {
|
||||||
|
item {
|
||||||
|
label: _("Play");
|
||||||
|
action: "app.launch_game";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
item {
|
||||||
|
label: _("Edit");
|
||||||
|
action: "app.edit_details";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Hide");
|
||||||
|
action: "app.hide_game";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Remove");
|
||||||
|
action: "app.remove_game";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu hidden_game_options {
|
||||||
|
section {
|
||||||
|
item {
|
||||||
|
label: _("Play");
|
||||||
|
action: "app.launch_game";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
item {
|
||||||
|
label: _("Edit");
|
||||||
|
action: "app.edit_details";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Unhide");
|
||||||
|
action: "app.hide_game";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Remove");
|
||||||
|
action: "app.remove_game";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/gtk/help-overlay.blp
Normal file
34
src/gtk/help-overlay.blp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
ShortcutsWindow help_overlay {
|
||||||
|
modal: true;
|
||||||
|
|
||||||
|
ShortcutsSection {
|
||||||
|
section-name: "shortcuts";
|
||||||
|
max-height: 10;
|
||||||
|
|
||||||
|
ShortcutsGroup {
|
||||||
|
title: C_("shortcut window", "General");
|
||||||
|
|
||||||
|
ShortcutsShortcut {
|
||||||
|
title: C_("shortcut window", "Quit");
|
||||||
|
action-name: "app.quit";
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortcutsShortcut {
|
||||||
|
title: C_("shortcut window", "Search");
|
||||||
|
action-name: "win.toggle_search";
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortcutsShortcut {
|
||||||
|
title: C_("shortcut window", "Shortcuts");
|
||||||
|
action-name: "win.show-help-overlay";
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortcutsShortcut {
|
||||||
|
title: C_("shortcut window", "Undo");
|
||||||
|
action-name: "win.undo_remove";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/gtk/preferences.blp
Normal file
35
src/gtk/preferences.blp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
template PreferencesWindow : Adw.PreferencesWindow {
|
||||||
|
search-enabled: false;
|
||||||
|
default-height: 400;
|
||||||
|
|
||||||
|
Adw.PreferencesPage {
|
||||||
|
Adw.PreferencesGroup {
|
||||||
|
title: _("General");
|
||||||
|
|
||||||
|
Adw.ActionRow {
|
||||||
|
title: _("Exit after launching a game");
|
||||||
|
|
||||||
|
Switch exit_after_launch_switch {
|
||||||
|
valign: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.PreferencesGroup {
|
||||||
|
title: "Steam";
|
||||||
|
|
||||||
|
Adw.ActionRow {
|
||||||
|
title: _("Steam install location");
|
||||||
|
subtitle: _("Directory to use when importing games");
|
||||||
|
|
||||||
|
Button steam_file_chooser_button {
|
||||||
|
icon-name: "folder-symbolic";
|
||||||
|
valign: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
151
src/main.py
Normal file
151
src/main.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
# main.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import gi, sys, os, time, json
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "4.0")
|
||||||
|
gi.require_version("Adw", "1")
|
||||||
|
|
||||||
|
from gi.repository import Gtk, Gio, GLib, Adw
|
||||||
|
|
||||||
|
from .window import GameShelfWindow
|
||||||
|
from .preferences import PreferencesWindow
|
||||||
|
from .toggle_hidden import toggle_hidden
|
||||||
|
from .save_games import save_games
|
||||||
|
from .run_command import run_command
|
||||||
|
from .steam_parser import steam_parser
|
||||||
|
from .create_details_window import create_details_window
|
||||||
|
|
||||||
|
class GameShelfApplication(Adw.Application):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(application_id="hu.kramo.GameShelf", flags=Gio.ApplicationFlags.FLAGS_NONE)
|
||||||
|
self.create_action("quit", self.on_quit_action, ["<primary>q"])
|
||||||
|
self.create_action("about", self.on_about_action)
|
||||||
|
self.create_action("preferences", self.on_preferences_action)
|
||||||
|
self.create_action("steam_import", self.on_steam_import_action)
|
||||||
|
self.create_action("launch_game", self.on_launch_game_action)
|
||||||
|
self.create_action("hide_game", self.on_hide_game_action)
|
||||||
|
self.create_action("edit_details", self.on_edit_details_action)
|
||||||
|
self.create_action("add_game", self.on_add_game_action)
|
||||||
|
self.create_action("remove_game", self.on_remove_game_action)
|
||||||
|
|
||||||
|
def do_activate(self):
|
||||||
|
|
||||||
|
# Create the main window
|
||||||
|
win = self.props.active_window
|
||||||
|
if not win:
|
||||||
|
win = GameShelfWindow(application=self)
|
||||||
|
|
||||||
|
win.present()
|
||||||
|
|
||||||
|
# Create actions for the main window
|
||||||
|
self.create_action("show_hidden", win.on_show_hidden_action, None, win)
|
||||||
|
self.create_action("go_back", win.on_go_back_action, ["<alt>Left"], win)
|
||||||
|
self.create_action("go_to_parent", win.on_go_to_parent_action, ["<alt>Up"], win)
|
||||||
|
self.create_action("toggle_search", win.on_toggle_search_action, ["<primary>f"], win)
|
||||||
|
self.create_action("escape", win.on_escape_action, ["Escape"], win)
|
||||||
|
self.create_action("undo_remove", win.on_undo_remove_action, ["<primary>z"], win)
|
||||||
|
win.sort = Gio.SimpleAction.new_stateful("sort_by", GLib.VariantType.new("s"), GLib.Variant("s", "a-z"))
|
||||||
|
win.add_action(win.sort)
|
||||||
|
win.sort.connect("activate", win.on_sort_action)
|
||||||
|
win.on_sort_action(win.sort, win.schema.get_value("sort-mode"))
|
||||||
|
|
||||||
|
def on_about_action(self, widget, callback=None):
|
||||||
|
about = Adw.AboutWindow(transient_for=self.props.active_window,
|
||||||
|
application_name="Game Shelf",
|
||||||
|
application_icon="hu.kramo.GameShelf",
|
||||||
|
developer_name="kramo",
|
||||||
|
version="0.1.0",
|
||||||
|
developers=["kramo"],
|
||||||
|
copyright="© 2022 kramo",
|
||||||
|
license_type=Gtk.License.GPL_3_0)
|
||||||
|
about.present()
|
||||||
|
|
||||||
|
def on_preferences_action(self, widget, callback=None):
|
||||||
|
PreferencesWindow(self.props.active_window).present()
|
||||||
|
|
||||||
|
def on_steam_import_action(self, widget, callback=None):
|
||||||
|
games = steam_parser(self.props.active_window, self.on_steam_import_action)
|
||||||
|
save_games(games)
|
||||||
|
self.props.active_window.update_games(games.keys())
|
||||||
|
|
||||||
|
def on_launch_game_action(self, widget, callback=None):
|
||||||
|
|
||||||
|
# Launch the game and update the last played value
|
||||||
|
self.props.active_window.games[self.props.active_window.active_game_id]["last_played"] = int(time.time())
|
||||||
|
save_games({self.props.active_window.active_game_id : self.props.active_window.games[self.props.active_window.active_game_id]})
|
||||||
|
self.props.active_window.update_games([self.props.active_window.active_game_id])
|
||||||
|
run_command(self.props.active_window, self.props.active_window.games[self.props.active_window.active_game_id]["executable"])
|
||||||
|
|
||||||
|
if self.props.active_window.stack.get_visible_child() == self.props.active_window.overview:
|
||||||
|
self.props.active_window.show_overview(None, self.props.active_window.active_game_id)
|
||||||
|
|
||||||
|
def on_hide_game_action(self, widget, callback=None):
|
||||||
|
if self.props.active_window.stack.get_visible_child() == self.props.active_window.overview:
|
||||||
|
self.props.active_window.on_go_back_action(None, None)
|
||||||
|
toggle_hidden(self.props.active_window.active_game_id)
|
||||||
|
self.props.active_window.update_games([self.props.active_window.active_game_id])
|
||||||
|
|
||||||
|
def on_edit_details_action(self, widget, callback=None):
|
||||||
|
create_details_window(self.props.active_window, self.props.active_window.active_game_id)
|
||||||
|
|
||||||
|
def on_add_game_action(self, widget, callback=None):
|
||||||
|
create_details_window(self.props.active_window)
|
||||||
|
|
||||||
|
def on_remove_game_action(self, widget, callback=None):
|
||||||
|
|
||||||
|
# Add "removed=True" to the game properties so it can be deleted on next init
|
||||||
|
game_id = self.props.active_window.active_game_id
|
||||||
|
open_file = open(os.path.join(os.path.join(os.environ.get("XDG_DATA_HOME"), "games", game_id + ".json")), "r")
|
||||||
|
data = json.loads(open_file.read())
|
||||||
|
open_file.close()
|
||||||
|
data["removed"] = True
|
||||||
|
save_games({game_id : data})
|
||||||
|
|
||||||
|
self.props.active_window.update_games([game_id])
|
||||||
|
if self.props.active_window.stack.get_visible_child() == self.props.active_window.overview:
|
||||||
|
self.props.active_window.on_go_back_action(None, None)
|
||||||
|
|
||||||
|
# Create toast for undoing the remove action
|
||||||
|
toast = Adw.Toast.new(self.props.active_window.games[game_id]["name"] + (_(" removed")))
|
||||||
|
toast.set_button_label(_("Undo"))
|
||||||
|
toast.connect("button-clicked", self.props.active_window.on_undo_remove_action, game_id)
|
||||||
|
toast.set_priority(Adw.ToastPriority.HIGH)
|
||||||
|
self.props.active_window.toasts[game_id] = toast
|
||||||
|
self.props.active_window.toast_overlay.add_toast(toast)
|
||||||
|
|
||||||
|
def on_quit_action(self, widget, callback=None):
|
||||||
|
self.quit()
|
||||||
|
|
||||||
|
def create_action(self, name, callback, shortcuts=None, win=None):
|
||||||
|
action = Gio.SimpleAction.new(name, None)
|
||||||
|
action.connect("activate", callback)
|
||||||
|
if not win:
|
||||||
|
self.add_action(action)
|
||||||
|
if shortcuts:
|
||||||
|
self.set_accels_for_action(f"app.{name}", shortcuts)
|
||||||
|
else:
|
||||||
|
win.add_action(action)
|
||||||
|
if shortcuts:
|
||||||
|
self.set_accels_for_action(f"win.{name}", shortcuts)
|
||||||
|
|
||||||
|
def main(version):
|
||||||
|
app = GameShelfApplication()
|
||||||
|
return app.run(sys.argv)
|
||||||
|
|
||||||
57
src/meson.build
Normal file
57
src/meson.build
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
|
||||||
|
moduledir = join_paths(pkgdatadir, 'gameshelf')
|
||||||
|
gnome = import('gnome')
|
||||||
|
|
||||||
|
blueprints = custom_target('blueprints',
|
||||||
|
input: files(
|
||||||
|
'gtk/help-overlay.blp',
|
||||||
|
'window.blp',
|
||||||
|
'gtk/game.blp',
|
||||||
|
'gtk/preferences.blp'
|
||||||
|
),
|
||||||
|
output: '.',
|
||||||
|
command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
|
||||||
|
)
|
||||||
|
|
||||||
|
gnome.compile_resources('gameshelf',
|
||||||
|
'gameshelf.gresource.xml',
|
||||||
|
gresource_bundle: true,
|
||||||
|
install: true,
|
||||||
|
install_dir: pkgdatadir,
|
||||||
|
dependencies: blueprints,
|
||||||
|
)
|
||||||
|
|
||||||
|
python = import('python')
|
||||||
|
|
||||||
|
conf = configuration_data()
|
||||||
|
conf.set('PYTHON', python.find_installation('python3').path())
|
||||||
|
conf.set('VERSION', meson.project_version())
|
||||||
|
conf.set('localedir', join_paths(get_option('prefix'), get_option('localedir')))
|
||||||
|
conf.set('pkgdatadir', pkgdatadir)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
input: 'gameshelf.in',
|
||||||
|
output: 'gameshelf',
|
||||||
|
configuration: conf,
|
||||||
|
install: true,
|
||||||
|
install_dir: get_option('bindir')
|
||||||
|
)
|
||||||
|
|
||||||
|
gameshelf_sources = [
|
||||||
|
'__init__.py',
|
||||||
|
'main.py',
|
||||||
|
'window.py',
|
||||||
|
'preferences.py',
|
||||||
|
'game.py',
|
||||||
|
'utils/steam_parser.py',
|
||||||
|
'utils/run_command.py',
|
||||||
|
'utils/get_games.py',
|
||||||
|
'utils/get_cover.py',
|
||||||
|
'utils/save_games.py',
|
||||||
|
'utils/save_cover.py',
|
||||||
|
'utils/toggle_hidden.py',
|
||||||
|
'utils/create_dialog.py',
|
||||||
|
'utils/create_details_window.py'
|
||||||
|
]
|
||||||
|
|
||||||
|
install_data(gameshelf_sources, install_dir: moduledir)
|
||||||
47
src/preferences.py
Normal file
47
src/preferences.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# preferences.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from gi.repository import Adw, Gtk, Gio, GLib
|
||||||
|
|
||||||
|
@Gtk.Template(resource_path='/hu/kramo/GameShelf/gtk/preferences.ui')
|
||||||
|
class PreferencesWindow(Adw.PreferencesWindow):
|
||||||
|
__gtype_name__ = 'PreferencesWindow'
|
||||||
|
|
||||||
|
exit_after_launch_switch = Gtk.Template.Child()
|
||||||
|
steam_file_chooser_button = Gtk.Template.Child()
|
||||||
|
|
||||||
|
def __init__(self, parent_widget, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
self.set_transient_for(parent_widget)
|
||||||
|
schema = parent_widget.schema
|
||||||
|
schema.bind("exit-after-launch", self.exit_after_launch_switch, "active", Gio.SettingsBindFlags.DEFAULT)
|
||||||
|
|
||||||
|
filechooser = Gtk.FileDialog.new()
|
||||||
|
|
||||||
|
def set_steam_dir(source, result, user_data):
|
||||||
|
try:
|
||||||
|
schema.set_string("steam-location", filechooser.select_folder_finish(result).get_path())
|
||||||
|
except GLib.GError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def choose_folder(widget):
|
||||||
|
filechooser.select_folder(parent_widget, None, None, set_steam_dir, None)
|
||||||
|
|
||||||
|
self.steam_file_chooser_button.connect("clicked", choose_folder)
|
||||||
194
src/utils/create_details_window.py
Normal file
194
src/utils/create_details_window.py
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
# create_details_window.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def create_details_window(parent_widget, game_id = None):
|
||||||
|
import os, json, time
|
||||||
|
from gi.repository import Adw, Gtk, GLib, GdkPixbuf
|
||||||
|
from .create_dialog import create_dialog
|
||||||
|
from .save_games import save_games
|
||||||
|
from .save_cover import save_cover
|
||||||
|
|
||||||
|
window = Adw.Window.new()
|
||||||
|
|
||||||
|
games = parent_widget.games
|
||||||
|
pixbuf = None
|
||||||
|
|
||||||
|
if game_id == None:
|
||||||
|
window.set_title(_("Add New Game"))
|
||||||
|
cover = Gtk.Picture.new_for_pixbuf(parent_widget.placeholder_pixbuf)
|
||||||
|
name = Gtk.Entry.new()
|
||||||
|
executable = Gtk.Entry.new()
|
||||||
|
apply_button = Gtk.Button.new_with_label(_("Confirm"))
|
||||||
|
else:
|
||||||
|
window.set_title(_("Edit Game Details"))
|
||||||
|
cover = Gtk.Picture.new_for_pixbuf((parent_widget.visible_widgets | parent_widget.hidden_widgets)[game_id].pixbuf)
|
||||||
|
name = Gtk.Entry.new_with_buffer(Gtk.EntryBuffer.new(games[game_id]["name"], -1))
|
||||||
|
executable = Gtk.Entry.new_with_buffer(Gtk.EntryBuffer.new((games[game_id]["executable"]), -1))
|
||||||
|
apply_button = Gtk.Button.new_with_label(_("Apply"))
|
||||||
|
|
||||||
|
file_filter = Gtk.FileFilter.new()
|
||||||
|
file_filter.set_name(_("Images"))
|
||||||
|
file_filter.add_pixbuf_formats()
|
||||||
|
filechooser = Gtk.FileDialog.new()
|
||||||
|
filechooser.set_current_filter(file_filter)
|
||||||
|
|
||||||
|
cover.add_css_class("card")
|
||||||
|
cover.set_size_request(200, 300)
|
||||||
|
|
||||||
|
cover_button = Gtk.Button.new_from_icon_name("document-edit-symbolic")
|
||||||
|
cover_button.set_halign(Gtk.Align.END)
|
||||||
|
cover_button.set_valign(Gtk.Align.END)
|
||||||
|
cover_button.set_margin_bottom(6)
|
||||||
|
cover_button.set_margin_end(6)
|
||||||
|
cover_button.add_css_class("circular")
|
||||||
|
cover_button.add_css_class("osd")
|
||||||
|
|
||||||
|
cover_overlay = Gtk.Overlay.new()
|
||||||
|
cover_overlay.set_child(cover)
|
||||||
|
cover_overlay.add_overlay(cover_button)
|
||||||
|
cover_overlay.set_halign(Gtk.Align.CENTER)
|
||||||
|
cover_overlay.set_valign(Gtk.Align.CENTER)
|
||||||
|
|
||||||
|
cover_group = Adw.PreferencesGroup.new()
|
||||||
|
cover_group.add(cover_overlay)
|
||||||
|
|
||||||
|
title_group = Adw.PreferencesGroup.new()
|
||||||
|
title_group.set_title(_("Title"))
|
||||||
|
title_group.set_description(_("The title of the game"))
|
||||||
|
title_group.add(name)
|
||||||
|
|
||||||
|
exec_group = Adw.PreferencesGroup.new()
|
||||||
|
exec_group.set_title(_("Executable"))
|
||||||
|
exec_group.set_description(_("File to open or command to run when launching the game"))
|
||||||
|
exec_group.add(executable)
|
||||||
|
|
||||||
|
general_page = Adw.PreferencesPage.new()
|
||||||
|
general_page.add(cover_group)
|
||||||
|
general_page.add(title_group)
|
||||||
|
general_page.add(exec_group)
|
||||||
|
|
||||||
|
cancel_button = Gtk.Button.new_with_label(_("Cancel"))
|
||||||
|
|
||||||
|
apply_button.add_css_class("suggested-action")
|
||||||
|
|
||||||
|
header_bar = Adw.HeaderBar.new()
|
||||||
|
header_bar.set_show_start_title_buttons(False)
|
||||||
|
header_bar.set_show_end_title_buttons(False)
|
||||||
|
header_bar.pack_start(cancel_button)
|
||||||
|
header_bar.pack_end(apply_button)
|
||||||
|
|
||||||
|
main_box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
|
||||||
|
main_box.append(header_bar)
|
||||||
|
main_box.append(general_page)
|
||||||
|
|
||||||
|
window.set_modal(True)
|
||||||
|
window.set_default_size(500, 650)
|
||||||
|
window.set_content(main_box)
|
||||||
|
window.set_transient_for(parent_widget)
|
||||||
|
|
||||||
|
def choose_cover(widget):
|
||||||
|
filechooser.open(window, None, None, set_cover, None)
|
||||||
|
|
||||||
|
def set_cover(source, result, _):
|
||||||
|
nonlocal pixbuf
|
||||||
|
|
||||||
|
try:
|
||||||
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(filechooser.open_finish(result).get_path(), 200, 300, False)
|
||||||
|
cover.set_pixbuf(pixbuf)
|
||||||
|
except GLib.GError:
|
||||||
|
return
|
||||||
|
|
||||||
|
def close_window(widget, callback=None):
|
||||||
|
window.close()
|
||||||
|
|
||||||
|
def apply_preferences(widget, callback=None):
|
||||||
|
nonlocal pixbuf
|
||||||
|
nonlocal game_id
|
||||||
|
|
||||||
|
values = {}
|
||||||
|
|
||||||
|
games_dir = os.path.join(os.environ.get("XDG_DATA_HOME"), "games")
|
||||||
|
final_name = name.get_buffer().get_text()
|
||||||
|
final_executable = executable.get_buffer().get_text()
|
||||||
|
|
||||||
|
if game_id == None:
|
||||||
|
|
||||||
|
if final_name == "":
|
||||||
|
create_dialog(window, _("Couldn't Add Game"), _("Game title cannot be empty."))
|
||||||
|
return
|
||||||
|
|
||||||
|
if final_executable == "":
|
||||||
|
create_dialog(window, _("Couldn't Add Game"), _("Executable cannot be empty."))
|
||||||
|
return
|
||||||
|
|
||||||
|
numbers = [0]
|
||||||
|
|
||||||
|
for game in games:
|
||||||
|
if "imported_" in game:
|
||||||
|
numbers.append(int(game.replace("imported_", "")))
|
||||||
|
|
||||||
|
game_id = "imported_" + str(max(numbers)+1)
|
||||||
|
|
||||||
|
games[game_id] = {}
|
||||||
|
|
||||||
|
values["game_id"] = game_id
|
||||||
|
values["hidden"] = False
|
||||||
|
values["source"] = "imported"
|
||||||
|
values["added"] = int(time.time())
|
||||||
|
values["last_played"] = 0
|
||||||
|
|
||||||
|
else:
|
||||||
|
if final_name == "":
|
||||||
|
create_dialog(window, _("Couldn't Apply Preferences"), _("Game title cannot be empty."))
|
||||||
|
return
|
||||||
|
|
||||||
|
if final_executable == "":
|
||||||
|
create_dialog(window, _("Couldn't Apply Preferences"), _("Executable cannot be empty."))
|
||||||
|
return
|
||||||
|
|
||||||
|
if pixbuf != None:
|
||||||
|
values["pixbuf_options"] = save_cover(None, parent_widget, None, pixbuf, game_id)
|
||||||
|
|
||||||
|
values["name"] = final_name
|
||||||
|
values["executable"] = final_executable
|
||||||
|
|
||||||
|
games[game_id].update(values)
|
||||||
|
save_games(games)
|
||||||
|
parent_widget.update_games([game_id])
|
||||||
|
if parent_widget.stack.get_visible_child() == parent_widget.overview:
|
||||||
|
parent_widget.show_overview(None, game_id)
|
||||||
|
window.close()
|
||||||
|
parent_widget.show_overview(None, game_id)
|
||||||
|
|
||||||
|
def focus_executable(widget):
|
||||||
|
window.set_focus(executable)
|
||||||
|
|
||||||
|
cover_button.connect("clicked", choose_cover)
|
||||||
|
cancel_button.connect("clicked", close_window)
|
||||||
|
apply_button.connect("clicked", apply_preferences)
|
||||||
|
name.connect("activate", focus_executable)
|
||||||
|
executable.connect("activate", apply_preferences)
|
||||||
|
|
||||||
|
shortcut_controller = Gtk.ShortcutController.new()
|
||||||
|
shortcut_controller.add_shortcut(Gtk.Shortcut.new(Gtk.ShortcutTrigger.parse_string('Escape'), Gtk.CallbackAction.new(close_window)))
|
||||||
|
|
||||||
|
window.add_controller(shortcut_controller)
|
||||||
|
window.set_focus(name)
|
||||||
|
window.present()
|
||||||
|
|
||||||
30
src/utils/create_dialog.py
Normal file
30
src/utils/create_dialog.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# create_dialog.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def create_dialog(parent_widget, heading, body, extra_option=None, extra_label=None):
|
||||||
|
from gi.repository import Adw, Gtk
|
||||||
|
|
||||||
|
dialog = Adw.MessageDialog.new(parent_widget, _(heading), body)
|
||||||
|
dialog.add_response("dismiss", _("Dismiss"))
|
||||||
|
|
||||||
|
if extra_option:
|
||||||
|
dialog.add_response(extra_option, _(extra_label))
|
||||||
|
|
||||||
|
Gtk.Window.present(dialog)
|
||||||
|
return dialog
|
||||||
35
src/utils/get_cover.py
Normal file
35
src/utils/get_cover.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# get_cover.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def get_cover(game, parent_widget):
|
||||||
|
from gi.repository import GdkPixbuf
|
||||||
|
import os
|
||||||
|
|
||||||
|
cover_path = os.path.join(os.environ.get("XDG_DATA_HOME"), "covers", game["game_id"] + ".dat")
|
||||||
|
|
||||||
|
if os.path.isfile(cover_path) == False:
|
||||||
|
return parent_widget.placeholder_pixbuf
|
||||||
|
|
||||||
|
open_file = open((cover_path), "rb")
|
||||||
|
data = open_file.read()
|
||||||
|
open_file.close()
|
||||||
|
try:
|
||||||
|
return GdkPixbuf.Pixbuf.new_from_data(data, *parent_widget.games[game["game_id"]]["pixbuf_options"])
|
||||||
|
except KeyError:
|
||||||
|
return parent_widget.placeholder_pixbuf
|
||||||
34
src/utils/get_games.py
Normal file
34
src/utils/get_games.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# get_games.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def get_games():
|
||||||
|
import os, json
|
||||||
|
|
||||||
|
games_dir = os.path.join(os.environ.get("XDG_DATA_HOME"), "games")
|
||||||
|
games = {}
|
||||||
|
|
||||||
|
if os.path.exists(games_dir) == False:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
for game in os.listdir(games_dir):
|
||||||
|
open_file = open(os.path.join(games_dir, game), "r")
|
||||||
|
data = json.loads(open_file.read())
|
||||||
|
open_file.close()
|
||||||
|
games[data["game_id"]] = data
|
||||||
|
return games
|
||||||
28
src/utils/run_command.py
Normal file
28
src/utils/run_command.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# run_command.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def run_command(parent_widget, executable):
|
||||||
|
import subprocess, sys
|
||||||
|
|
||||||
|
from gi.repository import Gio
|
||||||
|
|
||||||
|
subprocess.Popen(["flatpak-spawn --host " + executable], shell=True, start_new_session=True)
|
||||||
|
|
||||||
|
if Gio.Settings.new("hu.kramo.GameShelf").get_boolean("exit-after-launch") == True:
|
||||||
|
sys.exit()
|
||||||
39
src/utils/save_cover.py
Normal file
39
src/utils/save_cover.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# save_cover.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def save_cover(game, parent_widget, file_path, pixbuf = None, game_id = None):
|
||||||
|
from gi.repository import GdkPixbuf
|
||||||
|
import os
|
||||||
|
|
||||||
|
covers_dir = os.path.join(os.environ.get("XDG_DATA_HOME"), "covers")
|
||||||
|
if os.path.exists(covers_dir) == False:
|
||||||
|
os.makedirs(covers_dir)
|
||||||
|
|
||||||
|
if game_id == None:
|
||||||
|
game_id = game["game_id"]
|
||||||
|
|
||||||
|
cover_path = os.path.join(covers_dir, game_id + ".dat")
|
||||||
|
|
||||||
|
if pixbuf == None:
|
||||||
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(file_path, 200, 300, False)
|
||||||
|
|
||||||
|
open_file = open((cover_path), "wb")
|
||||||
|
open_file.write(bytes(pixbuf.get_pixels()))
|
||||||
|
open_file.close()
|
||||||
|
return [pixbuf.get_colorspace(), pixbuf.get_has_alpha(), pixbuf.get_bits_per_sample(), pixbuf.get_width(), pixbuf.get_height(), pixbuf.get_rowstride()]
|
||||||
31
src/utils/save_games.py
Normal file
31
src/utils/save_games.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# save_games.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def save_games(games):
|
||||||
|
import os, json
|
||||||
|
games_dir = os.path.join(os.environ.get("XDG_DATA_HOME"), "games")
|
||||||
|
existing = []
|
||||||
|
|
||||||
|
if os.path.exists(games_dir) == False:
|
||||||
|
os.makedirs(games_dir)
|
||||||
|
|
||||||
|
for game in games:
|
||||||
|
open_file = open(os.path.join(games_dir, game + ".json"), "w")
|
||||||
|
open_file.write(json.dumps(games[game], indent=4))
|
||||||
|
open_file.close()
|
||||||
103
src/utils/steam_parser.py
Normal file
103
src/utils/steam_parser.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# steam_parser.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def steam_parser(parent_widget, action):
|
||||||
|
import os, re, time
|
||||||
|
|
||||||
|
from gi.repository import Gtk, GLib
|
||||||
|
|
||||||
|
from .create_dialog import create_dialog
|
||||||
|
from .save_cover import save_cover
|
||||||
|
|
||||||
|
schema = parent_widget.schema
|
||||||
|
steam_dir = os.path.expanduser(os.path.join(schema.get_string("steam-location")))
|
||||||
|
|
||||||
|
def steam_not_found():
|
||||||
|
filechooser = Gtk.FileDialog.new()
|
||||||
|
|
||||||
|
def set_steam_dir(source, result, _):
|
||||||
|
try:
|
||||||
|
schema.set_string("steam-location", filechooser.select_folder_finish(result).get_path())
|
||||||
|
steam_dir = steam_dir = os.path.join(schema.get_string("steam-location"))
|
||||||
|
action(None, None)
|
||||||
|
except GLib.GError:
|
||||||
|
return
|
||||||
|
|
||||||
|
def choose_folder(widget):
|
||||||
|
filechooser.select_folder(parent_widget, None, None, set_steam_dir, None)
|
||||||
|
|
||||||
|
def response(widget, response):
|
||||||
|
if response == "choose_folder":
|
||||||
|
choose_folder(widget)
|
||||||
|
|
||||||
|
create_dialog(parent_widget, _("Couldn't Import Games"), _("Steam directory cannot be found."), "choose_folder", _("Set Steam Location")).connect("response", response)
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(steam_dir, "steamapps")) == True:
|
||||||
|
pass
|
||||||
|
elif os.path.exists(os.path.join(steam_dir, "steam", "steamapps")) == True:
|
||||||
|
schema.set_string("steam-location", os.path.join(steam_dir, "steam"))
|
||||||
|
elif os.path.exists(os.path.join(steam_dir, "Steam", "steamapps")) == True:
|
||||||
|
schema.set_string("steam-location", os.path.join(steam_dir, "Steam"))
|
||||||
|
else:
|
||||||
|
steam_not_found()
|
||||||
|
return {}
|
||||||
|
|
||||||
|
steam_dir = os.path.join(schema.get_string("steam-location"))
|
||||||
|
|
||||||
|
appmanifests = []
|
||||||
|
datatypes = ["appid", "name"]
|
||||||
|
steam_games = {}
|
||||||
|
current_time = int(time.time())
|
||||||
|
|
||||||
|
for file in os.listdir(os.path.join(steam_dir, "steamapps")):
|
||||||
|
path = os.path.join(steam_dir, "steamapps", file)
|
||||||
|
if os.path.isfile(path) and "appmanifest" in file:
|
||||||
|
appmanifests.append(path)
|
||||||
|
|
||||||
|
for appmanifest in appmanifests:
|
||||||
|
values = {}
|
||||||
|
file = open(appmanifest, "r")
|
||||||
|
data = file.read()
|
||||||
|
file.close()
|
||||||
|
for datatype in datatypes:
|
||||||
|
value = re.findall("\"" + datatype + "\"\t\t\"(.*)\"\n", data)
|
||||||
|
values [datatype] = value[0]
|
||||||
|
|
||||||
|
values["game_id"] = "steam_" + values["appid"]
|
||||||
|
|
||||||
|
if values["game_id"] in parent_widget.games and "removed" not in parent_widget.games[values["game_id"]].keys():
|
||||||
|
continue
|
||||||
|
|
||||||
|
values["executable"] = "xdg-open steam://rungameid/" + values["appid"]
|
||||||
|
values["hidden"] = False
|
||||||
|
values["source"] = "steam"
|
||||||
|
values["added"] = current_time
|
||||||
|
values["last_played"] = 0
|
||||||
|
|
||||||
|
if os.path.isfile(os.path.join(steam_dir, "appcache", "librarycache", values["appid"] + "_library_600x900.jpg")) == True:
|
||||||
|
values["pixbuf_options"] = save_cover(values, parent_widget, os.path.join(steam_dir, "appcache", "librarycache", values["appid"] + "_library_600x900.jpg"))
|
||||||
|
steam_games[values["game_id"]] = values
|
||||||
|
|
||||||
|
if len(steam_games) == 0:
|
||||||
|
create_dialog(parent_widget, _("No Games Found"), _("No new games found in Steam library."))
|
||||||
|
elif len(steam_games) == 1:
|
||||||
|
create_dialog(parent_widget, _("Steam Games Imported"), _("Successfully imported 1 game."))
|
||||||
|
elif len(steam_games) > 1:
|
||||||
|
create_dialog(parent_widget, _("Steam Games Imported"), _("Successfully imported ") + str(len(steam_games)) + _(" games."))
|
||||||
|
return steam_games
|
||||||
33
src/utils/toggle_hidden.py
Normal file
33
src/utils/toggle_hidden.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# toggle_hidden.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
def toggle_hidden(game):
|
||||||
|
import os, json
|
||||||
|
games_dir = os.path.join(os.environ.get("XDG_DATA_HOME"), "games")
|
||||||
|
|
||||||
|
if os.path.exists(games_dir) == False:
|
||||||
|
return
|
||||||
|
|
||||||
|
file = open(os.path.join(games_dir, game + ".json"), "r")
|
||||||
|
data = json.loads(file.read())
|
||||||
|
file.close()
|
||||||
|
file = open(os.path.join(games_dir, game + ".json"), "w")
|
||||||
|
data["hidden"] = not data["hidden"]
|
||||||
|
file.write(json.dumps(data, indent=4))
|
||||||
|
file.close()
|
||||||
407
src/window.blp
Normal file
407
src/window.blp
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
Adw.StatusPage notice_no_results {
|
||||||
|
icon-name: "system-search-symbolic";
|
||||||
|
title: _("No Games Found");
|
||||||
|
description: _("Try a different search.");
|
||||||
|
vexpand: true;
|
||||||
|
valign: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.StatusPage notice_empty {
|
||||||
|
icon-name: "applications-games-symbolic";
|
||||||
|
title: _("No Games Found");
|
||||||
|
description: _("Use the + button to add games.");
|
||||||
|
vexpand: true;
|
||||||
|
valign: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.StatusPage hidden_notice_empty {
|
||||||
|
icon-name: "view-conceal-symbolic";
|
||||||
|
title: _("No Hidden Games");
|
||||||
|
description: _("Games you hide will appear here.");
|
||||||
|
vexpand: true;
|
||||||
|
valign: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
template GameShelfWindow : Adw.ApplicationWindow {
|
||||||
|
title: _("Game Shelf");
|
||||||
|
default-width: 1110;
|
||||||
|
default-height: 820;
|
||||||
|
|
||||||
|
Adw.ToastOverlay toast_overlay {
|
||||||
|
Stack stack {
|
||||||
|
visible-child: library_view;
|
||||||
|
transition-type: over_left;
|
||||||
|
|
||||||
|
Overlay overview {
|
||||||
|
[overlay]
|
||||||
|
Box overview_box {
|
||||||
|
orientation: vertical;
|
||||||
|
|
||||||
|
Adw.HeaderBar {
|
||||||
|
[start]
|
||||||
|
Button back_button {
|
||||||
|
action-name: "win.go_back";
|
||||||
|
icon-name: "go-previous-symbolic";
|
||||||
|
}
|
||||||
|
|
||||||
|
[title]
|
||||||
|
Adw.WindowTitle overview_header_bar_title {
|
||||||
|
title: _("Game Details");
|
||||||
|
}
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"flat",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.Bin {
|
||||||
|
hexpand: true;
|
||||||
|
vexpand: true;
|
||||||
|
|
||||||
|
Box {
|
||||||
|
halign: center;
|
||||||
|
valign: center;
|
||||||
|
margin-start: 24;
|
||||||
|
margin-end: 24;
|
||||||
|
margin-top: 24;
|
||||||
|
margin-bottom: 24;
|
||||||
|
|
||||||
|
Picture overview_cover {
|
||||||
|
halign: end;
|
||||||
|
valign: start;
|
||||||
|
width-request: 200;
|
||||||
|
height-request: 300;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"card",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Box {
|
||||||
|
orientation: vertical;
|
||||||
|
margin-start: 48;
|
||||||
|
vexpand: true;
|
||||||
|
valign: center;
|
||||||
|
|
||||||
|
Label overview_title {
|
||||||
|
label: _("Game Title");
|
||||||
|
hexpand: true;
|
||||||
|
halign: start;
|
||||||
|
wrap: true;
|
||||||
|
wrap-mode: word_char;
|
||||||
|
natural-wrap-mode: word;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"title-1",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Label overview_added {
|
||||||
|
margin-top: 12;
|
||||||
|
hexpand: true;
|
||||||
|
halign: start;
|
||||||
|
wrap: true;
|
||||||
|
wrap-mode: word_char;
|
||||||
|
natural-wrap-mode: word;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"dim-label",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Label overview_last_played {
|
||||||
|
margin-top: 6;
|
||||||
|
hexpand: true;
|
||||||
|
halign: start;
|
||||||
|
wrap: true;
|
||||||
|
wrap-mode: word_char;
|
||||||
|
natural-wrap-mode: word;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"dim-label",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Box {
|
||||||
|
hexpand: true;
|
||||||
|
vexpand: true;
|
||||||
|
valign: center;
|
||||||
|
|
||||||
|
Button overview_launch {
|
||||||
|
action-name: "app.launch_game";
|
||||||
|
label: _("Play");
|
||||||
|
halign: start;
|
||||||
|
margin-top: 24;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"suggested-action",
|
||||||
|
"pill",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuButton overview_menu_button {
|
||||||
|
icon-name: "view-more-symbolic";
|
||||||
|
hexpand: true;
|
||||||
|
vexpand: true;
|
||||||
|
halign: start;
|
||||||
|
valign: center;
|
||||||
|
margin-top: 24;
|
||||||
|
margin-start: 6;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"circular",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"background",
|
||||||
|
]
|
||||||
|
|
||||||
|
Picture overview_blurred_cover {
|
||||||
|
opacity: 0.2;
|
||||||
|
can-shrink: true;
|
||||||
|
keep-aspect-ratio: false;
|
||||||
|
hexpand: true;
|
||||||
|
vexpand: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box library_view {
|
||||||
|
orientation: vertical;
|
||||||
|
|
||||||
|
Adw.HeaderBar header_bar {
|
||||||
|
[start]
|
||||||
|
MenuButton {
|
||||||
|
icon-name: "list-add-symbolic";
|
||||||
|
menu-model: add_games;
|
||||||
|
}
|
||||||
|
|
||||||
|
[end]
|
||||||
|
MenuButton {
|
||||||
|
icon-name: "open-menu-symbolic";
|
||||||
|
menu-model: primary_menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
[end]
|
||||||
|
ToggleButton search_button {
|
||||||
|
icon-name: "system-search-symbolic";
|
||||||
|
action-name: "win.toggle_search";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchBar search_bar {
|
||||||
|
Adw.Clamp {
|
||||||
|
maximum-size: 500;
|
||||||
|
tightening-threshold: 500;
|
||||||
|
|
||||||
|
SearchEntry search_entry {
|
||||||
|
hexpand: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.Bin library_bin {
|
||||||
|
ScrolledWindow scrolledwindow {
|
||||||
|
hexpand: true;
|
||||||
|
vexpand: true;
|
||||||
|
|
||||||
|
FlowBox library {
|
||||||
|
homogeneous: true;
|
||||||
|
halign: center;
|
||||||
|
valign: start;
|
||||||
|
column-spacing: 12;
|
||||||
|
row-spacing: 12;
|
||||||
|
margin-top: 16;
|
||||||
|
margin-bottom: 16;
|
||||||
|
margin-start: 16;
|
||||||
|
margin-end: 16;
|
||||||
|
selection-mode: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box hidden_library_view {
|
||||||
|
orientation: vertical;
|
||||||
|
|
||||||
|
Adw.HeaderBar hidden_header_bar {
|
||||||
|
[start]
|
||||||
|
Button hidden_back_button {
|
||||||
|
action-name: "win.go_back";
|
||||||
|
icon-name: "go-previous-symbolic";
|
||||||
|
}
|
||||||
|
|
||||||
|
[title]
|
||||||
|
Adw.WindowTitle {
|
||||||
|
title: _("Hidden Games");
|
||||||
|
}
|
||||||
|
|
||||||
|
[end]
|
||||||
|
MenuButton {
|
||||||
|
icon-name: "open-menu-symbolic";
|
||||||
|
menu-model: primary_menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
[end]
|
||||||
|
ToggleButton hidden_search_button {
|
||||||
|
icon-name: "system-search-symbolic";
|
||||||
|
action-name: "win.toggle_search";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchBar hidden_search_bar {
|
||||||
|
Adw.Clamp {
|
||||||
|
maximum-size: 500;
|
||||||
|
tightening-threshold: 500;
|
||||||
|
|
||||||
|
SearchEntry hidden_search_entry {
|
||||||
|
hexpand: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.Bin hidden_library_bin {
|
||||||
|
ScrolledWindow hidden_scrolledwindow {
|
||||||
|
hexpand: true;
|
||||||
|
vexpand: true;
|
||||||
|
|
||||||
|
FlowBox hidden_library {
|
||||||
|
homogeneous: true;
|
||||||
|
halign: center;
|
||||||
|
valign: start;
|
||||||
|
column-spacing: 12;
|
||||||
|
row-spacing: 12;
|
||||||
|
margin-top: 16;
|
||||||
|
margin-bottom: 16;
|
||||||
|
margin-start: 16;
|
||||||
|
margin-end: 16;
|
||||||
|
selection-mode: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"background",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu primary_menu {
|
||||||
|
section {
|
||||||
|
submenu {
|
||||||
|
label: _("Sort");
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("A-Z");
|
||||||
|
action: "win.sort_by";
|
||||||
|
target: "a-z";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Z-A");
|
||||||
|
action: "win.sort_by";
|
||||||
|
target: "z-a";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Newest");
|
||||||
|
action: "win.sort_by";
|
||||||
|
target: "newest";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Oldest");
|
||||||
|
action: "win.sort_by";
|
||||||
|
target: "oldest";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Last Played");
|
||||||
|
action: "win.sort_by";
|
||||||
|
target: "last_played";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Show Hidden");
|
||||||
|
action: "win.show_hidden";
|
||||||
|
hidden-when: "action-disabled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
item {
|
||||||
|
label: _("Preferences");
|
||||||
|
action: "app.preferences";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Keyboard Shortcuts");
|
||||||
|
action: "win.show-help-overlay";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("About Game Shelf");
|
||||||
|
action: "app.about";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu add_games {
|
||||||
|
section {
|
||||||
|
item {
|
||||||
|
label: _("Add Game");
|
||||||
|
action: "app.add_game";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Import From Steam");
|
||||||
|
action: "app.steam_import";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu game_options {
|
||||||
|
section {
|
||||||
|
item {
|
||||||
|
label: _("Edit");
|
||||||
|
action: "app.edit_details";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Hide");
|
||||||
|
action: "app.hide_game";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Remove");
|
||||||
|
action: "app.remove_game";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu hidden_game_options {
|
||||||
|
section {
|
||||||
|
item {
|
||||||
|
label: _("Edit");
|
||||||
|
action: "app.edit_details";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Unhide");
|
||||||
|
action: "app.hide_game";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Remove");
|
||||||
|
action: "app.remove_game";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
385
src/window.py
Normal file
385
src/window.py
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
# window.py
|
||||||
|
#
|
||||||
|
# Copyright 2022 kramo
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from gi.repository import Gio, GLib, Adw, GdkPixbuf, Gtk
|
||||||
|
|
||||||
|
import os, json, time, datetime
|
||||||
|
|
||||||
|
from .game import game
|
||||||
|
from .get_cover import get_cover
|
||||||
|
from .get_games import get_games
|
||||||
|
from .save_games import save_games
|
||||||
|
|
||||||
|
@Gtk.Template(resource_path="/hu/kramo/GameShelf/window.ui")
|
||||||
|
class GameShelfWindow(Adw.ApplicationWindow):
|
||||||
|
__gtype_name__ = "GameShelfWindow"
|
||||||
|
|
||||||
|
toast_overlay = Gtk.Template.Child()
|
||||||
|
stack = Gtk.Template.Child()
|
||||||
|
overview = Gtk.Template.Child()
|
||||||
|
library_view = Gtk.Template.Child()
|
||||||
|
library = Gtk.Template.Child()
|
||||||
|
scrolledwindow = Gtk.Template.Child()
|
||||||
|
library_bin = Gtk.Template.Child()
|
||||||
|
notice_empty = Gtk.Template.Child()
|
||||||
|
notice_no_results = Gtk.Template.Child()
|
||||||
|
game_options = Gtk.Template.Child()
|
||||||
|
search_bar = Gtk.Template.Child()
|
||||||
|
search_entry = Gtk.Template.Child()
|
||||||
|
search_button = Gtk.Template.Child()
|
||||||
|
|
||||||
|
overview_box = Gtk.Template.Child()
|
||||||
|
overview_cover = Gtk.Template.Child()
|
||||||
|
overview_title = Gtk.Template.Child()
|
||||||
|
overview_header_bar_title = Gtk.Template.Child()
|
||||||
|
overview_launch = Gtk.Template.Child()
|
||||||
|
overview_blurred_cover = Gtk.Template.Child()
|
||||||
|
overview_menu_button = Gtk.Template.Child()
|
||||||
|
overview_added = Gtk.Template.Child()
|
||||||
|
overview_last_played = Gtk.Template.Child()
|
||||||
|
|
||||||
|
hidden_library = Gtk.Template.Child()
|
||||||
|
hidden_library_view = Gtk.Template.Child()
|
||||||
|
hidden_scrolledwindow = Gtk.Template.Child()
|
||||||
|
hidden_library_bin = Gtk.Template.Child()
|
||||||
|
hidden_notice_empty = Gtk.Template.Child()
|
||||||
|
hidden_game_options = Gtk.Template.Child()
|
||||||
|
hidden_search_bar = Gtk.Template.Child()
|
||||||
|
hidden_search_entry = Gtk.Template.Child()
|
||||||
|
hidden_search_button = Gtk.Template.Child()
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
self.visible_widgets = {}
|
||||||
|
self.hidden_widgets = {}
|
||||||
|
self.filtered = {}
|
||||||
|
self.hidden_filtered = {}
|
||||||
|
self.previous_page = self.library_view
|
||||||
|
self.toasts = {}
|
||||||
|
|
||||||
|
self.overview.set_measure_overlay(self.overview_box, True)
|
||||||
|
self.overview.set_clip_overlay(self.overview_box, False)
|
||||||
|
|
||||||
|
self.schema = Gio.Settings.new("hu.kramo.GameShelf")
|
||||||
|
self.placeholder_pixbuf = GdkPixbuf.Pixbuf.new_from_resource_at_scale("/hu/kramo/GameShelf/assets/library_placeholder.svg", 200, 300, False)
|
||||||
|
games = get_games()
|
||||||
|
for game in games:
|
||||||
|
if "removed" in games[game].keys():
|
||||||
|
os.remove(os.path.join(os.environ.get("XDG_DATA_HOME"), "games", game + ".json"))
|
||||||
|
try:
|
||||||
|
os.remove(os.path.join(os.environ.get("XDG_DATA_HOME"), "covers", game + ".dat"))
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.library.set_filter_func(self.search_filter)
|
||||||
|
self.hidden_library.set_filter_func(self.hidden_search_filter)
|
||||||
|
|
||||||
|
self.update_games(get_games())
|
||||||
|
|
||||||
|
# Connect signals
|
||||||
|
self.search_entry.connect("search-changed", self.search_changed, False)
|
||||||
|
self.hidden_search_entry.connect("search-changed", self.search_changed, True)
|
||||||
|
|
||||||
|
def update_games(self, games):
|
||||||
|
# Update the displayed games and the self.games instance variable to reference later
|
||||||
|
self.games = get_games()
|
||||||
|
|
||||||
|
for game_id in games:
|
||||||
|
if game_id in self.visible_widgets:
|
||||||
|
self.library.remove(self.visible_widgets[game_id])
|
||||||
|
self.filtered.pop(self.visible_widgets[game_id])
|
||||||
|
self.visible_widgets.pop(game_id)
|
||||||
|
elif game_id in self.hidden_widgets:
|
||||||
|
self.hidden_library.remove(self.hidden_widgets[game_id])
|
||||||
|
self.hidden_filtered.pop(self.hidden_widgets[game_id])
|
||||||
|
self.hidden_widgets.pop(game_id)
|
||||||
|
if game_id in self.games:
|
||||||
|
current_game = self.games[game_id]
|
||||||
|
|
||||||
|
if "removed" in current_game.keys():
|
||||||
|
continue
|
||||||
|
|
||||||
|
entry = game(current_game["name"], get_cover(current_game, self), game_id)
|
||||||
|
|
||||||
|
if self.games[game_id]["hidden"] == False:
|
||||||
|
self.visible_widgets[game_id] = entry
|
||||||
|
self.library.append(entry)
|
||||||
|
else:
|
||||||
|
self.hidden_widgets[game_id] = entry
|
||||||
|
entry.menu_button.set_menu_model(entry.hidden_game_options)
|
||||||
|
self.hidden_library.append(entry)
|
||||||
|
|
||||||
|
entry.cover_button.connect("clicked", self.show_overview, game_id)
|
||||||
|
entry.menu_button.connect("state-flags-changed", self.set_active_game, game_id)
|
||||||
|
|
||||||
|
if self.visible_widgets == {}:
|
||||||
|
self.library_bin.set_child(self.notice_empty)
|
||||||
|
else:
|
||||||
|
self.library_bin.set_child(self.scrolledwindow)
|
||||||
|
|
||||||
|
if self.hidden_widgets == {}:
|
||||||
|
self.hidden_library_bin.set_child(self.hidden_notice_empty)
|
||||||
|
else:
|
||||||
|
self.hidden_library_bin.set_child(self.hidden_scrolledwindow)
|
||||||
|
|
||||||
|
self.library.invalidate_filter()
|
||||||
|
self.hidden_library.invalidate_filter()
|
||||||
|
|
||||||
|
def search_changed(self, widget, hidden):
|
||||||
|
# Refresh search filter on keystroke in search box
|
||||||
|
if hidden == False:
|
||||||
|
self.library.invalidate_filter()
|
||||||
|
else:
|
||||||
|
self.hidden_library.invalidate_filter()
|
||||||
|
|
||||||
|
def search_filter(self, child):
|
||||||
|
# Only show games matching the contents of the search box
|
||||||
|
text = self.search_entry.get_text().lower()
|
||||||
|
if text == "":
|
||||||
|
filtered = True
|
||||||
|
elif text in child.get_first_child().name.lower():
|
||||||
|
filtered = True
|
||||||
|
else:
|
||||||
|
filtered = False
|
||||||
|
|
||||||
|
# Add filtered entry to dict of filtered widgets
|
||||||
|
self.filtered[child.get_first_child()] = filtered
|
||||||
|
|
||||||
|
if True not in self.filtered.values():
|
||||||
|
self.library_bin.set_child(self.notice_no_results)
|
||||||
|
else:
|
||||||
|
self.library_bin.set_child(self.scrolledwindow)
|
||||||
|
return filtered
|
||||||
|
|
||||||
|
def hidden_search_filter(self, child):
|
||||||
|
text = self.hidden_search_entry.get_text().lower()
|
||||||
|
if text == "":
|
||||||
|
filtered = True
|
||||||
|
elif text in child.get_first_child().name.lower():
|
||||||
|
filtered = True
|
||||||
|
else:
|
||||||
|
filtered = False
|
||||||
|
|
||||||
|
self.hidden_filtered[child.get_first_child()] = filtered
|
||||||
|
|
||||||
|
if True not in self.hidden_filtered.values():
|
||||||
|
self.hidden_library_bin.set_child(self.notice_no_results)
|
||||||
|
else:
|
||||||
|
self.hidden_library_bin.set_child(self.hidden_scrolledwindow)
|
||||||
|
return filtered
|
||||||
|
|
||||||
|
def set_active_game(self, widget, flags, game):
|
||||||
|
if "GTK_STATE_FLAG_FOCUS_WITHIN" in flags.value_names:
|
||||||
|
self.active_game_id = game
|
||||||
|
|
||||||
|
def get_time(self, timestamp):
|
||||||
|
date = datetime.datetime.fromtimestamp(timestamp)
|
||||||
|
|
||||||
|
if (datetime.datetime.today() - date).days == 0:
|
||||||
|
return _("Today")
|
||||||
|
elif (datetime.datetime.today() - date).days == 1:
|
||||||
|
return _("Yesterday")
|
||||||
|
elif (datetime.datetime.today() - date).days < 8:
|
||||||
|
return GLib.DateTime.new_from_unix_utc(timestamp).format("%A")
|
||||||
|
else:
|
||||||
|
return GLib.DateTime.new_from_unix_utc(timestamp).format("%x")
|
||||||
|
|
||||||
|
def show_overview(self, widget, game_id):
|
||||||
|
game = self.games[game_id]
|
||||||
|
|
||||||
|
if game["hidden"] == False:
|
||||||
|
self.overview_menu_button.set_menu_model(self.game_options)
|
||||||
|
else:
|
||||||
|
self.overview_menu_button.set_menu_model(self.hidden_game_options)
|
||||||
|
|
||||||
|
if self.stack.get_visible_child() != self.overview:
|
||||||
|
self.stack.set_transition_type(Gtk.StackTransitionType.OVER_LEFT)
|
||||||
|
self.stack.set_visible_child(self.overview)
|
||||||
|
|
||||||
|
self.active_game_id = game_id
|
||||||
|
pixbuf = (self.visible_widgets | self.hidden_widgets)[self.active_game_id].pixbuf
|
||||||
|
self.overview_cover.set_pixbuf(pixbuf)
|
||||||
|
self.overview_blurred_cover.set_pixbuf(pixbuf.scale_simple(2, 3, GdkPixbuf.InterpType.BILINEAR))
|
||||||
|
self.overview_title.set_label(game["name"])
|
||||||
|
self.overview_header_bar_title.set_title(game["name"])
|
||||||
|
self.overview_added.set_label(_("Added: ") + self.get_time(game["added"]))
|
||||||
|
self.overview_last_played.set_label(_("Last played: ") + self.get_time(game["last_played"]) if game["last_played"] != 0 else _("Last played: Never"))
|
||||||
|
|
||||||
|
def a_z_sort(self, child1, child2):
|
||||||
|
name1 = child1.get_first_child().name.lower()
|
||||||
|
name2 = child2.get_first_child().name.lower()
|
||||||
|
if name1 > name2:
|
||||||
|
return 1
|
||||||
|
elif name1 < name2:
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
if child1.get_first_child().game_id > child2.get_first_child().game_id:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def z_a_sort(self, child1, child2):
|
||||||
|
name1 = child1.get_first_child().name.lower()
|
||||||
|
name2 = child2.get_first_child().name.lower()
|
||||||
|
if name1 > name2:
|
||||||
|
return -1
|
||||||
|
elif name1 < name2:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return self.a_z_sort(child1, child2)
|
||||||
|
|
||||||
|
def newest_sort(self, child1, child2):
|
||||||
|
time1 = self.games[child1.get_first_child().game_id]["added"]
|
||||||
|
time2 = self.games[child2.get_first_child().game_id]["added"]
|
||||||
|
if time1 > time2:
|
||||||
|
return -1
|
||||||
|
elif time1 < time2:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return self.a_z_sort(child1, child2)
|
||||||
|
|
||||||
|
def oldest_sort(self, child1, child2):
|
||||||
|
time1 = self.games[child1.get_first_child().game_id]["added"]
|
||||||
|
time2 = self.games[child2.get_first_child().game_id]["added"]
|
||||||
|
if time1 > time2:
|
||||||
|
return 1
|
||||||
|
elif time1 < time2:
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
return self.a_z_sort(child1, child2)
|
||||||
|
|
||||||
|
def last_played_sort(self, child1, child2):
|
||||||
|
time1 = self.games[child1.get_first_child().game_id]["last_played"]
|
||||||
|
time2 = self.games[child2.get_first_child().game_id]["last_played"]
|
||||||
|
if time1 > time2:
|
||||||
|
return -1
|
||||||
|
elif time1 < time2:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return self.a_z_sort(child1, child2)
|
||||||
|
|
||||||
|
def on_go_back_action(self, widget, _):
|
||||||
|
if self.stack.get_visible_child() == self.hidden_library_view:
|
||||||
|
self.on_show_library_action(None, None)
|
||||||
|
elif self.stack.get_visible_child() == self.overview:
|
||||||
|
self.on_go_to_parent_action(None, None)
|
||||||
|
|
||||||
|
def on_go_to_parent_action(self, widget, _):
|
||||||
|
if self.stack.get_visible_child() == self.overview:
|
||||||
|
if self.previous_page == self.library_view:
|
||||||
|
self.on_show_library_action(None, None)
|
||||||
|
else:
|
||||||
|
self.on_show_hidden_action(None, None)
|
||||||
|
|
||||||
|
def on_show_library_action(self, widget, _):
|
||||||
|
self.stack.set_transition_type(Gtk.StackTransitionType.UNDER_RIGHT)
|
||||||
|
self.stack.set_visible_child(self.library_view)
|
||||||
|
self.lookup_action("show_hidden").set_enabled(True)
|
||||||
|
self.previous_page = self.library_view
|
||||||
|
|
||||||
|
def on_show_hidden_action(self, widget, _):
|
||||||
|
if self.stack.get_visible_child() == self.library_view:
|
||||||
|
self.stack.set_transition_type(Gtk.StackTransitionType.OVER_LEFT)
|
||||||
|
else:
|
||||||
|
self.stack.set_transition_type(Gtk.StackTransitionType.UNDER_RIGHT)
|
||||||
|
self.lookup_action("show_hidden").set_enabled(False)
|
||||||
|
self.stack.set_visible_child(self.hidden_library_view)
|
||||||
|
self.previous_page = self.hidden_library_view
|
||||||
|
|
||||||
|
def on_sort_action(self, action, state):
|
||||||
|
action.set_state(state)
|
||||||
|
state = str(state).strip("\'")
|
||||||
|
|
||||||
|
if state == "a-z":
|
||||||
|
sort_func = self.a_z_sort
|
||||||
|
|
||||||
|
elif state == "z-a":
|
||||||
|
sort_func = self.z_a_sort
|
||||||
|
|
||||||
|
elif state == "newest":
|
||||||
|
sort_func = self.newest_sort
|
||||||
|
|
||||||
|
elif state == "oldest":
|
||||||
|
sort_func = self.oldest_sort
|
||||||
|
|
||||||
|
elif state == "last_played":
|
||||||
|
sort_func = self.last_played_sort
|
||||||
|
|
||||||
|
self.schema.set_string("sort-mode", state)
|
||||||
|
self.library.set_sort_func(sort_func)
|
||||||
|
self.hidden_library.set_sort_func(sort_func)
|
||||||
|
|
||||||
|
def on_toggle_search_action(self, widget, _):
|
||||||
|
if self.stack.get_visible_child() == self.library_view:
|
||||||
|
search_bar = self.search_bar
|
||||||
|
search_entry = self.search_entry
|
||||||
|
search_button = self.search_button
|
||||||
|
elif self.stack.get_visible_child() == self.hidden_library_view:
|
||||||
|
search_bar = self.hidden_search_bar
|
||||||
|
search_entry = self.hidden_search_entry
|
||||||
|
search_button = self.hidden_search_button
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
search_mode = search_bar.get_search_mode()
|
||||||
|
search_bar.set_search_mode(not search_mode)
|
||||||
|
search_button.set_active(not search_button.get_active())
|
||||||
|
|
||||||
|
if search_mode == False:
|
||||||
|
self.set_focus(search_entry)
|
||||||
|
else:
|
||||||
|
search_entry.set_text("")
|
||||||
|
|
||||||
|
def on_escape_action(self, widget, _):
|
||||||
|
if self.stack.get_visible_child() == self.overview:
|
||||||
|
self.on_go_back_action(None, None)
|
||||||
|
return
|
||||||
|
elif self.stack.get_visible_child() == self.library_view:
|
||||||
|
search_bar = self.search_bar
|
||||||
|
search_entry = self.search_entry
|
||||||
|
search_button = self.search_button
|
||||||
|
elif self.stack.get_visible_child() == self.hidden_library_view:
|
||||||
|
search_bar = self.hidden_search_bar
|
||||||
|
search_entry = self.hidden_search_entry
|
||||||
|
search_button = self.hidden_search_button
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.get_focus() == search_entry.get_focus_child():
|
||||||
|
search_bar.set_search_mode(False)
|
||||||
|
search_button.set_active(False)
|
||||||
|
search_entry.set_text("")
|
||||||
|
|
||||||
|
def on_undo_remove_action(self, widget, game_id=None):
|
||||||
|
# Remove the "removed=True" property from the game and dismiss the toast
|
||||||
|
|
||||||
|
if not game_id:
|
||||||
|
try:
|
||||||
|
game_id = list(self.toasts)[-1]
|
||||||
|
except IndexError:
|
||||||
|
return
|
||||||
|
open_file = open(os.path.join(os.path.join(os.environ.get("XDG_DATA_HOME"), "games", game_id + ".json")), "r")
|
||||||
|
data = json.loads(open_file.read())
|
||||||
|
open_file.close()
|
||||||
|
data.pop("removed")
|
||||||
|
save_games({game_id : data})
|
||||||
|
self.update_games({game_id : self.games[game_id]})
|
||||||
|
self.toasts[game_id].dismiss()
|
||||||
|
self.toasts.pop(game_id)
|
||||||
8
subprojects/blueprint-compiler.wrap
Normal file
8
subprojects/blueprint-compiler.wrap
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[wrap-git]
|
||||||
|
directory = blueprint-compiler
|
||||||
|
url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git
|
||||||
|
revision = v0.4.0
|
||||||
|
depth = 1
|
||||||
|
|
||||||
|
[provide]
|
||||||
|
program_names = blueprint-compiler
|
||||||
Reference in New Issue
Block a user