fix:issues

This commit is contained in:
intelligence committed 2026-08-14 13:24:17 +02:00
1 parent 8e06d7f6ac
commit 51751b5dbf
5 files changed
+129 -26

No files matched your search

+121 -19
View File
@@ -22,7 +22,8 @@ constexpr const char* kConfigGroup = "transui";
const SecretSchema kSecretSchema = {
"io.github.transui.credentials", SECRET_SCHEMA_NONE,
{{"scope", SECRET_SCHEMA_ATTRIBUTE_STRING}, {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING}}};
{{"scope", SECRET_SCHEMA_ATTRIBUTE_STRING}, {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING}},
0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
struct Config {
std::string hosted_url;
@@ -46,6 +47,7 @@ struct App {
GstElement* pipeline = nullptr;
std::string recording_path;
std::atomic<bool> cancelled{false};
bool open_settings_requested = false;
};
struct SettingsFields {
@@ -170,6 +172,7 @@ bool save_config(App* app, const Config& config, const std::string& hosted_key,
GtkWidget* labelled(GtkWidget* grid, const char* text, GtkWidget* control, int row) {
GtkWidget* label = gtk_label_new(text);
gtk_style_context_add_class(gtk_widget_get_style_context(label), "field-label");
gtk_label_set_xalign(GTK_LABEL(label), 0);
gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
gtk_grid_attach(GTK_GRID(grid), label, 0, row, 1, 1);
@@ -207,17 +210,20 @@ void open_settings(App* app) {
}
GtkWidget* window = gtk_application_window_new(app->gtk_app);
app->settings = window;
gtk_style_context_add_class(gtk_widget_get_style_context(window), "settings-window");
gtk_window_set_title(GTK_WINDOW(window), "Transui settings");
gtk_window_set_default_size(GTK_WINDOW(window), 590, 0);
gtk_window_set_resizable(GTK_WINDOW(window), false);
GtkWidget* root = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add(GTK_CONTAINER(window), root);
GtkWidget* header = gtk_header_bar_new();
gtk_style_context_add_class(gtk_widget_get_style_context(header), "transui-header");
gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(header), true);
gtk_header_bar_set_title(GTK_HEADER_BAR(header), "Transui");
gtk_window_set_titlebar(GTK_WINDOW(window), header);
GtkWidget* grid = gtk_grid_new();
gtk_style_context_add_class(gtk_widget_get_style_context(grid), "settings-panel");
gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
gtk_grid_set_column_spacing(GTK_GRID(grid), 18);
gtk_widget_set_margin_start(grid, 28);
@@ -254,7 +260,7 @@ void open_settings(App* app) {
gtk_widget_set_margin_end(actions, 28);
gtk_widget_set_margin_bottom(actions, 24);
gtk_widget_set_halign(actions, GTK_ALIGN_END);
GtkWidget* save = gtk_button_new_with_label("Save");
GtkWidget* save = gtk_button_new_with_label("Save settings");
gtk_style_context_add_class(gtk_widget_get_style_context(save), "suggested-action");
gtk_box_pack_end(GTK_BOX(actions), save, false, false, 0);
gtk_box_pack_start(GTK_BOX(root), actions, false, false, 0);
@@ -265,6 +271,7 @@ void open_settings(App* app) {
delete static_cast<SettingsFields*>(p);
}), fields, nullptr, G_CONNECT_AFTER);
gtk_widget_show_all(window);
gtk_window_present(GTK_WINDOW(window));
}
gboolean tick_elapsed(gpointer data) {
@@ -319,6 +326,8 @@ bool transcription_request(const std::string& url, const std::string& key,
part = curl_mime_addpart(mime);
curl_mime_name(part, "file");
curl_mime_filedata(part, path.c_str());
curl_mime_filename(part, "recording.wav");
curl_mime_type(part, "audio/wav");
if (!prompt.empty()) {
part = curl_mime_addpart(mime);
curl_mime_name(part, "prompt");
@@ -468,15 +477,18 @@ void cancel_processing(GtkButton* button, gpointer data) {
void show_processing(App* app) {
GtkWidget* window = gtk_application_window_new(app->gtk_app);
app->processing = window;
gtk_style_context_add_class(gtk_widget_get_style_context(window), "processing-window");
gtk_window_set_title(GTK_WINDOW(window), "Transui");
gtk_window_set_default_size(GTK_WINDOW(window), 310, 190);
gtk_window_set_resizable(GTK_WINDOW(window), false);
gtk_window_set_deletable(GTK_WINDOW(window), false);
GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_style_context_add_class(gtk_widget_get_style_context(box), "process-panel");
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_container_add(GTK_CONTAINER(window), box);
GtkWidget* spinner = gtk_spinner_new();
gtk_style_context_add_class(gtk_widget_get_style_context(spinner), "signal-spinner");
gtk_widget_set_size_request(spinner, 36, 36);
gtk_spinner_start(GTK_SPINNER(spinner));
gtk_box_pack_start(GTK_BOX(box), spinner, false, false, 0);
@@ -488,6 +500,7 @@ void show_processing(App* app) {
g_signal_connect(cancel, "clicked", G_CALLBACK(cancel_processing), app);
g_signal_connect(window, "destroy", G_CALLBACK(processing_closed), app);
gtk_widget_show_all(window);
gtk_window_present(GTK_WINDOW(window));
}
void stop_recording(GtkButton*, gpointer data) {
@@ -510,7 +523,8 @@ void stop_recording(GtkButton*, gpointer data) {
app->recorder = nullptr;
app->cancelled.store(false);
show_processing(app);
auto* job = new Job{app, app->recording_path, app->config, app->hosted_key, app->local_key};
auto* job = new Job{app, app->recording_path, app->config, app->hosted_key,
app->local_key, false, {}, {}};
g_thread_unref(g_thread_new("transcription", job_thread, job));
}
@@ -566,16 +580,20 @@ void start_recording(App* app) {
}
GtkWidget* window = gtk_application_window_new(app->gtk_app);
app->recorder = window;
gtk_style_context_add_class(gtk_widget_get_style_context(window), "recorder-window");
gtk_window_set_title(GTK_WINDOW(window), "Transui");
gtk_window_set_default_size(GTK_WINDOW(window), 330, 250);
gtk_window_set_resizable(GTK_WINDOW(window), false);
GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_style_context_add_class(gtk_widget_get_style_context(box), "record-panel");
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_container_add(GTK_CONTAINER(window), box);
GtkWidget* dot = gtk_label_new("●");
gtk_style_context_add_class(gtk_widget_get_style_context(dot), "record-dot");
gtk_box_pack_start(GTK_BOX(box), dot, false, false, 0);
GtkWidget* light = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_size_request(light, 30, 30);
gtk_widget_set_halign(light, GTK_ALIGN_CENTER);
gtk_style_context_add_class(gtk_widget_get_style_context(light), "record-light");
gtk_box_pack_start(GTK_BOX(box), light, false, false, 0);
GtkWidget* state = gtk_label_new("RECORDING");
gtk_style_context_add_class(gtk_widget_get_style_context(state), "record-state");
gtk_box_pack_start(GTK_BOX(box), state, false, false, 0);
@@ -595,19 +613,88 @@ void start_recording(App* app) {
g_signal_connect(stop, "clicked", G_CALLBACK(stop_recording), app);
g_signal_connect(window, "destroy", G_CALLBACK(recorder_closed), app);
gtk_widget_show_all(window);
gtk_window_present(GTK_WINDOW(window));
}
void install_css() {
const char* css = R"CSS(
window { background-color: #111827; color: #edf1f7; }
entry, combobox button { background: #1e293b; color: #edf1f7; border: 1px solid #334155; border-radius: 5px; }
label { color: #cbd5e1; }
.record-dot { color: #fb7185; font-size: 30px; }
.record-state { color: #fb7185; font-weight: 800; letter-spacing: 2px; font-size: 12px; }
.elapsed { color: #f8fafc; font-family: monospace; font-size: 38px; font-weight: 700; }
.state-title { color: #f8fafc; font-size: 18px; font-weight: 700; }
button.suggested-action { background: #f97316; color: #111827; border-color: #f97316; font-weight: 700; }
button.suggested-action:hover { background: #fb923c; }
window {
background-color: #181b1a;
color: #eef0e8;
font-family: Cantarell, sans-serif;
}
headerbar.transui-header {
background: #202421;
color: #eef0e8;
border-bottom: 1px solid #3b413c;
box-shadow: none;
}
.settings-panel {
background-color: #202421;
border: 1px solid #3b413c;
border-radius: 8px;
padding: 20px;
}
.field-label {
color: #aeb7ae;
font-size: 12px;
font-weight: 700;
}
entry, combobox button {
background: #2a2f2b;
color: #eef0e8;
border: 1px solid #4a514b;
border-radius: 4px;
padding: 7px 9px;
}
entry:focus, combobox button:focus, button:focus {
border-color: #d4a44c;
box-shadow: 0 0 0 1px #d4a44c;
}
label { color: #d8ddd5; }
checkbutton { color: #d8ddd5; }
.record-panel, .process-panel {
background-color: #202421;
border: 1px solid #3b413c;
border-radius: 12px;
padding: 28px 36px;
}
.record-light {
background: #e64a3c;
border: 6px solid #552a25;
border-radius: 50%;
box-shadow: 0 0 0 1px #f17a6f;
}
.record-state {
color: #f17a6f;
font-weight: 800;
letter-spacing: 2px;
font-size: 11px;
}
.elapsed {
color: #eef0e8;
font-family: "DejaVu Sans Mono", monospace;
font-size: 42px;
font-weight: 700;
letter-spacing: 1px;
}
.state-title { color: #eef0e8; font-size: 17px; font-weight: 700; }
.signal-spinner { color: #d4a44c; }
button {
background: #2a2f2b;
color: #eef0e8;
border: 1px solid #4a514b;
border-radius: 4px;
padding: 7px 12px;
}
button:hover { background: #343a35; }
button.suggested-action {
background: #d4a44c;
color: #181b1a;
border-color: #d4a44c;
font-weight: 800;
}
button.suggested-action:hover { background: #e1b760; }
)CSS";
GtkCssProvider* provider = gtk_css_provider_new();
gtk_css_provider_load_from_data(provider, css, -1, nullptr);
@@ -616,7 +703,22 @@ void install_css() {
g_object_unref(provider);
}
void activate(GtkApplication*, gpointer data) { start_recording(static_cast<App*>(data)); }
void activate(GtkApplication*, gpointer data) {
auto* app = static_cast<App*>(data);
if (app->open_settings_requested) open_settings(app);
else start_recording(app);
}
int command_line(GApplication* application, GApplicationCommandLine* command, gpointer data) {
auto* app = static_cast<App*>(data);
int argument_count = 0;
gchar** arguments = g_application_command_line_get_arguments(command, &argument_count);
app->open_settings_requested =
argument_count == 2 && std::strcmp(arguments[1], "settings") == 0;
g_strfreev(arguments);
g_application_activate(application);
return 0;
}
} // namespace
@@ -630,12 +732,12 @@ int main(int argc, char** argv) {
curl_global_init(CURL_GLOBAL_DEFAULT);
App app;
load_config(&app);
app.gtk_app = gtk_application_new(kAppId, G_APPLICATION_DEFAULT_FLAGS);
app.gtk_app = gtk_application_new(kAppId, G_APPLICATION_HANDLES_COMMAND_LINE);
g_signal_connect(app.gtk_app, "startup", G_CALLBACK(+[](GtkApplication*, gpointer) {
install_css();
}), nullptr);
if (settings) g_signal_connect_swapped(app.gtk_app, "activate", G_CALLBACK(open_settings), &app);
else g_signal_connect(app.gtk_app, "activate", G_CALLBACK(activate), &app);
g_signal_connect(app.gtk_app, "activate", G_CALLBACK(activate), &app);
g_signal_connect(app.gtk_app, "command-line", G_CALLBACK(command_line), &app);
const int result = g_application_run(G_APPLICATION(app.gtk_app), argc, argv);
if (app.pipeline) close_recorder(&app);
remove_recording(&app);