legacyMessaging.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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 Contacts from '../ui/contacts.js';
  8. import * as Messaging from '../ui/messaging.js';
  9. import * as URI from '../utils/uri.js';
  10. import '../utils/ui.js';
  11. const Dialog = GObject.registerClass({
  12. GTypeName: 'GSConnectLegacyMessagingDialog',
  13. Properties: {
  14. 'device': GObject.ParamSpec.object(
  15. 'device',
  16. 'Device',
  17. 'The device associated with this window',
  18. GObject.ParamFlags.READWRITE,
  19. GObject.Object
  20. ),
  21. 'plugin': GObject.ParamSpec.object(
  22. 'plugin',
  23. 'Plugin',
  24. 'The plugin providing messages',
  25. GObject.ParamFlags.READWRITE,
  26. GObject.Object
  27. ),
  28. },
  29. Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/legacy-messaging-dialog.ui',
  30. Children: [
  31. 'infobar', 'stack',
  32. 'message-box', 'message-avatar', 'message-label', 'entry',
  33. ],
  34. }, class Dialog extends Gtk.Dialog {
  35. _init(params) {
  36. super._init({
  37. application: Gio.Application.get_default(),
  38. device: params.device,
  39. plugin: params.plugin,
  40. use_header_bar: true,
  41. });
  42. this.set_response_sensitive(Gtk.ResponseType.OK, false);
  43. // Dup some functions
  44. this.headerbar = this.get_titlebar();
  45. this._setHeaderBar = Messaging.Window.prototype._setHeaderBar;
  46. // Info bar
  47. this.device.bind_property(
  48. 'connected',
  49. this.infobar,
  50. 'reveal-child',
  51. GObject.BindingFlags.INVERT_BOOLEAN
  52. );
  53. // Message Entry/Send Button
  54. this.device.bind_property(
  55. 'connected',
  56. this.entry,
  57. 'sensitive',
  58. GObject.BindingFlags.DEFAULT
  59. );
  60. this._connectedId = this.device.connect(
  61. 'notify::connected',
  62. this._onStateChanged.bind(this)
  63. );
  64. this._entryChangedId = this.entry.buffer.connect(
  65. 'changed',
  66. this._onStateChanged.bind(this)
  67. );
  68. // Set the message if given
  69. if (params.message) {
  70. this.message = params.message;
  71. this.addresses = params.message.addresses;
  72. this.message_avatar.contact = this.device.contacts.query({
  73. number: this.addresses[0].address,
  74. });
  75. this.message_label.label = URI.linkify(this.message.body);
  76. this.message_box.visible = true;
  77. // Otherwise set the address(es) if we were passed those
  78. } else if (params.addresses) {
  79. this.addresses = params.addresses;
  80. }
  81. // Load the contact list if we weren't supplied with an address
  82. if (this.addresses.length === 0) {
  83. this.contact_chooser = new Contacts.ContactChooser({
  84. device: this.device,
  85. });
  86. this.stack.add_named(this.contact_chooser, 'contact-chooser');
  87. this.stack.child_set_property(this.contact_chooser, 'position', 0);
  88. this._numberSelectedId = this.contact_chooser.connect(
  89. 'number-selected',
  90. this._onNumberSelected.bind(this)
  91. );
  92. this.stack.visible_child_name = 'contact-chooser';
  93. }
  94. this.restoreGeometry('legacy-messaging-dialog');
  95. this.connect('destroy', this._onDestroy);
  96. }
  97. _onDestroy(dialog) {
  98. if (dialog._numberSelectedId !== undefined) {
  99. dialog.contact_chooser.disconnect(dialog._numberSelectedId);
  100. dialog.contact_chooser.destroy();
  101. }
  102. dialog.entry.buffer.disconnect(dialog._entryChangedId);
  103. dialog.device.disconnect(dialog._connectedId);
  104. }
  105. vfunc_delete_event() {
  106. this.saveGeometry();
  107. return false;
  108. }
  109. vfunc_response(response_id) {
  110. if (response_id === Gtk.ResponseType.OK) {
  111. // Refuse to send empty or whitespace only texts
  112. if (!this.entry.buffer.text.trim())
  113. return;
  114. this.plugin.sendMessage(
  115. this.addresses,
  116. this.entry.buffer.text,
  117. 1,
  118. true
  119. );
  120. }
  121. this.destroy();
  122. }
  123. get addresses() {
  124. if (this._addresses === undefined)
  125. this._addresses = [];
  126. return this._addresses;
  127. }
  128. set addresses(addresses = []) {
  129. this._addresses = addresses;
  130. // Set the headerbar
  131. this._setHeaderBar(this._addresses);
  132. // Show the message editor
  133. this.stack.visible_child_name = 'message-editor';
  134. this._onStateChanged();
  135. }
  136. get device() {
  137. if (this._device === undefined)
  138. this._device = null;
  139. return this._device;
  140. }
  141. set device(device) {
  142. this._device = device;
  143. }
  144. get plugin() {
  145. if (this._plugin === undefined)
  146. this._plugin = null;
  147. return this._plugin;
  148. }
  149. set plugin(plugin) {
  150. this._plugin = plugin;
  151. }
  152. _onActivateLink(label, uri) {
  153. Gtk.show_uri_on_window(
  154. this.get_toplevel(),
  155. uri.includes('://') ? uri : `https://${uri}`,
  156. Gtk.get_current_event_time()
  157. );
  158. return true;
  159. }
  160. _onNumberSelected(chooser, number) {
  161. const contacts = chooser.getSelected();
  162. this.addresses = Object.keys(contacts).map(address => {
  163. return {address: address};
  164. });
  165. }
  166. _onStateChanged() {
  167. if (this.device.connected &&
  168. this.entry.buffer.text.trim() &&
  169. this.stack.visible_child_name === 'message-editor')
  170. this.set_response_sensitive(Gtk.ResponseType.OK, true);
  171. else
  172. this.set_response_sensitive(Gtk.ResponseType.OK, false);
  173. }
  174. /**
  175. * Set the contents of the message entry
  176. *
  177. * @param {string} text - The message to place in the entry
  178. */
  179. setMessage(text) {
  180. this.entry.buffer.text = text;
  181. }
  182. });
  183. export default Dialog;