Rewrite TROMjaro Welcome app in Nim #1
159
tromjaroWelcomeApp.nim
Normal file
159
tromjaroWelcomeApp.nim
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
from std/osproc import ProcessOption, startProcess, waitForExit, close
|
||||||
|
from std/options import Option, some, get, isNone
|
||||||
|
from std/strutils import splitLines
|
||||||
|
from std/strformat import fmt
|
||||||
|
import owlkettle, std/os
|
||||||
|
|
||||||
|
const
|
||||||
|
picturesDir = "/usr/share/tromjaro-welcome-app/pictures"
|
||||||
|
desktopFile = "tromjaro-welcome-app.desktop"
|
||||||
|
desktopFilePath = "/usr/share/applications" / desktopFile
|
||||||
|
applicationID = "com.tromjaro.WelcomeApp"
|
||||||
|
|
||||||
|
let
|
||||||
|
autostartSymlinkPath = getConfigDir() / "autostart" / desktopFile
|
||||||
|
|
||||||
|
const pages = [
|
||||||
|
(
|
||||||
|
title: "Welcome to TROMjaro",
|
||||||
|
description: """
|
||||||
|
This operating system is trade-free.
|
||||||
|
This means that you do not have to trade anything to us in order to use it.
|
||||||
|
Not your data, not your attention, currency or anything else.
|
||||||
|
There are no free trials here, no ads, and no trackers.
|
||||||
|
""",
|
||||||
|
image: "",
|
||||||
|
buttonText: "TAKE A MINUTE TO CUSTOMIZE YOUR DESKTOP EXPERIENCE",
|
||||||
|
buttonCommand: @[]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
title: "Choose a Layout",
|
||||||
|
description: "Make it morph into any configuration you like!",
|
||||||
|
image: "layout-switcher-thumbnail.png",
|
||||||
|
buttonText: "OPEN THE LAYOUT SWITCHER",
|
||||||
|
buttonCommand: @["/usr/bin/tromjaro-layout-switcher"]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
title: "Choose a Theme",
|
||||||
|
description: "Choose between the many variations of themes that sync across different types of applications.",
|
||||||
|
image: "theme-switcher-thumbnail.png",
|
||||||
|
buttonText: "OPEN THE THEME SWITCHER",
|
||||||
|
buttonCommand: @["/usr/bin/tromjaro-theme-switcher"]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
title: "Choose a Background",
|
||||||
|
description: "Pick a cool background to go along with your theme!",
|
||||||
|
image: "wallpapers-thumbnail.png",
|
||||||
|
buttonText: "CHANGE THE WALLPAPER",
|
||||||
|
buttonCommand: @["/usr/bin/xfdesktop-settings"]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
title: "Setup the Internet Content Blocker",
|
||||||
|
description: "Setup your Operating System to block pesky ads and trackers, system-wide.",
|
||||||
|
image: "tblock-thumbnail.png",
|
||||||
|
buttonText: "SETUP INTERNET CONTENT BLOCKER",
|
||||||
|
buttonCommand: @["/usr/bin/tblockg"]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
title: "Settings Manager",
|
||||||
|
description: "If you want to do more tweaks, you will find all of the settings in one single place.",
|
||||||
|
image: "settings-manager-thumbnail.png",
|
||||||
|
buttonText: "OPEN SETTINGS MANAGER",
|
||||||
|
buttonCommand: @["/usr/bin/xfce4-settings-manager"]
|
||||||
|
),
|
||||||
|
(
|
||||||
|
title: "Support Us",
|
||||||
|
description: "TROMjaro is one of the many trade-free projects that we are doing. Please support us if you can. Thank you!",
|
||||||
|
image: "trom-projects-thumbnail.png",
|
||||||
|
buttonText: "DONATE",
|
||||||
|
buttonCommand: @["/usr/bin/xdg-open", "https://www.tromsite.com/donate/"]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
var pageNumber: int = 0
|
||||||
|
|
||||||
|
proc runBackgroundCommand(commandLine: seq[string]) =
|
||||||
|
let process = startProcess("/usr/bin/setsid", args= @["-f"] & commandLine, options={poParentStreams})
|
||||||
|
discard process.waitForExit()
|
||||||
|
process.close()
|
||||||
|
|
||||||
|
var
|
||||||
|
oldConfigDir: Option[string]
|
||||||
|
configDirChanged: bool
|
||||||
|
|
||||||
|
# Prevent loading GTK theme from ~/.config/gtk-4.0 directory when it is a symlink
|
||||||
|
if symlinkExists(getConfigDir() / "gtk-4.0"):
|
||||||
|
if existsEnv("XDG_CONFIG_HOME"):
|
||||||
|
oldConfigDir = some(getEnv("XDG_CONFIG_HOME"))
|
||||||
|
putEnv("XDG_CONFIG_HOME", "/dev/null")
|
||||||
|
configDirChanged = true
|
||||||
|
|
||||||
|
viewable App:
|
||||||
|
hooks:
|
||||||
|
build:
|
||||||
|
# Reset the user's XDG_CONFIG_HOME variable back to what it was before
|
||||||
|
if configDirChanged == true:
|
||||||
|
if oldConfigDir.isNone():
|
||||||
|
delEnv("XDG_CONFIG_HOME")
|
||||||
|
else:
|
||||||
|
putEnv("XDG_CONFIG_HOME", get(oldConfigDir))
|
||||||
|
|
||||||
|
method view(app: AppState): Widget =
|
||||||
|
result = gui:
|
||||||
|
Window:
|
||||||
|
title = "TROMjaro Welcome"
|
||||||
|
defaultSize = (900, 600)
|
||||||
|
Box(orient = OrientY, margin = 20, spacing = 15):
|
||||||
|
Label:
|
||||||
|
useMarkup = true
|
||||||
|
text = fmt"<span size='x-large' weight='bold'>{pages[pageNumber].title}</span>"
|
||||||
|
for line in splitLines(pages[pageNumber].description):
|
||||||
|
Label {.expand: false.}:
|
||||||
|
useMarkup = true
|
||||||
|
text = fmt"<span size='large'>{line}</span>"
|
||||||
|
if pages[pageNumber].image != "":
|
||||||
|
Box(margin = 20):
|
||||||
|
Picture:
|
||||||
|
Pixbuf = loadPixbuf(picturesDir / pages[pageNumber].image)
|
||||||
|
Button {.vAlign: AlignCenter, hAlign: AlignCenter.}:
|
||||||
|
text = pages[pageNumber].buttonText
|
||||||
|
style = ButtonSuggested
|
||||||
|
proc clicked() =
|
||||||
|
let command: seq[string] = pages[pageNumber].buttonCommand
|
||||||
|
if command.len() == 0:
|
||||||
|
inc pageNumber
|
||||||
|
return
|
||||||
|
runBackgroundCommand(command)
|
||||||
|
if pageNumber > 0:
|
||||||
|
Box(orient = OrientX):
|
||||||
|
Button {.hAlign: AlignStart, vAlign: AlignCenter.}:
|
||||||
|
text = "Previous"
|
||||||
|
proc clicked() =
|
||||||
|
dec pageNumber
|
||||||
|
if pageNumber == pages.high():
|
||||||
|
Button {.hAlign: AlignEnd, vAlign: AlignCenter.}:
|
||||||
|
text = "Finish"
|
||||||
|
proc clicked() =
|
||||||
|
app.closeWindow()
|
||||||
|
else:
|
||||||
|
Button {.hAlign: AlignEnd, vAlign: AlignCenter.}:
|
||||||
|
text = "Next"
|
||||||
|
proc clicked() =
|
||||||
|
inc pageNumber
|
||||||
|
Box(orient = OrientX, spacing = 12):
|
||||||
|
Label {.hAlign: AlignEnd.}:
|
||||||
|
text = "Open this Welcome Screen on every boot"
|
||||||
|
Switch {.vAlign: AlignCenter, hAlign: AlignStart.}:
|
||||||
|
state = if symlinkExists(autostartSymlinkPath): true else: false
|
||||||
|
proc changed(state: bool) =
|
||||||
|
if state == true:
|
||||||
|
if not symlinkExists(autostartSymlinkPath):
|
||||||
|
try:
|
||||||
|
createSymlink(desktopFilePath, autostartSymlinkPath)
|
||||||
|
except:
|
||||||
|
echo "Failed to create symlink!"
|
||||||
|
else:
|
||||||
|
if not tryRemoveFile(autostartSymlinkPath):
|
||||||
|
echo "Failed to remove symlink!"
|
||||||
|
|
||||||
|
brew(applicationID, gui(App()))
|
254
welcome.py
254
welcome.py
|
@ -1,254 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
import gi
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
|
||||||
from gi.repository import Gtk, Gdk, Gio
|
|
||||||
|
|
||||||
workdir_path = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
|
|
||||||
def resolve_workdir_path(filename):
|
|
||||||
return os.path.join(workdir_path, filename)
|
|
||||||
|
|
||||||
DESKTOP_FILE = "tromjaro-welcome-app.desktop"
|
|
||||||
DESKTOP_FILE_PATH = os.path.join("/usr/share/applications", DESKTOP_FILE)
|
|
||||||
AUTOSTART_SYMLINK_PATH = os.path.join(os.path.expanduser("~/.config/autostart"), DESKTOP_FILE)
|
|
||||||
|
|
||||||
class WelcomeScreen(Gtk.Window):
|
|
||||||
def __init__(self):
|
|
||||||
Gtk.Window.__init__(self, title="TROMjaro Welcome")
|
|
||||||
|
|
||||||
icon_path = resolve_workdir_path("tromjaro-welcome.svg")
|
|
||||||
if os.path.exists(icon_path):
|
|
||||||
self.set_icon_from_file(icon_path)
|
|
||||||
else:
|
|
||||||
print("Error: Icon not found:", icon_path)
|
|
||||||
|
|
||||||
self.set_border_width(10)
|
|
||||||
self.set_resizable(False)
|
|
||||||
self.set_size_request(800, 600)
|
|
||||||
self.set_default_size(800, 600)
|
|
||||||
|
|
||||||
self.pages = [
|
|
||||||
{"title": "Welcome to TROMjaro",
|
|
||||||
"description": "This operating system is trade-free.\nThis means that you do not have to trade anything to us in order to use it.\nNot your data, not your attention, currency or anything else.\nThere are no free trials here, no ads, and no trackers.",
|
|
||||||
"image_filename": "",
|
|
||||||
"with_button": True,
|
|
||||||
"button_text": "Take a minute to customize your desktop experience",
|
|
||||||
"button_handler": self.on_next_button_clicked},
|
|
||||||
{"title": "Choose a Layout",
|
|
||||||
"description": "Make it morph into any configuration you like!",
|
|
||||||
"image_filename": "tromjaro-layout-switcher-thumb.png",
|
|
||||||
"with_button": True,
|
|
||||||
"button_text": "Open the Layout Switcher",
|
|
||||||
"button_handler": self.on_layout_switcher_button_clicked},
|
|
||||||
{"title": "Choose a Theme",
|
|
||||||
"description": "Choose between the many variations of themes that sync across different types of applications.",
|
|
||||||
"image_filename": "tromjaro-theme-switcher-thumb.png",
|
|
||||||
"with_button": True,
|
|
||||||
"button_text": "Open the Theme Switcher",
|
|
||||||
"button_handler": self.on_theme_switcher_button_clicked},
|
|
||||||
{"title": "Choose a Background",
|
|
||||||
"description": "Pick a cool background to go along with your theme!",
|
|
||||||
"image_filename": "wallpapers-thumbnail.png",
|
|
||||||
"with_button": True,
|
|
||||||
"button_text": "Change the Wallpaper",
|
|
||||||
"button_handler": self.on_background_button_clicked},
|
|
||||||
{"title": "Setup the Internet Content Blocker",
|
|
||||||
"description": "Setup your Operating System to block the pesky ads and trackers, system-wide.",
|
|
||||||
"image_filename": "content-blocker-thumbnail.png",
|
|
||||||
"with_button": True,
|
|
||||||
"button_text": "Setup Internet Content Blocker",
|
|
||||||
"button_handler": self.on_content_blocker_button_clicked},
|
|
||||||
{"title": "Settings Manager",
|
|
||||||
"description": "If you want to do more tweaks, you will find all of the settings into one single place.",
|
|
||||||
"image_filename": "settings-thumbnail.png",
|
|
||||||
"with_button": True,
|
|
||||||
"button_text": "Open Settings Manager",
|
|
||||||
"button_handler": self.on_settings_button_clicked},
|
|
||||||
{"title": "Support Us",
|
|
||||||
"description": "TROMjaro is one of the many trade-free projects that we are doing. Please support us if you can. Thank you!",
|
|
||||||
"image_filename": "donation-thumb.png",
|
|
||||||
"with_button": True,
|
|
||||||
"button_text": "Donate",
|
|
||||||
"button_handler": self.on_donate_button_clicked},
|
|
||||||
]
|
|
||||||
|
|
||||||
self.current_page = 0
|
|
||||||
self.create_ui()
|
|
||||||
|
|
||||||
def create_ui(self):
|
|
||||||
for child in self.get_children():
|
|
||||||
self.remove(child)
|
|
||||||
|
|
||||||
grid = Gtk.Grid()
|
|
||||||
grid.set_column_homogeneous(True)
|
|
||||||
grid.set_row_spacing(10)
|
|
||||||
|
|
||||||
header_label = Gtk.Label(label=self.pages[self.current_page]["title"].upper())
|
|
||||||
header_label.set_markup("<big><b>{}</b></big>".format(self.pages[self.current_page]["title"].upper()))
|
|
||||||
header_label.set_hexpand(True)
|
|
||||||
if self.current_page == 0:
|
|
||||||
header_label.set_margin_top(178)
|
|
||||||
header_label.set_margin_bottom(20)
|
|
||||||
grid.attach(header_label, 0, 0, 2, 1)
|
|
||||||
|
|
||||||
grid_row = 1
|
|
||||||
if self.current_page == 0:
|
|
||||||
description = self.pages[self.current_page]["description"]
|
|
||||||
description_lines = description.split("\n")
|
|
||||||
for line in description_lines:
|
|
||||||
description_label = Gtk.Label(label=line)
|
|
||||||
description_label.set_markup('<span size="large">{}</span>'.format(line))
|
|
||||||
description_label.set_size_request(600, 30)
|
|
||||||
description_label.set_justify(Gtk.Justification.CENTER)
|
|
||||||
description_label.set_hexpand(True)
|
|
||||||
description_label.set_line_wrap(True)
|
|
||||||
grid.attach(description_label, 0, grid_row, 2, 1)
|
|
||||||
grid_row += 1
|
|
||||||
else:
|
|
||||||
description_label = Gtk.Label(label=self.pages[self.current_page]["description"])
|
|
||||||
description_label.set_hexpand(True)
|
|
||||||
description_label.set_justify(Gtk.Justification.CENTER)
|
|
||||||
description_label.set_line_wrap(True)
|
|
||||||
grid.attach(description_label, 0, grid_row, 2, 1)
|
|
||||||
grid_row += 1
|
|
||||||
|
|
||||||
image_filename = self.pages[self.current_page]["image_filename"]
|
|
||||||
if image_filename:
|
|
||||||
full_path = resolve_workdir_path(image_filename)
|
|
||||||
if os.path.exists(full_path):
|
|
||||||
image = Gtk.Image.new_from_file(full_path)
|
|
||||||
image.set_size_request(600, 400)
|
|
||||||
grid.attach(image, 0, grid_row, 2, 1)
|
|
||||||
grid_row += 1
|
|
||||||
else:
|
|
||||||
print("Error: Image not found:", full_path)
|
|
||||||
|
|
||||||
if self.pages[self.current_page]["with_button"]:
|
|
||||||
button_text = self.pages[self.current_page]["button_text"]
|
|
||||||
button_handler = self.pages[self.current_page]["button_handler"]
|
|
||||||
button = Gtk.Button(label=button_text.upper())
|
|
||||||
button.set_size_request(100, -1)
|
|
||||||
button.set_halign(Gtk.Align.CENTER)
|
|
||||||
button.set_name("accent_button")
|
|
||||||
button.set_margin_top(20)
|
|
||||||
if self.current_page == 0:
|
|
||||||
button.set_margin_bottom(200)
|
|
||||||
else:
|
|
||||||
button.set_margin_bottom(20)
|
|
||||||
button.connect("clicked", button_handler)
|
|
||||||
grid.attach(button, 0, grid_row, 2, 1)
|
|
||||||
grid_row += 1
|
|
||||||
|
|
||||||
if self.current_page > 0:
|
|
||||||
left_button = Gtk.Button(label="Previous")
|
|
||||||
left_button.set_size_request(60, -1)
|
|
||||||
left_button.set_halign(Gtk.Align.START)
|
|
||||||
left_button.set_margin_top(20)
|
|
||||||
left_button.set_margin_bottom(20)
|
|
||||||
left_button.connect("clicked", self.on_previous_button_clicked)
|
|
||||||
grid.attach(left_button, 0, grid_row, 1, 1)
|
|
||||||
|
|
||||||
if self.current_page > 0 and self.current_page < len(self.pages) - 1:
|
|
||||||
right_button = Gtk.Button(label="Next")
|
|
||||||
right_button.set_size_request(60, -1)
|
|
||||||
right_button.set_halign(Gtk.Align.END)
|
|
||||||
right_button.set_margin_top(20)
|
|
||||||
right_button.set_margin_bottom(20)
|
|
||||||
right_button.connect("clicked", self.on_next_button_clicked)
|
|
||||||
grid.attach(right_button, 1, grid_row, 1, 1)
|
|
||||||
grid_row += 1
|
|
||||||
|
|
||||||
if self.current_page == len(self.pages) - 1:
|
|
||||||
right_button = Gtk.Button(label="Finish")
|
|
||||||
right_button.connect("clicked", self.on_finish_button_clicked)
|
|
||||||
right_button.set_size_request(60, -1)
|
|
||||||
right_button.set_halign(Gtk.Align.END)
|
|
||||||
right_button.set_margin_top(20)
|
|
||||||
right_button.set_margin_bottom(20)
|
|
||||||
grid.attach(right_button, 1, grid_row, 1, 1)
|
|
||||||
grid_row += 1
|
|
||||||
|
|
||||||
checkbox = Gtk.CheckButton(label="Open the Welcome Screen on every boot")
|
|
||||||
checkbox.set_active(self.is_autostarted())
|
|
||||||
checkbox.connect("toggled", self.on_checkbox_toggled)
|
|
||||||
checkbox.set_halign(Gtk.Align.CENTER)
|
|
||||||
grid.attach(checkbox, 0, grid_row, 2, 1)
|
|
||||||
grid_row += 1
|
|
||||||
|
|
||||||
css_provider = Gtk.CssProvider()
|
|
||||||
css_provider.load_from_data(b"""
|
|
||||||
button#accent_button {
|
|
||||||
background-color: @theme_selected_bg_color;
|
|
||||||
color: @theme_selected_fg_color;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
button#accent_button:hover {
|
|
||||||
background-color: @theme_selected_bg_color;
|
|
||||||
color: @theme_selected_fg_color;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
""")
|
|
||||||
|
|
||||||
context = Gtk.StyleContext()
|
|
||||||
context.add_provider_for_screen(Gdk.Screen.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
|
||||||
|
|
||||||
self.add(grid)
|
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
def on_previous_button_clicked(self, button):
|
|
||||||
if self.current_page > 0:
|
|
||||||
self.current_page -= 1
|
|
||||||
self.create_ui()
|
|
||||||
|
|
||||||
def on_layout_switcher_button_clicked(self, button):
|
|
||||||
self.run_command("tromjaro-layout-switcher")
|
|
||||||
|
|
||||||
def on_theme_switcher_button_clicked(self, button):
|
|
||||||
self.run_command("tromjaro-theme-switcher")
|
|
||||||
|
|
||||||
def on_background_button_clicked(self, button):
|
|
||||||
self.run_command("xfdesktop-settings")
|
|
||||||
|
|
||||||
def on_content_blocker_button_clicked(self, button):
|
|
||||||
self.run_command("tblockg")
|
|
||||||
|
|
||||||
def on_settings_button_clicked(self, button):
|
|
||||||
self.run_command("xfce4-settings-manager")
|
|
||||||
|
|
||||||
def on_donate_button_clicked(self, button):
|
|
||||||
self.run_command("xdg-open https://www.tromsite.com/donate/")
|
|
||||||
|
|
||||||
def on_checkbox_toggled(self, checkbox):
|
|
||||||
if checkbox.get_active():
|
|
||||||
print("Welcome Screen will be opened on every boot.")
|
|
||||||
if not os.path.isfile(AUTOSTART_SYMLINK_PATH):
|
|
||||||
os.symlink(DESKTOP_FILE_PATH, AUTOSTART_SYMLINK_PATH)
|
|
||||||
else:
|
|
||||||
print("Welcome Screen will not be opened on every boot.")
|
|
||||||
if os.path.isfile(AUTOSTART_SYMLINK_PATH):
|
|
||||||
os.unlink(AUTOSTART_SYMLINK_PATH)
|
|
||||||
|
|
||||||
def on_next_button_clicked(self, button):
|
|
||||||
if self.current_page < len(self.pages) - 1:
|
|
||||||
self.current_page += 1
|
|
||||||
self.create_ui()
|
|
||||||
|
|
||||||
def on_finish_button_clicked(self, button):
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
def run_command(self, command):
|
|
||||||
subprocess.Popen(command.split(' '), start_new_session=True)
|
|
||||||
|
|
||||||
def is_autostarted(self):
|
|
||||||
return os.path.isfile(AUTOSTART_SYMLINK_PATH)
|
|
||||||
|
|
||||||
|
|
||||||
win = WelcomeScreen()
|
|
||||||
win.connect("destroy", Gtk.main_quit)
|
|
||||||
win.show_all()
|
|
||||||
Gtk.main()
|
|
Loading…
Reference in New Issue
Block a user