diff --git a/data/GameHub.css b/data/GameHub.css index 7a3bf52e..cd5180e1 100644 --- a/data/GameHub.css +++ b/data/GameHub.css @@ -1,6 +1,6 @@ .gamecard { - opacity: 0.8; + opacity: 0.75; border-radius: 4px; transition: 100ms; } @@ -10,6 +10,11 @@ opacity: 1; } +.gamecard.hover:not(.installed) +{ + opacity: 0.8; +} + .gamecard label { color: rgba(255, 255, 255, 0.9); diff --git a/data/com.github.tkashkin.gamehub.appdata.xml.in b/data/com.github.tkashkin.gamehub.appdata.xml.in index a9d86184..5473e7b5 100644 --- a/data/com.github.tkashkin.gamehub.appdata.xml.in +++ b/data/com.github.tkashkin.gamehub.appdata.xml.in @@ -35,6 +35,11 @@ + + +

Settings dialog

+
+

GOG games installation and running

diff --git a/data/com.github.tkashkin.gamehub.gschema.xml b/data/com.github.tkashkin.gamehub.gschema.xml index 8f7e5fac..96313372 100644 --- a/data/com.github.tkashkin.gamehub.gschema.xml +++ b/data/com.github.tkashkin.gamehub.gschema.xml @@ -24,10 +24,19 @@ + + + false + + + false + + '8B10B604CAC6AC90F57AACE025DD904C' + diff --git a/data/icons/icons.gresource.xml b/data/icons/icons.gresource.xml index 5a0725f0..566fd5b4 100644 --- a/data/icons/icons.gresource.xml +++ b/data/icons/icons.gresource.xml @@ -2,10 +2,9 @@ steam.svg - steam-symbolic.svg gog.svg - steam-symbolic-white.svg + steam-white.svg gog-white.svg diff --git a/data/icons/steam-symbolic.svg b/data/icons/steam-symbolic.svg deleted file mode 100644 index a89e27f6..00000000 --- a/data/icons/steam-symbolic.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/data/icons/steam-symbolic-white.svg b/data/icons/steam-white.svg similarity index 100% rename from data/icons/steam-symbolic-white.svg rename to data/icons/steam-white.svg diff --git a/data/icons/steam.svg b/data/icons/steam.svg index 0c27cadc..a89e27f6 100644 --- a/data/icons/steam.svg +++ b/data/icons/steam.svg @@ -1,43 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/debian/changelog b/debian/changelog index 7b975e42..69123af3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +com.github.tkashkin.gamehub (0.2.4) xenial; urgency=low + + * Settings dialog + + -- tkashkin Fri, 01 Jun 2018 23:20:42 +0300 + com.github.tkashkin.gamehub (0.2.3) xenial; urgency=low * GOG games installation and running diff --git a/meson.build b/meson.build index e42c10f3..16af7e49 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('com.github.tkashkin.gamehub', 'vala', 'c', version: '0.2.2') +project('com.github.tkashkin.gamehub', 'vala', 'c', version: '0.2.4') i18n = import('i18n') gnome = import('gnome') diff --git a/po/POTFILES b/po/POTFILES index 56f70e0d..d7d1d4ea 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -17,7 +17,9 @@ src/data/sources/gog/GOGGame.vala src/ui/windows/MainWindow.vala src/ui/windows/WebAuthWindow.vala -src/ui/windows/GOGGameInstallWindow.vala + +src/ui/dialogs/SettingsDialog.vala +src/ui/dialogs/GOGGameInstallDialog.vala src/ui/views/BaseView.vala src/ui/views/WelcomeView.vala diff --git a/po/com.github.tkashkin.gamehub.pot b/po/com.github.tkashkin.gamehub.pot index 71d7a362..3023f1c6 100644 --- a/po/com.github.tkashkin.gamehub.pot +++ b/po/com.github.tkashkin.gamehub.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.tkashkin.gamehub\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-01 04:08+0300\n" +"POT-Creation-Date: 2018-06-02 05:53+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -26,7 +26,7 @@ msgstr "" #: data/com.github.tkashkin.gamehub.appdata.xml.in:9 #: data/com.github.tkashkin.gamehub.desktop.in:5 -#: src/ui/views/WelcomeView.vala:18 +#: src/ui/views/WelcomeView.vala:32 msgid "All your games in one place" msgstr "" @@ -50,40 +50,98 @@ msgstr "" msgid "Your SteamID will be read from Steam configuration file" msgstr "" -#: src/ui/windows/GOGGameInstallWindow.vala:22 src/ui/views/WelcomeView.vala:92 -#, c-format -msgid "Install %s" +#: src/ui/dialogs/SettingsDialog.vala:27 +msgid "Use dark theme" msgstr "" -#: src/ui/windows/GOGGameInstallWindow.vala:48 +#: src/ui/dialogs/SettingsDialog.vala:31 +msgid "Steam API keys have limited number of uses per day" +msgstr "" + +#: src/ui/dialogs/SettingsDialog.vala:31 +msgid "Generate key" +msgstr "" + +#: src/ui/dialogs/SettingsDialog.vala:32 +msgid "Steam API key" +msgstr "" + +#: src/ui/dialogs/SettingsDialog.vala:33 +msgid "Steam installation directory" +msgstr "" + +#: src/ui/dialogs/SettingsDialog.vala:37 +msgid "GOG games directory" +msgstr "" + +#: src/ui/dialogs/SettingsDialog.vala:50 +msgid "Close" +msgstr "" + +#: src/ui/dialogs/GOGGameInstallDialog.vala:47 +msgid "Select game language" +msgstr "" + +#: src/ui/dialogs/GOGGameInstallDialog.vala:69 +msgid "Cancel" +msgstr "" + +#: src/ui/dialogs/GOGGameInstallDialog.vala:70 msgid "Install" msgstr "" -#: src/ui/views/WelcomeView.vala:18 +#: src/ui/views/WelcomeView.vala:32 msgid "Let's get started" msgstr "" -#: src/ui/views/WelcomeView.vala:26 +#: src/ui/views/WelcomeView.vala:42 msgid "Skip" msgstr "" -#: src/ui/views/WelcomeView.vala:71 +#: src/ui/views/WelcomeView.vala:49 +#: src/ui/views/GamesGridView/GamesGridView.vala:92 +msgid "Settings" +msgstr "" + +#: src/ui/views/WelcomeView.vala:101 msgid "Ready" msgstr "" -#: src/ui/views/WelcomeView.vala:77 +#: src/ui/views/WelcomeView.vala:107 msgid "Authentication required" msgstr "" -#: src/ui/views/WelcomeView.vala:81 +#: src/ui/views/WelcomeView.vala:112 msgid "Authenticating..." msgstr "" -#: src/ui/views/WelcomeView.vala:93 +#: src/ui/views/WelcomeView.vala:123 +#, c-format +msgid "Install %s" +msgstr "" + +#: src/ui/views/WelcomeView.vala:124 msgid "Return to GameHub after installing" msgstr "" -#: src/ui/views/GamesGridView/GamesGridView.vala:91 +#: src/ui/views/GamesGridView/GamesGridView.vala:60 +msgid "All games" +msgstr "" + +#: src/ui/views/GamesGridView/GamesGridView.vala:70 +#, c-format +msgid "%s games" +msgstr "" + +#: src/ui/views/GamesGridView/GamesGridView.vala:76 +msgid "Downloads" +msgstr "" + +#: src/ui/views/GamesGridView/GamesGridView.vala:87 +msgid "Search" +msgstr "" + +#: src/ui/views/GamesGridView/GamesGridView.vala:118 #, c-format msgid "%u game" msgid_plural "%u games" diff --git a/po/ru.po b/po/ru.po index cb8f20d3..c1b6609d 100644 --- a/po/ru.po +++ b/po/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.tkashkin.gamehub\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-01 04:08+0300\n" +"POT-Creation-Date: 2018-06-02 05:53+0300\n" "PO-Revision-Date: 2018-05-27 03:39+0300\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -26,7 +26,7 @@ msgstr "" #: data/com.github.tkashkin.gamehub.appdata.xml.in:9 #: data/com.github.tkashkin.gamehub.desktop.in:5 -#: src/ui/views/WelcomeView.vala:18 +#: src/ui/views/WelcomeView.vala:32 msgid "All your games in one place" msgstr "Все игры в одном месте" @@ -34,59 +34,103 @@ msgstr "Все игры в одном месте" msgid "Manage your Steam and GOG games in one place." msgstr "Управляйте играми из Steam и GOG в одном месте" -#: data/com.github.tkashkin.gamehub.appdata.xml.in:15 -msgid "Anatoliy Kashkin" -msgstr "" - -#: data/com.github.tkashkin.gamehub.desktop.in:7 -msgid "Game;Hub;Steam;GOG;" -msgstr "" - -#: data/com.github.tkashkin.gamehub.desktop.in:10 -msgid "com.github.tkashkin.gamehub" -msgstr "" - #: src/data/sources/steam/Steam.vala:13 msgid "Your SteamID will be read from Steam configuration file" msgstr "Ваш SteamID будет прочитан из файла конфигурации Steam" -#: src/ui/windows/GOGGameInstallWindow.vala:22 src/ui/views/WelcomeView.vala:92 -#, c-format -msgid "Install %s" -msgstr "Установить %s" +#: src/ui/dialogs/SettingsDialog.vala:27 +msgid "Use dark theme" +msgstr "Использовать тёмную тему" + +#: src/ui/dialogs/SettingsDialog.vala:31 +msgid "Steam API keys have limited number of uses per day" +msgstr "API-ключи Steam имеют ограничение на количество использований в день" + +#: src/ui/dialogs/SettingsDialog.vala:31 +msgid "Generate key" +msgstr "Сгенерировать ключ" + +#: src/ui/dialogs/SettingsDialog.vala:32 +msgid "Steam API key" +msgstr "API-ключ Steam" + +#: src/ui/dialogs/SettingsDialog.vala:33 +msgid "Steam installation directory" +msgstr "Папка установки Steam" + +#: src/ui/dialogs/SettingsDialog.vala:37 +msgid "GOG games directory" +msgstr "Папка игр GOG" + +#: src/ui/dialogs/SettingsDialog.vala:50 +msgid "Close" +msgstr "Закрыть" -#: src/ui/windows/GOGGameInstallWindow.vala:48 -#, fuzzy +#: src/ui/dialogs/GOGGameInstallDialog.vala:47 +msgid "Select game language" +msgstr "Выберите язык игры" + +#: src/ui/dialogs/GOGGameInstallDialog.vala:69 +msgid "Cancel" +msgstr "Отмена" + +#: src/ui/dialogs/GOGGameInstallDialog.vala:70 msgid "Install" msgstr "Установить" -#: src/ui/views/WelcomeView.vala:18 +#: src/ui/views/WelcomeView.vala:32 msgid "Let's get started" msgstr "Давайте начнём" -#: src/ui/views/WelcomeView.vala:26 +#: src/ui/views/WelcomeView.vala:42 msgid "Skip" msgstr "Пропустить" -#: src/ui/views/WelcomeView.vala:71 +#: src/ui/views/WelcomeView.vala:49 +#: src/ui/views/GamesGridView/GamesGridView.vala:92 +msgid "Settings" +msgstr "Настройки" + +#: src/ui/views/WelcomeView.vala:101 msgid "Ready" msgstr "Готово" -#: src/ui/views/WelcomeView.vala:77 +#: src/ui/views/WelcomeView.vala:107 msgid "Authentication required" msgstr "Требуется авторизация" -#: src/ui/views/WelcomeView.vala:81 -#, fuzzy +#: src/ui/views/WelcomeView.vala:112 msgid "Authenticating..." -msgstr "Требуется авторизация" +msgstr "Авторизация..." + +#: src/ui/views/WelcomeView.vala:123 +#, c-format +msgid "Install %s" +msgstr "Установить %s" -#: src/ui/views/WelcomeView.vala:93 +#: src/ui/views/WelcomeView.vala:124 msgid "Return to GameHub after installing" msgstr "Вернитесь в GameHub после установки" -#: src/ui/views/GamesGridView/GamesGridView.vala:91 -#, fuzzy, c-format +#: src/ui/views/GamesGridView/GamesGridView.vala:60 +msgid "All games" +msgstr "Все игры" + +#: src/ui/views/GamesGridView/GamesGridView.vala:70 +#, c-format +msgid "%s games" +msgstr "Игры из %s" + +#: src/ui/views/GamesGridView/GamesGridView.vala:76 +msgid "Downloads" +msgstr "Загрузки" + +#: src/ui/views/GamesGridView/GamesGridView.vala:87 +msgid "Search" +msgstr "Поиск" + +#: src/ui/views/GamesGridView/GamesGridView.vala:118 +#, c-format msgid "%u game" msgid_plural "%u games" msgstr[0] "%u игра" diff --git a/src/app.vala b/src/app.vala index 6e6c895a..bfa3abd6 100644 --- a/src/app.vala +++ b/src/app.vala @@ -16,6 +16,7 @@ namespace GameHub application_id = ProjectConfig.PROJECT_NAME; flags = ApplicationFlags.FLAGS_NONE; program_name = "GameHub"; + build_version = ProjectConfig.VERSION; } protected override void activate() diff --git a/src/data/sources/gog/GOG.vala b/src/data/sources/gog/GOG.vala index a0650b90..531e7153 100644 --- a/src/data/sources/gog/GOG.vala +++ b/src/data/sources/gog/GOG.vala @@ -65,7 +65,7 @@ namespace GameHub.Data.Sources.GOG public override bool can_authenticate_automatically() { - return Settings.Auth.GOG.get_instance().authenticated; + return user_refresh_token != null && Settings.Auth.GOG.get_instance().authenticated; } private async bool get_auth_code() diff --git a/src/data/sources/gog/GOGGame.vala b/src/data/sources/gog/GOGGame.vala index 5bfa836a..9dd41dcb 100644 --- a/src/data/sources/gog/GOGGame.vala +++ b/src/data/sources/gog/GOGGame.vala @@ -63,7 +63,7 @@ namespace GameHub.Data.Sources.GOG if(installer.os == "linux") installers.add(installer); } - var wnd = new GameHub.UI.Windows.GOGGameInstallWindow(this, installers); + var wnd = new GameHub.UI.Dialogs.GOGGameInstallDialog(this, installers); wnd.canceled.connect(() => Idle.add(install.callback)); @@ -78,9 +78,11 @@ namespace GameHub.Data.Sources.GOG var file = Downloader.get_instance().download.end(res).get_path(); FSUtils.mkdir(FSUtils.Paths.GOG.Games); var install_dir = FSUtils.expand(FSUtils.Paths.GOG.Games, name.escape().replace(" ", "_").replace("'", "\\'")); - Utils.run(@"chmod +x '$(file)'"); - Utils.run_async(@"'$(file)' -- --i-agree-to-all-licenses --noreadme --nooptions --noprompt --destination \"$(install_dir)\""); - Idle.add(install.callback); + Utils.run(@"chmod +x \"$(file)\""); + Utils.run_async.begin(@"$(file) -- --i-agree-to-all-licenses --noreadme --nooptions --noprompt --destination \"$(install_dir)\"", (obj, res) => { + Utils.run_async.end(res); + Idle.add(install.callback); + }); } catch(Error e) { @@ -100,7 +102,7 @@ namespace GameHub.Data.Sources.GOG if(is_installed()) { var path = executable.get_path(); - Utils.run_async(@"\"$(path)\""); + yield Utils.run_async(@"$(path)"); } } diff --git a/src/data/sources/steam/Steam.vala b/src/data/sources/steam/Steam.vala index 69c88bc2..1f3d2b10 100644 --- a/src/data/sources/steam/Steam.vala +++ b/src/data/sources/steam/Steam.vala @@ -6,10 +6,10 @@ namespace GameHub.Data.Sources.Steam { public class Steam: GameSource { - private const string API_KEY = "8B10B604CAC6AC90F57AACE025DD904C"; + private string api_key; public override string name { get { return "Steam"; } } - public override string icon { get { return "steam-symbolic"; } } + public override string icon { get { return "steam"; } } public override string auth_description { owned get { return ".\n%s".printf(_("Your SteamID will be read from Steam configuration file")); } } public string? user_id { get; protected set; } @@ -83,6 +83,8 @@ namespace GameHub.Data.Sources.Steam private ArrayList games = new ArrayList(Game.is_equal); public override async ArrayList load_games(FutureResult? game_loaded = null) { + api_key = Settings.Auth.Steam.get_instance().api_key; + if(!is_authenticated() || games.size > 0) { return games; @@ -103,7 +105,7 @@ namespace GameHub.Data.Sources.Steam } } - var url = @"https://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=$(API_KEY)&steamid=$(user_id)&format=json&include_appinfo=1&include_played_free_games=1"; + var url = @"https://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=$(api_key)&steamid=$(user_id)&format=json&include_appinfo=1&include_played_free_games=1"; var root = yield Parser.parse_remote_json_file_async(url); var json_games = root.get_object_member("response").get_array_member("games"); diff --git a/src/meson.build b/src/meson.build index 3b281d0f..380d5b79 100644 --- a/src/meson.build +++ b/src/meson.build @@ -28,7 +28,9 @@ executable( 'ui/windows/MainWindow.vala', 'ui/windows/WebAuthWindow.vala', - 'ui/windows/GOGGameInstallWindow.vala', + + 'ui/dialogs/SettingsDialog.vala', + 'ui/dialogs/GOGGameInstallDialog.vala', 'ui/views/BaseView.vala', 'ui/views/WelcomeView.vala', diff --git a/src/ui/windows/GOGGameInstallWindow.vala b/src/ui/dialogs/GOGGameInstallDialog.vala similarity index 50% rename from src/ui/windows/GOGGameInstallWindow.vala rename to src/ui/dialogs/GOGGameInstallDialog.vala index 2badbdad..e58a7575 100644 --- a/src/ui/windows/GOGGameInstallWindow.vala +++ b/src/ui/dialogs/GOGGameInstallDialog.vala @@ -6,9 +6,9 @@ using GameHub.Utils; using GameHub.Data; using GameHub.Data.Sources.GOG; -namespace GameHub.UI.Windows +namespace GameHub.UI.Dialogs { - public class GOGGameInstallWindow: Window + public class GOGGameInstallDialog: Granite.MessageDialog { public signal void install(GOGGame.Installer installer); public signal void canceled(); @@ -17,17 +17,16 @@ namespace GameHub.UI.Windows private bool is_finished = false; - public GOGGameInstallWindow(GOGGame game, ArrayList installers) + public GOGGameInstallDialog(GOGGame game, ArrayList installers) { - title = _("Install %s").printf(game.name); - var titlebar = new HeaderBar(); - titlebar.title = title; - titlebar.show_close_button = true; - titlebar.has_subtitle = false; - set_titlebar(titlebar); + Object(transient_for: Windows.MainWindow.instance, deletable: false, resizable: false); set_modal(true); + image_icon = Icon.new_for_string("go-down"); + + primary_text = game.name; + languages_list = new ListBox(); var sys_langs = Intl.get_language_names(); @@ -43,21 +42,34 @@ namespace GameHub.UI.Windows } } - add(languages_list); + if(installers.size > 1) + { + secondary_text = _("Select game language"); + custom_bin.child = languages_list; + } - var install_btn = new Button.with_label(_("Install")); + destroy.connect(() => { if(!is_finished) canceled(); }); - install_btn.clicked.connect(() => { - var row = languages_list.get_selected_row() as LangRow; - - is_finished = true; - install(row.installer); - destroy(); + response.connect((source, response_id) => { + switch(response_id) + { + case ResponseType.CANCEL: + destroy(); + break; + + case ResponseType.ACCEPT: + var row = languages_list.get_selected_row() as LangRow; + is_finished = true; + install(row.installer); + destroy(); + break; + } }); - - titlebar.pack_end(install_btn); - - destroy.connect(() => { if(!is_finished) canceled(); }); + + add_button(_("Cancel"), ResponseType.CANCEL); + var install_btn = add_button(_("Install"), ResponseType.ACCEPT); + install_btn.get_style_context().add_class(STYLE_CLASS_SUGGESTED_ACTION); + install_btn.grab_default(); show_all(); } @@ -72,7 +84,7 @@ namespace GameHub.UI.Windows var label = new Label(installer.lang_full); label.xpad = 16; - label.ypad = 8; + label.ypad = 4; child = label; } } diff --git a/src/ui/dialogs/SettingsDialog.vala b/src/ui/dialogs/SettingsDialog.vala new file mode 100644 index 00000000..a1a11f85 --- /dev/null +++ b/src/ui/dialogs/SettingsDialog.vala @@ -0,0 +1,159 @@ +using Gtk; +using Granite; +using GameHub.Utils; + +namespace GameHub.UI.Dialogs +{ + public class SettingsDialog: Dialog + { + private Box box; + + public SettingsDialog() + { + Object(transient_for: Windows.MainWindow.instance, deletable: false, resizable: false); + + set_modal(true); + + var content = get_content_area(); + content.set_size_request(480, -1); + + box = new Box(Orientation.VERTICAL, 0); + box.margin_start = box.margin_end = 8; + + var ui = Settings.UI.get_instance(); + var paths = FSUtils.Paths.Settings.get_instance(); + var steam_auth = Settings.Auth.Steam.get_instance(); + + add_switch(_("Use dark theme"), ui.dark_theme, e => { ui.dark_theme = e; }); + add_separator(); + + add_header("Steam"); + add_labeled_link(_("Steam API keys have limited number of uses per day"), _("Generate key"), "https://steamcommunity.com/dev/apikey"); + add_entry(_("Steam API key"), steam_auth.api_key, v => { steam_auth.api_key = v; }); + add_file_chooser(_("Steam installation directory"), FileChooserAction.SELECT_FOLDER, paths.steam_home, v => { paths.steam_home = v; }, false); + add_separator(); + + add_header("GOG"); + add_file_chooser(_("GOG games directory"), FileChooserAction.SELECT_FOLDER, paths.gog_games, v => { paths.gog_games = v; }); + + content.pack_start(box, false, false, 0); + + response.connect((source, response_id) => { + switch(response_id) + { + case ResponseType.CLOSE: + destroy(); + break; + } + }); + + add_button(_("Close"), ResponseType.CLOSE).margin_end = 7; + show_all(); + } + + private void add_switch(string text, bool enabled, owned SwitchAction action) + { + var sw = new Switch(); + sw.active = enabled; + sw.halign = Align.END; + sw.notify["active"].connect(() => { action(sw.active); }); + + var label = new Label(text); + label.halign = Align.START; + label.hexpand = true; + + var hbox = new Box(Orientation.HORIZONTAL, 12); + hbox.add(label); + hbox.add(sw); + add_widget(hbox); + } + + private void add_entry(string text, string val, owned EntryAction action) + { + var entry = new Entry(); + entry.text = val; + entry.notify["text"].connect(() => { action(entry.text); }); + entry.set_size_request(280, -1); + + var label = new Label(text); + label.halign = Align.START; + label.hexpand = true; + + var hbox = new Box(Orientation.HORIZONTAL, 12); + hbox.add(label); + hbox.add(entry); + add_widget(hbox); + } + + private void add_file_chooser(string text, FileChooserAction mode, string val, owned EntryAction action, bool create=true) + { + var chooser = new FileChooserButton(text, mode); + chooser.create_folders = create; + chooser.select_filename(FSUtils.expand(val)); + chooser.file_set.connect(() => { action(chooser.get_filename()); }); + chooser.set_size_request(280, -1); + + var label = new Label(text); + label.halign = Align.START; + label.hexpand = true; + + var hbox = new Box(Orientation.HORIZONTAL, 12); + hbox.add(label); + hbox.add(chooser); + add_widget(hbox); + } + + private void add_label(string text) + { + var label = new Label(text); + label.halign = Align.START; + label.hexpand = true; + add_widget(label); + } + + private void add_header(string text) + { + var label = new HeaderLabel(text); + label.xpad = 4; + label.halign = Align.START; + label.hexpand = true; + add_widget(label); + } + + private void add_link(string text, string uri) + { + var link = new LinkButton.with_label(uri, text); + link.halign = Align.START; + link.hexpand = true; + add_widget(link); + } + + private void add_labeled_link(string label_text, string text, string uri) + { + var label = new Label(label_text); + label.halign = Align.START; + + var link = new LinkButton.with_label(uri, text); + link.halign = Align.START; + + var hbox = new Box(Orientation.HORIZONTAL, 12); + hbox.add(label); + hbox.add(link); + add_widget(hbox); + } + + private void add_separator() + { + add_widget(new Separator(Orientation.HORIZONTAL)); + } + + private void add_widget(Widget widget) + { + if(!(widget is HeaderLabel)) widget.margin = 4; + box.add(widget); + } + + private delegate void SwitchAction(bool active); + private delegate void EntryAction(string val); + } +} diff --git a/src/ui/views/BaseView.vala b/src/ui/views/BaseView.vala index ec8dc3d7..2ba5b6cb 100644 --- a/src/ui/views/BaseView.vala +++ b/src/ui/views/BaseView.vala @@ -14,7 +14,6 @@ namespace GameHub.UI.Views titlebar = new HeaderBar(); titlebar.title = "GameHub"; titlebar.show_close_button = true; - titlebar.has_subtitle = false; } public virtual void attach_to_window(MainWindow wnd) diff --git a/src/ui/views/GamesGridView/GameCard.vala b/src/ui/views/GamesGridView/GameCard.vala index 770f82b1..9d30d35d 100644 --- a/src/ui/views/GamesGridView/GameCard.vala +++ b/src/ui/views/GamesGridView/GameCard.vala @@ -46,7 +46,7 @@ namespace GameHub.UI.Views src_icon.valign = Align.START; src_icon.halign = Align.START; src_icon.margin = 8; - src_icon.opacity = 0.5; + src_icon.opacity = 0.6; src_icon.set_events(0); label = new Label(""); diff --git a/src/ui/views/GamesGridView/GamesGridView.vala b/src/ui/views/GamesGridView/GamesGridView.vala index 17f40ed8..5d0e06b7 100644 --- a/src/ui/views/GamesGridView/GamesGridView.vala +++ b/src/ui/views/GamesGridView/GamesGridView.vala @@ -23,12 +23,16 @@ namespace GameHub.UI.Views private Spinner spinner; private int loading_sources = 0; + private Button settings; + private MenuButton downloads; private Popover downloads_popover; private ListBox downloads_list; construct { + var ui_settings = Settings.UI.get_instance(); + foreach(var src in GameSources) { if(src.is_authenticated()) sources.add(src); @@ -39,7 +43,7 @@ namespace GameHub.UI.Views games_list.activate_on_single_click = false; games_list.homogeneous = false; - games_list.min_children_per_line = 3; + games_list.min_children_per_line = 2; games_list.selection_mode = SelectionMode.NONE; games_list.valign = Align.START; @@ -50,25 +54,47 @@ namespace GameHub.UI.Views add(scrolled); filter = new Granite.Widgets.ModeButton(); - filter.append_icon("view-filter-symbolic", IconSize.SMALL_TOOLBAR); - foreach(var src in sources) filter.append_pixbuf(FSUtils.get_icon(src.icon, 16)); + filter.halign = Align.CENTER; + filter.valign = Align.CENTER; + + add_filter_button(new Image.from_icon_name("view-filter-symbolic", IconSize.MENU), _("All games")); + + foreach(var src in sources) + { + var image = new Image.from_pixbuf(FSUtils.get_icon(src.icon + (ui_settings.dark_theme ? "-white" : ""), 16)); + + ui_settings.notify["dark-theme"].connect(() => { + image.pixbuf = FSUtils.get_icon(src.icon + (ui_settings.dark_theme ? "-white" : ""), 16); + }); + + add_filter_button(image, _("%s games").printf(src.name)); + } + filter.set_active(sources.size > 1 ? 0 : 1); downloads = new MenuButton(); - downloads.image = new Image.from_icon_name("folder-download", IconSize.SMALL_TOOLBAR); + downloads.tooltip_text = _("Downloads"); + downloads.image = new Image.from_icon_name("folder-download", IconSize.LARGE_TOOLBAR); downloads_popover = new Popover(downloads); downloads_list = new ListBox(); downloads_popover.add(downloads_list); downloads_popover.position = PositionType.BOTTOM; downloads_popover.set_size_request(384, -1); downloads.popover = downloads_popover; - titlebar.pack_end(downloads); downloads.set_sensitive(false); search = new SearchEntry(); + search.placeholder_text = _("Search"); + search.halign = Align.CENTER; + search.valign = Align.CENTER; + + settings = new Button(); + settings.tooltip_text = _("Settings"); + settings.image = new Image.from_icon_name("open-menu", IconSize.LARGE_TOOLBAR); + + settings.clicked.connect(() => new Dialogs.SettingsDialog().show_all()); if(sources.size > 1) titlebar.pack_start(filter); - titlebar.pack_end(search); games_list.set_sort_func((child1, child2) => { var item1 = child1 as GameCard; @@ -88,7 +114,8 @@ namespace GameHub.UI.Views if(f > 0) src = sources[f - 1]; var games = src == null ? games_list.get_children().length() : src.games_count; - titlebar.title = "GameHub" + (src == null ? "" : "/" + src.name) + ": " + ngettext("%u game", "%u games", games).printf(games); + titlebar.title = "GameHub" + (src == null ? "" : "/" + src.name); + titlebar.subtitle = ngettext("%u game", "%u games", games).printf(games); return (src == null || item == null || src == item.game.source) && (item == null || search.text.casefold() in item.game.name.casefold()); }); @@ -97,6 +124,10 @@ namespace GameHub.UI.Views search.search_changed.connect(games_list.invalidate_filter); spinner = new Spinner(); + + titlebar.pack_end(settings); + titlebar.pack_end(downloads); + titlebar.pack_end(search); titlebar.pack_end(spinner); show_all(); @@ -123,7 +154,7 @@ namespace GameHub.UI.Views downloads_list.remove(p); var has_downloads = downloads_list.get_children().length() > 0; downloads.set_sensitive(has_downloads); - if(!has_downloads) downloads_popover.popdown(); + if(!has_downloads) downloads_popover.hide(); }); games_list.add(card); games_list.show_all(); @@ -133,5 +164,11 @@ namespace GameHub.UI.Views }); } } + + private void add_filter_button(Image image, string tooltip) + { + image.tooltip_text = tooltip; + filter.append(image); + } } } diff --git a/src/ui/views/WelcomeView.vala b/src/ui/views/WelcomeView.vala index 58216c35..fbe31435 100644 --- a/src/ui/views/WelcomeView.vala +++ b/src/ui/views/WelcomeView.vala @@ -6,33 +6,63 @@ using GameHub.Utils; namespace GameHub.UI.Views { public class WelcomeView: BaseView - { + { + private Stack stack; private Granite.Widgets.Welcome welcome; private Button skip_btn; + private Button settings; private bool is_updating = false; construct { + var ui_settings = Settings.UI.get_instance(); + + stack = new Stack(); + stack.transition_type = StackTransitionType.CROSSFADE; + + var spinner = new Spinner(); + spinner.active = true; + spinner.set_size_request(36, 36); + spinner.halign = Align.CENTER; + spinner.valign = Align.CENTER; + stack.add(spinner); + welcome = new Granite.Widgets.Welcome(_("All your games in one place"), _("Let's get started")); welcome.activated.connect(index => { on_entry_clicked.begin(index); }); - add(welcome); + stack.add(welcome); + + add(stack); skip_btn = new Button.with_label(_("Skip")); skip_btn.clicked.connect(open_games_grid); + skip_btn.halign = Align.CENTER; + skip_btn.valign = Align.CENTER; skip_btn.set_sensitive(false); + settings = new Button(); + settings.tooltip_text = _("Settings"); + settings.image = new Image.from_icon_name("open-menu", IconSize.LARGE_TOOLBAR); + + settings.clicked.connect(() => new Dialogs.SettingsDialog().show_all()); + + titlebar.pack_end(settings); titlebar.pack_end(skip_btn); foreach(var src in GameSources) - { - var image = FSUtils.get_icon(src.icon); - welcome.append_with_pixbuf(image, src.name, ""); + { + var image = FSUtils.get_icon(src.icon + (ui_settings.dark_theme ? "-white" : "")); + + var i = welcome.append_with_pixbuf(image, src.name, ""); + + ui_settings.notify["dark-theme"].connect(() => { + welcome.get_button_from_index(i).icon = new Image.from_pixbuf(FSUtils.get_icon(src.icon + (ui_settings.dark_theme ? "-white" : ""))); + }); } update_entries.begin(); @@ -76,6 +106,7 @@ namespace GameHub.UI.Views { btn.description = _("Authentication required") + src.auth_description; all_authenticated = false; + if(src.can_authenticate_automatically()) { btn.description = _("Authenticating..."); @@ -99,6 +130,10 @@ namespace GameHub.UI.Views { open_games_grid(); } + else + { + stack.set_visible_child(welcome); + } welcome.show_all(); diff --git a/src/ui/windows/MainWindow.vala b/src/ui/windows/MainWindow.vala index 0e526394..aa14d5a1 100644 --- a/src/ui/windows/MainWindow.vala +++ b/src/ui/windows/MainWindow.vala @@ -6,6 +6,8 @@ namespace GameHub.UI.Windows { public class MainWindow: Gtk.ApplicationWindow { + public static MainWindow instance; + private SavedState saved_state; public HeaderBar titlebar; @@ -14,10 +16,17 @@ namespace GameHub.UI.Windows public MainWindow(GameHub.Application app) { Object(application: app); + instance = this; } construct { + var ui_settings = Settings.UI.get_instance(); + ui_settings.notify["dark-theme"].connect(() => { + Gtk.Settings.get_default().gtk_application_prefer_dark_theme = ui_settings.dark_theme; + }); + ui_settings.notify["dark-theme"](((ObjectClass) typeof(Settings.UI).class_ref()).find_property("dark-theme")); + title = "GameHub"; titlebar = new HeaderBar(); diff --git a/src/ui/windows/WebAuthWindow.vala b/src/ui/windows/WebAuthWindow.vala index 690a375e..ad23eb1c 100644 --- a/src/ui/windows/WebAuthWindow.vala +++ b/src/ui/windows/WebAuthWindow.vala @@ -16,6 +16,8 @@ namespace GameHub.UI.Windows public WebAuthWindow(string source, string url, string success_url_prefix) { + Object(transient_for: Windows.MainWindow.instance); + title = source; var titlebar = new HeaderBar(); titlebar.title = title; diff --git a/src/utils/Downloader.vala b/src/utils/Downloader.vala index 72944cd8..27c1a97a 100644 --- a/src/utils/Downloader.vala +++ b/src/utils/Downloader.vala @@ -48,6 +48,8 @@ namespace GameHub.Utils { downloads = new GLib.HashTable(str_hash, str_equal); session = new Soup.Session(); + session.max_conns = 32; + session.max_conns_per_host = 16; } public async File download(File remote_file, string[] cached_paths, DownloadProgress progress = (d, t) => {}, Cancellable? cancellable = null) throws GLib.Error diff --git a/src/utils/FSUtils.vala b/src/utils/FSUtils.vala index 5a1b948c..c5eb49cd 100644 --- a/src/utils/FSUtils.vala +++ b/src/utils/FSUtils.vala @@ -86,6 +86,9 @@ namespace GameHub.Utils mkdir(FSUtils.Paths.Cache.Home); mkdir(FSUtils.Paths.Cache.Images); mkdir(FSUtils.Paths.GOG.Installers); + + var cached_installers = FSUtils.expand(FSUtils.Paths.GOG.Installers, "{gog_*.sh~,.goutputstream-*}"); + Utils.run(@"bash -c 'rm $(cached_installers)'"); } public static Pixbuf? get_icon(string name, int size=48) diff --git a/src/utils/Settings.vala b/src/utils/Settings.vala index f6c40d49..1e38d3ed 100644 --- a/src/utils/Settings.vala +++ b/src/utils/Settings.vala @@ -35,11 +35,32 @@ namespace GameHub.Settings } } + public class UI: Granite.Services.Settings + { + public bool dark_theme { get; set; } + + public UI() + { + base(ProjectConfig.PROJECT_NAME + ".ui"); + } + + private static UI? instance; + public static unowned UI get_instance() + { + if(instance == null) + { + instance = new UI(); + } + return instance; + } + } + namespace Auth { public class Steam: Granite.Services.Settings { public bool authenticated { get; set; } + public string api_key { get; set; } public Steam() { diff --git a/src/utils/Utils.vala b/src/utils/Utils.vala index a72e3284..e7795cf0 100644 --- a/src/utils/Utils.vala +++ b/src/utils/Utils.vala @@ -33,16 +33,17 @@ namespace GameHub.Utils return stdout; } - public static void run_async(string cmd) + public static async int run_async(string cmd) { - try - { - Process.spawn_command_line_async(cmd); - } - catch (Error e) - { - warning(e.message); - } + int result = -1; + var c = new Granite.Services.SimpleCommand(Environment.get_home_dir(), cmd); + c.done.connect(code => { + result = code; + Idle.add(run_async.callback); + }); + c.run(); + yield; + return result; } public static bool is_package_installed(string package)