Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
privacy_consent.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#ifdef HAVE_CONFIG_H
20#include "config.h"
21#endif
22
24#include "common/darktable.h"
25
26#if defined(HAVE_SENTRY) || defined(HAVE_TELEMETRY)
27
28#include "control/conf.h"
29#include "gui/gtk.h"
30
31// Non-confgen sentinel: its presence means the user has already been asked. The
32// per-feature toggles (sentry/enabled, telemetry/enabled) are confgen keys shown
33// in Preferences ▸ Storage ▸ Privacy, so they can be changed later.
34#define DT_PRIVACY_ASKED_KEY "privacy/consent_asked"
35
36// User-facing documentation describing exactly what is collected, where it goes
37// and why. Linked from the consent dialog so the decision is informed.
38#define DT_PRIVACY_DOC_URL "https://ansel.photos/en/data-privacy/"
39
40void dt_privacy_ask_consent(const gboolean have_gui)
41{
42 // Already decided once: never ask again (toggles live in Preferences).
43 if(dt_conf_key_exists(DT_PRIVACY_ASKED_KEY)) return;
44
45 // Without a GUI we cannot prompt; leave both features at their (off) defaults
46 // until the user is shown the dialog on a future GUI launch.
47 if(!have_gui) return;
48
50
51 GtkWidget *dialog = gtk_dialog_new_with_buttons(
52 _("Help us improve Ansel"), GTK_WINDOW(parent),
53 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
54 _("Confirm choices"), GTK_RESPONSE_ACCEPT, NULL);
55 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
56
57 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
58 gtk_box_set_spacing(GTK_BOX(content), DT_PIXEL_APPLY_DPI(8));
59 gtk_container_set_border_width(GTK_CONTAINER(content), DT_PIXEL_APPLY_DPI(12));
60
61 GtkWidget *intro = gtk_label_new(
62 _("Ansel can share anonymous data with its developers to help fix bugs and "
63 "decide what to work on. This is entirely optional, separate for each purpose, "
64 "and can be changed any time in Preferences ▸ Storage ▸ Privacy.\n\n"
65 "We never send your images, file names or any personal data."));
66 gtk_label_set_line_wrap(GTK_LABEL(intro), TRUE);
67 gtk_label_set_xalign(GTK_LABEL(intro), 0.0);
68 gtk_label_set_max_width_chars(GTK_LABEL(intro), 64);
69 gtk_box_pack_start(GTK_BOX(content), intro, FALSE, FALSE, 0);
70
71#ifdef HAVE_SENTRY
72 GtkWidget *crash_check = gtk_check_button_new_with_label(
73 _("Send crash reports (backtrace, OS and hardware specs, app version)"));
74 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(crash_check), TRUE);
75 gtk_box_pack_start(GTK_BOX(content), crash_check, FALSE, FALSE, 0);
76#endif
77
78#ifdef HAVE_TELEMETRY
79 GtkWidget *usage_check = gtk_check_button_new_with_label(
80 _("Share anonymous usage statistics (features used, file types, OS and hardware)"));
81 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(usage_check), TRUE);
82 gtk_box_pack_start(GTK_BOX(content), usage_check, FALSE, FALSE, 0);
83#endif
84
85 GtkWidget *link = gtk_link_button_new_with_label(
86 DT_PRIVACY_DOC_URL, _("Read what is collected, where it goes and why"));
87 gtk_widget_set_halign(link, GTK_ALIGN_START);
88 gtk_box_pack_start(GTK_BOX(content), link, FALSE, FALSE, 0);
89
90 gtk_widget_show_all(dialog);
91 gtk_dialog_run(GTK_DIALOG(dialog));
92
93 // Whatever the close action, honor the current checkbox state (both default to
94 // on). Features not built in stay disabled.
95#ifdef HAVE_SENTRY
96 dt_conf_set_bool("sentry/enabled", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(crash_check)));
97#endif
98#ifdef HAVE_TELEMETRY
99 dt_conf_set_bool("telemetry/enabled", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(usage_check)));
100#endif
101
102 gtk_widget_destroy(dialog);
103
104 // Record that the user has decided so the dialog never shows again.
105 dt_conf_set_bool(DT_PRIVACY_ASKED_KEY, TRUE);
106}
107
108#else // neither crash reporting nor analytics built in
109
110void dt_privacy_ask_consent(const gboolean have_gui)
111{
112}
113
114#endif
115
116// clang-format off
117// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
118// vim: shiftwidth=2 expandtab tabstop=2 cindent
119// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
120// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_conf_set_bool(const char *name, int val)
int dt_conf_key_exists(const char *key)
darktable_t darktable
Definition darktable.c:181
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_PIXEL_APPLY_DPI(value)
Definition gtk.h:90
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_gui_gtk_t * gui
Definition darktable.h:775
dt_ui_t * ui
Definition gtk.h:164