Commit bf692e7f authored by Roman Alifanov's avatar Roman Alifanov

2.0.0

parent 6dc5d74a
all:
echo "We don't need any build"
cmd_list = epmgpi
# get version from the spec by default
PKGVER = $(shell grep "^Version: " epmgpi.spec | cut -d" " -f2)
PKGREL = $(shell grep "^Release: " epmgpi.spec | cut -d" " -f2)
version := $(PKGVER)-$(PKGREL)
PREFIX=/usr
DATADIR=$(PREFIX)/share
LOCALEDIR=$(DATADIR)/locale
install: install_common install_locale
install_common:
mkdir -p $(DESTDIR)$(PREFIX)/bin
install -p -Dm 0755 bin/* $(DESTDIR)$(PREFIX)/bin/
install -p -Dm 0644 epmgpi.desktop $(DESTDIR)$(DATADIR)/applications/epmgpi.desktop
install -p -Dm 0644 epmgpi.svg $(DESTDIR)$(DATADIR)/pixmaps/epmgpi.svg
install_locale:
@for lang in $(shell cat po/LINGUAS); do \
mkdir -p $(DESTDIR)$(LOCALEDIR)/$$lang/LC_MESSAGES; \
msgfmt -o $(DESTDIR)$(LOCALEDIR)/$$lang/LC_MESSAGES/epmgpi.mo po/$$lang.po; \
done
#!/bin/bash
export TEXTDOMAIN=epmgpi
export TEXTDOMAINDIR=/usr/share/locale
gtxt() {
gettext "$@"
}
if [ $(id -u) -eq 0 ]; then
gtxt "epmgpi cannot be run as root user."
exit 1
fi
# Temporary files
clean_up_tmp() {
rm -fr "$EPMGPI_TMP"
}
EPMGPI_TMP=$(mktemp -d -t epmgpi.XXXXXXX)
trap "clean_up_tmp $EPMGPI_TMP" EXIT
EPMGPI_LOG_FILE="$EPMGPI_TMP/epmgpi.log"
# Default yad parameters
YAD_DEFAULT="/usr/bin/yad --window-icon=epmgpi --title=epmgpi --class=epmgpi"
VALID_FILE_EXTENSIONS=(
"*.rpm" "*.deb" "*.run"
"*.appimage" "*.AppImage" "*.Appimage"
)
check_extension() {
local FILE="$1"
for EXT in "${VALID_FILE_EXTENSIONS[@]}"; do
if [[ "$FILE" == $EXT ]]; then
return 0
fi
done
return 1
}
# Notifications
ntf() {
notify-send --icon=epmgpi "$1"
}
# Error notification
ntf_error() {
notify-send --icon=error "$1"
}
file_exec_warn() {
local NEED_RULES
if [ -x "$1" ]; then
NEED_RULES=False
else
NEED_RULES=True
fi
$YAD_DEFAULT --image="dialog-warning" \
\
--width=500 --height=200 \
--text="$(
gtxt \
"epmgpi has detected that you are running a file.
Launching extraneous files can lead to unforeseen consequences."
echo
echo
if [ "$NEED_RULES" = True ]; then
gtxt "Additionally, the file needs execute permissions.
Do you want to grant the file execute permissions and run it?"
else
gtxt "Do you really want to run the file?"
fi
)" \
--button="yad-yes:0" \
--button="yad-no:1"
local ANSWER=$?
if [[ $ANSWER -eq 0 ]]; then
if [ "$NEED_RULES" = True ]; then
chmod +x "$1"
fi
exec "$1"
fi
}
# Function to ask the user if the package should be repacked
repackq() {
# Non-rpm files are repacked without --repack key
if [[ $PKG_PATH == *.rpm ]]; then
$YAD_DEFAULT --image="dialog-question" --text="$(gtxt "Do you want to repack the rpm file to override dependencies?")" \
--button="yad-yes:0" \
--button="yad-no:1"
local ANSWER=$?
if [[ $ANSWER -eq 0 ]]; then
local EEPM_ARGS="--auto --repack -i"
else
local EEPM_ARGS="--auto -i"
fi
else
local EEPM_ARGS="--auto -i"
fi
echo "$EEPM_ARGS"
}
# GUI package selector
pkgselection() {
$YAD_DEFAULT --file --file-filter="${VALID_FILE_EXTENSIONS[*]}"
}
yad_log_view() {
$YAD_DEFAULT --title="$(gtxt "Error Log")" --no-buttons --text-align=center \
--text-info --show-uri --wrap --width=1200 --height=550 --uri-color=red \
--filename="$EPMGPI_LOG_FILE"
rm "$EPMGPI_LOG_FILE"
exit 1
}
epmgpi_logging() {
tee -a "$EPMGPI_LOG_FILE"
}
# Check if the file is a package
hack_for_paths_with_spaces() {
PKG_PATH="$1"
local PKG_NAME
PKG_NAME=$(basename -- "$PKG_PATH" | tr -d ' ')
local PKG_SYMB_LINK_PATH="$EPMGPI_TMP/$PKG_NAME"
ln -s "$PKG_PATH" "$PKG_SYMB_LINK_PATH"
echo "$PKG_SYMB_LINK_PATH"
}
# Install package
installpkg() {
local PKG_PATH="$1"
local EEPM_ARGS="$2"
# Pkexec for executing as root
(
/usr/bin/pkexec /usr/bin/epm $EEPM_ARGS "$PKG_PATH" 2>&1
exit_code=$?
case $exit_code in
0)
gtxt "Command completed successfully"
echo
ntf "$(gtxt "Package installed!")"
exit 0
;;
100)
ntf_error "$(gtxt "Package not installed. Command failed.")"
echo "!!! EPMGPI ERROR" >> "$EPMGPI_LOG_FILE"
;;
126)
ntf_error "$(gtxt "Package not installed. Action canceled by the user.")"
exit 1
;;
*)
ntf_error "$(gtxt "Package not installed.")"
echo "!!! EPMGPI ERROR" >> "$EPMGPI_LOG_FILE"
;;
esac
) | epmgpi_logging | sed -u 's/^/# /' | $YAD_DEFAULT \
--title="$(gtxt "Package Installation")" \
--progress --width=800 --height=500 \
--enable-log="$(gtxt "Log")" --log-expanded --log-on-top \
--auto-kill --auto-close
}
show_help() {
gtxt "Usage: epmgpi [option] [path-to-package]"
echo
gtxt "Options:"
echo
gtxt " --help, -h Show this help"
echo
gtxt " --version, -v Show version information"
echo
gtxt "Pass the path to the package if you don't want to use the file selection dialog."
echo
}
main() {
local PKG_PATH
local FILE_PATH
FILE_PATH="$1"
# Check and call file selection dialog if PKG_PATH is not set
if [[ -z "$FILE_PATH" ]]; then
gtxt "Package path not specified. Calling package selection function..."
FILE_PATH=$(pkgselection)
fi
if [ ! -f "$FILE_PATH" ]; then
printf "$(gtxt "Error: %s is not a file.")\n" "$FILE_PATH"
exit 1
fi
if ! check_extension "$FILE_PATH"; then
file_exec_warn "$FILE_PATH"
exit 0
fi
if echo "$FILE_PATH" | grep -q " "; then
gtxt "Package path contains spaces"
echo
PKG_PATH=$(hack_for_paths_with_spaces "$FILE_PATH")
else
PKG_PATH=$FILE_PATH
fi
installpkg "$PKG_PATH" "$(repackq)"
if grep -q "!!! EPMGPI ERROR" "$EPMGPI_LOG_FILE" ; then
yad_log_view
fi
}
if [[ $# -eq 0 ]]; then
main | epmgpi_logging
else
while [[ $# -gt 0 ]]; do
case "$1" in
--help|-h)
show_help
exit 0
;;
--version|-v)
gtxt "Version:"
echo " 1.5.1"
exit 0
;;
*)
printf "$(gtxt "Arguments passed: %s")\n" "$1"
main "$(realpath "$1")" | epmgpi_logging
shift
;;
esac
done
fi
......@@ -14,4 +14,4 @@ Icon=epmgpi
MimeType=application/x-executable;application/x-rpm;application/x-redhat-package-manager;application/x-deb;application/x-debian-package;application/x-app-package;
Categories=System;PackageManager;
Categories=Settings;PackageManager;
project(
'epmgpi',
['c', 'vala'],
version: '2.0.0',
meson_version: '>= 0.62.0',
license: 'AGPL-3.0-or-later',
)
gnome = import('gnome')
i18n = import('i18n')
prefix = get_option('prefix')
datadir = get_option('datadir')
localedir = get_option('localedir')
pkgdatadir = join_paths(prefix, datadir, meson.project_name())
conf = configuration_data()
conf.set_quoted('VERSION', meson.project_version())
conf.set_quoted('GETTEXT_PACKAGE', meson.project_name())
conf.set_quoted('LOCALEDIR', join_paths(prefix, localedir))
conf.set_quoted('PKGDATADIR', pkgdatadir)
config_vala = configure_file(
input: 'src/config.vala.in',
output: 'config.vala',
configuration: conf,
)
blueprint_compiler = find_program('blueprint-compiler')
blueprint_files = [
'window',
'start-page',
'review-page',
'unsupported-page',
'installing-page',
'result-page',
]
ui_files = []
foreach blueprint_file : blueprint_files
ui_files += custom_target(
blueprint_file + '.ui',
input: 'src/' + blueprint_file + '.blp',
output: blueprint_file + '.ui',
command: [blueprint_compiler, 'compile', '--output', '@OUTPUT@', '@INPUT@'],
)
endforeach
resources = gnome.compile_resources(
'epmgpi-resources',
'src/epmgpi.gresource.xml',
source_dir: meson.current_build_dir(),
dependencies: ui_files,
)
epmgpi_sources = [
'src/i18n.vala',
'src/package-file.vala',
'src/package-installer.vala',
'src/start-page.vala',
'src/review-page.vala',
'src/unsupported-page.vala',
'src/installing-page.vala',
'src/result-page.vala',
'src/main-window.vala',
'src/application.vala',
'src/cli.vala',
'src/main.vala',
config_vala,
resources,
]
executable(
'epmgpi',
epmgpi_sources,
c_args: ['-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name())],
dependencies: [
dependency('glib-2.0'),
dependency('gio-2.0'),
dependency('gtk4'),
dependency('libadwaita-1'),
],
install: true,
)
install_data(
'epmgpi.desktop',
install_dir: join_paths(prefix, datadir, 'applications'),
)
install_data(
'epmgpi.svg',
install_dir: join_paths(prefix, datadir, 'pixmaps'),
)
subdir('po')
src/cli.vala
src/i18n.vala
src/package-file.vala
src/package-installer.vala
src/start-page.vala
src/review-page.vala
src/unsupported-page.vala
src/installing-page.vala
src/result-page.vala
src/main-window.vala
src/main.vala
src/window.blp
src/start-page.blp
src/review-page.blp
src/unsupported-page.blp
src/installing-page.blp
src/result-page.blp
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the epmgpi package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Language: ru\n"
"Project-Id-Version: epmgpi\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-06 18:15+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: src/cli.vala:12
msgid "Usage: epmgpi [option] [path-to-package]"
msgstr ""
msgid "epmgpi cannot be run as root user."
#: src/cli.vala:13
msgid "Options:"
msgstr ""
msgid "Do you want to repack the rpm file to override dependencies?"
#: src/cli.vala:14
msgid " --help, -h Show this help"
msgstr ""
#: src/cli.vala:15
msgid " --version, -v Show version information"
msgstr ""
#: src/cli.vala:18
msgid ""
"Pass the path to the package if you don't want to use the file selection "
"dialog."
msgstr ""
#: src/package-installer.vala:35
#, c-format
msgid "Installing: %s"
msgstr ""
#: src/package-installer.vala:53 src/package-installer.vala:111
#: src/main-window.vala:147
msgid "Package not installed."
msgstr ""
#: src/package-installer.vala:86
msgid "Command completed successfully"
msgstr ""
#: src/package-installer.vala:88 src/result-page.blp:6 src/result-page.blp:37
msgid "Package installed!"
msgstr ""
#: src/package-installer.vala:94
msgid "Package not installed. Action canceled by the user."
msgstr ""
#: src/package-installer.vala:103
msgid "Package not installed. Command failed."
msgstr ""
msgid "Package not installed. Action canceled by the user."
#: src/result-page.vala:21
msgid "Next File"
msgstr ""
msgid "Package not installed."
#: src/result-page.vala:21 src/result-page.blp:70
msgid "Choose Another File"
msgstr ""
msgid "Package Installation"
#: src/main-window.vala:55
msgid "Choose package"
msgstr ""
msgid "Error Log"
#: src/main-window.vala:67
#, c-format
msgid "File selection failed: %s"
msgstr ""
msgid "Log"
#: src/main-window.vala:69
msgid "File selection failed"
msgstr ""
msgid "Version:"
msgstr "Версия:"
#: src/main-window.vala:78
msgid "Packages"
msgstr ""
msgid "Usage: epmgpi [option] [path-to-package]"
#: src/main-window.vala:88
msgid "All files"
msgstr ""
msgid "Options:"
#: src/main-window.vala:145
#, c-format
msgid "Error: %s is not a file."
msgstr ""
msgid " --help, -h Show this help"
#: src/main-window.vala:153
msgid "Repack RPM package?"
msgstr ""
msgid " --version, -v Show version information"
#: src/main-window.vala:154
msgid "Do you want to repack the rpm file to override dependencies?"
msgstr ""
msgid "Pass the path to the package if you don't want to use the file selection dialog."
#: src/main-window.vala:156
msgid "No"
msgstr ""
msgid "Package path not specified. Calling package selection function..."
#: src/main-window.vala:157
msgid "Yes"
msgstr ""
msgid "epmgpi has detected that you are running a file.\nLaunching extraneous files can lead to unforeseen consequences."
#: src/main-window.vala:178
msgid "Canceled"
msgstr ""
#: src/main-window.vala:187
#, c-format
msgid "Launching: %s"
msgstr ""
#: src/main-window.vala:192
msgid "Launch failed"
msgstr ""
#: src/main-window.vala:197
msgid "epmgpi has detected that you are running a file."
msgstr ""
#: src/main-window.vala:199
msgid "Launching extraneous files can lead to unforeseen consequences."
msgstr ""
#: src/main-window.vala:202
msgid "Do you really want to run the file?"
msgstr ""
msgid "Additionally, the file needs execute permissions.\n\nDo you want to grant the file execute permissions and run it?"
#: src/main-window.vala:203
msgid "Additionally, the file needs execute permissions."
msgstr ""
msgid "Error: %s is not a file."
#: src/main-window.vala:205
msgid "Do you want to grant the file execute permissions and run it?"
msgstr ""
#: src/main.vala:15
msgid "Version:"
msgstr ""
#: src/main.vala:24 src/main.vala:34
msgid "epmgpi cannot be run as root user."
msgstr ""
#: src/window.blp:5 src/window.blp:14 src/start-page.blp:6
msgid "Package Installation"
msgstr ""
#: src/start-page.blp:34
msgid "Install packages with EPM"
msgstr ""
#: src/start-page.blp:42
msgid "RPM, DEB, RUN and AppImage files"
msgstr ""
#: src/start-page.blp:50
msgid "Choose File"
msgstr ""
#: src/review-page.blp:6 src/installing-page.blp:47
msgid "Package"
msgstr ""
msgid "Package path contains spaces"
#: src/review-page.blp:42
msgid "Ready to install"
msgstr ""
msgid "Arguments passed: %s"
#: src/review-page.blp:50
msgid "The selected package will be installed with EPM."
msgstr ""
#: src/review-page.blp:60 src/unsupported-page.blp:49
#: src/installing-page.blp:50
msgid "Selected file"
msgstr ""
#: src/review-page.blp:63 src/installing-page.blp:51
msgid "No file selected"
msgstr ""
#: src/review-page.blp:77
msgid "Install"
msgstr ""
#: src/unsupported-page.blp:6 src/unsupported-page.blp:34
msgid "Unsupported file"
msgstr ""
#: src/unsupported-page.blp:52
msgid "File"
msgstr ""
#: src/unsupported-page.blp:76
msgid "Cancel"
msgstr ""
#: src/unsupported-page.blp:82
msgid "Run"
msgstr ""
#: src/installing-page.blp:6 src/installing-page.blp:38
msgid "Installing"
msgstr ""
#: src/installing-page.blp:59 src/result-page.blp:47
msgid "Log"
msgstr ""
i18n.gettext(
meson.project_name(),
preset: 'glib',
args: ['--language=C'],
)
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: epmgpi\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-06 18:15+0300\n"
"PO-Revision-Date: 2026-06-05 17:15+0300\n"
"Last-Translator: Roman Alifanov <ximper@altlinux.org>\n"
"Language-Team: Russian\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "epmgpi cannot be run as root user."
msgstr "Нельзя запускать epmgpi от пользователя root."
#: src/cli.vala:12
msgid "Usage: epmgpi [option] [path-to-package]"
msgstr "Использование: epmgpi [опция] [путь-к-пакету]"
msgid "Do you want to repack the rpm file to override dependencies?"
msgstr "Перепаковать ли rpm файл для переопределения зависимостей?"
#: src/cli.vala:13
msgid "Options:"
msgstr "Опции:"
#: src/cli.vala:14
msgid " --help, -h Show this help"
msgstr " --help, -h Показать эту справку"
#: src/cli.vala:15
msgid " --version, -v Show version information"
msgstr " --version, -v Показать информацию о версии"
#: src/cli.vala:18
msgid ""
"Pass the path to the package if you don't want to use the file selection "
"dialog."
msgstr ""
"Передайте путь к пакету, если не хотите использовать окно выбора файла."
#: src/package-installer.vala:35
#, c-format
msgid "Installing: %s"
msgstr "Установка: %s"
#: src/package-installer.vala:53 src/package-installer.vala:111
#: src/main-window.vala:147
msgid "Package not installed."
msgstr "Пакет не установлен."
#: src/package-installer.vala:86
msgid "Command completed successfully"
msgstr "Команда завершилась успешно"
#: src/package-installer.vala:88 src/result-page.blp:6 src/result-page.blp:37
msgid "Package installed!"
msgstr "Пакет установлен!"
#: src/package-installer.vala:94
msgid "Package not installed. Action canceled by the user."
msgstr "Пакет не установлен. Действие прервано пользователем."
#: src/package-installer.vala:103
msgid "Package not installed. Command failed."
msgstr "Пакет не установлен. Команда завершилась с ошибкой."
msgid "Package not installed. Action canceled by the user."
msgstr "Пакет не установлен. Действие прервано пользователем."
#: src/result-page.vala:21
msgid "Next File"
msgstr "Следующий файл"
msgid "Package not installed."
msgstr "Пакет не установлен."
#: src/result-page.vala:21 src/result-page.blp:70
msgid "Choose Another File"
msgstr "Выбрать другой файл"
msgid "Package Installation"
msgstr "Установка пакета"
#: src/main-window.vala:55
msgid "Choose package"
msgstr "Выберите пакет"
msgid "Error Log"
msgstr "Лог ошибки"
#: src/main-window.vala:67
#, c-format
msgid "File selection failed: %s"
msgstr "Не удалось выбрать файл: %s"
msgid "Log"
msgstr "Лог"
#: src/main-window.vala:69
msgid "File selection failed"
msgstr "Не удалось выбрать файл"
msgid "Version:"
msgstr "Версия:"
#: src/main-window.vala:78
msgid "Packages"
msgstr "Пакеты"
msgid "Usage: epmgpi [option] [path-to-package]"
msgstr "Использование: epmgpi [опция] [путь-к-пакету]"
#: src/main-window.vala:88
msgid "All files"
msgstr "Все файлы"
msgid "Options:"
msgstr "Опции:"
#: src/main-window.vala:145
#, c-format
msgid "Error: %s is not a file."
msgstr "Ошибка: %s - это не файл."
msgid " --help, -h Show this help"
msgstr " --help, -h Показать эту справку"
#: src/main-window.vala:153
msgid "Repack RPM package?"
msgstr "Перепаковать RPM-пакет?"
msgid " --version, -v Show version information"
msgstr " --version, -v Показать информацию о версии"
#: src/main-window.vala:154
msgid "Do you want to repack the rpm file to override dependencies?"
msgstr "Перепаковать ли rpm файл для переопределения зависимостей?"
#: src/main-window.vala:156
msgid "No"
msgstr "Нет"
#: src/main-window.vala:157
msgid "Yes"
msgstr "Да"
msgid "Pass the path to the package if you don't want to use the file selection dialog."
msgstr "Передайте путь к пакету, если не хотите использовать окно выбора файла."
#: src/main-window.vala:178
msgid "Canceled"
msgstr "Отменено"
msgid "Package path not specified. Calling package selection function..."
msgstr "Путь к пакету не указан. Вызов функции выбора пакета..."
#: src/main-window.vala:187
#, c-format
msgid "Launching: %s"
msgstr "Запуск: %s"
msgid "epmgpi has detected that you are running a file.\nLaunching extraneous files can lead to unforeseen consequences."
msgstr "epmgpi обнаружил, что вы запускаете файл.\nЗапуск посторонних файлов может привести к непредвиденным последствиям."
#: src/main-window.vala:192
msgid "Launch failed"
msgstr "Не удалось запустить"
#: src/main-window.vala:197
msgid "epmgpi has detected that you are running a file."
msgstr "epmgpi обнаружил, что вы запускаете файл."
#: src/main-window.vala:199
msgid "Launching extraneous files can lead to unforeseen consequences."
msgstr ""
"Запуск посторонних файлов может привести к непредвиденным последствиям."
#: src/main-window.vala:202
msgid "Do you really want to run the file?"
msgstr "Вы действительно хотите запустить файл?"
msgid "Additionally, the file needs execute permissions.\n\nDo you want to grant the file execute permissions and run it?"
msgstr "Кроме того, файлу необходимы права на выполнение.\n\nВы хотите предоставить файлу права на выполнение и запустить его?"
#: src/main-window.vala:203
msgid "Additionally, the file needs execute permissions."
msgstr "Кроме того, файлу необходимы права на выполнение."
msgid "Error: %s is not a file."
msgstr "Ошибка: %s - это не файл."
#: src/main-window.vala:205
msgid "Do you want to grant the file execute permissions and run it?"
msgstr "Вы хотите предоставить файлу права на выполнение и запустить его?"
msgid "Package path contains spaces"
msgstr "Путь к пакету содержит пробелы"
#: src/main.vala:15
msgid "Version:"
msgstr "Версия:"
#: src/main.vala:24 src/main.vala:34
msgid "epmgpi cannot be run as root user."
msgstr "Нельзя запускать epmgpi от пользователя root."
msgid "Arguments passed: %s"
msgstr "Переданы аргументы: %s"
#: src/window.blp:5 src/window.blp:14 src/start-page.blp:6
msgid "Package Installation"
msgstr "Установка пакета"
#: src/start-page.blp:34
msgid "Install packages with EPM"
msgstr "Установка пакетов через EPM"
#: src/start-page.blp:42
msgid "RPM, DEB, RUN and AppImage files"
msgstr "Файлы RPM, DEB, RUN и AppImage"
#: src/start-page.blp:50
msgid "Choose File"
msgstr "Выбрать файл"
#: src/review-page.blp:6 src/installing-page.blp:47
msgid "Package"
msgstr "Пакет"
#: src/review-page.blp:42
msgid "Ready to install"
msgstr "Готово к установке"
#: src/review-page.blp:50
msgid "The selected package will be installed with EPM."
msgstr "Выбранный пакет будет установлен через EPM."
#: src/review-page.blp:60 src/unsupported-page.blp:49
#: src/installing-page.blp:50
msgid "Selected file"
msgstr "Выбранный файл"
#: src/review-page.blp:63 src/installing-page.blp:51
msgid "No file selected"
msgstr "Файл не выбран"
#: src/review-page.blp:77
msgid "Install"
msgstr "Установить"
#: src/unsupported-page.blp:6 src/unsupported-page.blp:34
msgid "Unsupported file"
msgstr "Неподдерживаемый файл"
#: src/unsupported-page.blp:52
msgid "File"
msgstr "Файл"
#: src/unsupported-page.blp:76
msgid "Cancel"
msgstr "Отмена"
#: src/unsupported-page.blp:82
msgid "Run"
msgstr "Запустить"
#: src/installing-page.blp:6 src/installing-page.blp:38
msgid "Installing"
msgstr "Установка"
#: src/installing-page.blp:59 src/result-page.blp:47
msgid "Log"
msgstr "Лог"
namespace Epmgpi {
public class Application : Adw.Application {
private MainWindow? window;
private string[] startup_paths = {};
public Application () {
Object (
application_id: "org.altlinux.epmgpi",
flags: ApplicationFlags.NON_UNIQUE
);
}
public override void activate () {
MainWindow main_window = ensure_window ();
main_window.present ();
if (startup_paths.length > 0) {
main_window.enqueue_paths (startup_paths);
startup_paths = {};
}
}
public override void open (File[] files, string hint) {
MainWindow main_window = ensure_window ();
string[] paths = {};
foreach (File file in files) {
paths += file.get_path () ?? file.get_uri ();
}
main_window.enqueue_paths (paths);
main_window.present ();
}
public void set_startup_paths (string[] paths) {
startup_paths = paths;
}
private MainWindow ensure_window () {
if (window == null) {
window = new MainWindow (this);
}
return window;
}
}
}
namespace Epmgpi {
[Compact]
public class Cli {
public static void init_locale () {
Intl.setlocale (LocaleCategory.ALL, "");
Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
Intl.textdomain (Config.GETTEXT_PACKAGE);
}
public static void show_help () {
stdout.printf ("%s\n\n", _("Usage: epmgpi [option] [path-to-package]"));
stdout.printf ("%s\n", _("Options:"));
stdout.printf ("%s\n", _(" --help, -h Show this help"));
stdout.printf ("%s\n", _(" --version, -v Show version information"));
stdout.printf (
"%s\n",
_("Pass the path to the package if you don't want to use the file selection dialog.")
);
}
public static bool is_root_user () {
try {
var credentials = new Credentials ();
return credentials.get_unix_user () == 0;
} catch (Error error) {
return Environment.get_user_name () == "root";
}
}
}
}
namespace Epmgpi.Config {
public const string VERSION = @VERSION@;
public const string GETTEXT_PACKAGE = @GETTEXT_PACKAGE@;
public const string LOCALEDIR = @LOCALEDIR@;
public const string PKGDATADIR = @PKGDATADIR@;
}
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/ru/eepm/GPI">
<file compressed="true" preprocess="xml-stripblanks">window.ui</file>
<file compressed="true" preprocess="xml-stripblanks">start-page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">review-page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">unsupported-page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">installing-page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">result-page.ui</file>
</gresource>
</gresources>
namespace Epmgpi {
internal string _(string text) {
return dgettext (Config.GETTEXT_PACKAGE, text);
}
}
using Gtk 4.0;
using Adw 1;
template $EpmgpiInstallingPage : Adw.NavigationPage {
tag: "installing";
title: _("Installing");
can-pop: false;
child: Gtk.ScrolledWindow {
hscrollbar-policy: never;
propagate-natural-height: true;
vexpand: true;
Adw.Clamp {
maximum-size: 700;
tightening-threshold: 500;
Gtk.Box {
orientation: vertical;
spacing: 20;
valign: center;
margin-top: 24;
margin-bottom: 24;
margin-start: 24;
margin-end: 24;
Gtk.Box {
orientation: vertical;
spacing: 10;
halign: center;
Adw.Spinner {
width-request: 72;
height-request: 72;
}
Gtk.Label {
label: _("Installing");
xalign: 0.5;
justify: center;
wrap: true;
styles ["title-1"]
}
}
Adw.PreferencesGroup {
title: _("Package");
Adw.ActionRow installing_file_row {
title: _("Selected file");
subtitle: _("No file selected");
subtitle-selectable: true;
subtitle-lines: 2;
}
}
Adw.PreferencesGroup {
Adw.ExpanderRow {
title: _("Log");
Gtk.ScrolledWindow {
min-content-height: 120;
max-content-height: 180;
vexpand: false;
has-frame: true;
Gtk.TextView log_view {
editable: false;
cursor-visible: false;
monospace: true;
wrap-mode: word_char;
top-margin: 10;
bottom-margin: 10;
left-margin: 10;
right-margin: 10;
}
}
}
}
}
}
};
}
using Adw;
using Gtk;
namespace Epmgpi {
[GtkTemplate (ui = "/ru/eepm/GPI/installing-page.ui")]
public class InstallingPage : Adw.NavigationPage {
[GtkChild] private unowned Adw.ActionRow installing_file_row;
[GtkChild] private unowned Gtk.TextView log_view;
public void set_package_file (PackageFile package_file) {
installing_file_row.subtitle = package_file.path;
}
public void append_log (string text) {
append_to_buffer (log_view.buffer, text);
}
public void clear_log () {
log_view.buffer.set_text ("", 0);
}
private void append_to_buffer (TextBuffer buffer, string text) {
TextIter end;
buffer.get_end_iter (out end);
buffer.insert (ref end, text + "\n", -1);
}
}
}
using Adw;
using Gtk;
namespace Epmgpi {
[GtkTemplate (ui = "/ru/eepm/GPI/window.ui")]
public class MainWindow : Adw.ApplicationWindow {
[GtkChild] private unowned Adw.NavigationView navigation_view;
[GtkChild] private unowned Adw.ToastOverlay toast_overlay;
[GtkChild] private unowned StartPage start_page;
[GtkChild] private unowned ReviewPage review_page;
[GtkChild] private unowned UnsupportedPage unsupported_page;
[GtkChild] private unowned InstallingPage installing_page;
[GtkChild] private unowned ResultPage result_page;
private Queue<PackageFile> queue = new Queue<PackageFile> ();
private PackageInstaller installer;
private bool busy = false;
public MainWindow (Application app) {
Object (application: app);
}
construct {
installer = new PackageInstaller (append_log);
setup_review_breakpoint ();
start_page.choose_file_requested.connect (() => choose_file.begin ());
result_page.choose_another_requested.connect (() => {
if (!busy) {
choose_file.begin ();
}
});
}
private void setup_review_breakpoint () {
var breakpoint = new Adw.Breakpoint (
Adw.BreakpointCondition.parse ("max-height: 420sp")
);
breakpoint.apply.connect (() => review_page.set_compact_header (true));
breakpoint.unapply.connect (() => review_page.set_compact_header (false));
add_breakpoint (breakpoint);
}
public void enqueue_paths (string[] paths) {
foreach (string path in paths) {
queue.push_tail (PackageFile.from_commandline_arg (path));
}
if (!busy) {
process_queue.begin ();
}
}
private async void choose_file () {
var dialog = new Gtk.FileDialog ();
dialog.title = _("Choose package");
dialog.filters = create_file_filters ();
dialog.default_filter = (Gtk.FileFilter) dialog.filters.get_item (0);
try {
File file = yield dialog.open (this, null);
queue.push_tail (new PackageFile (file));
if (!busy) {
process_queue.begin ();
}
} catch (Error error) {
if (!(error is IOError.CANCELLED)) {
string message = _("File selection failed: %s");
append_log (message.printf (error.message));
show_result (_("File selection failed"), "dialog-error-symbolic");
}
}
}
private GLib.ListStore create_file_filters () {
var filters = new GLib.ListStore (typeof (Gtk.FileFilter));
var packages = new Gtk.FileFilter ();
packages.name = _("Packages");
packages.add_suffix ("rpm");
packages.add_suffix ("deb");
packages.add_suffix ("run");
packages.add_suffix ("appimage");
packages.add_suffix ("AppImage");
packages.add_suffix ("Appimage");
filters.append (packages);
var all_files = new Gtk.FileFilter ();
all_files.name = _("All files");
all_files.add_pattern ("*");
filters.append (all_files);
return filters;
}
private async void process_queue () {
if (busy) {
return;
}
busy = true;
start_page.set_choose_sensitive (false);
result_page.set_choose_sensitive (false);
while (!queue.is_empty ()) {
PackageFile package_file = queue.pop_head ();
prepare_package_pages (package_file);
if (!(yield validate_regular_file (package_file))) {
yield maybe_wait_for_next_file ();
continue;
}
if (!package_file.has_supported_extension ()) {
yield handle_unsupported_file (package_file);
yield maybe_wait_for_next_file ();
continue;
}
show_page (review_page);
yield review_page.wait_for_install ();
bool repack = false;
if (package_file.is_rpm ()) {
repack = yield ask_repack ();
}
yield install_package (package_file, repack);
yield maybe_wait_for_next_file ();
}
start_page.set_choose_sensitive (true);
result_page.set_choose_sensitive (true);
busy = false;
}
private async bool validate_regular_file (PackageFile package_file) {
try {
if (yield package_file.is_regular ()) {
return true;
}
} catch (Error error) {
append_log (error.message);
}
string message = _("Error: %s is not a file.");
append_log (message.printf (package_file.path));
show_result (_("Package not installed."), "dialog-error-symbolic");
return false;
}
private async bool ask_repack () {
var dialog = new Adw.AlertDialog (
_("Repack RPM package?"),
_("Do you want to repack the rpm file to override dependencies?")
);
dialog.add_response ("no", _("No"));
dialog.add_response ("yes", _("Yes"));
dialog.default_response = "no";
dialog.close_response = "no";
dialog.set_response_appearance ("yes", Adw.ResponseAppearance.SUGGESTED);
string response = yield dialog.choose (this, null);
return response == "yes";
}
private async void handle_unsupported_file (PackageFile package_file) {
bool executable = false;
try {
executable = yield package_file.is_executable ();
} catch (Error error) {
append_log (error.message);
}
unsupported_page.set_file (package_file, unsupported_warning (executable));
show_page (unsupported_page);
if (!(yield unsupported_page.wait_for_response ())) {
show_result (_("Canceled"), "dialog-information-symbolic");
return;
}
try {
if (!executable) {
package_file.grant_execute_permission ();
}
append_log (_("Launching: %s").printf (package_file.path));
package_file.launch ();
close ();
} catch (Error error) {
append_log (error.message);
show_result (_("Launch failed"), "dialog-error-symbolic");
}
}
private string unsupported_warning (bool executable) {
string body = _("epmgpi has detected that you are running a file.");
body += "\n";
body += _("Launching extraneous files can lead to unforeseen consequences.");
body += "\n\n";
body += executable
? _("Do you really want to run the file?")
: _("Additionally, the file needs execute permissions.")
+ "\n\n"
+ _("Do you want to grant the file execute permissions and run it?");
return body;
}
private async void install_package (PackageFile package_file, bool repack) {
show_page (installing_page);
InstallResult result = yield installer.install (package_file, repack);
show_result (result.title, result.icon_name);
send_notification (result.title);
}
private void prepare_package_pages (PackageFile package_file) {
reset_navigation ();
review_page.set_package_file (package_file);
installing_page.set_package_file (package_file);
clear_log ();
}
private void append_log (string text) {
installing_page.append_log (text);
result_page.append_log (text);
}
private void clear_log () {
installing_page.clear_log ();
result_page.clear_log ();
}
private void show_result (string title, string icon_name) {
result_page.show_result (title, icon_name, !queue.is_empty ());
show_page (result_page);
}
private void show_page (Adw.NavigationPage page) {
if (navigation_view.visible_page != page) {
navigation_view.push (page);
}
}
private void reset_navigation () {
navigation_view.replace ({ start_page });
}
private async void maybe_wait_for_next_file () {
if (!queue.is_empty ()) {
yield result_page.wait_for_choose_another ();
}
}
private void send_notification (string title) {
toast_overlay.add_toast (new Adw.Toast (title));
var notification = new Notification (title);
notification.set_icon (new ThemedIcon ("epmgpi"));
((Application) application).send_notification (null, notification);
}
}
}
namespace Epmgpi {
public static int main (string[] args) {
Cli.init_locale ();
if (args.length > 1) {
string[] paths = {};
for (int i = 1; i < args.length; i++) {
switch (args[i]) {
case "--help":
case "-h":
Cli.show_help ();
return 0;
case "--version":
case "-v":
stdout.printf ("%s %s\n", _("Version:"), Config.VERSION);
return 0;
default:
paths += args[i];
break;
}
}
if (Cli.is_root_user ()) {
stderr.printf ("%s\n", _("epmgpi cannot be run as root user."));
return 1;
}
var app = new Application ();
app.set_startup_paths (paths);
return app.run ({ args[0] });
}
if (Cli.is_root_user ()) {
stderr.printf ("%s\n", _("epmgpi cannot be run as root user."));
return 1;
}
var app = new Application ();
app.set_startup_paths ({});
return app.run (args);
}
}
namespace Epmgpi {
public class PackageFile {
private File package_file;
private string display_path;
public File file {
get {
return package_file;
}
}
public string path {
get {
return display_path;
}
}
public string display_name {
owned get {
return file.get_basename () ?? path;
}
}
public PackageFile (File file) {
package_file = file;
display_path = file.get_path () ?? file.get_parse_name ();
}
public static PackageFile from_commandline_arg (string arg) {
return new PackageFile (File.new_for_commandline_arg (arg));
}
public bool has_supported_extension () {
string lower = path.down ();
return lower.has_suffix (".rpm")
|| lower.has_suffix (".deb")
|| lower.has_suffix (".run")
|| lower.has_suffix (".appimage");
}
public bool is_rpm () {
return path.down ().has_suffix (".rpm");
}
public async bool is_regular () throws Error {
FileInfo info = yield file.query_info_async (
FileAttribute.STANDARD_TYPE,
FileQueryInfoFlags.NONE,
Priority.DEFAULT,
null
);
return info.get_file_type () == FileType.REGULAR;
}
public async bool is_executable () throws Error {
FileInfo info = yield file.query_info_async (
FileAttribute.ACCESS_CAN_EXECUTE,
FileQueryInfoFlags.NONE,
Priority.DEFAULT,
null
);
return info.get_attribute_boolean (FileAttribute.ACCESS_CAN_EXECUTE);
}
public void grant_execute_permission () throws Error {
FileInfo info = file.query_info (
FileAttribute.UNIX_MODE,
FileQueryInfoFlags.NONE,
null
);
uint32 mode = info.get_attribute_uint32 (FileAttribute.UNIX_MODE);
file.set_attribute_uint32 (
FileAttribute.UNIX_MODE,
mode | 0111,
FileQueryInfoFlags.NONE,
null
);
}
public void launch () throws Error {
var subprocess = new Subprocess (SubprocessFlags.NONE, path, null);
subprocess.wait_async.begin (null);
}
}
}
namespace Epmgpi {
public delegate void InstallerOutputFunc (string line);
[Compact (opaque = true)]
public class InstallResult {
private string display_title;
private string result_icon_name;
public string title {
get {
return display_title;
}
}
public string icon_name {
get {
return result_icon_name;
}
}
public InstallResult (string title, string icon_name) {
display_title = title;
result_icon_name = icon_name;
}
}
public class PackageInstaller {
private InstallerOutputFunc output;
public PackageInstaller (owned InstallerOutputFunc output) {
this.output = (owned) output;
}
public async InstallResult install (PackageFile package_file, bool repack) {
string installing_message = _("Installing: %s");
output (installing_message.printf (package_file.path));
try {
Subprocess subprocess = create_subprocess (package_file, repack);
yield read_stream (subprocess.get_stdout_pipe ());
int exit_code = 0;
try {
yield subprocess.wait_check_async (null);
} catch (Error error) {
exit_code = subprocess.get_exit_status ();
}
return result_from_exit_code (exit_code);
} catch (Error error) {
output (error.message);
return new InstallResult (
_("Package not installed."),
"dialog-error-symbolic"
);
}
}
private Subprocess create_subprocess (PackageFile package_file, bool repack) throws Error {
if (repack) {
return new Subprocess (
SubprocessFlags.STDOUT_PIPE | SubprocessFlags.STDERR_MERGE,
"/usr/bin/pkexec",
"/usr/bin/epm",
"--auto",
"--repack",
"-i",
package_file.path,
null
);
}
return new Subprocess (
SubprocessFlags.STDOUT_PIPE | SubprocessFlags.STDERR_MERGE,
"/usr/bin/pkexec",
"/usr/bin/epm",
"--auto",
"-i",
package_file.path,
null
);
}
private InstallResult result_from_exit_code (int exit_code) {
if (exit_code == 0) {
output (_("Command completed successfully"));
return new InstallResult (
_("Package installed!"),
"epmgpi"
);
}
if (exit_code == 126) {
string title = _("Package not installed. Action canceled by the user.");
output (title);
return new InstallResult (
title,
"dialog-information-symbolic"
);
}
if (exit_code == 100) {
string title = _("Package not installed. Command failed.");
output (title);
return new InstallResult (
title,
"dialog-error-symbolic"
);
}
string title = _("Package not installed.");
output ("%s (%d)".printf (title, exit_code));
return new InstallResult (
title,
"dialog-error-symbolic"
);
}
private async void read_stream (InputStream stream) throws Error {
var data_stream = new DataInputStream (stream);
string? line;
while ((line = yield data_stream.read_line_async (Priority.DEFAULT, null)) != null) {
output (line);
}
}
}
}
using Gtk 4.0;
using Adw 1;
template $EpmgpiResultPage : Adw.NavigationPage {
tag: "result";
title: _("Package installed!");
can-pop: false;
child: Gtk.ScrolledWindow {
hscrollbar-policy: never;
propagate-natural-height: true;
Adw.Clamp {
maximum-size: 700;
tightening-threshold: 500;
Gtk.Box {
orientation: vertical;
spacing: 20;
valign: center;
margin-top: 24;
margin-bottom: 24;
margin-start: 24;
margin-end: 24;
Gtk.Box {
orientation: vertical;
spacing: 10;
halign: center;
Gtk.Image result_status_icon {
icon-name: "epmgpi";
pixel-size: 128;
accessible-role: presentation;
}
Gtk.Label result_status_label {
label: _("Package installed!");
xalign: 0.5;
justify: center;
wrap: true;
styles ["title-1"]
}
}
Adw.PreferencesGroup {
Adw.ExpanderRow {
title: _("Log");
Gtk.ScrolledWindow {
min-content-height: 120;
max-content-height: 180;
vexpand: false;
has-frame: true;
Gtk.TextView result_log_view {
editable: false;
cursor-visible: false;
monospace: true;
wrap-mode: word_char;
top-margin: 10;
bottom-margin: 10;
left-margin: 10;
right-margin: 10;
}
}
}
}
Gtk.Button choose_another_button {
label: _("Choose Another File");
halign: center;
width-request: 220;
styles ["suggested-action", "pill"]
}
}
}
};
}
using Adw;
using Gtk;
namespace Epmgpi {
[GtkTemplate (ui = "/ru/eepm/GPI/result-page.ui")]
public class ResultPage : Adw.NavigationPage {
[GtkChild] private unowned Gtk.Image result_status_icon;
[GtkChild] private unowned Gtk.Label result_status_label;
[GtkChild] private unowned Gtk.TextView result_log_view;
[GtkChild] private unowned Gtk.Button choose_another_button;
public signal void choose_another_requested ();
construct {
choose_another_button.clicked.connect (() => choose_another_requested ());
}
public void show_result (string title, string icon_name, bool has_next_file) {
result_status_label.label = title;
result_status_icon.icon_name = icon_name;
choose_another_button.label = has_next_file ? _("Next File") : _("Choose Another File");
choose_another_button.sensitive = true;
}
public void set_choose_sensitive (bool sensitive) {
choose_another_button.sensitive = sensitive;
}
public async void wait_for_choose_another () {
SourceFunc resume = wait_for_choose_another.callback;
ulong handler = choose_another_requested.connect (() => resume ());
yield;
disconnect (handler);
}
public void append_log (string text) {
append_to_buffer (result_log_view.buffer, text);
}
public void clear_log () {
result_log_view.buffer.set_text ("", 0);
}
private void append_to_buffer (TextBuffer buffer, string text) {
TextIter end;
buffer.get_end_iter (out end);
buffer.insert (ref end, text + "\n", -1);
}
}
}
using Gtk 4.0;
using Adw 1;
template $EpmgpiReviewPage : Adw.NavigationPage {
tag: "review";
title: _("Package");
can-pop: false;
child: Gtk.ScrolledWindow {
hscrollbar-policy: never;
propagate-natural-height: true;
vexpand: true;
Adw.Clamp {
maximum-size: 680;
tightening-threshold: 520;
Gtk.Box {
orientation: vertical;
spacing: 24;
valign: center;
margin-top: 24;
margin-bottom: 24;
margin-start: 24;
margin-end: 24;
Gtk.Box review_hero_box {
orientation: vertical;
spacing: 10;
halign: center;
Gtk.Image review_hero_icon {
icon-name: "epmgpi";
pixel-size: 128;
accessible-role: presentation;
}
Gtk.Box review_hero_text_box {
orientation: vertical;
spacing: 6;
Gtk.Label review_title_label {
label: _("Ready to install");
xalign: 0.5;
justify: center;
wrap: true;
styles ["title-1"]
}
Gtk.Label review_description_label {
label: _("The selected package will be installed with EPM.");
xalign: 0.5;
justify: center;
wrap: true;
styles ["dim-label"]
}
}
}
Adw.PreferencesGroup {
title: _("Selected file");
Adw.ActionRow review_file_row {
title: _("No file selected");
subtitle-selectable: true;
subtitle-lines: 2;
[prefix]
Gtk.Image {
icon-name: "package-x-generic-symbolic";
pixel-size: 42;
valign: center;
accessible-role: presentation;
}
}
}
Gtk.Button install_button {
label: _("Install");
halign: center;
width-request: 220;
styles ["suggested-action", "pill"]
}
}
}
};
}
using Adw;
using Gtk;
namespace Epmgpi {
[GtkTemplate (ui = "/ru/eepm/GPI/review-page.ui")]
public class ReviewPage : Adw.NavigationPage {
[GtkChild] private unowned Gtk.Button install_button;
[GtkChild] private unowned Gtk.Box review_hero_box;
[GtkChild] private unowned Gtk.Image review_hero_icon;
[GtkChild] private unowned Gtk.Box review_hero_text_box;
[GtkChild] private unowned Gtk.Label review_title_label;
[GtkChild] private unowned Gtk.Label review_description_label;
[GtkChild] private unowned Adw.ActionRow review_file_row;
public void set_package_file (PackageFile package_file) {
review_file_row.title = package_file.display_name;
review_file_row.subtitle = package_file.path;
}
public async void wait_for_install () {
SourceFunc resume = wait_for_install.callback;
ulong handler = install_button.clicked.connect (() => resume ());
yield;
install_button.disconnect (handler);
}
public void set_compact_header (bool compact) {
review_hero_box.orientation = compact ? Orientation.HORIZONTAL : Orientation.VERTICAL;
review_hero_box.spacing = compact ? 20 : 10;
review_hero_icon.pixel_size = compact ? 96 : 128;
review_hero_text_box.valign = compact ? Align.CENTER : Align.FILL;
review_title_label.xalign = compact ? 0 : 0.5f;
review_title_label.justify = compact ? Justification.LEFT : Justification.CENTER;
review_description_label.xalign = compact ? 0 : 0.5f;
review_description_label.justify = compact ? Justification.LEFT : Justification.CENTER;
}
}
}
using Gtk 4.0;
using Adw 1;
template $EpmgpiStartPage : Adw.NavigationPage {
tag: "start";
title: _("Package Installation");
can-pop: false;
child: Gtk.ScrolledWindow {
hscrollbar-policy: never;
propagate-natural-height: true;
vexpand: true;
Adw.Clamp {
maximum-size: 420;
tightening-threshold: 360;
Gtk.Box {
orientation: vertical;
spacing: 18;
halign: center;
valign: center;
margin-top: 48;
margin-bottom: 48;
margin-start: 36;
margin-end: 36;
Gtk.Image {
icon-name: "epmgpi";
pixel-size: 156;
accessible-role: presentation;
}
Gtk.Label {
label: _("Install packages with EPM");
xalign: 0.5;
justify: center;
wrap: true;
styles ["title-2"]
}
Gtk.Label {
label: _("RPM, DEB, RUN and AppImage files");
xalign: 0.5;
justify: center;
wrap: true;
styles ["dim-label"]
}
Gtk.Button choose_button {
label: _("Choose File");
halign: center;
margin-top: 10;
width-request: 220;
styles ["suggested-action", "pill"]
}
}
}
};
}
using Adw;
using Gtk;
namespace Epmgpi {
[GtkTemplate (ui = "/ru/eepm/GPI/start-page.ui")]
public class StartPage : Adw.NavigationPage {
[GtkChild] private unowned Gtk.Button choose_button;
public signal void choose_file_requested ();
construct {
choose_button.clicked.connect (() => choose_file_requested ());
}
public void set_choose_sensitive (bool sensitive) {
choose_button.sensitive = sensitive;
}
}
}
using Gtk 4.0;
using Adw 1;
template $EpmgpiUnsupportedPage : Adw.NavigationPage {
tag: "unsupported";
title: _("Unsupported file");
can-pop: false;
child: Gtk.ScrolledWindow {
hscrollbar-policy: never;
propagate-natural-height: true;
vexpand: true;
Adw.Clamp {
maximum-size: 560;
tightening-threshold: 460;
Gtk.Box {
orientation: vertical;
spacing: 18;
halign: center;
valign: center;
margin-top: 36;
margin-bottom: 36;
margin-start: 24;
margin-end: 24;
Gtk.Image {
icon-name: "dialog-warning-symbolic";
pixel-size: 128;
accessible-role: presentation;
}
Gtk.Label {
label: _("Unsupported file");
xalign: 0.5;
justify: center;
wrap: true;
styles ["title-1"]
}
Gtk.Label unsupported_description_label {
xalign: 0.5;
justify: center;
wrap: true;
styles ["dim-label"]
}
Adw.PreferencesGroup {
title: _("Selected file");
Adw.ActionRow {
title: _("File");
[prefix]
Gtk.Image {
icon-name: "text-x-generic-symbolic";
pixel-size: 32;
valign: center;
accessible-role: presentation;
}
[suffix]
Gtk.Label unsupported_file_label {
ellipsize: middle;
max-width-chars: 36;
selectable: true;
}
}
}
Gtk.Box {
orientation: horizontal;
spacing: 12;
halign: center;
Gtk.Button cancel_unsupported_button {
label: _("Cancel");
width-request: 150;
styles ["pill"]
}
Gtk.Button run_unsupported_button {
label: _("Run");
width-request: 150;
styles ["destructive-action", "pill"]
}
}
}
}
};
}
using Adw;
using Gtk;
namespace Epmgpi {
[GtkTemplate (ui = "/ru/eepm/GPI/unsupported-page.ui")]
public class UnsupportedPage : Adw.NavigationPage {
[GtkChild] private unowned Gtk.Label unsupported_description_label;
[GtkChild] private unowned Gtk.Label unsupported_file_label;
[GtkChild] private unowned Gtk.Button cancel_unsupported_button;
[GtkChild] private unowned Gtk.Button run_unsupported_button;
public void set_file (PackageFile package_file, string warning) {
unsupported_description_label.label = warning;
unsupported_file_label.label = package_file.path;
}
public async bool wait_for_response () {
bool should_run = false;
SourceFunc resume = wait_for_response.callback;
ulong cancel_handler = cancel_unsupported_button.clicked.connect (() => {
should_run = false;
resume ();
});
ulong run_handler = run_unsupported_button.clicked.connect (() => {
should_run = true;
resume ();
});
yield;
cancel_unsupported_button.disconnect (cancel_handler);
run_unsupported_button.disconnect (run_handler);
return should_run;
}
}
}
using Gtk 4.0;
using Adw 1;
template $EpmgpiMainWindow : Adw.ApplicationWindow {
title: _("Package Installation");
default-width: 780;
default-height: 600;
Adw.ToolbarView {
[top]
Adw.HeaderBar {
title-widget: Adw.WindowTitle {
title: _("epmgpi");
subtitle: _("Package Installation");
};
}
Adw.ToastOverlay toast_overlay {
Adw.NavigationView navigation_view {
animate-transitions: true;
pop-on-escape: false;
hhomogeneous: false;
vhomogeneous: false;
$EpmgpiStartPage start_page {}
$EpmgpiReviewPage review_page {}
$EpmgpiUnsupportedPage unsupported_page {}
$EpmgpiInstallingPage installing_page {}
$EpmgpiResultPage result_page {}
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment