aboutsummaryrefslogtreecommitdiff
path: root/main/src/ui/conversation_content_view
diff options
context:
space:
mode:
authorfiaxh <git@lightrise.org>2021-03-19 23:09:56 +0100
committerfiaxh <git@lightrise.org>2021-03-21 12:41:39 +0100
commit0f46facecd558786631c2ad4cf66d27331f16a86 (patch)
tree74ba0d120dabbaf55e204cca5355022f3c3ba60e /main/src/ui/conversation_content_view
parentcdb4d77259e6c361aaca64a483a43d7441f4803d (diff)
downloaddino-0f46facecd558786631c2ad4cf66d27331f16a86.tar.gz
dino-0f46facecd558786631c2ad4cf66d27331f16a86.zip
Add UI for audio/video calls
Diffstat (limited to 'main/src/ui/conversation_content_view')
-rw-r--r--main/src/ui/conversation_content_view/call_widget.vala215
-rw-r--r--main/src/ui/conversation_content_view/content_populator.vala3
-rw-r--r--main/src/ui/conversation_content_view/file_widget.vala3
3 files changed, 218 insertions, 3 deletions
diff --git a/main/src/ui/conversation_content_view/call_widget.vala b/main/src/ui/conversation_content_view/call_widget.vala
new file mode 100644
index 00000000..66788e28
--- /dev/null
+++ b/main/src/ui/conversation_content_view/call_widget.vala
@@ -0,0 +1,215 @@
+using Gee;
+using Gdk;
+using Gtk;
+using Pango;
+
+using Dino.Entities;
+
+namespace Dino.Ui {
+
+ public class CallMetaItem : ConversationSummary.ContentMetaItem {
+
+ private StreamInteractor stream_interactor;
+
+ public CallMetaItem(ContentItem content_item, StreamInteractor stream_interactor) {
+ base(content_item);
+ this.stream_interactor = stream_interactor;
+ }
+
+ public override Object? get_widget(Plugins.WidgetType type) {
+ CallItem call_item = content_item as CallItem;
+ return new CallWidget(stream_interactor, call_item.call, call_item.conversation) { visible=true };
+ }
+
+ public override Gee.List<Plugins.MessageAction>? get_item_actions(Plugins.WidgetType type) { return null; }
+ }
+
+ [GtkTemplate (ui = "/im/dino/Dino/call_widget.ui")]
+ public class CallWidget : SizeRequestBox {
+
+ [GtkChild] public Image image;
+ [GtkChild] public Label title_label;
+ [GtkChild] public Label subtitle_label;
+ [GtkChild] public Revealer incoming_call_revealer;
+ [GtkChild] public Button accept_call_button;
+ [GtkChild] public Button reject_call_button;
+
+ private StreamInteractor stream_interactor;
+ private Call call;
+ private Conversation conversation;
+ public Call.State call_state { get; set; } // needs to be public for binding
+ private uint time_update_handler_id = 0;
+
+ construct {
+ margin_top = 4;
+ size_request_mode = SizeRequestMode.HEIGHT_FOR_WIDTH;
+ }
+
+ public CallWidget(StreamInteractor stream_interactor, Call call, Conversation conversation) {
+ this.stream_interactor = stream_interactor;
+ this.call = call;
+ this.conversation = conversation;
+
+ size_allocate.connect((allocation) => {
+ if (allocation.height > parent.get_allocated_height()) {
+ Idle.add(() => { parent.queue_resize(); return false; });
+ }
+ });
+
+ call.bind_property("state", this, "call-state");
+ this.notify["call-state"].connect(update_widget);
+
+ accept_call_button.clicked.connect(() => {
+ stream_interactor.get_module(Calls.IDENTITY).accept_call(call);
+
+ var call_window = new CallWindow();
+ call_window.controller = new CallWindowController(call_window, call, stream_interactor);
+ call_window.present();
+ });
+
+ reject_call_button.clicked.connect(() => {
+ stream_interactor.get_module(Calls.IDENTITY).reject_call(call);
+ });
+
+ update_widget();
+ }
+
+ private void update_widget() {
+ incoming_call_revealer.reveal_child = false;
+ incoming_call_revealer.get_style_context().remove_class("incoming");
+
+ switch (call.state) {
+ case Call.State.RINGING:
+ image.set_from_icon_name("dino-phone-ring-symbolic", IconSize.LARGE_TOOLBAR);
+ if (call.direction == Call.DIRECTION_INCOMING) {
+ bool video = stream_interactor.get_module(Calls.IDENTITY).should_we_send_video(call);
+ title_label.label = video ? _("Video call incoming") : _("Call incoming");
+ subtitle_label.label = "Ring ring…!";
+ incoming_call_revealer.reveal_child = true;
+ incoming_call_revealer.get_style_context().add_class("incoming");
+ } else {
+ title_label.label = _("Establishing call");
+ subtitle_label.label = "Ring ring…?";
+ }
+ break;
+ case Call.State.ESTABLISHING:
+ image.set_from_icon_name("dino-phone-ring-symbolic", IconSize.LARGE_TOOLBAR);
+ if (call.direction == Call.DIRECTION_INCOMING) {
+ bool video = stream_interactor.get_module(Calls.IDENTITY).should_we_send_video(call);
+ title_label.label = video ? _("Video call establishing") : _("Call establishing");
+ subtitle_label.label = "Connecting…";
+ }
+ break;
+ case Call.State.IN_PROGRESS:
+ image.set_from_icon_name("dino-phone-in-talk-symbolic", IconSize.LARGE_TOOLBAR);
+ title_label.label = _("Call in progress…");
+ string duration = get_duration_string((new DateTime.now_utc()).difference(call.local_time));
+ subtitle_label.label = _("Started %s ago").printf(duration);
+
+ time_update_handler_id = Timeout.add_seconds(get_next_time_change() + 1, () => {
+ Source.remove(time_update_handler_id);
+ time_update_handler_id = 0;
+ update_widget();
+ return true;
+ });
+
+ break;
+ case Call.State.OTHER_DEVICE_ACCEPTED:
+ image.set_from_icon_name("dino-phone-hangup-symbolic", IconSize.LARGE_TOOLBAR);
+ title_label.label = call.direction == Call.DIRECTION_INCOMING ? _("Incoming call") : _("Outgoing call");
+ subtitle_label.label = _("You handled this call on another device");
+
+ break;
+ case Call.State.ENDED:
+ image.set_from_icon_name("dino-phone-hangup-symbolic", IconSize.LARGE_TOOLBAR);
+ title_label.label = _("Call ended");
+ string formated_end = Util.format_time(call.end_time, _("%H∶%M"), _("%l∶%M %p"));
+ string duration = get_duration_string(call.end_time.difference(call.local_time));
+ subtitle_label.label = _("Ended at %s").printf(formated_end) +
+ " · " +
+ _("Lasted for %s").printf(duration);
+ break;
+ case Call.State.MISSED:
+ image.set_from_icon_name("dino-phone-missed-symbolic", IconSize.LARGE_TOOLBAR);
+ title_label.label = _("Call missed");
+ string who = null;
+ if (call.direction == Call.DIRECTION_INCOMING) {
+ who = "You";
+ } else {
+ who = Util.get_participant_display_name(stream_interactor, conversation, call.to);
+ }
+ subtitle_label.label = "%s missed this call".printf(who);
+ break;
+ case Call.State.DECLINED:
+ image.set_from_icon_name("dino-phone-hangup-symbolic", IconSize.LARGE_TOOLBAR);
+ title_label.label = _("Call declined");
+ string who = null;
+ if (call.direction == Call.DIRECTION_INCOMING) {
+ who = "You";
+ } else {
+ who = Util.get_participant_display_name(stream_interactor, conversation, call.to);
+ }
+ subtitle_label.label = "%s declined this call".printf(who);
+ break;
+ case Call.State.FAILED:
+ image.set_from_icon_name("dino-phone-hangup-symbolic", IconSize.LARGE_TOOLBAR);
+ title_label.label = _("Call failed");
+ subtitle_label.label = "This call failed to establish";
+ break;
+ }
+ }
+
+ private string get_duration_string(TimeSpan duration) {
+ DateTime a = new DateTime.now_utc();
+ DateTime b = new DateTime.now_utc();
+ a.difference(b);
+
+ TimeSpan remainder_duration = duration;
+
+ int hours = (int) Math.floor(remainder_duration / TimeSpan.HOUR);
+ remainder_duration -= hours * TimeSpan.HOUR;
+
+ int minutes = (int) Math.floor(remainder_duration / TimeSpan.MINUTE);
+ remainder_duration -= minutes * TimeSpan.MINUTE;
+
+ string ret = "";
+
+ if (hours > 0) {
+ ret += n("%i hour", "%i hours", hours).printf(hours);
+ }
+
+ if (minutes > 0) {
+ if (ret.length > 0) {
+ ret += " ";
+ }
+ ret += n("%i minute", "%i minutes", minutes).printf(minutes);
+ }
+
+ if (ret.length > 0) {
+ return ret;
+ }
+
+ return _("seconds");
+ }
+
+ private int get_next_time_change() {
+ DateTime now = new DateTime.now_local();
+ DateTime item_time = call.local_time;
+
+ if (now.get_second() < item_time.get_second()) {
+ return item_time.get_second() - now.get_second();
+ } else {
+ return 60 - (now.get_second() - item_time.get_second());
+ }
+ }
+
+ public override void dispose() {
+ base.dispose();
+
+ if (time_update_handler_id != 0) {
+ Source.remove(time_update_handler_id);
+ time_update_handler_id = 0;
+ }
+ }
+ }
+}
diff --git a/main/src/ui/conversation_content_view/content_populator.vala b/main/src/ui/conversation_content_view/content_populator.vala
index 97f15bf9..d7ce9ce5 100644
--- a/main/src/ui/conversation_content_view/content_populator.vala
+++ b/main/src/ui/conversation_content_view/content_populator.vala
@@ -68,7 +68,10 @@ public class ContentProvider : ContentItemCollection, Object {
return new MessageMetaItem(content_item, stream_interactor);
} else if (content_item.type_ == FileItem.TYPE) {
return new FileMetaItem(content_item, stream_interactor);
+ } else if (content_item.type_ == CallItem.TYPE) {
+ return new CallMetaItem(content_item, stream_interactor);
}
+ critical("Got unknown content item type %s", content_item.type_);
return null;
}
}
diff --git a/main/src/ui/conversation_content_view/file_widget.vala b/main/src/ui/conversation_content_view/file_widget.vala
index 9b748876..7d77ba11 100644
--- a/main/src/ui/conversation_content_view/file_widget.vala
+++ b/main/src/ui/conversation_content_view/file_widget.vala
@@ -32,9 +32,6 @@ public class FileWidget : SizeRequestBox {
DEFAULT
}
- private const int MAX_HEIGHT = 300;
- private const int MAX_WIDTH = 600;
-
private StreamInteractor stream_interactor;
private FileTransfer file_transfer;
public FileTransfer.State file_transfer_state { get; set; }