mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-22 12:33:05 +08:00
236 lines
13 KiB
Plaintext
236 lines
13 KiB
Plaintext
import { ScrollView, TextEdit } from "std-widgets.slint";
|
|
import { SettingsDialog, SettingsButton } from "settings_controls.slint";
|
|
import { WorkbenchStyle } from "workbench_controls.slint";
|
|
import { UiRadius } from "ui_radius.slint";
|
|
import { GalleryStrings } from "device_strings.slint";
|
|
import { FontAwesomeIcons } from "common.slint";
|
|
import "../assets/fonts/message_spacing.ttf";
|
|
|
|
export enum AboutPage { overview, components, component, document, source }
|
|
export struct AboutDocument { title: string, text: string }
|
|
export struct AboutComponent {
|
|
id: string,
|
|
name: string,
|
|
version: string,
|
|
license: string,
|
|
source-url: string,
|
|
documents: [AboutDocument],
|
|
}
|
|
|
|
export global AboutStrings {
|
|
out property <string> software-license: GalleryStrings.tr("软件许可", "Software license", "Лицензия программы");
|
|
out property <string> components: GalleryStrings.tr("开源组件", "Open-source components", "Компоненты с открытым кодом");
|
|
out property <string> source: GalleryStrings.tr("源码与构建说明", "Source code and build instructions", "Исходный код и сборка");
|
|
out property <string> notices: GalleryStrings.tr("许可与版权声明", "Licenses and copyright notices", "Лицензии и авторские права");
|
|
out property <string> view-source: GalleryStrings.tr("查看源码", "View source code", "Открыть исходный код");
|
|
out property <string> back: GalleryStrings.tr("返回", "Back", "Назад");
|
|
}
|
|
|
|
export component AboutNavigationGroup inherits Rectangle {
|
|
height: rows.preferred-height + 2px;
|
|
background: WorkbenchStyle.surface;
|
|
border-radius: UiRadius.control;
|
|
border-width: 1px; border-color: WorkbenchStyle.separator;
|
|
clip: true;
|
|
rows := VerticalLayout {
|
|
x: 1px; y: 1px; width: parent.width - 2px;
|
|
height: self.preferred-height; padding: 0px; spacing: 0px;
|
|
@children
|
|
}
|
|
}
|
|
|
|
export component AboutRowSeparator inherits Rectangle {
|
|
height: 1px;
|
|
Rectangle {
|
|
x: 14px; width: parent.width - 30px; height: 1px;
|
|
background: WorkbenchStyle.separator;
|
|
}
|
|
}
|
|
|
|
export component AboutNavigationRow inherits Rectangle {
|
|
in property <string> title;
|
|
in property <string> subtitle;
|
|
in property <string> icon;
|
|
in property <string> detail;
|
|
in property <bool> grouped: false;
|
|
in property <bool> external: false;
|
|
callback clicked;
|
|
min-width: 0px;
|
|
min-height: max(44px, labels.preferred-height + 20px);
|
|
background: touch.pressed ? WorkbenchStyle.pressed-surface
|
|
: touch.has-hover ? WorkbenchStyle.hover-surface : WorkbenchStyle.surface;
|
|
border-radius: root.grouped ? 0px : UiRadius.control;
|
|
border-width: root.grouped ? 0px : 1px; border-color: WorkbenchStyle.separator;
|
|
accessible-role: button;
|
|
accessible-label: root.title + (root.subtitle != "" ? ", " + root.subtitle : "")
|
|
+ (root.detail != "" ? ", " + root.detail : "");
|
|
accessible-action-default => { root.clicked(); }
|
|
if root.icon != "": Rectangle {
|
|
x: 12px; y: (parent.height - self.height) / 2;
|
|
width: 28px; height: 28px;
|
|
border-radius: UiRadius.control;
|
|
background: WorkbenchStyle.field-surface;
|
|
Text {
|
|
text: root.icon; font-family: "Font Awesome 6 Free"; font-weight: 900;
|
|
font-size: 13px; color: WorkbenchStyle.muted;
|
|
horizontal-alignment: center; vertical-alignment: center;
|
|
accessible-role: none;
|
|
}
|
|
}
|
|
labels := VerticalLayout {
|
|
x: root.icon != "" ? 52px : 14px;
|
|
y: (parent.height - self.height) / 2;
|
|
width: parent.width - self.x - 36px - (root.detail != "" ? detail-label.width + 12px : 0px);
|
|
height: self.preferred-height; spacing: 4px;
|
|
Text { text: root.title; color: WorkbenchStyle.text; font-size: 13px; wrap: word-wrap; }
|
|
if root.subtitle != "": Text {
|
|
text: root.subtitle; color: WorkbenchStyle.muted; font-size: 11px; wrap: word-wrap;
|
|
}
|
|
}
|
|
detail-label := Text {
|
|
x: parent.width - self.width - 36px; height: parent.height;
|
|
width: min(100px, self.preferred-width);
|
|
text: root.detail; color: WorkbenchStyle.muted; font-size: 11px;
|
|
vertical-alignment: center; overflow: elide;
|
|
accessible-role: none;
|
|
}
|
|
Text {
|
|
x: parent.width - 30px; width: 18px; height: parent.height;
|
|
text: root.external ? FontAwesomeIcons.arrow-up-right-from-square : FontAwesomeIcons.angle-right;
|
|
font-family: "Font Awesome 6 Free"; font-weight: 900;
|
|
color: touch.has-hover ? WorkbenchStyle.accent : WorkbenchStyle.muted;
|
|
font-size: 11px; vertical-alignment: center; horizontal-alignment: center;
|
|
accessible-role: none;
|
|
}
|
|
touch := TouchArea { mouse-cursor: pointer; clicked => { root.clicked(); } }
|
|
}
|
|
|
|
export component AboutPanel inherits SettingsDialog {
|
|
show-close-button: false;
|
|
in-out property <AboutPage> page: AboutPage.components;
|
|
in-out property <int> component-index: 0;
|
|
private property <int> document-index: 0;
|
|
in property <[AboutComponent]> components;
|
|
in property <int> openfec-index: -1;
|
|
in property <string> revision;
|
|
in property <string> source-url;
|
|
in property <string> build-url;
|
|
private property <AboutComponent> selected: root.components[root.component-index];
|
|
callback back;
|
|
callback open-link(string);
|
|
title: root.page == AboutPage.components ? AboutStrings.components
|
|
: root.page == AboutPage.source ? AboutStrings.source
|
|
: root.page == AboutPage.document ? AboutStrings.notices
|
|
: root.selected.name;
|
|
|
|
if root.page != AboutPage.document: ScrollView {
|
|
x: 24px; y: root.content-top; width: parent.width - 48px + 22px;
|
|
height: footer.y - self.y - 16px;
|
|
viewport-width: self.visible-width;
|
|
viewport-height: content.preferred-height;
|
|
horizontal-scrollbar-policy: always-off;
|
|
vertical-scrollbar-policy: as-needed;
|
|
content := VerticalLayout {
|
|
width: parent.width; height: self.preferred-height;
|
|
padding: 0px; padding-right: 22px; spacing: 10px;
|
|
if root.page == AboutPage.components: VerticalLayout {
|
|
padding: 0px; spacing: 10px;
|
|
Text {
|
|
text: GalleryStrings.tr("以下列出本版本的主要开源组件。各组件遵循各自的开源许可。", "Main open-source components used in this build. Each component is covered by its own license.", "Основные открытые компоненты этой сборки. Каждый распространяется по своей лицензии.");
|
|
color: WorkbenchStyle.muted; font-size: 12px; wrap: word-wrap;
|
|
}
|
|
Rectangle {
|
|
height: notice.preferred-height + 32px;
|
|
background: WorkbenchStyle.field-surface; border-radius: UiRadius.control;
|
|
notice := VerticalLayout {
|
|
x: 16px; y: 16px; width: parent.width - 32px;
|
|
height: self.preferred-height; spacing: 12px;
|
|
Text { text: GalleryStrings.tr("OpenFEC 告知", "OpenFEC notice", "Уведомление OpenFEC"); color: WorkbenchStyle.text; font-size: 14px; font-weight: 600; }
|
|
Text {
|
|
text: GalleryStrings.tr("本应用使用 OpenFEC 提供前向纠错功能,遵循 CeCILL-C 1.0 许可。该许可规定了有限保证及责任限制,详情见许可全文。", "This application uses OpenFEC for forward error correction under CeCILL-C 1.0, which provides limited warranties and limits liability. See the full license for details.", "Приложение использует OpenFEC для прямого исправления ошибок по лицензии CeCILL-C 1.0 с ограниченной гарантией и ответственностью. Подробности — в тексте лицензии.");
|
|
color: WorkbenchStyle.muted; font-size: 13px; wrap: word-wrap;
|
|
font-family: "CrossDesk Message Spacing";
|
|
}
|
|
Text {
|
|
text: "(c) Copyright 2009 - 2012 INRIA - All rights reserved";
|
|
color: WorkbenchStyle.muted; font-size: 11px; wrap: word-wrap;
|
|
font-family: "CrossDesk Message Spacing";
|
|
}
|
|
if root.openfec-index >= 0: AboutNavigationRow {
|
|
title: GalleryStrings.tr("OpenFEC 许可与源码", "OpenFEC license and source", "Лицензия и исходный код OpenFEC");
|
|
clicked => { root.component-index = root.openfec-index; root.page = AboutPage.component; }
|
|
}
|
|
}
|
|
}
|
|
for component[index] in root.components: VerticalLayout {
|
|
padding: 0px; spacing: 0px;
|
|
if component.id != "crossdesk" && component.id != "openfec": AboutNavigationRow {
|
|
title: component.name;
|
|
subtitle: component.version + " · " + component.license;
|
|
clicked => { root.component-index = index; root.page = AboutPage.component; }
|
|
}
|
|
}
|
|
}
|
|
if root.page == AboutPage.component: VerticalLayout {
|
|
padding: 0px; spacing: 12px;
|
|
Text { text: root.selected.version + " · " + root.selected.license; color: WorkbenchStyle.muted; font-size: 12px; wrap: word-wrap; }
|
|
AboutNavigationRow {
|
|
title: AboutStrings.view-source; external: true;
|
|
clicked => { root.open-link(root.selected.source-url); }
|
|
}
|
|
Text { text: AboutStrings.notices; color: WorkbenchStyle.text; font-size: 13px; font-weight: 600; }
|
|
for document[index] in root.selected.documents: AboutNavigationRow {
|
|
title: document.title;
|
|
clicked => { root.document-index = index; root.page = AboutPage.document; }
|
|
}
|
|
if root.selected.documents.length == 0: Text {
|
|
text: GalleryStrings.tr("本组件未内置许可文本,请通过“查看源码”查阅许可与版权声明。", "License text is not bundled for this component. Use View source code to read its license and copyright notices.", "Текст лицензии не включён. Откройте исходный код для просмотра лицензии и авторских прав.");
|
|
color: WorkbenchStyle.muted; font-size: 12px; wrap: word-wrap;
|
|
}
|
|
}
|
|
if root.page == AboutPage.source: VerticalLayout {
|
|
padding: 0px; spacing: 12px;
|
|
Text {
|
|
text: root.revision != "" ? GalleryStrings.tr("源码版本:", "Source revision: ", "Ревизия исходного кода: ") + root.revision
|
|
: GalleryStrings.tr("本版本源码信息暂不可用。", "Source revision is unavailable for this build.", "Ревизия исходного кода этой сборки недоступна.");
|
|
color: WorkbenchStyle.text; font-size: 13px; wrap: word-wrap;
|
|
}
|
|
AboutNavigationRow { title: AboutStrings.view-source; external: true; clicked => { root.open-link(root.source-url); } }
|
|
AboutNavigationRow {
|
|
title: GalleryStrings.tr("构建说明", "Build instructions", "Инструкции по сборке"); external: true;
|
|
clicked => { root.open-link(root.build-url); }
|
|
}
|
|
AboutNavigationRow {
|
|
title: GalleryStrings.tr("项目主页", "Project website", "Сайт проекта"); external: true;
|
|
clicked => { root.open-link("https://crossdesk.cn"); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if root.page == AboutPage.document: VerticalLayout {
|
|
x: 24px; y: root.content-top; width: parent.width - 48px;
|
|
height: footer.y - self.y - 16px; spacing: 12px;
|
|
Text { text: root.selected.documents[root.document-index].title; color: WorkbenchStyle.text; font-size: 13px; font-weight: 600; wrap: word-wrap; }
|
|
TextEdit {
|
|
text: root.selected.documents[root.document-index].text;
|
|
read-only: true; wrap: word-wrap; font-size: 14px;
|
|
// Use the same 1.5em line spacing as other long-form reading views.
|
|
font-family: "CrossDesk Message Spacing";
|
|
vertical-stretch: 1;
|
|
key-pressed(event) => {
|
|
if event.text == Key.Escape { root.back(); return accept; }
|
|
return reject;
|
|
}
|
|
}
|
|
}
|
|
footer := VerticalLayout {
|
|
x: 24px; y: parent.height - self.height - 24px;
|
|
width: parent.width - 48px; height: self.preferred-height; spacing: 12px;
|
|
Rectangle { height: 1px; background: WorkbenchStyle.separator; }
|
|
HorizontalLayout {
|
|
alignment: end;
|
|
SettingsButton { text: AboutStrings.back; clicked => { root.back(); } }
|
|
}
|
|
}
|
|
}
|