diff --git a/data/styles/Category.scss b/data/styles/Category.scss index 3a88b6d45..6bad92764 100644 --- a/data/styles/Category.scss +++ b/data/styles/Category.scss @@ -18,6 +18,7 @@ margin: rem(12px); padding: rem(12px); min-height: 3em; + -gtk-icon-size: 48px; &.accessibility { background-image: @@ -264,15 +265,8 @@ 0 1px 2px #{'alpha(@SLATE_900, 0.2)'}, 0 2px 6px #{'alpha(@SLATE_900, 0.1)'}; - label.pink { - font-size: 1em; - text-shadow: - 0 1px 2px #{'alpha(@BUBBLEGUM_900, 0.2)'}, - 0 2px 6px #{'alpha(@BUBBLEGUM_900, 0.1)'}; - margin-bottom: -12px; - } - - label.blue { + label { + color: #{'@BLUEBERRY_500'}; font-size: 1.5em; text-shadow: 0 1px 2px #{'alpha(@BLUEBERRY_900, 0.2)'}, @@ -280,6 +274,7 @@ } image { + color: #{'@SLATE_500'}; -gtk-icon-size: rem(64px); } } diff --git a/po/POTFILES b/po/POTFILES index c79a779e1..59fdb8e14 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -3,6 +3,7 @@ src/AsyncMutex.vala src/MainWindow.vala src/SuspendControl.vala src/Utils.vala +src/Core/CategoryManager.vala src/Core/ChangeInformation.vala src/Core/FlatpakBackend.vala src/Core/Job.vala diff --git a/src/Core/CategoryManager.vala b/src/Core/CategoryManager.vala new file mode 100644 index 000000000..c7aea211f --- /dev/null +++ b/src/Core/CategoryManager.vala @@ -0,0 +1,162 @@ +/* + * SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +public class AppCenter.CategoryManager : Object { + public GenericArray categories { get; private set; } + + private static GLib.Once instance; + public static unowned CategoryManager get_default () { + return instance.once (() => { return new CategoryManager (); }); + } + + private CategoryManager () {} + + construct { + categories = new GenericArray (); + + append ("accessories", _("Accessories"), "applications-accessories", {"Utility"}); + append ("audio", _("Audio"), "appcenter-audio", {"Audio", "Music"}); + + append ("communication", _("Communication"), "", { + "Chat", + "ContactManagement", + "Email", + "InstantMessaging", + "IRCClient", + "Telephony", + "VideoConference" + }); + + append ("development", _("Development"), "", { + "Database", + "Debugger", + "Development", + "GUIDesigner", + "IDE", + "RevisionControl", + "TerminalEmulator", + "WebDevelopment" + }); + + append ("education", _("Education"), "", {"Education"}); + + append ("finance", _("Finance"), "appcenter-finance", { + "Economy", + "Finance" + }); + + append ("games", _("Fun & Games"), "appcenter-games-symbolic", { + "ActionGame", + "AdventureGame", + "Amusement", + "ArcadeGame", + "BlocksGame", + "BoardGame", + "CardGame", + "Game", + "KidsGame", + "LogicGame", + "RolePlaying", + "Shooter", + "Simulation", + "SportsGame", + "StrategyGame" + }); + + append ("graphics", _("Graphics"), "", { + "2DGraphics", + "3DGraphics", + "Graphics", + "ImageProcessing", + "Photography", + "RasterGraphics", + "VectorGraphics" + }); + + append ("internet", _("Internet"), "applications-internet", { + "Network", + "P2P" + }); + + append ("science", _("Math, Science, & Engineering"), "", { + "ArtificialIntelligence", + "Astronomy", + "Biology", + "Calculator", + "Chemistry", + "ComputerScience", + "DataVisualization", + "Electricity", + "Electronics", + "Engineering", + "Geology", + "Geoscience", + "Math", + "NumericalAnalysis", + "Physics", + "Robotics", + "Science" + }); + + append ("media-production", _("Media Production"), "appcenter-multimedia-symbolic", { + "AudioVideoEditing", + "Midi", + "Mixer", + "Recorder", + "Sequencer" + }); + + append ("office", _("Office"), "appcenter-office-symbolic", { + "Office", + "Presentation", + "Publishing", + "Spreadsheet", + "WordProcessor" + }); + + append ("system", _("System"), "applications-system", { + "Monitor", + "System" + }); + + append ("accessibility", _("Universal Access"), "appcenter-accessibility-symbolic", {"Accessibility"}); + + append ("video", _("Video"), "appcenter-video-symbolic", { + "Tuner", + "TV", + "Video" + }); + + append ("writing-language", _("Writing & Language"), "preferences-desktop-locale", { + "Dictionary", + "Languages", + "Literature", + "OCR", + "TextEditor", + "TextTools", + "Translation", + "WordProcessor" + }); + + append ("privacy-security", _("Privacy & Security"), "preferences-system-privacy", { + "Security" + }); + } + + private void append (string id, string name, string icon, string[] groups) { + var category = new AppStream.Category () { + name = name, + icon = icon, + id = id + }; + + foreach (unowned var group in groups) { + category.add_desktop_group (group); + } + + categories.add (category); + } +} diff --git a/src/Views/Homepage.vala b/src/Views/Homepage.vala index ac6c58d89..63ee744c4 100644 --- a/src/Views/Homepage.vala +++ b/src/Views/Homepage.vala @@ -97,8 +97,8 @@ public class AppCenter.Homepage : Adw.NavigationPage { }; category_flow.set_sort_func ((child1, child2) => { - var item1 = (AbstractCategoryCard) child1; - var item2 = (AbstractCategoryCard) child2; + var item1 = (CategoryCard) child1; + var item2 = (CategoryCard) child2; if (item1 != null && item2 != null) { return item1.category.name.collate (item2.category.name); } @@ -106,104 +106,9 @@ public class AppCenter.Homepage : Adw.NavigationPage { return 0; }); - var games_card = new GamesCard (); - - category_flow.append (new LegacyCard (_("Accessories"), "applications-accessories", {"Utility"}, "accessories")); - category_flow.append (new LegacyCard (_("Audio"), "appcenter-audio-symbolic", {"Audio", "Music"}, "audio")); - category_flow.append (new LegacyCard (_("Communication"), "", { - "Chat", - "ContactManagement", - "Email", - "InstantMessaging", - "IRCClient", - "Telephony", - "VideoConference" - }, "communication")); - category_flow.append (new LegacyCard (_("Development"), "", { - "Database", - "Debugger", - "Development", - "GUIDesigner", - "IDE", - "RevisionControl", - "TerminalEmulator", - "WebDevelopment" - }, "development")); - category_flow.append (new LegacyCard (_("Education"), "", {"Education"}, "education")); - category_flow.append (new LegacyCard (_("Finance"), "appcenter-finance-symbolic", { - "Economy", - "Finance" - }, "finance")); - category_flow.append (games_card); - category_flow.append (new LegacyCard (_("Graphics"), "", { - "2DGraphics", - "3DGraphics", - "Graphics", - "ImageProcessing", - "Photography", - "RasterGraphics", - "VectorGraphics" - }, "graphics")); - category_flow.append (new LegacyCard (_("Internet"), "applications-internet", { - "Network", - "P2P" - }, "internet")); - category_flow.append (new LegacyCard (_("Math, Science, & Engineering"), "", { - "ArtificialIntelligence", - "Astronomy", - "Biology", - "Calculator", - "Chemistry", - "ComputerScience", - "DataVisualization", - "Electricity", - "Electronics", - "Engineering", - "Geology", - "Geoscience", - "Math", - "NumericalAnalysis", - "Physics", - "Robotics", - "Science" - }, "science")); - category_flow.append (new LegacyCard (_("Media Production"), "appcenter-multimedia-symbolic", { - "AudioVideoEditing", - "Midi", - "Mixer", - "Recorder", - "Sequencer" - }, "media-production")); - category_flow.append (new LegacyCard (_("Office"), "appcenter-office-symbolic", { - "Office", - "Presentation", - "Publishing", - "Spreadsheet", - "WordProcessor" - }, "office")); - category_flow.append (new LegacyCard (_("System"), "applications-system-symbolic", { - "Monitor", - "System" - }, "system")); - category_flow.append (new LegacyCard (_("Universal Access"), "appcenter-accessibility-symbolic", {"Accessibility"}, "accessibility")); - category_flow.append (new LegacyCard (_("Video"), "appcenter-video-symbolic", { - "Tuner", - "TV", - "Video" - }, "video")); - category_flow.append (new LegacyCard (_("Writing & Language"), "preferences-desktop-locale", { - "Dictionary", - "Languages", - "Literature", - "OCR", - "TextEditor", - "TextTools", - "Translation", - "WordProcessor" - }, "writing-language")); - category_flow.append (new LegacyCard (_("Privacy & Security"), "preferences-system-privacy", { - "Security", - }, "privacy-security")); + foreach (unowned var category in CategoryManager.get_default ().categories) { + category_flow.append (new CategoryCard (category)); + } var box = new Gtk.Box (VERTICAL, 0); box.append (banner_carousel); @@ -294,7 +199,7 @@ public class AppCenter.Homepage : Adw.NavigationPage { }); category_flow.child_activated.connect ((child) => { - var card = (AbstractCategoryCard) child; + var card = (CategoryCard) child; show_category (card.category); }); @@ -428,141 +333,78 @@ public class AppCenter.Homepage : Adw.NavigationPage { }); } - private abstract class AbstractCategoryCard : Gtk.FlowBoxChild { - public AppStream.Category category { get; protected set; } + private class CategoryCard : Gtk.FlowBoxChild { + public AppStream.Category category { get; construct; } - protected Gtk.Grid content_area; + public CategoryCard (AppStream.Category category) { + Object (category: category); + } construct { - var expanded_grid = new Gtk.Grid () { - hexpand = true, - vexpand = true + var name_label = new Gtk.Label (category.name) { + wrap = true, + max_width_chars = 15 }; - content_area = new Gtk.Grid (); - content_area.attach (expanded_grid, 0, 0); - content_area.add_css_class (Granite.STYLE_CLASS_CARD); - content_area.add_css_class (Granite.STYLE_CLASS_ROUNDED); - content_area.add_css_class ("category"); - - child = content_area; - - AppCenterCore.UpdateManager.get_default ().installed_apps_changed.connect (() => { - Idle.add (() => { - // Clear the cached categories when the AppStream pool is updated - if (visible) { - return GLib.Source.REMOVE; - } - - var category_components = category.get_components (); - category_components.remove_range (0, category_components.length); - - return GLib.Source.REMOVE; - }); - }); - } - } - - private class LegacyCard : AbstractCategoryCard { - public LegacyCard (string name, string icon, string[] groups, string style) { - category = new AppStream.Category (); - category.set_name (name); - category.set_icon (icon); - - foreach (var group in groups) { - category.add_desktop_group (group); - } - - var name_label = new Gtk.Label (null); - name_label.wrap = true; - name_label.max_width_chars = 15; - - var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6) { - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER + var box = new Gtk.Box (HORIZONTAL, 6) { + halign = CENTER, + valign = CENTER }; if (category.icon != "") { var display_image = new Gtk.Image.from_icon_name (category.icon) { - halign = Gtk.Align.END, - valign = Gtk.Align.CENTER, - pixel_size = 48 + halign = END, + valign = CENTER, }; box.append (display_image); name_label.xalign = 0; - name_label.halign = Gtk.Align.START; + name_label.halign = START; } else { - name_label.justify = Gtk.Justification.CENTER; + name_label.justify = CENTER; } box.append (name_label); + var expanded_grid = new Gtk.Grid () { + hexpand = true, + vexpand = true + }; + + var content_area = new Gtk.Grid (); content_area.attach (box, 0, 0); - content_area.add_css_class (style); + content_area.attach (expanded_grid, 0, 0); + content_area.add_css_class (Granite.STYLE_CLASS_CARD); + content_area.add_css_class (Granite.STYLE_CLASS_ROUNDED); + content_area.add_css_class ("category"); + content_area.add_css_class (category.id); + + child = content_area; - if (style == "accessibility") { + if (category.id == "accessibility") { name_label.label = category.name.up (); } else { name_label.label = category.name; } - if (style == "science") { - name_label.justify = Gtk.Justification.CENTER; + if (category.id == "science") { + name_label.justify = CENTER; } - } - } - private class GamesCard : AbstractCategoryCard { - construct { - category = new AppStream.Category () { - name = _("Fun & Games"), - icon = "appcenter-games-symbolic" - }; - category.add_desktop_group ("ActionGame"); - category.add_desktop_group ("AdventureGame"); - category.add_desktop_group ("Amusement"); - category.add_desktop_group ("ArcadeGame"); - category.add_desktop_group ("BlocksGame"); - category.add_desktop_group ("BoardGame"); - category.add_desktop_group ("CardGame"); - category.add_desktop_group ("Game"); - category.add_desktop_group ("KidsGame"); - category.add_desktop_group ("LogicGame"); - category.add_desktop_group ("RolePlaying"); - category.add_desktop_group ("Shooter"); - category.add_desktop_group ("Simulation"); - category.add_desktop_group ("SportsGame"); - category.add_desktop_group ("StrategyGame"); - - var image = new Gtk.Image () { - icon_name = "appcenter-games-symbolic" - }; - image.add_css_class (Granite.STYLE_CLASS_ACCENT); - image.add_css_class ("slate"); - - var fun_label = new Gtk.Label (_("Fun &")) { - halign = Gtk.Align.START - }; - fun_label.add_css_class (Granite.STYLE_CLASS_ACCENT); - fun_label.add_css_class ("pink"); - - var games_label = new Gtk.Label (_("Games")); - games_label.add_css_class (Granite.STYLE_CLASS_ACCENT); - games_label.add_css_class ("blue"); + AppCenterCore.UpdateManager.get_default ().installed_apps_changed.connect (() => { + Idle.add (() => { + // Clear the cached categories when the AppStream pool is updated + if (visible) { + return GLib.Source.REMOVE; + } - var grid = new Gtk.Grid () { - column_spacing = 12, - halign = Gtk.Align.CENTER, - valign = Gtk.Align.CENTER - }; - grid.attach (image, 0, 0, 1, 2); - grid.attach (fun_label, 1, 0); - grid.attach (games_label, 1, 1); + var category_components = category.get_components (); + category_components.remove_range (0, category_components.length); - content_area.attach (grid, 0, 0); - content_area.add_css_class ("games"); + return GLib.Source.REMOVE; + }); + }); } } } diff --git a/src/meson.build b/src/meson.build index 33c9f22d1..4209a80a7 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,6 +5,7 @@ appcenter_files = files( 'SuspendControl.vala', 'Utils.vala', 'Core/CardUtils.vala', + 'Core' / 'CategoryManager.vala', 'Core/ChangeInformation.vala', 'Core/FlatpakBackend.vala', 'Core/HttpClient.vala',