Merge pull request #66 from kra-mo/main

Add app selection page
main
Mirko Brombin 2 years ago committed by GitHub
commit b3b3b8bbb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

3
.gitignore vendored

@ -6,4 +6,5 @@ debian/vanilla-first-setup.debhelper.log
debian/vanilla-first-setup
debian/.debhelper
*/__pycache__
*.pyc
*.pyc
/localbuild

@ -38,11 +38,10 @@
"description": "Choose one or more package managers to install",
"without_selection": {
"allowed": true,
"message": "You have chosen not to install any package manager, you will only be able to install packages using the package manager (apx).\n\nGNOME Software will be disabled since it is not compatible with the On-Demand Immutability.",
"message": "You have chosen not to install any package manager, you will only be able to install packages using the package manager (apx).\n\nGNOME Software will be disabled.",
"title": "No package manager selected",
"final": [
{
"if": "warp::immutability",
"type": "command",
"commands": [
"apt remove -y gnome-software"
@ -75,7 +74,7 @@
"type": "command",
"commands": [
"apt install -y flatpak gnome-software-plugin-flatpak",
"!outRun echo '[Desktop Entry]\nType=Application\nExec=kgx -e bash -c \"echo 'Configuring Flathub..' && flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo && rm -f ~/.config/autostart/flathub.desktop && echo 'Flathub installed successfully' || echo 'Failed installing Flathub. Are you connected to the internet?'\"\nName=Flatpak Flathub\nComment=Add Flathub repository to Flatpak\n' > ~/.config/autostart/flathub.desktop"
"!nextBoot flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo"
]
},
{
@ -90,6 +89,231 @@
}
]
},
"apps": {
"template": "applications",
"icon": "org.gnome.Software-symbolic",
"title": "Applications",
"description": "Choose which applications to install.",
"bundles": [
{
"id": "essential-apps",
"title": "Essential Applications",
"subtitle": "Core GNOME apps like Calendar or Calculator.",
"default": true,
"applications" : [
{
"name" : "Calculator",
"icon" : "org.gnome.Calculator",
"flatpak" : true,
"snap" : true
},
{
"name" : "Calendar",
"icon" : "org.gnome.Calendar",
"flatpak" : true
},
{
"name" : "Characters",
"icon" : "org.gnome.Characters",
"flatpak" : true,
"snap" : true
},
{
"name" : "Cheese",
"icon" : "org.gnome.Cheese",
"flatpak" : true,
"snap" : true
},
{
"name" : "Clocks",
"icon" : "org.gnome.clocks",
"flatpak" : true,
"snap" : true
},
{
"name" : "Contacts",
"icon" : "org.gnome.Contacts",
"flatpak" : true,
"snap" : true
},
{
"name" : "Disk Usage Analyzer",
"icon" : "org.gnome.baobab",
"flatpak" : true
},
{
"name" : "Document Viewer",
"icon" : "org.gnome.Evince",
"flatpak" : true,
"snap" : true
},
{
"name" : "Extensions",
"icon" : "org.gnome.Extensions",
"flatpak" : true
},
{
"name" : "Fonts",
"icon" : "org.gnome.font-viewer",
"flatpak" : true
},
{
"name" : "Image Viewer",
"icon" : "org.gnome.eog",
"flatpak" : true,
"snap" : true
},
{
"name" : "Logs",
"icon" : "org.gnome.Logs",
"flatpak" : "org.gnome.Logs",
"snap" : true
},
{
"name" : "Maps",
"icon" : "org.gnome.Maps",
"flatpak" : true
},
{
"name" : "Music",
"icon" : "org.gnome.Music",
"flatpak" : true
},
{
"name" : "Photos",
"icon" : "org.gnome.Photos",
"flatpak" : true
},
{
"name" : "Text Editor",
"icon" : "org.gnome.TextEditor",
"flatpak" : true
},
{
"name" : "Videos",
"icon" : "org.gnome.Totem",
"flatpak" : true
},
{
"name" : "Weather",
"icon" : "org.gnome.Weather",
"flatpak" : true,
"snap" : true
}
]
},
{
"id": "utilities",
"title": "Common Utilities",
"subtitle": "Useful utilities like Bottles.",
"default": true,
"applications" : [
{
"name" : "Bottles",
"icon" : "com.usebottles.bottles",
"flatpak" : "com.usebottles.bottles"
}
]
}
],
"final": [
{
"if" : "Calculator",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Calculator || snap install gnome-calculator"]
},
{
"if" : "Calendar",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Calendar"]
},
{
"if" : "Characters",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Characters || snap install gnome-characters"]
},
{
"if" : "Cheese",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Cheese || snap install cheese"]
},
{
"if" : "Clocks",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.clocks || snap install gnome-clocks"]
},
{
"if" : "Contacts",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Contacts || snap install gnome-contacts"]
},
{
"if" : "Disk Usage Analyzer",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.baobab"]
},
{
"if" : "Document Viewer",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Evince || snap install evince"]
},
{
"if" : "Extensions",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Extensions"]
},
{
"if" : "Fonts",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Fonts"]
},
{
"if" : "Image Viewer",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.eog || snap install eog"]
},
{
"if" : "Logs",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Logs || snap install gnome-logs"]
},
{
"if" : "Maps",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Maps"]
},
{
"if" : "Music",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Music"]
},
{
"if" : "Photos",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Photos"]
},
{
"if" : "Text Editor",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.TextEditor"]
},
{
"if" : "Videos",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Totem"]
},
{
"if" : "Weather",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y org.gnome.Weather || snap install gnome-weather"]
},
{
"if" : "Bottles",
"type" : "command",
"commands" : ["!nextBoot flatpak install -y com.usebottles.bottles"]
}
]
},
"nvidia": {
"template": "yes-no",
"display-conditions": [

@ -0,0 +1,181 @@
# applications.py
#
# Copyright 2022 mirkobrombin
#
# 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 Foundationat version 3 of the License.
#
# 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/>.
from gi.repository import Gtk, Adw
from vanilla_first_setup.dialog import VanillaDialog
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/layout-applications.ui')
class VanillaLayoutApplications(Adw.Bin):
__gtype_name__ = 'VanillaLayoutApplications'
status_page = Gtk.Template.Child()
bundles_list = Gtk.Template.Child()
btn_next = Gtk.Template.Child()
def __init__(self, window, distro_info, key, step, **kwargs):
super().__init__(**kwargs)
self.__window = window
self.__distro_info = distro_info
self.__key = key
self.__step = step
self.__register_widgets = []
self.__build_ui()
# signals
self.btn_next.connect("clicked", self.__next_step)
@property
def step_id(self):
return self.__key
def __build_ui(self):
self.status_page.set_icon_name(self.__step["icon"])
self.status_page.set_title(self.__step["title"])
self.status_page.set_description(self.__step["description"])
selection_dialogs = []
_index = 0
def present_customize(widget, dialog, apps_list, item):
for app in item["applications"]:
try:
apps_list.remove(app["apps_action_row"])
except KeyError:
pass
if self.__window.builder.get_temp_finals("packages")["vars"]["flatpak"] == True:
package_manager = "flatpak"
elif self.__window.builder.get_temp_finals("packages")["vars"]["snap"] == True:
try:
package_manager = "snap"
except KeyError:
continue
else:
continue
try:
if app[package_manager]:
_apps_action_row = Adw.ActionRow(
title=app["name"],
icon_name=app["icon"]
)
_app_switcher = Gtk.Switch()
_app_switcher.set_active(True)
_app_switcher.set_valign(Gtk.Align.CENTER)
_apps_action_row.add_suffix(_app_switcher)
apps_list.add(_apps_action_row)
app["apps_action_row"] = _apps_action_row
app["switch"] = _app_switcher
try:
app["switch"].set_active(app["active"])
except KeyError:
pass
except KeyError:
continue
dialog.show()
def close_customize(widget, dialog):
dialog.hide()
def apply_preferences(widget, dialog, apps_list, item):
for app in item["applications"]:
app["active"] = app["switch"].get_active()
dialog.hide()
for item in self.__step["bundles"]:
_selection_dialog = VanillaDialog(
self.__window,
"Select Applications",
"Description",
)
_cancel_button = Gtk.Button()
_apply_button = Gtk.Button()
_cancel_button.set_label("Cancel")
_apply_button.set_label("Apply")
_apply_button.add_css_class("suggested-action")
_header_bar = Adw.HeaderBar()
_header_bar.pack_start(_cancel_button)
_header_bar.pack_end(_apply_button)
_header_bar.set_show_end_title_buttons(False)
_header_bar.set_show_start_title_buttons(False)
_apps_list = Adw.PreferencesGroup()
_apps_list.set_description("The following list includes only applications available in your preferred package manager.")
_apps_page = Adw.PreferencesPage()
_apps_page.add(_apps_list)
_box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
_box.append(_header_bar)
_box.append(_apps_page)
_selection_dialog.set_content(_box)
_selection_dialog.set_default_size(500, 600)
selection_dialogs.append(_selection_dialog)
_action_row = Adw.ActionRow(
title=item["title"],
subtitle=item.get("subtitle", "")
)
_switcher = Gtk.Switch()
_switcher.set_active(item.get("default", False))
_switcher.set_valign(Gtk.Align.CENTER)
_action_row.add_suffix(_switcher)
_customize = Gtk.Button()
_customize.set_icon_name("go-next-symbolic")
_customize.set_valign(Gtk.Align.CENTER)
_customize.add_css_class("flat")
_action_row.add_suffix(_customize)
_customize.connect("clicked", present_customize, selection_dialogs[-1], _apps_list, item)
_cancel_button.connect("clicked", close_customize, selection_dialogs[-1])
_apply_button.connect("clicked", apply_preferences, selection_dialogs[-1], _apps_list, item)
self.bundles_list.add(_action_row)
self.__register_widgets.append((item["id"], _switcher, _index))
_index += 1
def __next_step(self, widget):
self.__window.next()
def get_finals(self):
finals = {"vars": {}, "funcs": [x for x in self.__step["final"]]}
if self.__window.builder.get_temp_finals("packages")["vars"]["flatpak"] == True:
package_manager = "flatpak"
elif self.__window.builder.get_temp_finals("packages")["vars"]["snap"] == True:
try:
package_manager = "snap"
except KeyError:
package_manager = None
else:
package_manager = None
for _id, switcher, index in self.__register_widgets:
if switcher.get_active() == True:
for app in self.__step["bundles"][index]["applications"]:
if package_manager not in app.keys():
app["active"] = False
if "active" not in app.keys():
app["active"] = True
finals["vars"][app["name"]] = app["active"]
else:
for app in self.__step["bundles"][index]["applications"]:
finals["vars"][app["name"]] = False
return finals

@ -5,6 +5,7 @@ sources = [
'__init__.py',
'welcome.py',
'theme.py',
'applications.py'
]
install_data(sources, install_dir: defaultsdir)
install_data(sources, install_dir: defaultsdir)

@ -14,8 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
from gi.repository import Gtk, Gio, GLib, Adw
from gi.repository import Gtk, Gio
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/default-theme.ui')
@ -38,6 +37,10 @@ class VanillaDefaultTheme(Gtk.Box):
self.btn_next.connect("clicked", self.__window.next)
self.btn_default.connect('toggled', self.__set_theme, "light")
self.btn_dark.connect('toggled', self.__set_theme, "dark")
@property
def step_id(self):
return self.__key
def __build_ui(self):
self.btn_dark.set_group(self.btn_default)

@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
from gi.repository import Gtk, Gio, GLib, Adw
from gi.repository import Gtk, GLib, Adw
from vanilla_first_setup.utils.run_async import RunAsync
@ -79,6 +79,10 @@ class VanillaDefaultWelcome(Adw.Bin):
# set distro logo
self.status_page.set_icon_name(self.__distro_info["logo"])
@property
def step_id(self):
return self.__key
def __start_welcome_animation(self):
def change_langs():

@ -28,3 +28,10 @@ class VanillaDialog(Adw.Window):
self.set_transient_for(window)
self.set_title(title)
self.label_text.set_text(text)
def hide(action, callback=None):
self.hide()
shortcut_controller = Gtk.ShortcutController.new()
shortcut_controller.add_shortcut(Gtk.Shortcut.new(Gtk.ShortcutTrigger.parse_string('Escape'), Gtk.CallbackAction.new(hide)))
self.add_controller(shortcut_controller)

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<template class="VanillaLayoutApplications" parent="AdwBin">
<property name="halign">fill</property>
<property name="valign">fill</property>
<property name="hexpand">true</property>
<child>
<object class="AdwStatusPage" id="status_page">
<property name="halign">fill</property>
<property name="valign">fill</property>
<property name="hexpand">true</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="vexpand">true</property>
<property name="hexpand">true</property>
<property name="valign">center</property>
<child>
<object class="AdwPreferencesPage">
<child>
<object class="AdwPreferencesGroup" id="bundles_list"></object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="btn_next">
<property name="label">Next</property>
<property name="halign">center</property>
<style>
<class name="pill"/>
<class name="suggested-action"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

@ -4,7 +4,7 @@ layoutsdir = join_paths(pkgdatadir, 'vanilla_first_setup/layouts')
sources = [
'__init__.py',
'preferences.py',
'yes_no.py',
'yes_no.py'
]
install_data(sources, install_dir: layoutsdir)
install_data(sources, install_dir: layoutsdir)

@ -14,10 +14,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
from gi.repository import Gtk, Gio, GLib, Adw
from gi.repository import Gtk, Adw
from vanilla_first_setup.utils.run_async import RunAsync
from vanilla_first_setup.dialog import VanillaDialog
@ -40,6 +38,10 @@ class VanillaLayoutPreferences(Adw.Bin):
# signals
self.btn_next.connect("clicked", self.__next_step)
@property
def step_id(self):
return self.__key
def __build_ui(self):
self.status_page.set_icon_name(self.__step["icon"])

@ -43,6 +43,10 @@ class VanillaLayoutYesNo(Adw.Bin):
self.btn_yes.connect("clicked", self.__on_response, True)
self.btn_no.connect("clicked", self.__on_response, False)
self.btn_info.connect("clicked", self.__on_info)
@property
def step_id(self):
return self.__key
def __build_ui(self):
self.status_page.set_icon_name(self.__step["icon"])

@ -18,9 +18,6 @@ import os
import sys
import logging
import subprocess
import json
from gi.repository import Gio
from vanilla_first_setup.utils.recipe import RecipeLoader
@ -29,6 +26,7 @@ from vanilla_first_setup.defaults.theme import VanillaDefaultTheme
from vanilla_first_setup.layouts.preferences import VanillaLayoutPreferences
from vanilla_first_setup.layouts.yes_no import VanillaLayoutYesNo
from vanilla_first_setup.defaults.applications import VanillaLayoutApplications
logger = logging.getLogger("FirstSetup::Builder")
@ -38,7 +36,8 @@ templates = {
"welcome": VanillaDefaultWelcome,
"theme": VanillaDefaultTheme,
"preferences": VanillaLayoutPreferences,
"yes-no": VanillaLayoutYesNo
"yes-no": VanillaLayoutYesNo,
"applications": VanillaLayoutApplications
}
@ -89,6 +88,13 @@ class Builder:
if step["template"] in templates:
_widget = templates[step["template"]](self.__window, self.distro_info, key, step)
self.__register_widgets.append(_widget)
def get_temp_finals(self, step_id: str):
for widget in self.__register_widgets:
if widget.step_id == step_id:
return widget.get_finals()
return None
def get_finals(self):
self.__register_finals = []

@ -14,10 +14,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import logging
import json
logger = logging.getLogger("FirstSetup::Parser")

@ -30,11 +30,50 @@ class Processor:
def run(log_path, pre_run, post_run, commands):
commands = pre_run + commands + post_run
out_run = ""
next_boot = []
next_boot_script_path = os.path.expanduser("~/.local/org.vanillaos.FirstSetup.nextBoot")
next_boot_autostart_path = os.path.expanduser("~/.config/autostart/org.vanillaos.FirstSetup.nextBoot.desktop")
abroot_bin = shutil.which("abroot")
logger.info("processing the following commands: \n%s" %
'\n'.join(commands))
# nextBoot commands are collected in ~/.local/org.vanillaos.FirstSetup.nextBoot
# and executed at the next boot by a desktop entry
for command in commands:
if command.startswith("!nextBoot"):
next_boot.append(command.replace("!nextBoot", ""))
continue
if len(next_boot) > 0:
with open(next_boot_script_path, "w") as f:
f.write("#!/bin/sh\n")
f.write("# This file was created by FirstSetup\n")
f.write("# Do not edit this file manually\n\n")
for command in next_boot:
f.write(f"{command}\n")
f.write(f"rm -f {next_boot_script_path}\n")
f.write(f"rm -f {next_boot_autostart_path}\n")
f.flush()
f.close()
# setting the file executable
os.chmod(next_boot_script_path, 0o755)
# creating the desktop entry
with open(next_boot_autostart_path, "w") as f:
f.write("[Desktop Entry]\n")
f.write("Name=FirstSetup Next Boot\n")
f.write("Comment=Run FirstSetup commands at the next boot\n")
f.write("Exec=kgx -e bash -c 'sh %s'\n" % next_boot_script_path)
f.write("Terminal=false\n")
f.write("Type=Application\n")
f.write("X-GNOME-Autostart-enabled=true\n")
f.flush()
f.close()
# generating a temporary file to store all the commands so we can
# run them all at once
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
@ -43,6 +82,9 @@ class Processor:
f.write("# Do not edit this file manually\n\n")
for command in commands:
if command.startswith("!nextBoot"):
continue
if command.startswith("!noSudo"):
command = command.replace("!noSudo", "sudo -u $USER")

@ -19,8 +19,6 @@ import sys
import logging
import json
from gi.repository import Gio
logger = logging.getLogger("FirstSetup::RecipeLoader")

@ -12,6 +12,7 @@
<file>gtk/layout-preferences.ui</file>
<file>gtk/layout-yes-no.ui</file>
<file>gtk/layout-applications.ui</file>
</gresource>
<gresource prefix="/io/github/vanilla-os/FirstSetup/icons/scalable/actions/">
<file preprocess="xml-stripblanks">../data/icons/hicolor/symbolic/actions/vanilla-package-symbolic.svg</file>

@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
from gi.repository import Gtk, Gio, GLib, Adw
from gi.repository import Gtk, Adw
from vanilla_first_setup.utils.builder import Builder
from vanilla_first_setup.utils.parser import Parser
@ -52,6 +52,10 @@ class VanillaWindow(Adw.ApplicationWindow):
# connect system signals
self.__connect_signals()
@property
def builder(self):
return self.__builder
def __connect_signals(self):
self.btn_back.connect("clicked", self.back)

Loading…
Cancel
Save