Commit 4db1a33c authored by Adrian Georgescu's avatar Adrian Georgescu

Implement auto answer

parent bee71a13
- Auto answer
- Device switching window when detected at runtime - Device switching window when detected at runtime
- Dial SIP URIs from the system - Dial SIP URIs from the system
- Desktop notifications - Desktop notifications
...@@ -29,4 +28,3 @@ ...@@ -29,4 +28,3 @@
instance of blink and it publishes its old state on startup instance of blink and it publishes its old state on startup
- when accepting a new contact from a presence request it adds the URI but - when accepting a new contact from a presence request it adds the URI but
it is not set as type SIP (it has no type selected) it is not set as type SIP (it has no type selected)
...@@ -22,7 +22,7 @@ class ContactExtension(ContactExtension): ...@@ -22,7 +22,7 @@ class ContactExtension(ContactExtension):
icon = Setting(type=IconDescriptor, nillable=True, default=None) icon = Setting(type=IconDescriptor, nillable=True, default=None)
alternate_icon = Setting(type=IconDescriptor, nillable=True, default=None) alternate_icon = Setting(type=IconDescriptor, nillable=True, default=None)
preferred_media = SharedSetting(type=str, default='audio') preferred_media = SharedSetting(type=str, default='audio')
#auto_answer = SharedSetting(type=bool, default=False) auto_answer = Setting(type=bool, default=False)
class GroupExtension(GroupExtension): class GroupExtension(GroupExtension):
......
...@@ -31,6 +31,8 @@ class AudioSettingsExtension(AudioSettings): ...@@ -31,6 +31,8 @@ class AudioSettingsExtension(AudioSettings):
recordings_directory = Setting(type=ApplicationDataPath, default=ApplicationDataPath('recordings')) recordings_directory = Setting(type=ApplicationDataPath, default=ApplicationDataPath('recordings'))
sample_rate = Setting(type=SampleRate, default=32000) sample_rate = Setting(type=SampleRate, default=32000)
echo_canceller = EchoCancellerSettingsExtension echo_canceller = EchoCancellerSettingsExtension
auto_answer_interval = Setting(type=int, default=15)
auto_answer = Setting(type=bool, default=False)
class ChatSettingsExtension(ChatSettings): class ChatSettingsExtension(ChatSettings):
......
...@@ -4651,6 +4651,7 @@ class ContactEditorDialog(base_class, ui_class): ...@@ -4651,6 +4651,7 @@ class ContactEditorDialog(base_class, ui_class):
self.name_editor.setText(contact.name) self.name_editor.setText(contact.name)
self.icon_selector.init_with_contact(contact) self.icon_selector.init_with_contact(contact)
self.presence.setChecked(contact.presence.subscribe) self.presence.setChecked(contact.presence.subscribe)
self.auto_answer.setChecked(contact.auto_answer)
self.preferred_media.setCurrentIndex(self.preferred_media.findData(contact.preferred_media)) self.preferred_media.setCurrentIndex(self.preferred_media.findData(contact.preferred_media))
self.accept_button.setText('Ok') self.accept_button.setText('Ok')
self.accept_button.setEnabled(True) self.accept_button.setEnabled(True)
...@@ -4694,6 +4695,11 @@ class ContactEditorDialog(base_class, ui_class): ...@@ -4694,6 +4695,11 @@ class ContactEditorDialog(base_class, ui_class):
contact.presence.policy = 'block' contact.presence.policy = 'block'
contact.presence.subscribe = False contact.presence.subscribe = False
if self.auto_answer.isChecked():
contact.auto_answer = True
else:
contact.auto_answer = False
if self.icon_selector.filename is self.icon_selector.NotSelected: if self.icon_selector.filename is self.icon_selector.NotSelected:
pass pass
elif self.icon_selector.filename is None: elif self.icon_selector.filename is None:
......
...@@ -195,6 +195,7 @@ class MainWindow(base_class, ui_class): ...@@ -195,6 +195,7 @@ class MainWindow(base_class, ui_class):
self.video_devices_group.triggered.connect(self._AH_VideoDeviceChanged) self.video_devices_group.triggered.connect(self._AH_VideoDeviceChanged)
self.mute_action.triggered.connect(self._SH_MuteButtonClicked) self.mute_action.triggered.connect(self._SH_MuteButtonClicked)
self.silent_action.triggered.connect(self._SH_SilentButtonClicked) self.silent_action.triggered.connect(self._SH_SilentButtonClicked)
self.auto_answer_action.triggered.connect(self._SH_AutoAnswerButtonClicked)
# Tools menu actions # Tools menu actions
self.sip_server_settings_action.triggered.connect(self._AH_SIPServerSettings) self.sip_server_settings_action.triggered.connect(self._AH_SIPServerSettings)
...@@ -741,6 +742,11 @@ class MainWindow(base_class, ui_class): ...@@ -741,6 +742,11 @@ class MainWindow(base_class, ui_class):
self.saved_account_state = None self.saved_account_state = None
self.account_state.setState(state, note) self.account_state.setState(state, note)
def _SH_AutoAnswerButtonClicked(self, answer):
settings = SIPSimpleSettings()
settings.audio.auto_answer = not settings.audio.auto_answer
settings.save()
def _SH_SilentButtonClicked(self, silent): def _SH_SilentButtonClicked(self, silent):
settings = SIPSimpleSettings() settings = SIPSimpleSettings()
settings.audio.silent = silent settings.audio.silent = silent
...@@ -768,6 +774,7 @@ class MainWindow(base_class, ui_class): ...@@ -768,6 +774,7 @@ class MainWindow(base_class, ui_class):
settings = SIPSimpleSettings() settings = SIPSimpleSettings()
self.silent_action.setChecked(settings.audio.silent) self.silent_action.setChecked(settings.audio.silent)
self.silent_button.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent)
self.auto_answer_action.setChecked(settings.audio.auto_answer)
self.answering_machine_action.setChecked(settings.answering_machine.enabled) self.answering_machine_action.setChecked(settings.answering_machine.enabled)
self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) self.auto_accept_chat_action.setChecked(settings.chat.auto_accept)
self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts) self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts)
...@@ -826,6 +833,8 @@ class MainWindow(base_class, ui_class): ...@@ -826,6 +833,8 @@ class MainWindow(base_class, ui_class):
if 'audio.silent' in notification.data.modified: if 'audio.silent' in notification.data.modified:
self.silent_action.setChecked(settings.audio.silent) self.silent_action.setChecked(settings.audio.silent)
self.silent_button.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent)
if 'audio.auto_answer' in notification.data.modified:
self.auto_answer_action.setChecked(settings.audio.auto_answer)
if 'audio.output_device' in notification.data.modified: if 'audio.output_device' in notification.data.modified:
action = next(action for action in self.output_devices_group.actions() if action.data() == settings.audio.output_device) action = next(action for action in self.output_devices_group.actions() if action.data() == settings.audio.output_device)
action.setChecked(True) action.setChecked(True)
......
...@@ -5142,6 +5142,11 @@ class IncomingDialog(IncomingDialogBase, ui_class): ...@@ -5142,6 +5142,11 @@ class IncomingDialog(IncomingDialogBase, ui_class):
self.reject_button.released.connect(self._set_reject_mode) self.reject_button.released.connect(self._set_reject_mode)
self.screensharing_stream.hidden.connect(self.screensharing_label.hide) self.screensharing_stream.hidden.connect(self.screensharing_label.hide)
self.screensharing_stream.shown.connect(self.screensharing_label.show) self.screensharing_stream.shown.connect(self.screensharing_label.show)
self.auto_answer_label.setText('Auto-answer is inactive')
self.auto_answer_interval = None
self._auto_answer_timer = None
self.passed_time = 0
self.auto_answer_confirmed = False
def show(self, activate=True): def show(self, activate=True):
self.setAttribute(Qt.WA_ShowWithoutActivating, not activate) self.setAttribute(Qt.WA_ShowWithoutActivating, not activate)
...@@ -5167,6 +5172,22 @@ class IncomingDialog(IncomingDialogBase, ui_class): ...@@ -5167,6 +5172,22 @@ class IncomingDialog(IncomingDialogBase, ui_class):
if self.accept_button.isEnabled() != was_enabled: if self.accept_button.isEnabled() != was_enabled:
self.accept_button.setFocus() self.accept_button.setFocus()
def setAutoAnswer(self, interval):
self.auto_answer_interval = interval
self._auto_answer_timer = QTimer()
self._auto_answer_timer.setInterval(1000)
self._auto_answer_timer.timeout.connect(self._update_auto_answer)
self._auto_answer_timer.start()
self.auto_answer_label.setText('Auto answer in %d seconds' % interval)
def _update_auto_answer(self):
self.passed_time = self.passed_time + 1
remaining_time = self.auto_answer_interval - self.passed_time
self.auto_answer_label.setText('Auto answer in %d seconds' % remaining_time)
if remaining_time == 0:
self._auto_answer_timer.stop()
self.hide()
def _update_streams_layout(self): def _update_streams_layout(self):
if len([stream for stream in self.streams if stream.in_use]) > 1: if len([stream for stream in self.streams if stream.in_use]) > 1:
self.audio_stream.active = True self.audio_stream.active = True
...@@ -5210,6 +5231,7 @@ class IncomingRequest(QObject): ...@@ -5210,6 +5231,7 @@ class IncomingRequest(QObject):
self.video_stream = video_stream self.video_stream = video_stream
self.chat_stream = chat_stream self.chat_stream = chat_stream
self.screensharing_stream = screensharing_stream self.screensharing_stream = screensharing_stream
self._auto_answer_timer = None
if proposal: if proposal:
self.dialog.setWindowTitle('Incoming Session Update') self.dialog.setWindowTitle('Incoming Session Update')
...@@ -5219,6 +5241,16 @@ class IncomingRequest(QObject): ...@@ -5219,6 +5241,16 @@ class IncomingRequest(QObject):
address = '%s@%s' % (session.remote_identity.uri.user, session.remote_identity.uri.host) address = '%s@%s' % (session.remote_identity.uri.user, session.remote_identity.uri.host)
self.dialog.uri_label.setText(address) self.dialog.uri_label.setText(address)
self.dialog.username_label.setText(contact.name or session.remote_identity.display_name or address) self.dialog.username_label.setText(contact.name or session.remote_identity.display_name or address)
settings = SIPSimpleSettings()
if settings.audio.auto_answer and contact and contact.settings.auto_answer and settings.audio.auto_answer_interval:
self.dialog.setAutoAnswer(settings.audio.auto_answer_interval)
self._auto_answer_timer = QTimer()
self._auto_answer_timer.setInterval(settings.audio.auto_answer_interval * 1000)
self._auto_answer_timer.setSingleShot(True)
self._auto_answer_timer.timeout.connect(self._auto_answer)
self._auto_answer_timer.start()
self.dialog.user_icon.setPixmap(contact.icon.pixmap(48)) self.dialog.user_icon.setPixmap(contact.icon.pixmap(48))
self.dialog.audio_stream.setVisible(self.audio_stream is not None) self.dialog.audio_stream.setVisible(self.audio_stream is not None)
self.dialog.video_stream.setVisible(self.video_stream is not None) self.dialog.video_stream.setVisible(self.video_stream is not None)
...@@ -5231,6 +5263,7 @@ class IncomingRequest(QObject): ...@@ -5231,6 +5263,7 @@ class IncomingRequest(QObject):
self.dialog.screensharing_label.setText('is asking to share your screen') self.dialog.screensharing_label.setText('is asking to share your screen')
# self.dialog.screensharing_stream.accepted = bool(proposal) # self.dialog.screensharing_stream.accepted = bool(proposal)
self.dialog.finished.connect(self._SH_DialogFinished) self.dialog.finished.connect(self._SH_DialogFinished)
def __eq__(self, other): def __eq__(self, other):
...@@ -5297,7 +5330,13 @@ class IncomingRequest(QObject): ...@@ -5297,7 +5330,13 @@ class IncomingRequest(QObject):
def stream_types(self): def stream_types(self):
return {stream.type for stream in (self.audio_stream, self.video_stream, self.screensharing_stream, self.chat_stream) if stream is not None} return {stream.type for stream in (self.audio_stream, self.video_stream, self.screensharing_stream, self.chat_stream) if stream is not None}
def _auto_answer(self):
self._SH_DialogFinished(QDialog.Accepted)
def _SH_DialogFinished(self, result): def _SH_DialogFinished(self, result):
if self._auto_answer_timer and self._auto_answer_timer.isActive():
self._auto_answer_timer.stop()
self.finished.emit(self) self.finished.emit(self)
if result == QDialog.Accepted: if result == QDialog.Accepted:
self.accepted.emit(self) self.accepted.emit(self)
......
...@@ -1054,7 +1054,7 @@ padding: 2px;</string> ...@@ -1054,7 +1054,7 @@ padding: 2px;</string>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>285</width> <width>285</width>
<height>29</height> <height>25</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="blink_menu"> <widget class="QMenu" name="blink_menu">
...@@ -1173,6 +1173,7 @@ padding: 2px;</string> ...@@ -1173,6 +1173,7 @@ padding: 2px;</string>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="mute_action"/> <addaction name="mute_action"/>
<addaction name="silent_action"/> <addaction name="silent_action"/>
<addaction name="auto_answer_action"/>
</widget> </widget>
<widget class="QMenu" name="window_menu"> <widget class="QMenu" name="window_menu">
<property name="title"> <property name="title">
...@@ -1281,10 +1282,6 @@ padding: 2px;</string> ...@@ -1281,10 +1282,6 @@ padding: 2px;</string>
</property> </property>
</action> </action>
<action name="redial_action"> <action name="redial_action">
<property name="icon">
<iconset>
<normaloff>icons/retry.svg</normaloff>icons/retry.svg</iconset>
</property>
<property name="text"> <property name="text">
<string>&amp;Redial</string> <string>&amp;Redial</string>
</property> </property>
...@@ -1424,6 +1421,17 @@ padding: 2px;</string> ...@@ -1424,6 +1421,17 @@ padding: 2px;</string>
<enum>Qt::ApplicationShortcut</enum> <enum>Qt::ApplicationShortcut</enum>
</property> </property>
</action> </action>
<action name="auto_answer_action">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="text">
<string>Auto-answer</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
......
...@@ -220,16 +220,6 @@ ...@@ -220,16 +220,6 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="presence">
<property name="text">
<string>Exchange Availability Information</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3"> <item row="4" column="0" colspan="3">
<widget class="QComboBox" name="preferred_media"> <widget class="QComboBox" name="preferred_media">
<property name="sizePolicy"> <property name="sizePolicy">
...@@ -260,6 +250,23 @@ ...@@ -260,6 +250,23 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QCheckBox" name="presence">
<property name="text">
<string>Enable Presence</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="auto_answer">
<property name="text">
<string>Auto-answer</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
......
...@@ -6,20 +6,20 @@ ...@@ -6,20 +6,20 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>480</width> <width>583</width>
<height>170</height> <height>191</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>480</width> <width>480</width>
<height>170</height> <height>188</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>16777215</width> <width>16777215</width>
<height>170</height> <height>300</height>
</size> </size>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
...@@ -29,10 +29,7 @@ ...@@ -29,10 +29,7 @@
<iconset> <iconset>
<normaloff>icons/blink48.png</normaloff>icons/blink48.png</iconset> <normaloff>icons/blink48.png</normaloff>icons/blink48.png</iconset>
</property> </property>
<layout class="QVBoxLayout" name="dialog_layout"> <layout class="QGridLayout" name="gridLayout">
<property name="spacing">
<number>32</number>
</property>
<property name="leftMargin"> <property name="leftMargin">
<number>8</number> <number>8</number>
</property> </property>
...@@ -45,7 +42,7 @@ ...@@ -45,7 +42,7 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>8</number> <number>8</number>
</property> </property>
<item> <item row="0" column="0">
<widget class="QFrame" name="frame"> <widget class="QFrame" name="frame">
<property name="styleSheet"> <property name="styleSheet">
<string>QFrame#frame { <string>QFrame#frame {
...@@ -188,7 +185,7 @@ ...@@ -188,7 +185,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>12</pointsize> <pointsize>14</pointsize>
<weight>75</weight> <weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
...@@ -531,7 +528,26 @@ ...@@ -531,7 +528,26 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item> <item row="1" column="0">
<widget class="QLabel" name="auto_answer_label">
<property name="enabled">
<bool>true</bool>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Auto answer in 10 seconds</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="button_layout"> <layout class="QHBoxLayout" name="button_layout">
<property name="spacing"> <property name="spacing">
<number>5</number> <number>5</number>
...@@ -564,7 +580,7 @@ ...@@ -564,7 +580,7 @@
<string>Refuse the call but leave other devices ringing</string> <string>Refuse the call but leave other devices ringing</string>
</property> </property>
<property name="text"> <property name="text">
<string>Busy</string> <string>Busy here</string>
</property> </property>
</widget> </widget>
</item> </item>
...@@ -609,7 +625,6 @@ ...@@ -609,7 +625,6 @@
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>accept_button</tabstop>
<tabstop>reject_button</tabstop> <tabstop>reject_button</tabstop>
<tabstop>busy_button</tabstop> <tabstop>busy_button</tabstop>
</tabstops> </tabstops>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment