misc: Support post install view

main
mirkobrombin 2 years ago
parent 6bfb69e877
commit 24fa015e76

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<requires lib="libadwaita" version="1.0" />
<template class="VanillaPostScript" parent="AdwBin">
<child>
<object class="AdwStatusPage">
<property name="valign">fill</property>
<property name="halign">fill</property>
<property name="icon-name">io.github.vanilla-os.FirstSetup</property>
<property name="title" translatable="yes">Finalizing</property>
<property name="description" translatable="yes">Your device will be ready soon.</property>
<child>
<object class="GtkBox" id="console_box">
<property name="margin-start">40</property>
<property name="margin-end">40</property>
<property name="margin-top">1</property>
<property name="margin-bottom">18</property>
<property name="height-request">250</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="console_output">
<property name="margin-top">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="orientation">vertical</property>
</object>
</child>
<style>
<class name="card"/>
</style>
</object>
</child>
</object>
</child>
</template>
</interface>

@ -22,8 +22,9 @@ from gettext import gettext as _
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
gi.require_version('Vte', '3.91')
from gi.repository import Gtk, Gdk, Gio, Adw
from gi.repository import Gtk, Gdk, Gio, GLib, Adw, Vte, Pango
from vanilla_first_setup.window import VanillaWindow
@ -35,8 +36,29 @@ class FirstSetupApplication(Adw.Application):
def __init__(self):
super().__init__(application_id='io.github.vanilla-os.FirstSetup',
flags=Gio.ApplicationFlags.FLAGS_NONE)
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
self.post_script = None
self.create_action('quit', self.close, ['<primary>q'])
self.__register_arguments()
def __register_arguments(self):
"""Register the command line arguments."""
self.add_main_option(
"run-post-script",
ord("p"),
GLib.OptionFlags.NONE,
GLib.OptionArg.STRING,
_("Run a post script"),
None
)
def do_command_line(self, command_line):
"""Handle command line arguments."""
options = command_line.get_options_dict()
if options.contains("run-post-script"):
self.post_script = options.lookup_value("run-post-script").get_string()
self.activate()
def do_activate(self):
"""
@ -100,7 +122,7 @@ class FirstSetupApplication(Adw.Application):
win = self.props.active_window
if not win:
win = VanillaWindow(application=self)
win = VanillaWindow(application=self, post_script=self.post_script)
win.present()
def create_action(self, name, callback, shortcuts=None):

@ -6,6 +6,7 @@
<file>gtk/progress.ui</file>
<file>gtk/dialog.ui</file>
<file>gtk/tour.ui</file>
<file>gtk/post-script.ui</file>
<file>gtk/default-theme.ui</file>
<file>gtk/default-welcome.ui</file>

@ -26,24 +26,35 @@ class VanillaDone(Adw.Bin):
btn_reboot = Gtk.Template.Child()
btn_close = Gtk.Template.Child()
def __init__(self, window, **kwargs):
def __init__(self, window, reboot: bool=True, title: str="", description: str="", fail_title: str="", fail_description: str="", **kwargs):
super().__init__(**kwargs)
self.__window = window
self.__fail_title = fail_title
self.__fail_description = fail_description
if not title and not description:
self.status_page.set_description(
_("Restart your device to enjoy your {} experience.").format(
self.__window.recipe["distro_name"]
)
)
else:
self.status_page.set_title(title)
self.status_page.set_description(description)
if reboot:
self.btn_reboot.connect("clicked", self.__on_reboot_clicked)
self.btn_close.connect("clicked", self.__on_close_clicked)
def set_result(self, result):
if not result:
self.status_page.set_icon_name("dialog-error-symbolic")
if not self.__fail_title and not self.__fail_description:
self.status_page.set_title(_("Something went wrong"))
self.status_page.set_description(_("Please contact the distribution developers."))
else:
self.status_page.set_title(self.__fail_title)
self.status_page.set_description(self.__fail_description)
self.btn_reboot.set_visible(False)
self.btn_close.set_visible(True)

@ -6,6 +6,7 @@ sources = [
'done.py',
'progress.py',
'tour.py',
'post_script.py',
]
install_data(sources, install_dir: viewsdir)

@ -0,0 +1,87 @@
# progress.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/>.
import time
from gi.repository import Gtk, Gio, Gdk, GLib, Adw, Vte, Pango
from vanilla_first_setup.utils.run_async import RunAsync
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/post-script.ui')
class VanillaPostScript(Adw.Bin):
__gtype_name__ = 'VanillaPostScript'
console_output = Gtk.Template.Child()
def __init__(self, window, post_script: str, **kwargs):
super().__init__(**kwargs)
self.__window = window
self.__terminal = Vte.Terminal()
self.__post_script = post_script
self.__font = Pango.FontDescription()
self.__font.set_family("Ubuntu Mono")
self.__font.set_size(13 * Pango.SCALE)
self.__font.set_weight(Pango.Weight.NORMAL)
self.__font.set_stretch(Pango.Stretch.NORMAL)
self.__build_ui()
def __build_ui(self):
self.__terminal.set_cursor_blink_mode(Vte.CursorBlinkMode.ON)
self.__terminal.set_font(self.__font)
self.__terminal.set_mouse_autohide(True)
self.console_output.append(self.__terminal)
self.__terminal.connect("child-exited", self.on_vte_child_exited)
palette = ["#353535", "#c01c28", "#26a269", "#a2734c", "#12488b", "#a347ba", "#2aa1b3", "#cfcfcf", "#5d5d5d", "#f66151", "#33d17a", "#e9ad0c", "#2a7bde", "#c061cb", "#33c7de", "#ffffff"]
FOREGROUND = palette[0]
BACKGROUND = palette[15]
FOREGROUND_DARK = palette[15]
BACKGROUND_DARK = palette[0]
self.fg = Gdk.RGBA()
self.bg = Gdk.RGBA()
self.colors = [Gdk.RGBA() for c in palette]
[color.parse(s) for (color, s) in zip(self.colors, palette)]
desktop_schema = Gio.Settings.new('org.gnome.desktop.interface')
if desktop_schema.get_enum('color-scheme') == 0:
self.fg.parse(FOREGROUND)
self.bg.parse(BACKGROUND)
elif desktop_schema.get_enum('color-scheme') == 1:
self.fg.parse(FOREGROUND_DARK)
self.bg.parse(BACKGROUND_DARK)
self.__terminal.set_colors(self.fg, self.bg, self.colors)
self.__terminal.spawn_async(
Vte.PtyFlags.DEFAULT,
None,
["/bin/sh", "-c", self.__post_script],
[],
GLib.SpawnFlags.DO_NOT_REAP_CHILD,
None,
None,
-1,
None,
None,
None,
)
def on_vte_child_exited(self, terminal, status, *args):
status = not bool(status)
self.__window.next(result=status)

@ -24,6 +24,7 @@ from vanilla_first_setup.utils.run_async import RunAsync
from vanilla_first_setup.views.progress import VanillaProgress
from vanilla_first_setup.views.done import VanillaDone
from vanilla_first_setup.views.post_script import VanillaPostScript
@Gtk.Template(resource_path='/io/github/vanilla-os/FirstSetup/gtk/window.ui')
@ -36,8 +37,40 @@ class VanillaWindow(Adw.ApplicationWindow):
btn_back = Gtk.Template.Child()
toasts = Gtk.Template.Child()
def __init__(self, **kwargs):
def __init__(self, post_script: str, **kwargs):
super().__init__(**kwargs)
# prepare a variable for the initialization mode:
# 0 = normal
# 1 = post script
self.__init_mode = 0
# some modes handle the result on their own, so we set
# a new variable where to store the result:
# None = no managed result
# True/False = managed result
self.__last_result = None
# if a post_script is provided, we are in the post setup
# so we can skip the builder and just run the post script
# in the Vte terminal
if post_script:
# set the initialization mode to 1
self.__init_mode = 1
# system views
self.__view_done = VanillaDone(self, reboot=False,
title=_("Done!"), description=_("Your device is ready to use."),
fail_title=_("Error!"), fail_description=_("Something went wrong."))
# this builds the UI for the post script only
self.__build_post_script_ui(post_script)
# connect system signals
self.__connect_signals()
return
# this starts the builder and generates the widgets
# to put in the carousel
self.__builder = Builder(self)
@ -53,6 +86,12 @@ class VanillaWindow(Adw.ApplicationWindow):
# connect system signals
self.__connect_signals()
def __build_post_script_ui(self, post_script):
self.__view_post_script = VanillaPostScript(self, post_script)
self.carousel.append(self.__view_post_script)
self.carousel.append(self.__view_done)
@property
def builder(self):
return self.__builder
@ -83,13 +122,18 @@ class VanillaWindow(Adw.ApplicationWindow):
)
def on_done(result, *args):
if self.__init_mode == 0:
self.__view_done.set_result(result)
self.next()
cur_index = self.carousel.get_position()
page = self.carousel.get_nth_page(cur_index)
if page not in [self.__view_progress, self.__view_done]:
pages_check = [self.__view_done]
if self.__init_mode == 0:
pages_check.append(self.__view_progress)
if page not in pages_check:
self.btn_back.set_visible(cur_index != 0.0)
self.carousel_indicator_dots.set_visible(cur_index != 0.0)
self.headerbar.set_show_end_title_buttons(cur_index != 0.0)
@ -99,6 +143,13 @@ class VanillaWindow(Adw.ApplicationWindow):
self.carousel_indicator_dots.set_visible(False)
self.headerbar.set_show_end_title_buttons(False)
# if there is a managed result, we can skip the processing
# and manage it directly instead
if self.__last_result is not None:
self.__view_done.set_result(self.__last_result)
self.__last_result = None
return
# keep the btn_back button locked if this is the last page
if page == self.__view_done:
return
@ -109,7 +160,10 @@ class VanillaWindow(Adw.ApplicationWindow):
# run the process in a thread
RunAsync(process, on_done)
def next(self, *args):
def next(self, result: bool=None, *args):
if result is not None:
self.__last_result = result
cur_index = self.carousel.get_position()
page = self.carousel.get_nth_page(cur_index + 1)
self.carousel.scroll_to(page, True)

Loading…
Cancel
Save