aboutsummaryrefslogtreecommitdiff
path: root/main/src/ui/call_window/call_bottom_bar.vala
blob: c6375ea22a6af0da26e78a40cfd8ad0c14c25fea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
using Dino.Entities;
using Gtk;
using Pango;

public class Dino.Ui.CallBottomBar : Gtk.Box {

    public signal void hang_up();

    public bool audio_enabled { get; set; }
    public bool video_enabled { get; set; }

    public static IconSize ICON_SIZE_MEDIADEVICE_BUTTON = Gtk.icon_size_register("im.dino.Dino.CALL_MEDIADEVICE_BUTTON", 10, 10);

    public string counterpart_display_name { get; set; }

    private Button audio_button = new Button() { height_request=45, width_request=45, halign=Align.START, valign=Align.START, visible=true };
    private Overlay audio_button_overlay = new Overlay() { visible=true };
    private Image audio_image = new Image() { visible=true };
    private MenuButton audio_settings_button = new MenuButton() { halign=Align.END, valign=Align.END };
    public AudioSettingsPopover? audio_settings_popover;

    private Button video_button = new Button() { height_request=45, width_request=45, halign=Align.START, valign=Align.START, visible=true };
    private Overlay video_button_overlay = new Overlay() { visible=true };
    private Image video_image = new Image() { visible=true };
    private MenuButton video_settings_button = new MenuButton() { halign=Align.END, valign=Align.END };
    public VideoSettingsPopover? video_settings_popover;

    private EventBox encryption_event_box = new EventBox() { visible=true };
    private MenuButton encryption_button = new MenuButton() { relief=ReliefStyle.NONE, height_request=30, width_request=30, margin_start=20, margin_bottom=25, halign=Align.START, valign=Align.END };
    private Image encryption_image = new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON) { visible=true };

    private Label label = new Label("") { margin=20, halign=Align.CENTER, valign=Align.CENTER, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true, visible=true };
    private Stack stack = new Stack() { visible=true };

    public CallBottomBar() {
        Object(orientation:Orientation.HORIZONTAL, spacing:0);

        Overlay default_control = new Overlay() { visible=true };
        encryption_button.add(encryption_image);
        encryption_button.get_style_context().add_class("encryption-box");
        default_control.add_overlay(encryption_button);

        Box main_buttons = new Box(Orientation.HORIZONTAL, 20) { margin_start=40, margin_end=40, margin=20, halign=Align.CENTER, hexpand=true, visible=true };

        audio_button.add(audio_image);
        audio_button.get_style_context().add_class("call-button");
        audio_button.clicked.connect(() => { audio_enabled = !audio_enabled; });
        audio_button.margin_end = audio_button.margin_bottom = 5; // space for the small settings button
        audio_button_overlay.add(audio_button);
        audio_button_overlay.add_overlay(audio_settings_button);
        audio_settings_button.set_image(new Image.from_icon_name("go-up-symbolic", ICON_SIZE_MEDIADEVICE_BUTTON) { visible=true });
        audio_settings_button.get_style_context().add_class("call-mediadevice-settings-button");
        audio_settings_button.use_popover = true;
        main_buttons.add(audio_button_overlay);

        video_button.add(video_image);
        video_button.get_style_context().add_class("call-button");
        video_button.clicked.connect(() => { video_enabled = !video_enabled; });
        video_button.margin_end = video_button.margin_bottom = 5;
        video_button_overlay.add(video_button);
        video_button_overlay.add_overlay(video_settings_button);
        video_settings_button.set_image(new Image.from_icon_name("go-up-symbolic", ICON_SIZE_MEDIADEVICE_BUTTON) { visible=true });
        video_settings_button.get_style_context().add_class("call-mediadevice-settings-button");
        video_settings_button.use_popover = true;
        main_buttons.add(video_button_overlay);

        Button button_hang = new Button.from_icon_name("dino-phone-hangup-symbolic", IconSize.LARGE_TOOLBAR) { height_request=45, width_request=45, halign=Align.START, valign=Align.START, visible=true };
        button_hang.get_style_context().add_class("call-button");
        button_hang.get_style_context().add_class("destructive-action");
        button_hang.clicked.connect(() => hang_up());
        main_buttons.add(button_hang);

        default_control.add(main_buttons);

        label.get_style_context().add_class("text-no-controls");

        stack.add_named(default_control, "control-buttons");
        stack.add_named(label, "label");
        this.add(stack);

        this.notify["audio-enabled"].connect(on_audio_enabled_changed);
        this.notify["video-enabled"].connect(on_video_enabled_changed);

        audio_enabled = true;
        video_enabled = false;

        on_audio_enabled_changed();
        on_video_enabled_changed();

        this.get_style_context().add_class("call-bottom-bar");
    }

    public void set_encryption(Xmpp.Xep.Jingle.ContentEncryption? encryption) {
        encryption_button.visible = true;

        Popover popover = new Popover(encryption_button);

        if (encryption == null) {
            encryption_image.set_from_icon_name("changes-allow-symbolic", IconSize.BUTTON);
            encryption_button.get_style_context().add_class("unencrypted");

            popover.add(new Label("This call isn't encrypted.") { margin=10, visible=true } );
        } else {
            encryption_image.set_from_icon_name("changes-prevent-symbolic", IconSize.BUTTON);
            encryption_button.get_style_context().remove_class("unencrypted");

            Grid encryption_info_grid = new Grid() { margin=10, row_spacing=3, column_spacing=5, visible=true };
            encryption_info_grid.attach(new Label("<b>This call is end-to-end encrypted.</b>") { use_markup=true, xalign=0, visible=true }, 1, 1, 2, 1);
            encryption_info_grid.attach(new Label("Peer key") { xalign=0, visible=true }, 1, 2, 1, 1);
            encryption_info_grid.attach(new Label("Your key") { xalign=0, visible=true }, 1, 3, 1, 1);
            encryption_info_grid.attach(new Label("<span font_family='monospace'>" + format_fingerprint(encryption.peer_key) + "</span>") { use_markup=true, max_width_chars=25, ellipsize=EllipsizeMode.MIDDLE, xalign=0, hexpand=true, visible=true }, 2, 2, 1, 1);
            encryption_info_grid.attach(new Label("<span font_family='monospace'>" + format_fingerprint(encryption.our_key) + "</span>") { use_markup=true, max_width_chars=25, ellipsize=EllipsizeMode.MIDDLE, xalign=0, hexpand=true, visible=true }, 2, 3, 1, 1);

            popover.add(encryption_info_grid);
        }

        encryption_button.set_popover(popover);
    }

    public AudioSettingsPopover? show_audio_device_choices(bool show) {
        audio_settings_button.visible = show;
        if (audio_settings_popover != null) audio_settings_popover.visible = false;
        if (!show) return null;

        audio_settings_popover = new AudioSettingsPopover();

        audio_settings_button.popover = audio_settings_popover;

        audio_settings_popover.set_relative_to(audio_settings_button);
        audio_settings_popover.microphone_selected.connect(() => { audio_settings_button.active = false; });
        audio_settings_popover.speaker_selected.connect(() => { audio_settings_button.active = false; });

        return audio_settings_popover;
    }

    public void show_audio_device_error() {
        audio_settings_button.set_image(new Image.from_icon_name("dialog-warning-symbolic", IconSize.BUTTON) { visible=true });
        Util.force_error_color(audio_settings_button);
    }

    public VideoSettingsPopover? show_video_device_choices(bool show) {
        video_settings_button.visible = show;
        if (video_settings_popover != null) video_settings_popover.visible = false;
        if (!show) return null;

        video_settings_popover = new VideoSettingsPopover();


        video_settings_button.popover = video_settings_popover;

        video_settings_popover.set_relative_to(video_settings_button);
        video_settings_popover.camera_selected.connect(() => { video_settings_button.active = false; });

        return video_settings_popover;
    }

    public void show_video_device_error() {
        video_settings_button.set_image(new Image.from_icon_name("dialog-warning-symbolic", IconSize.BUTTON) { visible=true });
        Util.force_error_color(video_settings_button);
    }

    public void on_audio_enabled_changed() {
        if (audio_enabled) {
            audio_image.set_from_icon_name("dino-microphone-symbolic", IconSize.LARGE_TOOLBAR);
            audio_button.get_style_context().add_class("white-button");
            audio_button.get_style_context().remove_class("transparent-white-button");
        } else {
            audio_image.set_from_icon_name("dino-microphone-off-symbolic", IconSize.LARGE_TOOLBAR);
            audio_button.get_style_context().remove_class("white-button");
            audio_button.get_style_context().add_class("transparent-white-button");
        }
    }

    public void on_video_enabled_changed() {
        if (video_enabled) {
            video_image.set_from_icon_name("dino-video-symbolic", IconSize.LARGE_TOOLBAR);
            video_button.get_style_context().add_class("white-button");
            video_button.get_style_context().remove_class("transparent-white-button");

        } else {
            video_image.set_from_icon_name("dino-video-off-symbolic", IconSize.LARGE_TOOLBAR);
            video_button.get_style_context().remove_class("white-button");
            video_button.get_style_context().add_class("transparent-white-button");
        }
    }

    public void show_counterpart_ended(string text) {
        stack.set_visible_child_name("label");
        label.label = text;
    }

    public bool is_menu_active() {
        return video_settings_button.active || audio_settings_button.active || encryption_button.active;
    }

    private string format_fingerprint(uint8[] fingerprint) {
        var sb = new StringBuilder();
        for (int i = 0; i < fingerprint.length; i++) {
            sb.append("%02x".printf(fingerprint[i]));
            if (i < fingerprint.length - 1) {
                sb.append(":");
            }
        }
        return sb.str;
    }
}