feat: Flatpak-Paket (Vorbereitung für Flathub)
- packaging/flatpak/eu.pansi.ink-notes.yml: Runtime freedesktop 26.08, Rust aus rust-stable, Abhängigkeiten offline aus cargo-sources.json. Rechte: Wayland/X11, GPU, Lesen von Bildern/Downloads/Schreibtisch, Schreiben in den Dokumente-Ordner (kein Zugriff auf den ganzen Home-Ordner). - Im Flatpak sucht und installiert ink-notes keine Updates selbst (Vorgabe von Flathub); der Update-Dialog verweist auf die Software-Verwaltung. - Export-Ordner aus user-dirs.dirs (z. B. ~/Dokumente) statt fest ~/Documents; nur dieser Ordner ist im Flatpak beschreibbar. - Metainfo und Desktop-Datei auf Englisch mit deutscher Übersetzung, Release-Einträge, unterstützte Eingabegeräte. - Test: cargo-sources.json deckt Cargo.lock ab. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+13
-2
@@ -46,7 +46,9 @@ pub fn sanitize_filename_component(title: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Ermittelt das Standard-Dokumentenverzeichnis ($XDG_DOCUMENTS_DIR mit Fallback ~/Documents).
|
||||
/// Ermittelt das Standard-Dokumentenverzeichnis: `$XDG_DOCUMENTS_DIR`, sonst der Eintrag in
|
||||
/// `~/.config/user-dirs.dirs` (z. B. „Dokumente“), sonst `~/Documents`. Im Flatpak ist nur
|
||||
/// dieser Ordner beschreibbar, der Fallback allein träfe bei deutschen Systemen daneben.
|
||||
pub fn default_documents_dir() -> PathBuf {
|
||||
if let Ok(dir) = std::env::var("XDG_DOCUMENTS_DIR") {
|
||||
if !dir.trim().is_empty() {
|
||||
@@ -56,7 +58,16 @@ pub fn default_documents_dir() -> PathBuf {
|
||||
|
||||
if let Ok(home) = std::env::var("HOME") {
|
||||
if !home.trim().is_empty() {
|
||||
return PathBuf::from(home).join("Documents");
|
||||
let home = PathBuf::from(home);
|
||||
let user_dirs =
|
||||
std::fs::read_to_string(home.join(".config/user-dirs.dirs")).unwrap_or_default();
|
||||
if let Some(dir) =
|
||||
crate::file_picker::parse_user_dir(&user_dirs, "XDG_DOCUMENTS_DIR", &home)
|
||||
.filter(|dir| *dir != home)
|
||||
{
|
||||
return dir;
|
||||
}
|
||||
return home.join("Documents");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,9 +66,11 @@ pub const EN: &[(&str, &str)] = &[
|
||||
("Die beschädigte Originaldatei wurde in Quarantäne gesichert:", "The damaged original file was saved to quarantine:"),
|
||||
("Die Datei ist kein lesbares PDF", "The file is not a readable PDF"),
|
||||
("Die einzige Seite eines Notizbuchs kann nicht gelöscht werden", "The only page of a notebook cannot be deleted"),
|
||||
("Die Flatpak-Version wird über die Software-Verwaltung aktualisiert.", "The Flatpak version is updated through the software manager."),
|
||||
("Die heruntergeladene Datei existiert nicht mehr.", "The downloaded file no longer exists."),
|
||||
("die oberste Ebene", "the top level"),
|
||||
("Die Zwischenablage ist leer", "The clipboard is empty"),
|
||||
("Diese Version wird über die Software-Verwaltung aktualisiert (z. B. GNOME Software oder „flatpak update“).", "This version is updated through the software manager (e.g. GNOME Software or “flatpak update”)."),
|
||||
("Dieser Ordner ist leer.", "This folder is empty."),
|
||||
("Dokument '{title}' erstellt", "Document '{title}' created"),
|
||||
("Dokument '{title}' geöffnet", "Document '{title}' opened"),
|
||||
|
||||
@@ -4281,6 +4281,18 @@ pub fn render_ui(
|
||||
ui.label(egui::RichText::new(format!("({})", runtime_name)).color(egui::Color32::from_gray(150)));
|
||||
});
|
||||
|
||||
if !updater.runtime().self_update_allowed() {
|
||||
ui.add_space(8.0);
|
||||
ui.label(
|
||||
egui::RichText::new(t!(
|
||||
"Diese Version wird über die Software-Verwaltung aktualisiert \
|
||||
(z. B. GNOME Software oder „flatpak update“)."
|
||||
))
|
||||
.color(egui::Color32::from_gray(210)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(egui::RichText::new(t!("Server:")).color(egui::Color32::from_gray(180)));
|
||||
ui.label(egui::RichText::new(format!("{}/{}/{}", updater.config().server_url, updater.config().repo_owner, updater.config().repo_name)).color(egui::Color32::from_gray(210)));
|
||||
@@ -4446,7 +4458,8 @@ pub fn render_ui(
|
||||
let action_label = match updater.runtime() {
|
||||
crate::updater::RuntimeEnvironment::AppImage { .. } => t!("🚀 AppImage aktualisieren & ausführen"),
|
||||
crate::updater::RuntimeEnvironment::DebPackage { .. } => t!("📦 Paket mit Software-Center öffnen / installieren"),
|
||||
crate::updater::RuntimeEnvironment::PortableOrDev { .. } => t!("📂 Im Dateimanager anzeigen"),
|
||||
crate::updater::RuntimeEnvironment::PortableOrDev { .. }
|
||||
| crate::updater::RuntimeEnvironment::Flatpak => t!("📂 Im Dateimanager anzeigen"),
|
||||
};
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
|
||||
@@ -118,11 +118,20 @@ pub enum RuntimeEnvironment {
|
||||
DebPackage { binary_path: PathBuf },
|
||||
/// Aus Quellcode / Entwicklungs-Binary (z.B. target/debug oder target/release)
|
||||
PortableOrDev { binary_path: PathBuf },
|
||||
/// Als Flatpak installiert: Updates kommen über die Software-Verwaltung, ink-notes lädt
|
||||
/// selbst nichts herunter (Vorgabe von Flathub)
|
||||
Flatpak,
|
||||
}
|
||||
|
||||
impl RuntimeEnvironment {
|
||||
/// Erkennt die aktuelle Laufzeitumgebung anhand der Umgebung und des Binärpfads.
|
||||
pub fn detect() -> Self {
|
||||
if is_flatpak(
|
||||
std::env::var("FLATPAK_ID").ok().as_deref(),
|
||||
Path::new("/.flatpak-info").exists(),
|
||||
) {
|
||||
return RuntimeEnvironment::Flatpak;
|
||||
}
|
||||
let appimage_var = std::env::var("APPIMAGE").ok();
|
||||
let current_exe = std::env::current_exe().unwrap_or_else(|_| PathBuf::from("ink-notes"));
|
||||
Self::detect_from(appimage_var.as_deref(), ¤t_exe)
|
||||
@@ -156,8 +165,20 @@ impl RuntimeEnvironment {
|
||||
RuntimeEnvironment::AppImage { .. } => t!("AppImage (Portabel)"),
|
||||
RuntimeEnvironment::DebPackage { .. } => t!("System-Paket (.deb)"),
|
||||
RuntimeEnvironment::PortableOrDev { .. } => t!("Entwicklung / Lokal"),
|
||||
RuntimeEnvironment::Flatpak => "Flatpak",
|
||||
}
|
||||
}
|
||||
|
||||
/// Ob ink-notes selbst nach Updates suchen und sie installieren darf
|
||||
pub fn self_update_allowed(&self) -> bool {
|
||||
!matches!(self, RuntimeEnvironment::Flatpak)
|
||||
}
|
||||
}
|
||||
|
||||
/// Läuft ink-notes in einer Flatpak-Sandbox (`FLATPAK_ID` gesetzt oder `/.flatpak-info`
|
||||
/// vorhanden)?
|
||||
pub fn is_flatpak(flatpak_id: Option<&str>, info_file_exists: bool) -> bool {
|
||||
flatpak_id.is_some_and(|id| !id.trim().is_empty()) || info_file_exists
|
||||
}
|
||||
|
||||
/// Bereinigt und validiert einen Asset-Dateinamen gegen Path Traversal Angriffe.
|
||||
@@ -578,6 +599,9 @@ impl UpdaterController {
|
||||
|
||||
/// Fragt im Hintergrund die Gitea-API ab.
|
||||
pub fn check_for_updates(&mut self) {
|
||||
if !self.runtime.self_update_allowed() {
|
||||
return;
|
||||
}
|
||||
if matches!(
|
||||
self.status,
|
||||
UpdaterStatus::Checking | UpdaterStatus::Downloading { .. }
|
||||
@@ -887,6 +911,10 @@ impl UpdaterController {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
RuntimeEnvironment::Flatpak => Err(t!(
|
||||
"Die Flatpak-Version wird über die Software-Verwaltung aktualisiert."
|
||||
)
|
||||
.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1074,6 +1102,19 @@ dcdeb7ac87d9e6cb8022e5a71bc7f2c56d779b4fce4efdd5bae5be3b0214884a ink-notes_0.1.
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_flatpak_detection_disables_self_update() {
|
||||
assert!(is_flatpak(Some("eu.pansi.ink-notes"), false));
|
||||
assert!(is_flatpak(None, true));
|
||||
assert!(!is_flatpak(Some(" "), false));
|
||||
assert!(!is_flatpak(None, false));
|
||||
assert!(!RuntimeEnvironment::Flatpak.self_update_allowed());
|
||||
assert!(
|
||||
RuntimeEnvironment::detect_from(None, Path::new("/usr/bin/ink-notes"))
|
||||
.self_update_allowed()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_https_enforcement() {
|
||||
let config = UpdaterConfig {
|
||||
|
||||
Reference in New Issue
Block a user