notification.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-FileCopyrightText: GSConnect Developers https://github.com/GSConnect
  2. //
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. import Gio from 'gi://Gio';
  5. import GObject from 'gi://GObject';
  6. import Gtk from 'gi://Gtk';
  7. import * as URI from '../utils/uri.js';
  8. import '../utils/ui.js';
  9. /**
  10. * A dialog for repliable notifications.
  11. */
  12. const ReplyDialog = GObject.registerClass({
  13. GTypeName: 'GSConnectNotificationReplyDialog',
  14. Properties: {
  15. 'device': GObject.ParamSpec.object(
  16. 'device',
  17. 'Device',
  18. 'The device associated with this window',
  19. GObject.ParamFlags.READWRITE,
  20. GObject.Object
  21. ),
  22. 'plugin': GObject.ParamSpec.object(
  23. 'plugin',
  24. 'Plugin',
  25. 'The plugin that owns this notification',
  26. GObject.ParamFlags.READWRITE,
  27. GObject.Object
  28. ),
  29. 'uuid': GObject.ParamSpec.string(
  30. 'uuid',
  31. 'UUID',
  32. 'The notification reply UUID',
  33. GObject.ParamFlags.READWRITE,
  34. null
  35. ),
  36. },
  37. Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/notification-reply-dialog.ui',
  38. Children: ['infobar', 'notification-title', 'notification-body', 'entry'],
  39. }, class ReplyDialog extends Gtk.Dialog {
  40. _init(params) {
  41. super._init({
  42. application: Gio.Application.get_default(),
  43. device: params.device,
  44. plugin: params.plugin,
  45. uuid: params.uuid,
  46. use_header_bar: true,
  47. });
  48. this.set_response_sensitive(Gtk.ResponseType.OK, false);
  49. // Info bar
  50. this.device.bind_property(
  51. 'connected',
  52. this.infobar,
  53. 'reveal-child',
  54. GObject.BindingFlags.INVERT_BOOLEAN
  55. );
  56. // Notification Data
  57. const headerbar = this.get_titlebar();
  58. headerbar.title = params.notification.appName;
  59. headerbar.subtitle = this.device.name;
  60. this.notification_title.label = params.notification.title;
  61. this.notification_body.label = URI.linkify(params.notification.text);
  62. // Message Entry/Send Button
  63. this.device.bind_property(
  64. 'connected',
  65. this.entry,
  66. 'sensitive',
  67. GObject.BindingFlags.DEFAULT
  68. );
  69. this._connectedId = this.device.connect(
  70. 'notify::connected',
  71. this._onStateChanged.bind(this)
  72. );
  73. this._entryChangedId = this.entry.buffer.connect(
  74. 'changed',
  75. this._onStateChanged.bind(this)
  76. );
  77. this.restoreGeometry('notification-reply-dialog');
  78. this.connect('destroy', this._onDestroy);
  79. }
  80. _onDestroy(dialog) {
  81. dialog.entry.buffer.disconnect(dialog._entryChangedId);
  82. dialog.device.disconnect(dialog._connectedId);
  83. }
  84. vfunc_delete_event() {
  85. this.saveGeometry();
  86. return false;
  87. }
  88. vfunc_response(response_id) {
  89. if (response_id === Gtk.ResponseType.OK) {
  90. // Refuse to send empty or whitespace only messages
  91. if (!this.entry.buffer.text.trim())
  92. return;
  93. this.plugin.replyNotification(
  94. this.uuid,
  95. this.entry.buffer.text
  96. );
  97. }
  98. this.destroy();
  99. }
  100. get device() {
  101. if (this._device === undefined)
  102. this._device = null;
  103. return this._device;
  104. }
  105. set device(device) {
  106. this._device = device;
  107. }
  108. get plugin() {
  109. if (this._plugin === undefined)
  110. this._plugin = null;
  111. return this._plugin;
  112. }
  113. set plugin(plugin) {
  114. this._plugin = plugin;
  115. }
  116. get uuid() {
  117. if (this._uuid === undefined)
  118. this._uuid = null;
  119. return this._uuid;
  120. }
  121. set uuid(uuid) {
  122. this._uuid = uuid;
  123. // We must have a UUID
  124. if (!uuid) {
  125. this.destroy();
  126. debug('no uuid for repliable notification');
  127. }
  128. }
  129. _onActivateLink(label, uri) {
  130. Gtk.show_uri_on_window(
  131. this.get_toplevel(),
  132. uri.includes('://') ? uri : `https://${uri}`,
  133. Gtk.get_current_event_time()
  134. );
  135. return true;
  136. }
  137. _onStateChanged() {
  138. if (this.device.connected && this.entry.buffer.text.trim())
  139. this.set_response_sensitive(Gtk.ResponseType.OK, true);
  140. else
  141. this.set_response_sensitive(Gtk.ResponseType.OK, false);
  142. }
  143. });
  144. export default ReplyDialog;