diff --git a/alt-tab-macos.xcodeproj/project.pbxproj b/alt-tab-macos.xcodeproj/project.pbxproj index 06317bc6..1ce5844c 100644 --- a/alt-tab-macos.xcodeproj/project.pbxproj +++ b/alt-tab-macos.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ D04BA004884A273D4D2D3EF1 /* HelperExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD91161791D42FEC4A60 /* HelperExtensions.swift */; }; D04BA0182F4734A5C8BB63DC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA5461DAEE9B5350C3020 /* Localizable.strings */; }; D04BA03B560B681AF96E4610 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA88ED495C54CFE0B7B87 /* InfoPlist.strings */; }; + D04BA079F61177D470F3E6C1 /* accessibility@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D04BA303761CFDD9BE8B6ECB /* accessibility@2x.png */; }; D04BA084CD1236EC78D90A01 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BACCBE5F97BE9B6CA645B /* Localizable.strings */; }; D04BA0AE9865276FF8EF5DEB /* UserDefaultsEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA5D9B4EBEB9E4333AE39 /* UserDefaultsEvents.swift */; }; D04BA0DD6819010987B578D1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA07BBF2237CC6C72D264 /* Localizable.strings */; }; @@ -29,6 +30,7 @@ D04BA26A691D56031FCCF00C /* Sysctl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA8DB8AA7E5570DAC568A /* Sysctl.swift */; }; D04BA276B3241D440F65B149 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA5C2BB394F1624DD5B45 /* InfoPlist.strings */; }; D04BA2A6FF9DDDC5A1A68E36 /* Applications.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA282BB16C1554595A968 /* Applications.swift */; }; + D04BA2B4364250FA07EE5793 /* screen-recording@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D04BA98B2A0815540E319908 /* screen-recording@2x.png */; }; D04BA2D8099594E1593EC8EF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA88EDDDD6CB3FBE71FC5 /* InfoPlist.strings */; }; D04BA2E64C59D96F6EB27D9D /* FeedbackWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA26C75F76C277653C932 /* FeedbackWindow.swift */; }; D04BA34AC850A273AB288B1E /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA3B51D05213404938366 /* Localizable.strings */; }; @@ -36,6 +38,7 @@ D04BA3C24F4F644EA91DE38C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA717693DA18CB74BAED1 /* Localizable.strings */; }; D04BA3CF766857381519B892 /* BackgroundWork.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAB74451B79FE18B8BEDF /* BackgroundWork.swift */; }; D04BA40CC1415DA69CCE5D89 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA17FC84640580894400E /* InfoPlist.strings */; }; + D04BA446D702C5E252AF2319 /* TitleLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAED1C4D6BB8E24847E79 /* TitleLabel.swift */; }; D04BA4575B13F1A148C108E2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA459B8804ABFBDA50663 /* InfoPlist.strings */; }; D04BA48B00B4211A465C7337 /* DebugProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BACABD048E62EBE4576CC /* DebugProfile.swift */; }; D04BA4A11F821548EE3C5E95 /* Bash.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA514F1C4B475B3CA6EB6 /* Bash.swift */; }; @@ -52,6 +55,7 @@ D04BA7B8D599E1A7A27FF5AE /* AcknowledgmentsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA788228BA86D9EFBD1ED /* AcknowledgmentsTab.swift */; }; D04BA7B9421871EDBD58F4E3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BABA255CD25D8724A06CD /* Localizable.strings */; }; D04BA7BE7F3DD24D58ACE942 /* AppearanceTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA64F1F344007EA13BA05 /* AppearanceTab.swift */; }; + D04BA7E39FA539DD8316447A /* PermissionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA0726EABD146753B9EF8 /* PermissionView.swift */; }; D04BA7F86F1926FBE31F44BF /* BaseLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA53992F116E5E704CAB3 /* BaseLabel.swift */; }; D04BA8092885B40CE3527370 /* UpdatesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD60C97E609A759E721E /* UpdatesTab.swift */; }; D04BA83AF2B1C3C5166C119F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAD58DF3FA085A45BEB50 /* InfoPlist.strings */; }; @@ -88,6 +92,7 @@ D04BAE8B16A06A10E2FA94DE /* AccessibilityEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA8FDCF137D892114F5F3 /* AccessibilityEvents.swift */; }; D04BAEE31B6FFCDC779E6C17 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D04BAC2FF99F629CD4ED20FC /* MainMenu.xib */; }; D04BAF12DF5D15B9D7D316A4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA61693F710CD7BD054D7 /* InfoPlist.strings */; }; + D04BAFB90E00AA5D662EAF24 /* PermissionsWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA9DF10D0CC4CA0C8F814 /* PermissionsWindow.swift */; }; D04BAFB973C3D28718FAEB87 /* Windows.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BACD976030676FD0761D5 /* Windows.swift */; }; D04BAFBC862BA5FE0294EA7A /* AXUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA6F823BC0EDA9AA4B80A /* AXUIElement.swift */; }; /* End PBXBuildFile section */ @@ -99,6 +104,7 @@ C0712B3BEA2B3780398C0999 /* Pods_alt_tab_macos.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_alt_tab_macos.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D04BA015A45DE7AFDC9794FE /* Window.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Window.swift; sourceTree = ""; }; D04BA03200F5A8FC0CD03607 /* CGWindowID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGWindowID.swift; sourceTree = ""; }; + D04BA0726EABD146753B9EF8 /* PermissionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionView.swift; sourceTree = ""; }; D04BA075E359F36C27CD5BAE /* package-lock.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "package-lock.json"; sourceTree = ""; }; D04BA084F638725465234830 /* favicon-16x16.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "favicon-16x16.png"; sourceTree = ""; }; D04BA088B8A550D9367A4AAB /* it */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = it; path = InfoPlist.strings; sourceTree = ""; }; @@ -130,6 +136,7 @@ D04BA2D022B64A876CCA6BB7 /* apple-touch-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "apple-touch-icon.png"; sourceTree = ""; }; D04BA2E723062A1DAC58618F /* setup_ci_pr.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = setup_ci_pr.sh; sourceTree = ""; }; D04BA2E8D5D5CC23456BC8F7 /* tr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = tr; path = Localizable.strings; sourceTree = ""; }; + D04BA303761CFDD9BE8B6ECB /* accessibility@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "accessibility@2x.png"; sourceTree = ""; }; D04BA32F25860B686DFE818A /* 3 windows - 1 line.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "3 windows - 1 line.jpg"; sourceTree = ""; }; D04BA3632A2EB5C64A3FEE59 /* hu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = hu; path = InfoPlist.strings; sourceTree = ""; }; D04BA369B4D9FD6A13936F53 /* bare.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = bare.html; sourceTree = ""; }; @@ -201,7 +208,9 @@ D04BA93F02C9B26B05032B7A /* ja */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ja; path = Localizable.strings; sourceTree = ""; }; D04BA94A1695D4FF5337C84B /* import_certificate_into_main_keychain.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = import_certificate_into_main_keychain.sh; sourceTree = ""; }; D04BA954319227829B646315 /* android-chrome-192x192.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "android-chrome-192x192.png"; sourceTree = ""; }; + D04BA98B2A0815540E319908 /* screen-recording@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "screen-recording@2x.png"; sourceTree = ""; }; D04BA9B93823398A542FF7A0 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; + D04BA9DF10D0CC4CA0C8F814 /* PermissionsWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionsWindow.swift; sourceTree = ""; }; D04BA9EF65B2E7AF9E3ADCA3 /* 2 windows - 1 line.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "2 windows - 1 line.jpg"; sourceTree = ""; }; D04BAA127E73B3114B75098A /* Gemfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Gemfile; sourceTree = ""; }; D04BAA4442D0CE3A4972937F /* nl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = nl; path = InfoPlist.strings; sourceTree = ""; }; @@ -258,6 +267,7 @@ D04BAE5D665680CB4B13CA26 /* app-icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = "app-icon.icns"; sourceTree = ""; }; D04BAE93A5854C501639C640 /* update_homebrew_cask.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = update_homebrew_cask.sh; sourceTree = ""; }; D04BAE94A2FD4D9B72830B43 /* favicon-32x32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "favicon-32x32.png"; sourceTree = ""; }; + D04BAED1C4D6BB8E24847E79 /* TitleLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleLabel.swift; sourceTree = ""; }; D04BAED450528DC3C28FABDE /* Changelog.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Changelog.md; sourceTree = ""; }; D04BAEF1D194C2379C9970F1 /* setup_ci_master.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = setup_ci_master.sh; sourceTree = ""; }; D04BAF076A30A1BAFEDBEA66 /* 5 windows - 2 lines.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "5 windows - 2 lines.jpg"; sourceTree = ""; }; @@ -297,7 +307,6 @@ 672F94799CC7C90282AEB3EA /* Pods-alt-tab-macos.debug.xcconfig */, 59DD4BE63D42EEFF1182BA7F /* Pods-alt-tab-macos.release.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -392,6 +401,15 @@ name = Products; sourceTree = ""; }; + D04BA1C271F0DA573345B860 /* permission-window */ = { + isa = PBXGroup; + children = ( + D04BA9DF10D0CC4CA0C8F814 /* PermissionsWindow.swift */, + D04BA0726EABD146753B9EF8 /* PermissionView.swift */, + ); + path = "permission-window"; + sourceTree = ""; + }; D04BA229883E5D540D00232D /* ui */ = { isa = PBXGroup; children = ( @@ -401,6 +419,7 @@ D04BAD905546AA93E5117B0A /* Menubar.swift */, D04BA26C75F76C277653C932 /* FeedbackWindow.swift */, D04BA2CBF267F267225CA671 /* generic-components */, + D04BA1C271F0DA573345B860 /* permission-window */, ); path = ui; sourceTree = ""; @@ -604,6 +623,8 @@ D04BA1C3E42AC44CA2C5D3D8 /* app-icon.svg */, D04BAE5D665680CB4B13CA26 /* app-icon.icns */, D04BA4356B4F575E66B32298 /* app-icon.iconset */, + D04BA303761CFDD9BE8B6ECB /* accessibility@2x.png */, + D04BA98B2A0815540E319908 /* screen-recording@2x.png */, ); path = icons; sourceTree = ""; @@ -702,6 +723,7 @@ D04BA7C836A8CE8C0B8D128B /* TextArea.swift */, D04BA53992F116E5E704CAB3 /* BaseLabel.swift */, D04BA5BD11C365C19461458C /* TextField.swift */, + D04BAED1C4D6BB8E24847E79 /* TitleLabel.swift */, ); path = text; sourceTree = ""; @@ -929,6 +951,8 @@ D04BAC463D66BB8E19CF8E2E /* InfoPlist.strings in Resources */, D04BA7B9421871EDBD58F4E3 /* Localizable.strings in Resources */, D04BA530F00E5989D66C6A1F /* Contributors.md in Resources */, + D04BA079F61177D470F3E6C1 /* accessibility@2x.png in Resources */, + D04BA2B4364250FA07EE5793 /* screen-recording@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1054,6 +1078,9 @@ D04BA1766FBCB2E941D081A5 /* WorkspaceEvents.swift in Sources */, D04BA0AE9865276FF8EF5DEB /* UserDefaultsEvents.swift in Sources */, D04BA4A11F821548EE3C5E95 /* Bash.swift in Sources */, + D04BAFB90E00AA5D662EAF24 /* PermissionsWindow.swift in Sources */, + D04BA7E39FA539DD8316447A /* PermissionView.swift in Sources */, + D04BA446D702C5E252AF2319 /* TitleLabel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/resources/icons/accessibility@2x.png b/resources/icons/accessibility@2x.png new file mode 100644 index 00000000..edd92e33 Binary files /dev/null and b/resources/icons/accessibility@2x.png differ diff --git a/resources/icons/screen-recording@2x.png b/resources/icons/screen-recording@2x.png new file mode 100644 index 00000000..85cac044 Binary files /dev/null and b/resources/icons/screen-recording@2x.png differ diff --git a/resources/l10n/Localizable.strings b/resources/l10n/Localizable.strings index b396f63e..8ad0a26f 100644 --- a/resources/l10n/Localizable.strings +++ b/resources/l10n/Localizable.strings @@ -1,6 +1,9 @@ /* No comment provided by engineer. */ "About" = "About"; +/* No comment provided by engineer. */ +"Accessibility" = "Accessibility"; + /* No comment provided by engineer. */ "Acknowledgments" = "Acknowledgments"; @@ -28,6 +31,12 @@ /* No comment provided by engineer. */ "All spaces" = "All spaces"; +/* No comment provided by engineer. */ +"Allowed" = "Allowed"; + +/* No comment provided by engineer. */ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /* No comment provided by engineer. */ "Apparition delay:" = "Apparition delay:"; @@ -118,6 +127,15 @@ /* No comment provided by engineer. */ "Mouse hover" = "Mouse hover"; +/* No comment provided by engineer. */ +"Not allowed" = "Not allowed"; + +/* No comment provided by engineer. */ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/* No comment provided by engineer. */ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /* No comment provided by engineer. */ "Optional: email (if you want a reply)" = "Optional: email (if you want a reply)"; @@ -142,6 +160,9 @@ /* No comment provided by engineer. */ "Screen including mouse" = "Screen including mouse"; +/* No comment provided by engineer. */ +"Screen Recording" = "Screen Recording"; + /* No comment provided by engineer. */ "Screen showing AltTab" = "Screen showing AltTab"; @@ -196,6 +217,12 @@ /* No comment provided by engineer. */ "then press:" = "then press:"; +/* No comment provided by engineer. */ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/* No comment provided by engineer. */ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /* No comment provided by engineer. */ "Updates" = "Updates"; diff --git a/resources/l10n/ar.lproj/Localizable.strings b/resources/l10n/ar.lproj/Localizable.strings index 33370a39..836b2c42 100644 --- a/resources/l10n/ar.lproj/Localizable.strings +++ b/resources/l10n/ar.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "حول"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "شكر وتقدير"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "كل المساحات"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "تأخر الوموض:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "تمرير المؤشر"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "رخصة GPL-3.0"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "اختياري: بريد (إذا كنت تريد رد)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "شاشة المؤشر"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "شاشة الـAltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "واضغط:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "تحديثات"; diff --git a/resources/l10n/de.lproj/Localizable.strings b/resources/l10n/de.lproj/Localizable.strings index 222a8b99..23d04686 100644 --- a/resources/l10n/de.lproj/Localizable.strings +++ b/resources/l10n/de.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "Über"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Drittanbieter Lizenzen"; @@ -24,7 +27,7 @@ "All apps" = "Alle Anwendungen"; /*No comment provided by engineer.*/ -"All data from this form will be made public, as a ticket on github.com" = "All data from this form will be made public, as a ticket on github.com"; +"All data from this form will be made public, as a ticket on github.com" = "Alle hier eigegebenen Daten werden auf github.com als Issue öffentlich einsehbar sein"; /*No comment provided by engineer.*/ "All screens" = "Alle Bildschirme"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Alle Spaces"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Verzögertes Einblenden:"; @@ -75,7 +84,7 @@ "Fade out animation:" = "Ausblenden animieren:"; /*No comment provided by engineer.*/ -"Fullscreen" = "Fullscreen"; +"Fullscreen" = "Vollbild"; /*No comment provided by engineer.*/ "General" = "Allgemein"; @@ -84,7 +93,7 @@ "Hidden" = "Versteckt"; /*No comment provided by engineer.*/ -"Hide menubar icon:" = "Hide menubar icon:"; +"Hide menubar icon:" = "Icon in Menüleiste verstecken:"; /*No comment provided by engineer.*/ "Hide space number labels:" = "Space Nummer ausblenden:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Maus hover"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0 Lizenz"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Optional: E-Mail (wenn du benachrichtigt werden willst)"; @@ -132,7 +150,7 @@ "Preferences…" = "Einstellungen…"; /*No comment provided by engineer.*/ -"Quit" = "Quit"; +"Quit" = "Beenden"; /*No comment provided by engineer.*/ "Quit %@" = "Beenden %@"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Bildschirm mit Maus"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Bildschirm zum Anzeigen von AltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "und drücke:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Updates"; diff --git a/resources/l10n/en.lproj/Localizable.strings b/resources/l10n/en.lproj/Localizable.strings index c83fdc7a..938cae03 100644 --- a/resources/l10n/en.lproj/Localizable.strings +++ b/resources/l10n/en.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "About"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Acknowledgments"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "All spaces"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Apparition delay:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Mouse hover"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0 license"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Optional: email (if you want a reply)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Screen including mouse"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Screen showing AltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "then press:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Updates"; diff --git a/resources/l10n/es.lproj/Localizable.strings b/resources/l10n/es.lproj/Localizable.strings index bd81cc42..dc15ac50 100644 --- a/resources/l10n/es.lproj/Localizable.strings +++ b/resources/l10n/es.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "Acerca de"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Agradecimientos"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Todos los escritorios"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Retraso al mostrar:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Al pasar el ratón"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "Licencia GPL-3.0"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Opcional: correo electrónico (si desea una respuesta)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Pantalla que tiene el ratón"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Pantalla que muestra AltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "y pulsar:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Actualizaciones"; diff --git a/resources/l10n/fi.lproj/Localizable.strings b/resources/l10n/fi.lproj/Localizable.strings index 11a1beac..dc238988 100644 --- a/resources/l10n/fi.lproj/Localizable.strings +++ b/resources/l10n/fi.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "Tietoja"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Kiitokset"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Kaikki tilat"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Ilmestymisviive:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Hiiren liike"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0 -lisenssi"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Vapaaehtoinen: sähköposti (jos haluat vastauksen)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Ruudulla jossa hiiri"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Ruudulla jossa AltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "sitten paina:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Päivitykset"; diff --git a/resources/l10n/fr.lproj/Localizable.strings b/resources/l10n/fr.lproj/Localizable.strings index cac5881e..edbb5f86 100644 --- a/resources/l10n/fr.lproj/Localizable.strings +++ b/resources/l10n/fr.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "À propos"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibilité"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Remerciements"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Tous les Espaces"; +/*No comment provided by engineer.*/ +"Allowed" = "Autorisé"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab a besoin de permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Délai d’apparition :"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Survol de la souris"; +/*No comment provided by engineer.*/ +"Not allowed" = "Non autorisé"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "Licence GPL-3.0"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Ouvrir Préférences Accessibilité…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Ouvrir Préférences Enregistrement de l’écran…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Optionnel : email (si vous voulez une réponse)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Écran contenant la souris"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Enregistrement de l’écran"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Écran affichant AltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "puis presser :"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "Cette permission est nécessaire pour afficher la fenêtre après le relâchement du raccourci clavier"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "Cette permission est nécessaire pour afficher les miniatures et titres des fenêtres ouvertes"; + /*No comment provided by engineer.*/ "Updates" = "Mises-à-jour"; diff --git a/resources/l10n/hu.lproj/Localizable.strings b/resources/l10n/hu.lproj/Localizable.strings index 87cfda3a..689384ad 100644 --- a/resources/l10n/hu.lproj/Localizable.strings +++ b/resources/l10n/hu.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "Az App-ról"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Köszönetnyílvánítás"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Minden terület"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Megjelenítés késleltetése:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Egér főlé vitele"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0 license"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Opcionális: email (ha választ szeretnél kapni)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "A képernyő ahol az egér van"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Az AltTab képernyője"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "majd nyomjon:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Frissítések"; diff --git a/resources/l10n/it.lproj/Localizable.strings b/resources/l10n/it.lproj/Localizable.strings index 548ed9a2..d051496e 100644 --- a/resources/l10n/it.lproj/Localizable.strings +++ b/resources/l10n/it.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "Introduzione"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Ringraziamenti"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Tutti gli spazi"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Ritardo di apparizione:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Passa il mouse"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "Licenza GPL-3.0"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Opzionale: email (se desideri una risposta)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Schermo compreso il mouse"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Schermata che mostra AltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "quindi premere:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Aggiornamenti"; diff --git a/resources/l10n/ja.lproj/Localizable.strings b/resources/l10n/ja.lproj/Localizable.strings index a8611ac3..b8be9584 100644 --- a/resources/l10n/ja.lproj/Localizable.strings +++ b/resources/l10n/ja.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "詳細"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "謝辞"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "全てのスペース"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "スクリーン表示速度:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "マウスホバー"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0ライセンス"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "任意:Eメール(返信を希望する場合)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "マウスのあるスクリーン"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "AltTabが表示されるスクリーン"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "を押したまま:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "アップデート"; diff --git a/resources/l10n/ko.lproj/Localizable.strings b/resources/l10n/ko.lproj/Localizable.strings index 4f815d58..6b3b8a55 100644 --- a/resources/l10n/ko.lproj/Localizable.strings +++ b/resources/l10n/ko.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "정보"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "감사의 말"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "모든 Space"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "나타나는 시간:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "마우스 올려놓기"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0 라이선스"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "답변을 원하면 이메일 남겨주세요"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "마우스를 포함한 화면"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "AltTab이 보여지는 화면"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "을 누르고 다음을 누르면:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "업데이트"; diff --git a/resources/l10n/nl.lproj/Localizable.strings b/resources/l10n/nl.lproj/Localizable.strings index ca743bbe..a3850c47 100644 --- a/resources/l10n/nl.lproj/Localizable.strings +++ b/resources/l10n/nl.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "Over"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Dankwoord"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Alle spaces"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Tonen met vertraging:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Muisbeweging"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL 3.0-licentie"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Optioneel: e-mail (als je een reactie wilt ontvangen)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Beeldscherm met muis"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Beeldscherm met AltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "ingedrukt, en druk dan op:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Updates"; diff --git a/resources/l10n/pt-BR.lproj/Localizable.strings b/resources/l10n/pt-BR.lproj/Localizable.strings index 9dd74ca8..1e823fc2 100644 --- a/resources/l10n/pt-BR.lproj/Localizable.strings +++ b/resources/l10n/pt-BR.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "Sobre"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Agradecimentos"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Todos os desktops"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Intervalo para exibição:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Ao passar o mouse"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "Licença GPL-3.0"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Opcional: e-mail (se você desejar uma resposta)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Tela onde o mouse está sendo exibido"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Tela onde o AltTab está sendo exibido"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "então pressione:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Atualizações"; diff --git a/resources/l10n/ru.lproj/Localizable.strings b/resources/l10n/ru.lproj/Localizable.strings index d392fc50..443b1c28 100644 --- a/resources/l10n/ru.lproj/Localizable.strings +++ b/resources/l10n/ru.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "О программе"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Лицензии"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Все рабочие столы"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Задержка появления:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Наведение мышью"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "Лицензия GPL-3.0"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "Опционально: эл.почта (если вы хотите ответа)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "Экран с курсором"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "Экран, показывающий AltTab"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "затем нажать:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Обновления"; diff --git a/resources/l10n/tr.lproj/Localizable.strings b/resources/l10n/tr.lproj/Localizable.strings index e0634a3c..58fd2ab3 100644 --- a/resources/l10n/tr.lproj/Localizable.strings +++ b/resources/l10n/tr.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "Hakkında"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "Teşekkür"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "Tüm boşluklar"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "Görünüm gecikmesi:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "Fare "; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0 lisansı"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "İsteğe bağlı: e-posta (bir yanıt istiyorsanız)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "İmleçin olduğu ekran"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "AltTab'ı gösteren ekran"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "ve:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "Güncellemeler"; diff --git a/resources/l10n/zh-CN.lproj/Localizable.strings b/resources/l10n/zh-CN.lproj/Localizable.strings index b4bc333c..529d25c2 100644 --- a/resources/l10n/zh-CN.lproj/Localizable.strings +++ b/resources/l10n/zh-CN.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "关于"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "致谢"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "所有桌面"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "切换窗口出现延迟:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "鼠标悬停"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0 协议"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "电子邮箱地址 (可选,若想接收答复)"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "鼠标所在屏幕"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "显示 AltTab 的屏幕"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "并按下:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "更新"; diff --git a/resources/l10n/zh-TW.lproj/Localizable.strings b/resources/l10n/zh-TW.lproj/Localizable.strings index b8ea3b85..d2df9760 100644 --- a/resources/l10n/zh-TW.lproj/Localizable.strings +++ b/resources/l10n/zh-TW.lproj/Localizable.strings @@ -5,6 +5,9 @@ /*No comment provided by engineer.*/ "About" = "關於"; +/*No comment provided by engineer.*/ +"Accessibility" = "Accessibility"; + /*No comment provided by engineer.*/ "Acknowledgments" = "鳴謝"; @@ -24,7 +27,7 @@ "All apps" = "全部程式"; /*No comment provided by engineer.*/ -"All data from this form will be made public, as a ticket on github.com" = "All data from this form will be made public, as a ticket on github.com"; +"All data from this form will be made public, as a ticket on github.com" = "此表單的所有資料都會被公開為 GitHub 上的 Ticket"; /*No comment provided by engineer.*/ "All screens" = "全部螢幕"; @@ -32,6 +35,12 @@ /*No comment provided by engineer.*/ "All spaces" = "全部桌面"; +/*No comment provided by engineer.*/ +"Allowed" = "Allowed"; + +/*No comment provided by engineer.*/ +"AltTab needs some permissions" = "AltTab needs some permissions"; + /*No comment provided by engineer.*/ "Apparition delay:" = "顯示前的延遲:"; @@ -75,7 +84,7 @@ "Fade out animation:" = "淡出動畫:"; /*No comment provided by engineer.*/ -"Fullscreen" = "Fullscreen"; +"Fullscreen" = "全螢幕"; /*No comment provided by engineer.*/ "General" = "一般"; @@ -84,7 +93,7 @@ "Hidden" = "隱藏"; /*No comment provided by engineer.*/ -"Hide menubar icon:" = "Hide menubar icon:"; +"Hide menubar icon:" = "隱藏選單列上的圖示:"; /*No comment provided by engineer.*/ "Hide space number labels:" = "隱藏空間編號的標籤:"; @@ -122,9 +131,18 @@ /*No comment provided by engineer.*/ "Mouse hover" = "滑鼠懸停"; +/*No comment provided by engineer.*/ +"Not allowed" = "Not allowed"; + /*Copyright (human-readable)*/ "NSHumanReadableCopyright" = "GPL-3.0 授權"; +/*No comment provided by engineer.*/ +"Open Accessibility Preferences…" = "Open Accessibility Preferences…"; + +/*No comment provided by engineer.*/ +"Open Screen Recording Preferences…" = "Open Screen Recording Preferences…"; + /*No comment provided by engineer.*/ "Optional: email (if you want a reply)" = "電子信箱(選填,如果你想要收到回覆)"; @@ -132,7 +150,7 @@ "Preferences…" = "偏好設定…"; /*No comment provided by engineer.*/ -"Quit" = "Quit"; +"Quit" = "離開"; /*No comment provided by engineer.*/ "Quit %@" = "離開 %@"; @@ -149,6 +167,9 @@ /*No comment provided by engineer.*/ "Screen including mouse" = "滑鼠所在的螢幕"; +/*No comment provided by engineer.*/ +"Screen Recording" = "Screen Recording"; + /*No comment provided by engineer.*/ "Screen showing AltTab" = "要顯示 AltTab 的螢幕"; @@ -203,6 +224,12 @@ /*No comment provided by engineer.*/ "then press:" = "並按下:"; +/*No comment provided by engineer.*/ +"This permission is needed to focus windows after you release the shortcut" = "This permission is needed to focus windows after you release the shortcut"; + +/*No comment provided by engineer.*/ +"This permission is needed to show screenshots and titles of open windows" = "This permission is needed to show screenshots and titles of open windows"; + /*No comment provided by engineer.*/ "Updates" = "更新"; diff --git a/src/api-wrappers/PrivateApis.swift b/src/api-wrappers/PrivateApis.swift index e3376e3b..13c50fdf 100644 --- a/src/api-wrappers/PrivateApis.swift +++ b/src/api-wrappers/PrivateApis.swift @@ -116,6 +116,7 @@ func CGSGetWindowLevel(_ cid: CGSConnectionID, _ wid: CGWindowID, _ level: inout // returns status of the checkbox in System Preferences > Security & Privacy > Privacy > Screen Recording // returns 1 if checked or 0 if unchecked; also prompts the user the first time if unchecked +// the return value will be the same during the app lifetime; it will not reflect the actual status of the checkbox @_silgen_name("SLSRequestScreenCaptureAccess") @discardableResult func SLSRequestScreenCaptureAccess() -> UInt8 diff --git a/src/logic/SystemPermissions.swift b/src/logic/SystemPermissions.swift index ed7f3878..c588142f 100644 --- a/src/logic/SystemPermissions.swift +++ b/src/logic/SystemPermissions.swift @@ -2,33 +2,85 @@ import Cocoa // macOS has some privacy restrictions. The user needs to grant certain permissions, app by app, in System Preferences > Security & Privacy class SystemPermissions { - static func ensureAccessibilityCheckboxIsChecked() { - guard #available(OSX 10.9, *) else { return } - if !AXIsProcessTrustedWithOptions([kAXTrustedCheckOptionPrompt.takeRetainedValue(): true] as CFDictionary) { - debugPrint("Before using this app, you need to give permission in System Preferences > Security & Privacy > Privacy > Accessibility.", - "Please authorize and re-launch.", - "See https://help.rescuetime.com/article/59-how-do-i-enable-accessibility-permissions-on-mac-osx", - separator: "\n") - App.shared.terminate(self) - } else { - // if the user removes the permission while the app is running, it can break keyboard inputs - DistributedNotificationCenter.default().addObserver(forName: NSNotification.Name("com.apple.accessibility.api"), object: nil, queue: nil) { _ in - // there is a delay between the notification and the permission being actually changed - DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { - ensureAccessibilityCheckboxIsChecked() - } - } + static var changeCallback: (() -> Void)! + static var screenRecordingObserver: Timer! + static var permissionsWindow: PermissionsWindow! + + static func accessibilityIsGranted() -> Bool { + if #available(OSX 10.9, *) { + return AXIsProcessTrustedWithOptions([kAXTrustedCheckOptionPrompt.takeRetainedValue(): false] as CFDictionary) } + return true } - static func ensureScreenRecordingCheckboxIsChecked() { - guard #available(OSX 10.15, *) else { return } - if SLSRequestScreenCaptureAccess() != 1 { - debugPrint("Before using this app, you need to give permission in System Preferences > Security & Privacy > Privacy > Screen Recording.", - "Please authorize and re-launch.", - "See https://dropshare.zendesk.com/hc/en-us/articles/360033453434-Enabling-Screen-Recording-Permission-on-macOS-Catalina-10-15-", - separator: "\n") - App.shared.terminate(self) + static func screenRecordingIsGranted() -> Bool { + if #available(OSX 10.15, *) { + return screenRecordingIsGranted_() + } + return true + } + + // there is no official API to check the status of the Screen Recording permission + // there is the private API SLSRequestScreenCaptureAccess, but its value is not updated during the app lifetime + // workaround: we check if we can get the title of at least one window, except from AltTab or the Dock + private static func screenRecordingIsGranted_() -> Bool { + let appPid = NSRunningApplication.current.processIdentifier + if let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID) as? [CGWindow], + let _ = windows.first(where: { (window) -> Bool in + if let windowPid = window.ownerPID(), + windowPid != appPid, + let windowRunningApplication = NSRunningApplication(processIdentifier: windowPid), + windowRunningApplication.executableURL?.lastPathComponent != "Dock", + let _ = window.title() { + return true + } + return false + }) { + return true + } + return false + } + + static func observePermissionsPostStartup() { + screenRecordingObserver = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { _ in + if !(accessibilityIsGranted() && screenRecordingIsGranted()) { + App.app.restart() + } + }) + } + + static func observePermissionsPreStartup(_ startupBlock: @escaping () -> Void) { + // this call triggers the permission prompt, however it's the only way to force the app to be listed with a checkbox + SLSRequestScreenCaptureAccess() + screenRecordingObserver = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in + let accessibility = accessibilityIsGranted() + let screenRecording = screenRecordingIsGranted() + if accessibility && screenRecording { + permissionsWindow.close() + screenRecordingObserver.invalidate() + startupBlock() + } else { + if accessibility != permissionsWindow.accessibilityView.isPermissionGranted { + permissionsWindow.accessibilityView.updatePermissionStatus(accessibility) + } + if #available(OSX 10.15, *), screenRecording != permissionsWindow.screenRecordingView.isPermissionGranted { + permissionsWindow.screenRecordingView.updatePermissionStatus(screenRecording) + } + } + }) + } + + static func ensurePermissionsAreGranted(_ continueAppStartup: @escaping () -> Void) { + let startupBlock = { + observePermissionsPostStartup() + continueAppStartup() + } + if accessibilityIsGranted() && screenRecordingIsGranted() { + startupBlock() + } else { + permissionsWindow = PermissionsWindow() + permissionsWindow.show() + observePermissionsPreStartup(startupBlock) } } } diff --git a/src/ui/App.swift b/src/ui/App.swift index a4fa3c15..afe65cd1 100644 --- a/src/ui/App.swift +++ b/src/ui/App.swift @@ -35,34 +35,30 @@ class App: NSApplication, NSApplicationDelegate { PFMoveToApplicationsFolderIfNecessary() #endif AXUIElement.setGlobalTimeout() - SystemPermissions.ensureAccessibilityCheckboxIsChecked() - SystemPermissions.ensureScreenRecordingCheckboxIsChecked() - BackgroundWork.start() - Preferences.migratePreferences() - Preferences.registerDefaults() - App.statusItem = Menubar.make() - loadMainMenuXib() - thumbnailsPanel = ThumbnailsPanel() - Spaces.initialDiscovery() - Applications.initialDiscovery() - loadPreferencesWindow() - KeyboardEvents.observe() - // TODO: undeterministic; events in the queue may still be processing; good enough for now - DispatchQueue.main.async { () -> () in Windows.sortByLevel() } - preloadWindows() - - #if DEBUG - showPreferencesPanel() - #endif - + SystemPermissions.ensurePermissionsAreGranted { [weak self] in + guard let self = self else { return } + BackgroundWork.start() + Preferences.migratePreferences() + Preferences.registerDefaults() + App.statusItem = Menubar.make() + self.loadMainMenuXib() + self.thumbnailsPanel = ThumbnailsPanel() + Spaces.initialDiscovery() + Applications.initialDiscovery() + self.loadPreferencesWindow() + KeyboardEvents.observe() + // TODO: undeterministic; events in the queue may still be processing; good enough for now + DispatchQueue.main.async { () -> () in Windows.sortByLevel() } + self.preloadWindows() + } } - + func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { NSApp.activate(ignoringOtherApps: true) showPreferencesPanel() return true } - + // pre-load some windows so they are faster on first display private func preloadWindows() { thumbnailsPanel.orderFront(nil) @@ -80,7 +76,7 @@ class App: NSApplication, NSApplicationDelegate { // pre-load tabs so we can interact with them before the user opens the preferences window tabs.forEach { (tab: NSViewController) in tab.loadView() } preferencesWindowController = PreferencesWindowController(preferencePanes: tabs as! [PreferencePane]) - + let window = preferencesWindowController.window! let quitButton = NSButton(title: NSLocalizedString("Quit", comment: ""), target: nil, action: #selector(NSApplication.terminate(_:))) let titleBarView = window.standardWindowButton(.closeButton)!.superview! @@ -89,7 +85,7 @@ class App: NSApplication, NSApplicationDelegate { let topConstraint = NSLayoutConstraint(item: quitButton, attribute: .top, relatedBy: .equal, toItem: titleBarView, attribute: .top, multiplier: 1, constant: 5) let rightConstraint = NSLayoutConstraint(item: quitButton, attribute: .right, relatedBy: .equal, toItem: titleBarView, attribute: .right, multiplier: 1, constant: -10) titleBarView.addConstraints([topConstraint, rightConstraint]) - + } // keyboard shortcuts are broken without a menu. We generated the default menu from XCode and load it @@ -106,6 +102,16 @@ class App: NSApplication, NSApplicationDelegate { thumbnailsPanel.thumbnailsView.layer!.cornerRadius = Preferences.windowCornerRadius } + func restart() { + let url = URL(fileURLWithPath: Bundle.main.resourcePath!) + let path = url.deletingLastPathComponent().deletingLastPathComponent().absoluteString + let task = Process() + task.launchPath = "/usr/bin/open" + task.arguments = [path] + task.launch() + exit(0) + } + func hideUi() { debugPrint("hideUi") appIsBeingUsed = false diff --git a/src/ui/generic-components/StackView.swift b/src/ui/generic-components/StackView.swift index d7201489..607dc640 100644 --- a/src/ui/generic-components/StackView.swift +++ b/src/ui/generic-components/StackView.swift @@ -1,11 +1,9 @@ import Cocoa class StackView: NSStackView { - var alignmentRectInsets_: NSEdgeInsets! - convenience init(_ views: [NSView], _ orientation: NSUserInterfaceLayoutOrientation = .horizontal, top: CGFloat = 0, right: CGFloat = 0, bottom: CGFloat = 0, left: CGFloat = 0) { self.init(views: views) - alignmentRectInsets_ = NSEdgeInsets(top: top, left: left, bottom: bottom, right: right) + edgeInsets = NSEdgeInsets(top: top, left: left, bottom: bottom, right: right) alignment = orientation == .horizontal ? .firstBaseline : .leading // workaround: for some reason, horizontal stackviews with a RecorderControl have extra fittingSize.height if orientation == .horizontal && (views.contains { $0 is CustomRecorderControl }) { @@ -14,6 +12,4 @@ class StackView: NSStackView { fit() } } - - override var alignmentRectInsets: NSEdgeInsets { alignmentRectInsets_ } } diff --git a/src/ui/generic-components/text/BoldLabel.swift b/src/ui/generic-components/text/BoldLabel.swift index 91cdc372..602a0fdf 100644 --- a/src/ui/generic-components/text/BoldLabel.swift +++ b/src/ui/generic-components/text/BoldLabel.swift @@ -3,9 +3,7 @@ import Cocoa class BoldLabel: NSTextField { convenience init(_ string: String) { self.init(labelWithString: string) - allowsEditingTextAttributes = true - attributedStringValue = NSAttributedString(string: string, attributes: [ - NSAttributedString.Key.font: NSFont.boldSystemFont(ofSize: NSFont.systemFontSize), - ]) + font = .boldSystemFont(ofSize: NSFont.systemFontSize) + stringValue = string } } diff --git a/src/ui/generic-components/text/TitleLabel.swift b/src/ui/generic-components/text/TitleLabel.swift new file mode 100644 index 00000000..db70b541 --- /dev/null +++ b/src/ui/generic-components/text/TitleLabel.swift @@ -0,0 +1,9 @@ +import Cocoa + +class TitleLabel: NSTextField { + convenience init(_ string: String) { + self.init(wrappingLabelWithString: string) + font = .systemFont(ofSize: NSFont.labelFontSize * 2) + stringValue = string + } +} diff --git a/src/ui/permission-window/PermissionView.swift b/src/ui/permission-window/PermissionView.swift new file mode 100644 index 00000000..1bdd9200 --- /dev/null +++ b/src/ui/permission-window/PermissionView.swift @@ -0,0 +1,62 @@ +import Cocoa + +class PermissionView: StackView { + static let greenColor = NSColor(srgbRed: 0.38, green: 0.75, blue: 0.33, alpha: 0.2) + static let redColor = NSColor(srgbRed: 0.90, green: 0.35, blue: 0.32, alpha: 0.2) + + var checkFunction: (() -> Bool)! + var button: NSButton! + var status: NSTextField! + var isPermissionGranted = false + + convenience init(_ iconName: String, _ title: String, _ justification: String, _ buttonText: String, _ buttonUrl: String, _ checkFunction: @escaping () -> Bool) { + let icon = NSImageView(image: NSImage(named: iconName)!) + icon.translatesAutoresizingMaskIntoConstraints = false + icon.fit() + let title = BoldLabel(title) + title.translatesAutoresizingMaskIntoConstraints = false + title.fit() + let titleStack = NSStackView(views: [icon, title]) + titleStack.translatesAutoresizingMaskIntoConstraints = false + titleStack.alignment = .centerY + titleStack.spacing = GridView.interPadding + titleStack.fit() + let justification = NSTextField(wrappingLabelWithString: justification) + justification.translatesAutoresizingMaskIntoConstraints = false + justification.preferredMaxLayoutWidth = 500 + justification.widthAnchor.constraint(equalToConstant: justification.fittingSize.width + 5).isActive = true + let button = NSButton(title: buttonText, target: nil, action: nil) + button.translatesAutoresizingMaskIntoConstraints = false + button.onAction = { _ in NSWorkspace.shared.open(URL(string: buttonUrl)!) } + button.fit() + let status = NSTextField(wrappingLabelWithString: "") + status.translatesAutoresizingMaskIntoConstraints = false + let buttonStack = NSStackView(views: [button, status]) + buttonStack.translatesAutoresizingMaskIntoConstraints = false + buttonStack.alignment = .centerY + self.init([titleStack, justification, buttonStack], .vertical, top: GridView.interPadding, right: GridView.interPadding, bottom: GridView.interPadding, left: GridView.interPadding) + self.checkFunction = checkFunction + self.button = button + self.status = status + wantsLayer = true + layer!.cornerRadius = GridView.interPadding / 2 + updatePermissionStatus(checkFunction()) + } + + func updatePermissionStatus(_ isPermissionGranted: Bool) { + self.isPermissionGranted = isPermissionGranted + if isPermissionGranted { + let color = PermissionView.greenColor + button.isEnabled = false + status.stringValue = "● " + NSLocalizedString("Allowed", comment: "") + status.textColor = color.withAlphaComponent(1) + layer!.backgroundColor = color.cgColor + } else { + let color = PermissionView.redColor + button.isEnabled = true + status.stringValue = "● " + NSLocalizedString("Not allowed", comment: "") + status.textColor = color.withAlphaComponent(1) + layer!.backgroundColor = color.cgColor + } + } +} diff --git a/src/ui/permission-window/PermissionsWindow.swift b/src/ui/permission-window/PermissionsWindow.swift new file mode 100644 index 00000000..79bcfdda --- /dev/null +++ b/src/ui/permission-window/PermissionsWindow.swift @@ -0,0 +1,72 @@ +import Cocoa + +class PermissionsWindow: NSWindow, NSWindowDelegate { + var accessibilityView: PermissionView! + var screenRecordingView: PermissionView! + + override init(contentRect: NSRect, styleMask style: StyleMask, backing backingStoreType: BackingStoreType, defer flag: Bool) { + super.init(contentRect: .zero, styleMask: style, backing: backingStoreType, defer: flag) + delegate = self + setupWindow() + setupView() + } + + func show() { + center() + App.shared.activate(ignoringOtherApps: true) + makeKeyAndOrderFront(nil) + } + + func windowShouldClose(_ sender: NSWindow) -> Bool { + debugPrint("Before using this app, you need to give permission in System Preferences > Security & Privacy > Privacy > Accessibility.", + "Please authorize and re-launch.", + "See https://help.rescuetime.com/article/59-how-do-i-enable-accessibility-permissions-on-mac-osx", + separator: "\n") + App.shared.terminate(self) + return true + } + + private func setupWindow() { + title = NSLocalizedString("AltTab needs some permissions", comment: "") + hidesOnDeactivate = false + styleMask.insert([.miniaturizable, .closable]) + } + + private func setupView() { + let appIcon = NSImageView(image: NSImage(named: "app-icon")!.resizedCopy(80, 80)) + appIcon.imageScaling = .scaleNone + let appText = TitleLabel(NSLocalizedString("AltTab needs some permissions", comment: "")) + appText.preferredMaxLayoutWidth = 380 + appText.font = .systemFont(ofSize: 25, weight: .regular) + let header = NSStackView(views: [appIcon, appText]) + header.spacing = GridView.interPadding + accessibilityView = PermissionView( + "accessibility", + NSLocalizedString("Accessibility", comment: ""), + NSLocalizedString("This permission is needed to focus windows after you release the shortcut", comment: ""), + NSLocalizedString("Open Accessibility Preferences…", comment: ""), + "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility", + SystemPermissions.accessibilityIsGranted + ) + var rows = [ + [header], + [accessibilityView], + ] + if #available(OSX 10.15, *) { + screenRecordingView = PermissionView( + "screen-recording", + NSLocalizedString("Screen Recording", comment: ""), + NSLocalizedString("This permission is needed to show screenshots and titles of open windows", comment: ""), + NSLocalizedString("Open Screen Recording Preferences…", comment: ""), + "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture", + SystemPermissions.screenRecordingIsGranted + ) + rows.append([screenRecordingView]) + } + let view = GridView(rows as! [[NSView]]) + view.fit() +// view.cell(atColumnIndex: 0, rowIndex: 4).xPlacement = .trailing + setContentSize(view.fittingSize) + contentView = view + } +}