feat: add export dialog
Build / Flatpak (x86_64) (push) Failing after 1h11m8s
Details
Build / Flatpak (x86_64) (push) Failing after 1h11m8s
Details
This commit is contained in:
parent
8feb2281bc
commit
9812f28970
|
@ -2,7 +2,9 @@
|
|||
<gresources>
|
||||
<gresource prefix="/io/github/Bavarder/Bavarder">
|
||||
<file preprocess="xml-stripblanks" alias="ui/window.ui">views/window.ui</file>
|
||||
<file preprocess="xml-stripblanks" alias="ui/export_dialog.ui">views/export_dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks" alias="ui/preferences_window.ui">views/preferences_window.ui</file>
|
||||
<file preprocess="xml-stripblanks" alias="ui/save_dialog.ui">views/save_dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks" alias="ui/thread_item.ui">widgets/thread_item.ui</file>
|
||||
<file preprocess="xml-stripblanks" alias="ui/item.ui">widgets/item.ui</file>
|
||||
<file preprocess="xml-stripblanks" alias="ui/provider_item.ui">providers/provider_item.ui</file>
|
||||
|
|
|
@ -5,7 +5,9 @@ python = import('python')
|
|||
blueprints = custom_target('blueprints',
|
||||
input: files(
|
||||
'gtk/help-overlay.blp',
|
||||
'views/export_dialog.blp',
|
||||
'views/preferences_window.blp',
|
||||
'views/save_dialog.blp',
|
||||
'views/window.blp',
|
||||
'widgets/thread_item.blp',
|
||||
'widgets/item.blp',
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
using GtkSource 5;
|
||||
|
||||
template $ExportDialog : Adw.MessageDialog {
|
||||
heading: _("Export Thread ?");
|
||||
response => $handle_response();
|
||||
|
||||
extra-child: Overlay {
|
||||
[overlay]
|
||||
Button {
|
||||
styles [
|
||||
"circular",
|
||||
]
|
||||
icon-name: "edit-copy-symbolic";
|
||||
halign: end;
|
||||
valign: end;
|
||||
margin-bottom: 7;
|
||||
margin-end: 7;
|
||||
clicked => $copy();
|
||||
}
|
||||
|
||||
Box box {
|
||||
orientation: vertical;
|
||||
vexpand: true;
|
||||
hexpand: true;
|
||||
|
||||
Gtk.ScrolledWindow view {
|
||||
vexpand: true;
|
||||
hexpand: true;
|
||||
min-content-height: 200;
|
||||
|
||||
GtkSource.View source_view {
|
||||
vexpand: true;
|
||||
hexpand: true;
|
||||
buffer: GtkSource.Buffer buffer {};
|
||||
editable: false;
|
||||
monospace: true;
|
||||
show-line-marks: false;
|
||||
show-line-numbers: false;
|
||||
smart-backspace: false;
|
||||
margin-top: 5;
|
||||
margin-bottom: 5;
|
||||
styles [ "codeview", "card" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
responses [
|
||||
close: _("Close"),
|
||||
export: _("Export") suggested,
|
||||
]
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
from gi.repository import Gtk, Adw, Gio, GtkSource, Gdk
|
||||
|
||||
from bavarder.constants import app_id, rootdir
|
||||
from bavarder.views.save_dialog import SaveDialog
|
||||
|
||||
GtkSource.init()
|
||||
|
||||
@Gtk.Template(resource_path=f"{rootdir}/ui/export_dialog.ui")
|
||||
class ExportDialog(Adw.MessageDialog):
|
||||
__gtype_name__ = "ExportDialog"
|
||||
|
||||
buffer = Gtk.Template.Child()
|
||||
source_view = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, parent, chat, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.text: str = ""
|
||||
self.parent = parent
|
||||
for i, x in zip(chat, range(len(chat))):
|
||||
self.text += f"{i['role']}: {i['content']}\n"
|
||||
|
||||
if (x % 2) != 0:
|
||||
self.text += "\n"
|
||||
|
||||
self.text = self.text[:-2]
|
||||
self.buffer.set_text(self.text)
|
||||
|
||||
if Adw.StyleManager().get_dark():
|
||||
self.buffer.set_style_scheme(GtkSource.StyleSchemeManager().get_scheme("Adwaita-dark"))
|
||||
else:
|
||||
self.buffer.set_style_scheme(GtkSource.StyleSchemeManager().get_scheme("Adwaita"))
|
||||
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def copy(self, *args, **kwargs):
|
||||
Gdk.Display.get_default().get_clipboard().set(self.text)
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def handle_response(self, dialog, response, *args, **kwargs):
|
||||
if response == "export":
|
||||
dialog = SaveDialog(self.parent, self.text)
|
||||
dialog.present()
|
|
@ -3,7 +3,9 @@ views_dir = join_paths(MODULE_DIR, 'views')
|
|||
views_sources = [
|
||||
'__init__.py',
|
||||
'about_window.py',
|
||||
'export_dialog.py',
|
||||
'preferences_window.py',
|
||||
'save_dialog.py',
|
||||
'window.py',
|
||||
]
|
||||
|
||||
|
|
|
@ -95,13 +95,13 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
|||
|
||||
@Gtk.Template.Callback()
|
||||
def on_bot_entry_apply(self, user_data, *args):
|
||||
self.app.bot_name = user_data.get_text().capitalize()
|
||||
self.app.bot_name = user_data.get_text()
|
||||
|
||||
self.app.load_bot_and_user_name()
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def on_user_entry_apply(self, user_data, *args):
|
||||
self.app.user_name = user_data.get_text().capitalize()
|
||||
self.app.user_name = user_data.get_text()
|
||||
|
||||
self.app.load_bot_and_user_name()
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $SaveDialog : Adw.MessageDialog {
|
||||
response => $handle_response();
|
||||
responses [
|
||||
cancel: _("Cancel"),
|
||||
disacard: _("Discard") destructive,
|
||||
save: _("Save") suggested disabled,
|
||||
]
|
||||
close-response: "cancel";
|
||||
modal: true;
|
||||
heading: _("Export Thread?");
|
||||
body: _("");
|
||||
|
||||
extra-child: Box {
|
||||
margin-top: 12;
|
||||
orientation: vertical;
|
||||
spacing: 24;
|
||||
|
||||
ListBox {
|
||||
selection-mode: none;
|
||||
styles ["boxed-list"]
|
||||
|
||||
Adw.EntryRow filename {
|
||||
title: _("File Name");
|
||||
entry-activated => $on_entry_activated();
|
||||
}
|
||||
}
|
||||
|
||||
Box {
|
||||
orientation: vertical;
|
||||
|
||||
ListBox {
|
||||
selection-mode: none;
|
||||
styles ["boxed-list"]
|
||||
|
||||
Adw.ActionRow location {
|
||||
title: _("Location");
|
||||
subtitle: "Select Location";
|
||||
activatable-widget: button_location;
|
||||
|
||||
Button button_location {
|
||||
icon-name: "folder-symbolic";
|
||||
valign: center;
|
||||
styles ["flat"]
|
||||
clicked => $on_location_button_clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
margin-start: 12;
|
||||
margin-top: 12;
|
||||
halign: start;
|
||||
label: _("The export of the Thread will be saved in this directory.");
|
||||
styles ["dim-label", "caption"]
|
||||
justify: left;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Gtk.FileDialog file_chooser {
|
||||
title: _("Choose a directory");
|
||||
modal: true;
|
||||
//action: open;
|
||||
//response => $on_filechooser_response();
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
from gi.repository import Gtk, Adw, Gio, Gdk
|
||||
|
||||
from bavarder.constants import app_id, rootdir
|
||||
|
||||
@Gtk.Template(resource_path=f"{rootdir}/ui/save_dialog.ui")
|
||||
class SaveDialog(Adw.MessageDialog):
|
||||
__gtype_name__ = "SaveDialog"
|
||||
|
||||
filename = Gtk.Template.Child()
|
||||
file_chooser = Gtk.Template.Child()
|
||||
location = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, parent, text, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.text: str = text
|
||||
self.parent = parent
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def handle_response(self, dialog, response, *args, **kwargs):
|
||||
if response == "save":
|
||||
filename = self.filename.get_text()
|
||||
path = f"{self.directory}/{filename}.md"
|
||||
|
||||
toast = Adw.Toast()
|
||||
try:
|
||||
with open(path, "w") as f:
|
||||
f.write(self.text)
|
||||
except FileNotFoundError:
|
||||
toast.set_title(_("Unable to save the Thread"))
|
||||
else:
|
||||
toast.set_title(_("Thread successfully saved!"))
|
||||
self.parent.toast_overlay.add_toast(toast)
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def on_location_button_clicked(self, widget, *args):
|
||||
self.file_chooser.select_folder(self, None, self.on_filechooser_response)
|
||||
|
||||
def on_filechooser_response(self, widget, response):
|
||||
self.directory = self.file_chooser.select_folder_finish(response).get_path()
|
||||
self.location.set_subtitle(self.directory)
|
||||
self.update_save_status()
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def on_entry_activated(self, widget, *args):
|
||||
self.update_save_status()
|
||||
|
||||
def update_save_status(self):
|
||||
try:
|
||||
self.directory
|
||||
except Exception:
|
||||
self.set_response_enabled("save", False)
|
||||
else:
|
||||
if self.filename.get_text().strip():
|
||||
self.set_response_enabled("save", True)
|
||||
else:
|
||||
self.set_response_enabled("save", False)
|
|
@ -28,6 +28,7 @@ from bavarder.constants import app_id, build_type, rootdir
|
|||
from bavarder.widgets.thread_item import ThreadItem
|
||||
from bavarder.widgets.item import Item
|
||||
from bavarder.threading import KillableThread
|
||||
from bavarder.views.export_dialog import ExportDialog
|
||||
|
||||
class CustomEntry(Gtk.TextView):
|
||||
def __init__(self, **kwargs):
|
||||
|
@ -85,6 +86,7 @@ class BavarderWindow(Adw.ApplicationWindow):
|
|||
|
||||
self.create_action("cancel", self.cancel, ["<primary>Escape"])
|
||||
self.create_action("clear_all", self.on_clear_all)
|
||||
self.create_action("export", self.on_export, ["<primary>e"])
|
||||
|
||||
self.settings.bind(
|
||||
"width", self, "default-width", Gio.SettingsBindFlags.DEFAULT
|
||||
|
@ -202,6 +204,12 @@ class BavarderWindow(Adw.ApplicationWindow):
|
|||
del self.chat["content"]
|
||||
self.stack.set_visible_child(self.status_no_chat)
|
||||
|
||||
def on_export(self, *args):
|
||||
if self.content:
|
||||
dialog = ExportDialog(self, self.chat["content"])
|
||||
dialog.set_transient_for(self)
|
||||
dialog.present()
|
||||
|
||||
# PROVIDER - ONLINE
|
||||
def load_provider_selector(self):
|
||||
provider_menu = Gio.Menu()
|
||||
|
@ -229,6 +237,11 @@ class BavarderWindow(Adw.ApplicationWindow):
|
|||
item_provider.set_action_and_target_value("win.clear_all", None)
|
||||
section.append_item(item_provider)
|
||||
|
||||
item_provider = Gio.MenuItem()
|
||||
item_provider.set_label(_("Export"))
|
||||
item_provider.set_action_and_target_value("win.export", None)
|
||||
section.append_item(item_provider)
|
||||
|
||||
provider_menu.append_section(None, section)
|
||||
|
||||
self.provider_selector_button.set_menu_model(provider_menu)
|
||||
|
@ -262,6 +275,11 @@ class BavarderWindow(Adw.ApplicationWindow):
|
|||
item_provider.set_action_and_target_value("win.clear_all", None)
|
||||
section.append_item(item_provider)
|
||||
|
||||
item_provider = Gio.MenuItem()
|
||||
item_provider.set_label(_("Export"))
|
||||
item_provider.set_action_and_target_value("win.export", None)
|
||||
section.append_item(item_provider)
|
||||
|
||||
provider_menu.append_section(None, section)
|
||||
|
||||
self.model_selector_button.set_menu_model(provider_menu)
|
||||
|
|
|
@ -109,7 +109,7 @@ class Item(Gtk.Box):
|
|||
label.set_halign(Gtk.Align.START)
|
||||
self.content.append(label)
|
||||
|
||||
t = self.item["role"].capitalize()
|
||||
t = self.item["role"].lower()
|
||||
|
||||
self.parent = parent
|
||||
self.settings = parent.settings
|
||||
|
@ -117,11 +117,11 @@ class Item(Gtk.Box):
|
|||
self.app = self.parent.get_application()
|
||||
self.win = self.app.get_active_window()
|
||||
|
||||
if t == self.app.user_name: # User
|
||||
if t == self.app.user_name.lower(): # User
|
||||
self.message_bubble.add_css_class("message-bubble-user")
|
||||
self.avatar.add_css_class("avatar-user")
|
||||
role = self.app.user_name
|
||||
elif t == self.app.bot_name: # Assistant
|
||||
elif t == self.app.bot_name.lower(): # Assistant
|
||||
self.avatar.set_icon_name("bot-symbolic")
|
||||
self.user.add_css_class("warning")
|
||||
role = self.app.bot_name
|
||||
|
|
Loading…
Reference in New Issue