diff --git a/syncplay/client.py b/syncplay/client.py index c675c3c..f5b4da6 100644 --- a/syncplay/client.py +++ b/syncplay/client.py @@ -105,6 +105,7 @@ class SyncplayClient(object): self._userOffset = 0.0 self._speedChanged = False self.behindFirstDetected = None + self.autoPlay = False self._warnings = self._WarningManager(self._player, self.userlist, self.ui, self) if constants.LIST_RELATIVE_CONFIGS and self._config.has_key('loadedRelativePaths') and self._config['loadedRelativePaths']: @@ -310,6 +311,7 @@ class SyncplayClient(object): self.ui.showMessage(getMessage("current-offset-notification").format(self._userOffset)) def onDisconnect(self): + self.resetAutoPlayState() if self._config['pauseOnLeave']: self.setPaused(True) self.lastPausedOnLeaveTime = time.time() @@ -396,6 +398,7 @@ class SyncplayClient(object): def setRoom(self, roomName): self.userlist.currentUser.room = roomName + self.resetAutoPlayState() def sendRoom(self): room = self.userlist.currentUser.room @@ -482,6 +485,18 @@ class SyncplayClient(object): return wrapper return requireMinVersionDecorator + def changeAutoPlayState(self, newState): + self.autoPlay = newState + self.autoPlayCheck() + + def autoPlayCheck(self): + if self.autoPlay and self.userlist.currentUser.canControl() and self.userlist.isReadinessSupported() and self.userlist.areAllUsersInRoomReady(): + self.setPaused(False) + + def resetAutoPlayState(self): + self.autoPlay = False + self.ui.updateAutoPlayState(False) + @requireMinServerVersion(constants.USER_READY_MIN_VERSION) def toggleReady(self, manuallyInitiated=True): self._protocol.setReady(not self.userlist.currentUser.isReady(), manuallyInitiated) @@ -613,14 +628,6 @@ class SyncplayClient(object): self._warnings["alone-in-the-room"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True) elif self._warnings["alone-in-the-room"]['timer'].running: self._warnings["alone-in-the-room"]['timer'].stop() - - def isReadinessSupported(self): - if not utils.meetsMinVersion(self._client.serverVersion,constants.USER_READY_MIN_VERSION): - return False - elif self._userlist.onlyUserInRoomWhoSupportsReadiness(): - return False - else: - return True def checkReadyStates(self): if not self._client: @@ -646,14 +653,14 @@ class SyncplayClient(object): osdMessage = None if not self._userlist.areAllFilesInRoomSame(): fileDifferencesMessage = getMessage("room-file-differences").format(self._userlist.getFileDifferencesForRoom()) - if self._userlist.currentUser.canControl() and self.isReadinessSupported(): + if self._userlist.currentUser.canControl() and self._userlist.isReadinessSupported(): if self._userlist.areAllUsersInRoomReady(): osdMessage = u"{}{}{}".format(fileDifferencesMessage, self._client._player.osdMessageSeparator, getMessage("all-users-ready")) else: osdMessage = u"{}{}{}".format(fileDifferencesMessage, self._client._player.osdMessageSeparator, getMessage("not-all-ready").format(self._userlist.usersInRoomNotReady())) else: osdMessage = fileDifferencesMessage - elif self.isReadinessSupported(): + elif self._userlist.isReadinessSupported(): if self._userlist.areAllUsersInRoomReady(): osdMessage = getMessage("all-users-ready") else: @@ -741,6 +748,14 @@ class SyncplayUserlist(object): self._client = client self._roomUsersChanged = True + def isReadinessSupported(self): + if not utils.meetsMinVersion(self._client.serverVersion,constants.USER_READY_MIN_VERSION): + return False + elif self.onlyUserInRoomWhoSupportsReadiness(): + return False + else: + return True + def isRoomSame(self, room): if room and self.currentUser.room and self.currentUser.room == room: return True @@ -925,6 +940,7 @@ class SyncplayUserlist(object): self.currentUser.setReady(isReady) elif self._users.has_key(username): self._users[username].setReady(isReady) + self._client.autoPlayCheck() def userListChange(self, room = None): if room is not None and self.isRoomSame(room): @@ -948,6 +964,7 @@ class SyncplayUserlist(object): rooms[self.currentUser.room].append(self.currentUser) rooms = self.sortList(rooms) self.ui.showUserList(self.currentUser, rooms) + self._client.autoPlayCheck() def clearList(self): self._users = {} @@ -976,6 +993,9 @@ class UiManager(object): if not noPlayer: self.showOSDMessage(message, duration=constants.OSD_DURATION, secondaryOSD=secondaryOSD) self.__ui.showMessage(message, noTimestamp) + def updateAutoPlayState(self, newState): + self.__ui.updateAutoPlayState(newState) + def showUserList(self, currentUser, rooms): self.__ui.showUserList(currentUser, rooms) diff --git a/syncplay/constants.py b/syncplay/constants.py index 3e741f1..4a04326 100644 --- a/syncplay/constants.py +++ b/syncplay/constants.py @@ -120,7 +120,8 @@ STYLE_SUBCHECKBOX = "QCheckBox, QLabel {{ margin-left: 6px; padding-left: 21px; STYLE_SUBLABEL = "QCheckBox, QLabel {{ margin-left: 6px; padding-left: 16px; background:url('{}') left no-repeat }}" #Graphic path STYLE_ERRORLABEL = "QLabel { color : black; border-style: outset; border-width: 2px; border-radius: 7px; border-color: red; padding: 2px; background: #FFAAAA; }" STYLE_SUCCESSLABEL = "QLabel { color : black; border-style: outset; border-width: 2px; border-radius: 7px; border-color: green; padding: 2px; background: #AAFFAA; }" -STYLE_READY_PUSHBUTTON = "QPushButton { text-align: left; color : black; border-style: outset; border-width: 2px; border-radius: 7px; padding: 2px; } QPushButton::Checked {border-color: green; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #00CC00, stop: 1 #00FF00); } QPushButton::!Checked { border-color: maroon; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #FF0000, stop: 1 #BB0000); } QPushButton::hover:Checked {border-color: green; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #00FF00, stop: 1 #00DD00); } QPushButton::hover:!Checked { border-color: maroon; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #BB0000, stop: 1 #FF0000); } QPushButton::pressed { border-style: inset; }" +STYLE_READY_PUSHBUTTON = "QPushButton { text-align: left; color : black; border-style: outset; border-width: 2px; border-radius: 7px; padding: 5px 3px 5px 3px; font-size: 11pt; font-weight: bold; } QPushButton::Checked {border-color: green; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #00CC00, stop: 1 #00FF00); } QPushButton::!Checked { border-color: maroon; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #FF0000, stop: 1 #BB0000); } QPushButton::hover:Checked {border-color: green; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #00FF00, stop: 1 #00DD00); } QPushButton::hover:!Checked { border-color: maroon; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #BB0000, stop: 1 #FF0000); } QPushButton::pressed { border-style: inset; }" +STYLE_AUTO_PLAY_PUSHBUTTON = "QPushButton { text-align: left; color : black; border-style: outset; border-width: 2px; border-radius: 7px; padding: 2px; margin-left: 10px; } QPushButton::Checked {border-color: green; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #00CC00, stop: 1 #00FF00); } QPushButton::!Checked { border-color: maroon; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #FF0000, stop: 1 #BB0000); } QPushButton::hover:Checked {border-color: green; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #00FF00, stop: 1 #00DD00); } QPushButton::hover:!Checked { border-color: maroon; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #BB0000, stop: 1 #FF0000); } QPushButton::pressed { border-style: inset; }" STYLE_NOTIFICATIONBOX = "Username { color: #367AA9; font-weight:bold; }" STYLE_USERNAME = "color: #367AA9; font-weight:bold;" STYLE_ERRORNOTIFICATION = "color: red;" diff --git a/syncplay/messages.py b/syncplay/messages.py index 3e4b0bf..00cf861 100755 --- a/syncplay/messages.py +++ b/syncplay/messages.py @@ -213,6 +213,8 @@ en = { "pause-guibuttonlabel" : "Pause", "ready-guipushbuttonlabel" : u"I'm ready to watch! (Click to toggle)", "notready-guipushbuttonlabel" : u"I'm not ready to watch! (Click to toggle)", + "autoplay-guipushbuttonlabel" : u"Auto-play when everyone is ready", + "noautoplay-guipushbuttonlabel" : u"Don't auto-play when everyone is ready", "roomuser-heading-label" : "Room / User", "size-heading-label" : "Size", @@ -550,6 +552,8 @@ ru = { "pause-guibuttonlabel" : u"Пауза", "ready-guipushbuttonlabel" : u"I'm ready to watch! (Click to toggle)", # TODO: Translate into Russian "notready-guipushbuttonlabel" : u"I'm not ready to watch! (Click to toggle)", # TODO: Translate into Russian + "autoplay-guipushbuttonlabel" : u"Auto-play when everyone is ready", # TODO: Translate into Russian + "noautoplay-guipushbuttonlabel" : u"Don't auto-play when everyone is ready", # TODO: Translate into Russian "roomuser-heading-label" : u"Комната / Пользователь", "size-heading-label" : u"Size", # TODO: Translate into Russian @@ -885,6 +889,8 @@ de = { "pause-guibuttonlabel" : u"Pause", "ready-guipushbuttonlabel" : u"I'm ready to watch! (Click to toggle)", # TODO: Translate into German "notready-guipushbuttonlabel" : u"I'm not ready to watch! (Click to toggle)", # TODO: Translate into German + "autoplay-guipushbuttonlabel" : u"Auto-play when everyone is ready", # TODO: Translate into German + "noautoplay-guipushbuttonlabel" : u"Don't auto-play when everyone is ready", # TODO: Translate into German "roomuser-heading-label" : u"Raum / Benutzer", "size-heading-label" : u"Größe", diff --git a/syncplay/ui/consoleUI.py b/syncplay/ui/consoleUI.py index b912e57..8f42bfd 100644 --- a/syncplay/ui/consoleUI.py +++ b/syncplay/ui/consoleUI.py @@ -39,6 +39,9 @@ class ConsoleUI(threading.Thread): def updateRoomName(self, room=""): pass + def updateAutoPlayState(self, newState): + pass + def promptFor(self, prompt=">", message=""): if message <> "": print(message) diff --git a/syncplay/ui/gui.py b/syncplay/ui/gui.py index 98c2ab2..51105db 100644 --- a/syncplay/ui/gui.py +++ b/syncplay/ui/gui.py @@ -209,6 +209,12 @@ class MainWindow(QtGui.QMainWindow): self.readyPushButton.setChecked(newState) self.updateReadyIcon() + def updateAutoPlayState(self, newState): + oldState = self.autoPlayPushButton.isChecked() + if newState != oldState and newState != None: + self.autoPlayPushButton.setChecked(newState) + self.updateAutoPlayIcon() + def roomClicked(self, item): while item.parent().row() != -1: item = item.parent() @@ -473,12 +479,23 @@ class MainWindow(QtGui.QMainWindow): readyFont = QtGui.QFont() readyFont.setWeight(QtGui.QFont.Bold) window.readyPushButton.setCheckable(True) - window.readyPushButton.setAutoExclusive(True) + window.readyPushButton.setAutoExclusive(False) window.readyPushButton.toggled.connect(self.changeReadyState) window.readyPushButton.setFont(readyFont) window.readyPushButton.setStyleSheet(constants.STYLE_READY_PUSHBUTTON) window.listLayout.addWidget(window.readyPushButton, Qt.AlignRight) + window.autoPlayPushButton = QtGui.QPushButton() + autoPlayFont = QtGui.QFont() + autoPlayFont.setWeight(QtGui.QFont.Bold) + window.autoPlayPushButton.setCheckable(True) + window.autoPlayPushButton.setAutoExclusive(False) + window.autoPlayPushButton.toggled.connect(self.changeAutoPlayState) + window.autoPlayPushButton.setFont(autoPlayFont) + window.autoPlayPushButton.setStyleSheet(constants.STYLE_AUTO_PLAY_PUSHBUTTON) + window.listLayout.addWidget(window.autoPlayPushButton, Qt.AlignRight) + self.updateAutoPlayIcon() + window.contactLabel = QtGui.QLabel() window.contactLabel.setWordWrap(True) window.contactLabel.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Sunken) @@ -649,6 +666,10 @@ class MainWindow(QtGui.QMainWindow): self.updateReadyIcon() self._syncplayClient.changeReadyState(self.readyPushButton.isChecked()) + def changeAutoPlayState(self): + self.updateAutoPlayIcon() + self._syncplayClient.changeAutoPlayState(self.autoPlayPushButton.isChecked()) + def updateReadyIcon(self): ready = self.readyPushButton.isChecked() if ready: @@ -658,6 +679,15 @@ class MainWindow(QtGui.QMainWindow): self.readyPushButton.setIcon(QtGui.QIcon(self.resourcespath + 'cross_checkbox.png')) self.readyPushButton.setText(getMessage("notready-guipushbuttonlabel")) + def updateAutoPlayIcon(self): + ready = self.autoPlayPushButton.isChecked() + if ready: + self.autoPlayPushButton.setIcon(QtGui.QIcon(self.resourcespath + 'tick_checkbox.png')) + self.autoPlayPushButton.setText(getMessage("autoplay-guipushbuttonlabel")) + else: + self.autoPlayPushButton.setIcon(QtGui.QIcon(self.resourcespath + 'cross_checkbox.png')) + self.autoPlayPushButton.setText(getMessage("noautoplay-guipushbuttonlabel")) + def automaticUpdateCheck(self): if not self.config['checkForUpdatesAutomatically']: return