From fbd505a647c316eab6e5c3661d038bf02ca078fd Mon Sep 17 00:00:00 2001 From: 0xmrtt <0xmrtt@proton.me> Date: Mon, 6 Apr 2026 17:18:35 +0200 Subject: [PATCH] Remove image handling and add Nix docs --- README.md | 35 +++++---- src/widgets/item.blp | 7 +- src/widgets/item.py | 168 ++++++++++++++----------------------------- 3 files changed, 75 insertions(+), 135 deletions(-) diff --git a/README.md b/README.md index fad1117..988b7ac 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,6 @@

-

- - Please do not theme this app - -

-

Preview @@ -49,6 +43,14 @@ Documentation is available [here](https://bavarder.codeberg.page) ## Installation +### Nix + +Nix is used to develop Bavarder, there is also a Nix flake available at [flake.nix](./flake.nix). You can run Bavarder without installing it by running + +``` shell +nix run github:Bavarder/Bavarder +``` + ### Flatpak You can either use your GNOME Software and search for "Bavarder" or you can run @@ -67,6 +69,18 @@ curl -s -o bavarder.flatpak https://codeberg.org/api/packages/Bavarder/generic/B #### From Source +### Nix + +Just clone the repo and run `nix develop` and you will be in a shell with all the dependencies installed, you can then run `nix run` to run the app or `nix build` to build it + +``` shell +git clone https://github.com/Bavarder/Bavarder # or https://codeberg.org/Bavarder/Bavarder +cd Bavarder +nix develop +nix run # Run the app +nix build # Build the app +``` + ### Flatpak-builder Clone the repo and run `flatpak-builder` @@ -115,12 +129,3 @@ You can translate Bavarder using [Codeberg Translate](https://translate.codeberg ## About the name Bavarder is a french word, the definiton of Bavarder is "Parler abondamment de choses sans grande portée" (Talking a lot about things that don't matter) (Larousse) which can be translated by Chit-Chat (informal conversation about matters that are not important). For non-french speakers, Bavarder can be hard to speak, it's prounouced as [bavaʀde]. Hear [here](https://youtu.be/9Qoogwxo5YA) - -## See also - -### [Imaginer : Imagine with AI](https://imaginer.codeberg.page) - -A tool for generating pictures with AI (GNOME app) - -- [GitHub](https://github.com/ImaginerApp/Imaginer) -- [Codeberg](https://codeberg.org/Imaginer/Imaginer) diff --git a/src/widgets/item.blp b/src/widgets/item.blp index 1c7b26c..1fe8e8a 100644 --- a/src/widgets/item.blp +++ b/src/widgets/item.blp @@ -105,11 +105,6 @@ menu popover-model { label: _("Edit"); action: "event.edit"; } - - item { - label: _("Save"); - action: "event.save"; - } } section { @@ -118,4 +113,4 @@ menu popover-model { action: "event.delete"; } } -} \ No newline at end of file +} diff --git a/src/widgets/item.py b/src/widgets/item.py index c1671da..25d7b40 100644 --- a/src/widgets/item.py +++ b/src/widgets/item.py @@ -4,8 +4,6 @@ import re import io import base64 -from PIL import Image, UnidentifiedImageError - from bavarder.constants import app_id, rootdir from bavarder.widgets.code_block import CodeBlock @@ -33,7 +31,7 @@ m2p_styles = [ { "name": BOLD, "re": re.compile(r"(^|[^\*])(\*\*)(.*)(\*\*)"), "sub": r"\1\3" }, { "name": BOLD, "re": re.compile(r"(\*\*)(.*)(\*\*)([^\*]|$)"), "sub": r"\3\4" }, { "name": EMPH, "re": re.compile(r"(^|[^\*])(\*)(.*)(\*)"), "sub": r"\1\3" }, - { "name": EMPH, "re": re.compile(r"(\*)(.*)(\*)([^\*]|$)"), "sub": r"\3\4" }, + { "name": EMPH, "re": re.compile(r"(\*)(.*)(\*)([^\*]|$)"), "sub": r"\3\4" }, { "name": PRE, "re": re.compile(r"(`)([^`]*)(`)"), "sub": r"\2" }, { "name": LINK, "re": re.compile(r"(!)?(\[)(.*)(\]\()(.+)(\))"), "sub": r"\3" }, { "name": LINK, "re": re.compile(r"(!)?(\[)(.*)(\]\(\))"), "sub": r"\3" }, @@ -82,76 +80,54 @@ class Item(Gtk.Box): self.app = self.parent.get_application() self.win = self.app.get_active_window() - try: - if not isinstance(self.content_text, Image.Image): - if isinstance(self.content_text, bytes): - self.image = Image.open(io.BytesIO(self.content_text)) - else: - self.image = Image.open(io.BytesIO(base64.b64decode(self.content_text))) - else: - self.image = self.content_text - except Exception: - self.convert_content_to_pango() + self.convert_content_to_pango() - result = "" - is_code = False - for line in self.content_markup: - if isinstance(line, str): - if "`" in line.strip(): - if is_code: - is_code = False - else: - is_code = True - continue - if is_code or not isinstance(line, str): - label = Gtk.Label() - label.set_use_markup(True) - label.set_wrap(True) - label.set_xalign(0) - label.set_wrap_mode(Pango.WrapMode.WORD) - label.set_markup(result) - label.set_justify(Gtk.Justification.LEFT) - label.set_valign(Gtk.Align.START) - label.set_hexpand(True) - label.set_halign(Gtk.Align.START) - self.content.append(label) - - if not isinstance(line, str): - result = "\n".join(line) + result = "" + is_code = False + for line in self.content_markup: + if isinstance(line, str): + if "`" in line.strip(): + if is_code: + is_code = False else: - result = line.strip() + is_code = True + continue + if is_code or not isinstance(line, str): + label = Gtk.Label() + label.set_use_markup(True) + label.set_wrap(True) + label.set_xalign(0) + label.set_wrap_mode(Pango.WrapMode.WORD) + label.set_markup(result) + label.set_justify(Gtk.Justification.LEFT) + label.set_valign(Gtk.Align.START) + label.set_hexpand(True) + label.set_halign(Gtk.Align.START) + self.content.append(label) - self.content.append(CodeBlock(result)) - result = "" - else: - result += f"{line}\n" - + if not isinstance(line, str): + result = "\n".join(line) + else: + result = line.strip() + + self.content.append(CodeBlock(result)) + result = "" else: - if not result.strip() == "`": - label = Gtk.Label() - label.set_use_markup(True) - label.set_wrap(True) - label.set_xalign(0) - label.set_wrap_mode(Pango.WrapMode.WORD) - label.set_markup(result) - label.set_justify(Gtk.Justification.LEFT) - label.set_valign(Gtk.Align.START) - label.set_hexpand(True) - label.set_halign(Gtk.Align.START) - self.content.append(label) + result += f"{line}\n" + else: - picture = Gtk.Picture() - picture.set_halign(Gtk.Align.CENTER) - picture.set_can_shrink(True) - picture.set_content_fit(Gtk.ContentFit.FILL) - picture.set_visible(True) - picture.add_css_class("card") - picture.set_margin_start(12) - picture.set_margin_end(12) - picture.set_size_request(270, 270) - self.image.save("/tmp/image.png") - picture.set_file(Gio.File.new_for_path("/tmp/image.png")) - self.content.append(picture) + if not result.strip() == "`": + label = Gtk.Label() + label.set_use_markup(True) + label.set_wrap(True) + label.set_xalign(0) + label.set_wrap_mode(Pango.WrapMode.WORD) + label.set_markup(result) + label.set_justify(Gtk.Justification.LEFT) + label.set_valign(Gtk.Align.START) + label.set_hexpand(True) + label.set_halign(Gtk.Align.START) + self.content.append(label) t = self.item["role"].lower() @@ -190,7 +166,6 @@ class Item(Gtk.Box): self.action_group = Gio.SimpleActionGroup() self.create_action("delete", self.on_delete) self.create_action("edit", self.on_edit) - self.create_action("save", self.on_save) self.create_action("copy", self.on_copy) self.insert_action_group("event", self.action_group); @@ -209,41 +184,6 @@ class Item(Gtk.Box): def on_edit(self, *args): self.win.message_entry.get_buffer().set_text(self.content_text) - def on_save(self, *args): - def on_save_response(dialog, response): - if response == Gtk.ResponseType.OK: - toast = Adw.Toast() - try: - self.image.save(dialog.get_file().get_path()) - except Exception as e: - toast.set_title(_("Failed to save the image")) - else: - toast.set_title(_("Image saved")) - finally: - self.parent.toast_overlay.add_toast(toast) - - dialog.destroy() - - try: - self.image - except AttributeError: - toast = Adw.Toast() - toast.set_title(_("No image to save")) - self.parent.toast_overlay.add_toast(toast) - else: - dialog = Gtk.FileChooserDialog( - title=_("Save message"), - action=Gtk.FileChooserAction.SAVE, - modal=True, - transient_for=self.win, - ) - dialog.add_button(_("Cancel"), Gtk.ResponseType.CANCEL) - dialog.add_button(_("Save"), Gtk.ResponseType.OK) - - dialog.connect('response', on_save_response) - dialog.present() - - def on_copy(self, *args): Gdk.Display.get_default().get_clipboard().set(self.content_text) @@ -268,7 +208,7 @@ class Item(Gtk.Box): if self.color_span_open: output.append('') self.color_span_open = False - + def try_open_span(): if not self.color_span_open: output.append('') @@ -296,7 +236,7 @@ class Item(Gtk.Box): colors = re_color.match(line) if colors or re_reset.match(line): try_close_span() - + if colors: try_close_span() @@ -309,19 +249,19 @@ class Item(Gtk.Box): fg = colors[6] else: fg = "" - + if colors[2] == 'bg': fg = colors[3] elif colors[5] == 'bg': fg = colors[6] else: fg = "" - + attrs = '' if fg != '': attrs += f" foreground='{fg}'" - + if bg != '': attrs += f" background='{bg}'" @@ -329,7 +269,7 @@ class Item(Gtk.Box): if attrs != '': output.append("") self.color_span_open = True - + if re_comment.match(line): continue @@ -376,22 +316,22 @@ class Item(Gtk.Box): if is_code and not code_start: code_lines.append(result) continue - + if re_h1line.match(line): output.append(re.sub(m2p_sections[0]["re"], m2p_sections[0]["sub"], f"# {output.pop()}")) continue - + if re_h2line.match(line): output.append(re.sub(m2p_sections[1]["re"], m2p_sections[1]["sub"], f"# {output.pop()}")) continue - + for style in m2p_styles: regexp = style["re"] sub = style["sub"] result = re.sub(regexp, sub, result) - + uri = re_uri.match(result) # look for any URI href = re_href.match(result) # and for URIs in href=''