mirror of https://github.com/Syncplay/syncplay
macOS: add localized Edit menu with dictation support and emoji picker
Qt on macOS automatically adds these entries to the menubar of GUI apps, providing that such apps have an Edit menu at their startup. Hence, this commit contains the following changes (macOS only): - create the menubar in the first dialog shown by the app (GuiConfiguration) - create an Edit menu, populate it with Cut/Copy/Paste/Select all actions - connect system-wide shortcuts to these new actions - pass the menubar and the Edit menu to the MainWindow through config and through an added optional argument in getUI and GraphicalUI - populate the menubar created before and not a new menubar in MainWindow - provide localized strings for the entries in the Edit menu - add xx.lproj folders in Syncplay.app/Contents/Resources/ to allow automatic localization of the entries added by the OS Known issues: - automatically added entries will always be in the OS language - the Edit menu might retain the previous language after a language change in the app settings. Reboot the app solves the issue. - the automatically added entries might disappear if the app language does not match the OS language
This commit is contained in:
parent
b3545a35bb
commit
12fc04326a
|
@ -8,7 +8,7 @@ class SyncplayClientManager(object):
|
||||||
def run(self):
|
def run(self):
|
||||||
config = ConfigurationGetter().getConfiguration()
|
config = ConfigurationGetter().getConfiguration()
|
||||||
from syncplay.client import SyncplayClient # Imported later, so the proper reactor is installed
|
from syncplay.client import SyncplayClient # Imported later, so the proper reactor is installed
|
||||||
interface = ui.getUi(graphical=not config["noGui"])
|
interface = ui.getUi(graphical=not config["noGui"], passedBar=config['menuBar'])
|
||||||
syncplayClient = SyncplayClient(config["playerClass"], interface, config)
|
syncplayClient = SyncplayClient(config["playerClass"], interface, config)
|
||||||
if syncplayClient:
|
if syncplayClient:
|
||||||
interface.addClient(syncplayClient)
|
interface.addClient(syncplayClient)
|
||||||
|
|
|
@ -304,6 +304,12 @@ de = {
|
||||||
"settrusteddomains-menu-label": "Set &trusted domains", # TODO: Translate
|
"settrusteddomains-menu-label": "Set &trusted domains", # TODO: Translate
|
||||||
"addtrusteddomain-menu-label": "Add {} as trusted domain", # Domain # TODO: Translate
|
"addtrusteddomain-menu-label": "Add {} as trusted domain", # Domain # TODO: Translate
|
||||||
|
|
||||||
|
"edit-menu-label": "&Bearbeiten",
|
||||||
|
"cut-menu-label": "Aus&schneiden",
|
||||||
|
"copy-menu-label": "&Kopieren",
|
||||||
|
"paste-menu-label": "&Einsetzen",
|
||||||
|
"selectall-menu-label": "&Alles auswälhen",
|
||||||
|
|
||||||
"playback-menu-label": "&Wiedergabe",
|
"playback-menu-label": "&Wiedergabe",
|
||||||
|
|
||||||
"help-menu-label": "&Hilfe",
|
"help-menu-label": "&Hilfe",
|
||||||
|
|
|
@ -306,6 +306,12 @@ en = {
|
||||||
"settrusteddomains-menu-label": "Set &trusted domains",
|
"settrusteddomains-menu-label": "Set &trusted domains",
|
||||||
"addtrusteddomain-menu-label": "Add {} as trusted domain", # Domain
|
"addtrusteddomain-menu-label": "Add {} as trusted domain", # Domain
|
||||||
|
|
||||||
|
"edit-menu-label": "&Edit",
|
||||||
|
"cut-menu-label": "Cu&t",
|
||||||
|
"copy-menu-label": "&Copy",
|
||||||
|
"paste-menu-label": "&Paste",
|
||||||
|
"selectall-menu-label": "&Select All",
|
||||||
|
|
||||||
"playback-menu-label": "&Playback",
|
"playback-menu-label": "&Playback",
|
||||||
|
|
||||||
"help-menu-label": "&Help",
|
"help-menu-label": "&Help",
|
||||||
|
|
|
@ -306,6 +306,12 @@ es = {
|
||||||
"settrusteddomains-menu-label": "Es&tablecer dominios de confianza",
|
"settrusteddomains-menu-label": "Es&tablecer dominios de confianza",
|
||||||
"addtrusteddomain-menu-label": "Agregar {} como dominio de confianza", # Domain
|
"addtrusteddomain-menu-label": "Agregar {} como dominio de confianza", # Domain
|
||||||
|
|
||||||
|
"edit-menu-label": "&Edición",
|
||||||
|
"cut-menu-label": "Cor&tar",
|
||||||
|
"copy-menu-label": "&Copiar",
|
||||||
|
"paste-menu-label": "&Pegar",
|
||||||
|
"selectall-menu-label": "&Seleccionar todo",
|
||||||
|
|
||||||
"playback-menu-label": "Re&producción",
|
"playback-menu-label": "Re&producción",
|
||||||
|
|
||||||
"help-menu-label": "A&yuda",
|
"help-menu-label": "A&yuda",
|
||||||
|
|
|
@ -306,6 +306,12 @@ it = {
|
||||||
"settrusteddomains-menu-label": "Imposta &domini fidati",
|
"settrusteddomains-menu-label": "Imposta &domini fidati",
|
||||||
"addtrusteddomain-menu-label": "Aggiungi {} come dominio fidato", # Domain
|
"addtrusteddomain-menu-label": "Aggiungi {} come dominio fidato", # Domain
|
||||||
|
|
||||||
|
"edit-menu-label": "&Modifica",
|
||||||
|
"cut-menu-label": "&Taglia",
|
||||||
|
"copy-menu-label": "&Copia",
|
||||||
|
"paste-menu-label": "&Incolla",
|
||||||
|
"selectall-menu-label": "&Seleziona tutto",
|
||||||
|
|
||||||
"playback-menu-label": "&Riproduzione",
|
"playback-menu-label": "&Riproduzione",
|
||||||
|
|
||||||
"help-menu-label": "&Aiuto",
|
"help-menu-label": "&Aiuto",
|
||||||
|
|
|
@ -307,6 +307,13 @@ ru = {
|
||||||
"identifyascontroller-menu-label": "&Войти как оператор комнаты",
|
"identifyascontroller-menu-label": "&Войти как оператор комнаты",
|
||||||
"settrusteddomains-menu-label": "Доверенные &сайты",
|
"settrusteddomains-menu-label": "Доверенные &сайты",
|
||||||
|
|
||||||
|
# Edit menu - TODO: check - these should match the values of macOS menubar
|
||||||
|
"edit-menu-label": "&Правка",
|
||||||
|
"cut-menu-label": "Bы&резать",
|
||||||
|
"copy-menu-label": "&Скопировать",
|
||||||
|
"paste-menu-label": "&Bставить",
|
||||||
|
"selectall-menu-label": "Bыбра&ть все",
|
||||||
|
|
||||||
"playback-menu-label": "&Управление",
|
"playback-menu-label": "&Управление",
|
||||||
|
|
||||||
"help-menu-label": "&Помощь",
|
"help-menu-label": "&Помощь",
|
||||||
|
|
|
@ -1294,6 +1294,30 @@ class ConfigDialog(QtWidgets.QDialog):
|
||||||
self.serverpassTextbox.setReadOnly(False)
|
self.serverpassTextbox.setReadOnly(False)
|
||||||
self.serverpassTextbox.setText(self.storedPassword)
|
self.serverpassTextbox.setText(self.storedPassword)
|
||||||
|
|
||||||
|
def createMenubar(self):
|
||||||
|
self.menuBar = QtWidgets.QMenuBar()
|
||||||
|
|
||||||
|
# Edit menu
|
||||||
|
self.editMenu = QtWidgets.QMenu(getMessage("edit-menu-label"), self)
|
||||||
|
|
||||||
|
self.cutAction = self.editMenu.addAction(getMessage("cut-menu-label"))
|
||||||
|
self.cutAction.setShortcuts(QtGui.QKeySequence.Cut)
|
||||||
|
|
||||||
|
self.copyAction = self.editMenu.addAction(getMessage("copy-menu-label"))
|
||||||
|
self.copyAction.setShortcuts(QtGui.QKeySequence.Copy)
|
||||||
|
|
||||||
|
self.pasteAction = self.editMenu.addAction(getMessage("paste-menu-label"))
|
||||||
|
self.pasteAction.setShortcuts(QtGui.QKeySequence.Paste)
|
||||||
|
|
||||||
|
self.selectAction = self.editMenu.addAction(getMessage("selectall-menu-label"))
|
||||||
|
self.selectAction.setShortcuts(QtGui.QKeySequence.SelectAll)
|
||||||
|
|
||||||
|
self.editMenu.addSeparator()
|
||||||
|
|
||||||
|
self.menuBar.addMenu(self.editMenu)
|
||||||
|
|
||||||
|
self.mainLayout.setMenuBar(self.menuBar)
|
||||||
|
|
||||||
def __init__(self, config, playerpaths, error, defaultConfig):
|
def __init__(self, config, playerpaths, error, defaultConfig):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.defaultConfig = defaultConfig
|
self.defaultConfig = defaultConfig
|
||||||
|
@ -1345,6 +1369,14 @@ class ConfigDialog(QtWidgets.QDialog):
|
||||||
self.addMiscTab()
|
self.addMiscTab()
|
||||||
self.tabList()
|
self.tabList()
|
||||||
|
|
||||||
|
if isMacOS():
|
||||||
|
self.createMenubar()
|
||||||
|
self.config['menuBar'] = dict()
|
||||||
|
self.config['menuBar']['bar'] = self.menuBar
|
||||||
|
self.config['menuBar']['editMenu'] = self.editMenu
|
||||||
|
else:
|
||||||
|
self.config['menuBar'] = None
|
||||||
|
|
||||||
self.mainLayout.addWidget(self.stackedFrame, 0, 1)
|
self.mainLayout.addWidget(self.stackedFrame, 0, 1)
|
||||||
self.addBottomLayout()
|
self.addBottomLayout()
|
||||||
self.updatePasswordVisibilty()
|
self.updatePasswordVisibilty()
|
||||||
|
|
|
@ -12,9 +12,9 @@ except ImportError:
|
||||||
from syncplay.ui.consoleUI import ConsoleUI
|
from syncplay.ui.consoleUI import ConsoleUI
|
||||||
|
|
||||||
|
|
||||||
def getUi(graphical=True):
|
def getUi(graphical=True, passedBar=None):
|
||||||
if graphical:
|
if graphical:
|
||||||
ui = GraphicalUI()
|
ui = GraphicalUI(passedBar=passedBar)
|
||||||
else:
|
else:
|
||||||
ui = ConsoleUI()
|
ui = ConsoleUI()
|
||||||
ui.setDaemon(True)
|
ui.setDaemon(True)
|
||||||
|
|
|
@ -1511,9 +1511,15 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
window.playbackFrame.setMaximumWidth(window.playbackFrame.sizeHint().width())
|
window.playbackFrame.setMaximumWidth(window.playbackFrame.sizeHint().width())
|
||||||
window.outputLayout.addWidget(window.playbackFrame)
|
window.outputLayout.addWidget(window.playbackFrame)
|
||||||
|
|
||||||
def addMenubar(self, window):
|
def loadMenubar(self, window, passedBar):
|
||||||
window.menuBar = QtWidgets.QMenuBar()
|
if passedBar is not None:
|
||||||
|
window.menuBar = passedBar['bar']
|
||||||
|
window.editMenu = passedBar['editMenu']
|
||||||
|
else:
|
||||||
|
window.menuBar = QtWidgets.QMenuBar()
|
||||||
|
window.editMenu = None
|
||||||
|
|
||||||
|
def populateMenubar(self, window):
|
||||||
# File menu
|
# File menu
|
||||||
|
|
||||||
window.fileMenu = QtWidgets.QMenu(getMessage("file-menu-label"), self)
|
window.fileMenu = QtWidgets.QMenu(getMessage("file-menu-label"), self)
|
||||||
|
@ -1527,10 +1533,17 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
getMessage("setmediadirectories-menu-label"))
|
getMessage("setmediadirectories-menu-label"))
|
||||||
window.openAction.triggered.connect(self.openSetMediaDirectoriesDialog)
|
window.openAction.triggered.connect(self.openSetMediaDirectoriesDialog)
|
||||||
|
|
||||||
window.exitAction = window.fileMenu.addAction(QtGui.QPixmap(resourcespath + 'cross.png'),
|
window.exitAction = window.fileMenu.addAction(getMessage("exit-menu-label"))
|
||||||
getMessage("exit-menu-label"))
|
if isMacOS():
|
||||||
|
window.exitAction.setMenuRole(QtWidgets.QAction.QuitRole)
|
||||||
|
else:
|
||||||
|
window.exitAction.setIcon(QtGui.QPixmap(resourcespath + 'cross.png'))
|
||||||
window.exitAction.triggered.connect(self.exitSyncplay)
|
window.exitAction.triggered.connect(self.exitSyncplay)
|
||||||
window.menuBar.addMenu(window.fileMenu)
|
|
||||||
|
if(window.editMenu is not None):
|
||||||
|
window.menuBar.insertMenu(window.editMenu.menuAction(), window.fileMenu)
|
||||||
|
else:
|
||||||
|
window.menuBar.addMenu(window.fileMenu)
|
||||||
|
|
||||||
# Playback menu
|
# Playback menu
|
||||||
|
|
||||||
|
@ -1607,11 +1620,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
getMessage("about-menu-label"))
|
getMessage("about-menu-label"))
|
||||||
else:
|
else:
|
||||||
window.about = window.helpMenu.addAction("&About")
|
window.about = window.helpMenu.addAction("&About")
|
||||||
|
window.about.setMenuRole(QtWidgets.QAction.AboutRole)
|
||||||
window.about.triggered.connect(self.openAbout)
|
window.about.triggered.connect(self.openAbout)
|
||||||
|
|
||||||
window.menuBar.addMenu(window.helpMenu)
|
window.menuBar.addMenu(window.helpMenu)
|
||||||
if not isMacOS():
|
window.mainLayout.setMenuBar(window.menuBar)
|
||||||
window.mainLayout.setMenuBar(window.menuBar)
|
|
||||||
|
|
||||||
@needsClient
|
@needsClient
|
||||||
def openSSLDetails(self):
|
def openSSLDetails(self):
|
||||||
|
@ -1887,7 +1900,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
settings.beginGroup("PublicServerList")
|
settings.beginGroup("PublicServerList")
|
||||||
self.publicServerList = settings.value("publicServers", None)
|
self.publicServerList = settings.value("publicServers", None)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, passedBar=None):
|
||||||
super(MainWindow, self).__init__()
|
super(MainWindow, self).__init__()
|
||||||
self.console = ConsoleInGUI()
|
self.console = ConsoleInGUI()
|
||||||
self.console.setDaemon(True)
|
self.console.setDaemon(True)
|
||||||
|
@ -1905,11 +1918,12 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
self.mainLayout = QtWidgets.QVBoxLayout()
|
self.mainLayout = QtWidgets.QVBoxLayout()
|
||||||
self.addTopLayout(self)
|
self.addTopLayout(self)
|
||||||
self.addBottomLayout(self)
|
self.addBottomLayout(self)
|
||||||
self.addMenubar(self)
|
self.loadMenubar(self, passedBar)
|
||||||
|
self.populateMenubar(self)
|
||||||
self.addMainFrame(self)
|
self.addMainFrame(self)
|
||||||
self.loadSettings()
|
self.loadSettings()
|
||||||
self.setWindowIcon(QtGui.QPixmap(resourcespath + "syncplay.png"))
|
self.setWindowIcon(QtGui.QPixmap(resourcespath + "syncplay.png"))
|
||||||
self.setWindowFlags(self.windowFlags() & Qt.WindowCloseButtonHint & Qt.AA_DontUseNativeMenuBar & Qt.WindowMinimizeButtonHint & ~Qt.WindowContextHelpButtonHint)
|
self.setWindowFlags(self.windowFlags() & Qt.WindowCloseButtonHint & Qt.WindowMinimizeButtonHint & ~Qt.WindowContextHelpButtonHint)
|
||||||
self.show()
|
self.show()
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
self.clearedPlaylistNote = False
|
self.clearedPlaylistNote = False
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
mkdir dist/Syncplay.app/Contents/Resources/German.lproj
|
||||||
|
mkdir dist/Syncplay.app/Contents/Resources/Italian.lproj
|
||||||
|
mkdir dist/Syncplay.app/Contents/Resources/ru.lproj
|
||||||
|
mkdir dist/Syncplay.app/Contents/Resources/Spanish.lproj
|
||||||
pip3 install dmgbuild
|
pip3 install dmgbuild
|
||||||
mv syncplay/resources/macOS_readme.pdf syncplay/resources/.macOS_readme.pdf
|
mv syncplay/resources/macOS_readme.pdf syncplay/resources/.macOS_readme.pdf
|
||||||
dmgbuild -s appdmg.py "Syncplay" dist_bintray/Syncplay_${VER}.dmg
|
dmgbuild -s appdmg.py "Syncplay" dist_bintray/Syncplay_${VER}.dmg
|
||||||
|
|
Loading…
Reference in New Issue