Compare commits

...

6 Commits

Author SHA1 Message Date
Keeley Hammond
9c045e97a7 test: remove redundent feedURL test 2026-02-12 15:21:02 -08:00
Keeley Hammond
6a87d47e83 fix: code-sign binaries for notification tests 2026-02-10 17:25:01 -08:00
Keeley Hammond
c05faa7bad build: update config to handle --translate-gender for pak files 2026-02-10 15:55:13 -08:00
Keeley Hammond
5b6403eb11 build: fix lint 2026-02-10 15:55:13 -08:00
Developer-Ecosystem-Engineering
1c6bb418bd Use NotificationImageRetainer pattern from //chrome 2026-02-10 15:55:13 -08:00
Developer-Ecosystem-Engineering
ed27a77558 refactor: replace deprecated NSUserNotifications with User Notifications
Removes deprecated NSUserNotification API, now using User Notifications

It replaces API calls for generating, scheduling, and receiving native
macOS notifications with equivalent API calls from the new framework,
or functionally equivalent implementations.

To preserve the existing Notification module API, special handling was
required in certain cases:

  - Dynamically declared notification actions
    Typically, notification actions should be declared at app launch time
    when using the User Notifications framework. However, this isn’t
    compatible with Electron’s architecture. Instead, we dynamically
    declare new notifications actions when necessary and carefully manage
    the existing actions registered at runtime.

  - Localizations for ‘Reply’ and ‘Show’ labels
    New translation files are added and processed through GRIT to add
    localizations for “Reply” and “Show” button labels which were
    initially supplied by the NSUserNotification framework.
2026-02-10 15:55:13 -08:00
96 changed files with 1045 additions and 254 deletions

View File

@@ -191,12 +191,18 @@ jobs:
run: |
cd src/out/Default
unzip -:o dist.zip
#- name: Import & Trust Self-Signed Codesigning Cert on MacOS
# if: ${{ inputs.target-platform == 'macos' && inputs.target-arch == 'x64' }}
# run: |
# sudo security authorizationdb write com.apple.trust-settings.admin allow
# cd src/electron
# ./script/codesign/generate-identity.sh
- name: Import & Trust Self-Signed Codesigning Cert on MacOS
if: ${{ inputs.target-platform == 'macos' }}
run: |
cd src/electron
./script/codesign/generate-identity.sh
- name: Sign Electron.app for macOS tests
if: ${{ inputs.target-platform == 'macos' }}
run: |
identity=$(src/electron/script/codesign/get-trusted-identity.sh)
if [ -n "$identity" ]; then
codesign -s "$identity" --deep --force src/out/Default/Electron.app
fi
- name: Run Electron Tests
shell: bash

View File

@@ -321,12 +321,33 @@ grit("resources") {
"grit/electron_resources.h",
"electron_resources.pak",
]
if (translate_genders) {
outputs += [
"electron_resources_MASCULINE.pak",
"electron_resources_FEMININE.pak",
"electron_resources_NEUTER.pak",
]
}
foreach(locale, all_chrome_locales) {
outputs += [ "electron_strings_$locale.pak" ]
if (translate_genders) {
outputs += [
"electron_strings_${locale}_MASCULINE.pak",
"electron_strings_${locale}_FEMININE.pak",
"electron_strings_${locale}_NEUTER.pak",
]
}
}
# Mojo manifest overlays are generated.
grit_flags = [
"-E",
"target_gen_dir=" + rebase_path(target_gen_dir, root_build_dir),
]
if (translate_genders) {
grit_flags += [ "--translate-genders" ]
}
deps = [ ":copy_shell_devtools_discovery_page" ]
@@ -450,6 +471,7 @@ source_set("electron_lib") {
"//chrome:strings",
"//chrome/app:command_ids",
"//chrome/app/resources:platform_locale_settings",
"//chrome/common/notifications",
"//components/autofill/core/common:features",
"//components/certificate_transparency",
"//components/compose:buildflags",
@@ -618,6 +640,7 @@ source_set("electron_lib") {
"SecurityInterface.framework",
"ServiceManagement.framework",
"StoreKit.framework",
"UserNotifications.framework",
]
weak_frameworks = [ "QuickLookThumbnailing.framework" ]

View File

@@ -183,6 +183,7 @@ template("electron_paks") {
"${root_gen_dir}/components/strings/components_locale_settings_",
"${root_gen_dir}/components/strings/components_strings_",
"${root_gen_dir}/device/bluetooth/strings/bluetooth_strings_",
"${root_gen_dir}/electron/electron_strings_",
"${root_gen_dir}/extensions/strings/extensions_strings_",
"${root_gen_dir}/services/strings/services_strings_",
"${root_gen_dir}/third_party/blink/public/strings/blink_strings_",
@@ -199,6 +200,7 @@ template("electron_paks") {
"//components/strings:components_locale_settings",
"//components/strings:components_strings",
"//device/bluetooth/strings",
"//electron:resources",
"//extensions/strings",
"//services/strings",
"//third_party/blink/public/strings",

View File

@@ -9,10 +9,189 @@
<emit emit_type='prepend'></emit>
</output>
<output filename="electron_resources.pak" type="data_package" />
<output filename="electron_strings_af.pak" type="data_package" lang="af" />
<output filename="electron_strings_am.pak" type="data_package" lang="am" />
<output filename="electron_strings_ar.pak" type="data_package" lang="ar" />
<output filename="electron_strings_as.pak" type="data_package" lang="as" />
<output filename="electron_strings_az.pak" type="data_package" lang="az" />
<output filename="electron_strings_be.pak" type="data_package" lang="be" />
<output filename="electron_strings_bg.pak" type="data_package" lang="bg" />
<output filename="electron_strings_bn.pak" type="data_package" lang="bn" />
<output filename="electron_strings_bs.pak" type="data_package" lang="bs" />
<output filename="electron_strings_ca.pak" type="data_package" lang="ca" />
<output filename="electron_strings_cs.pak" type="data_package" lang="cs" />
<output filename="electron_strings_cy.pak" type="data_package" lang="cy" />
<output filename="electron_strings_da.pak" type="data_package" lang="da" />
<output filename="electron_strings_de.pak" type="data_package" lang="de" />
<output filename="electron_strings_el.pak" type="data_package" lang="el" />
<output filename="electron_strings_en-GB.pak" type="data_package" lang="en-GB" />
<output filename="electron_strings_en-US.pak" type="data_package" lang="en" />
<output filename="electron_strings_es-419.pak" type="data_package" lang="es-419" />
<output filename="electron_strings_es.pak" type="data_package" lang="es" />
<output filename="electron_strings_et.pak" type="data_package" lang="et" />
<output filename="electron_strings_eu.pak" type="data_package" lang="eu" />
<output filename="electron_strings_fa.pak" type="data_package" lang="fa" />
<output filename="electron_strings_fi.pak" type="data_package" lang="fi" />
<output filename="electron_strings_fil.pak" type="data_package" lang="fil" />
<output filename="electron_strings_fr-CA.pak" type="data_package" lang="fr-CA" />
<output filename="electron_strings_fr.pak" type="data_package" lang="fr" />
<output filename="electron_strings_gl.pak" type="data_package" lang="gl" />
<output filename="electron_strings_gu.pak" type="data_package" lang="gu" />
<output filename="electron_strings_hi.pak" type="data_package" lang="hi" />
<output filename="electron_strings_hr.pak" type="data_package" lang="hr" />
<output filename="electron_strings_hu.pak" type="data_package" lang="hu" />
<output filename="electron_strings_hy.pak" type="data_package" lang="hy" />
<output filename="electron_strings_id.pak" type="data_package" lang="id" />
<output filename="electron_strings_is.pak" type="data_package" lang="is" />
<output filename="electron_strings_it.pak" type="data_package" lang="it" />
<output filename="electron_strings_he.pak" type="data_package" lang="he" />
<output filename="electron_strings_ja.pak" type="data_package" lang="ja" />
<output filename="electron_strings_ka.pak" type="data_package" lang="ka" />
<output filename="electron_strings_kk.pak" type="data_package" lang="kk" />
<output filename="electron_strings_km.pak" type="data_package" lang="km" />
<output filename="electron_strings_kn.pak" type="data_package" lang="kn" />
<output filename="electron_strings_ko.pak" type="data_package" lang="ko" />
<output filename="electron_strings_ky.pak" type="data_package" lang="ky" />
<output filename="electron_strings_lo.pak" type="data_package" lang="lo" />
<output filename="electron_strings_lt.pak" type="data_package" lang="lt" />
<output filename="electron_strings_lv.pak" type="data_package" lang="lv" />
<output filename="electron_strings_mk.pak" type="data_package" lang="mk" />
<output filename="electron_strings_ml.pak" type="data_package" lang="ml" />
<output filename="electron_strings_mn.pak" type="data_package" lang="mn" />
<output filename="electron_strings_mr.pak" type="data_package" lang="mr" />
<output filename="electron_strings_ms.pak" type="data_package" lang="ms" />
<output filename="electron_strings_my.pak" type="data_package" lang="my" />
<output filename="electron_strings_ne.pak" type="data_package" lang="ne" />
<output filename="electron_strings_nl.pak" type="data_package" lang="nl" />
<!-- The translation console uses 'no' for Norwegian Bokmål. It should
be 'nb'. -->
<output filename="electron_strings_nb.pak" type="data_package" lang="no" />
<output filename="electron_strings_or.pak" type="data_package" lang="or" />
<output filename="electron_strings_pa.pak" type="data_package" lang="pa" />
<output filename="electron_strings_pl.pak" type="data_package" lang="pl" />
<output filename="electron_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
<output filename="electron_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
<output filename="electron_strings_ro.pak" type="data_package" lang="ro" />
<output filename="electron_strings_ru.pak" type="data_package" lang="ru" />
<output filename="electron_strings_si.pak" type="data_package" lang="si" />
<output filename="electron_strings_sk.pak" type="data_package" lang="sk" />
<output filename="electron_strings_sl.pak" type="data_package" lang="sl" />
<output filename="electron_strings_sq.pak" type="data_package" lang="sq" />
<output filename="electron_strings_sr-Latn.pak" type="data_package" lang="sr-Latn" />
<output filename="electron_strings_sr.pak" type="data_package" lang="sr" />
<output filename="electron_strings_sv.pak" type="data_package" lang="sv" />
<output filename="electron_strings_sw.pak" type="data_package" lang="sw" />
<output filename="electron_strings_ta.pak" type="data_package" lang="ta" />
<output filename="electron_strings_te.pak" type="data_package" lang="te" />
<output filename="electron_strings_th.pak" type="data_package" lang="th" />
<output filename="electron_strings_tr.pak" type="data_package" lang="tr" />
<output filename="electron_strings_uk.pak" type="data_package" lang="uk" />
<output filename="electron_strings_ur.pak" type="data_package" lang="ur" />
<output filename="electron_strings_uz.pak" type="data_package" lang="uz" />
<output filename="electron_strings_vi.pak" type="data_package" lang="vi" />
<output filename="electron_strings_zh-CN.pak" type="data_package" lang="zh-CN" />
<output filename="electron_strings_zh-HK.pak" type="data_package" lang="zh-HK" />
<output filename="electron_strings_zh-TW.pak" type="data_package" lang="zh-TW" />
<output filename="electron_strings_zu.pak" type="data_package" lang="zu" />
<!-- CARO TODO: Pseudolocales? -->
<output filename="electron_strings_ar-XB.pak" type="data_package" lang="ar-XB" />
<output filename="electron_strings_en-XA.pak" type="data_package" lang="en-XA" />
</outputs>
<release seq="1" allow_pseudo="false">
<translations>
<file path="translations/electron_strings_af.xtb" lang="af" />
<file path="translations/electron_strings_am.xtb" lang="am" />
<file path="translations/electron_strings_ar.xtb" lang="ar" />
<file path="translations/electron_strings_as.xtb" lang="as" />
<file path="translations/electron_strings_az.xtb" lang="az" />
<file path="translations/electron_strings_be.xtb" lang="be" />
<file path="translations/electron_strings_bg.xtb" lang="bg" />
<file path="translations/electron_strings_bn.xtb" lang="bn" />
<file path="translations/electron_strings_bs.xtb" lang="bs" />
<file path="translations/electron_strings_ca.xtb" lang="ca" />
<file path="translations/electron_strings_cs.xtb" lang="cs" />
<file path="translations/electron_strings_cy.xtb" lang="cy" />
<file path="translations/electron_strings_da.xtb" lang="da" />
<file path="translations/electron_strings_de.xtb" lang="de" />
<file path="translations/electron_strings_el.xtb" lang="el" />
<file path="translations/electron_strings_en-GB.xtb" lang="en-GB" />
<file path="translations/electron_strings_es-419.xtb" lang="es-419" />
<file path="translations/electron_strings_es.xtb" lang="es" />
<file path="translations/electron_strings_et.xtb" lang="et" />
<file path="translations/electron_strings_eu.xtb" lang="eu" />
<file path="translations/electron_strings_fa.xtb" lang="fa" />
<file path="translations/electron_strings_fi.xtb" lang="fi" />
<file path="translations/electron_strings_fil.xtb" lang="fil" />
<file path="translations/electron_strings_fr-CA.xtb" lang="fr-CA" />
<file path="translations/electron_strings_fr.xtb" lang="fr" />
<file path="translations/electron_strings_gl.xtb" lang="gl" />
<file path="translations/electron_strings_gu.xtb" lang="gu" />
<file path="translations/electron_strings_hi.xtb" lang="hi" />
<file path="translations/electron_strings_hr.xtb" lang="hr" />
<file path="translations/electron_strings_hu.xtb" lang="hu" />
<file path="translations/electron_strings_hy.xtb" lang="hy" />
<file path="translations/electron_strings_id.xtb" lang="id" />
<file path="translations/electron_strings_is.xtb" lang="is" />
<file path="translations/electron_strings_it.xtb" lang="it" />
<!-- The translation console uses 'iw' for Hebrew, but we use 'he'. -->
<file path="translations/electron_strings_iw.xtb" lang="he" />
<file path="translations/electron_strings_ja.xtb" lang="ja" />
<file path="translations/electron_strings_ka.xtb" lang="ka" />
<file path="translations/electron_strings_kk.xtb" lang="kk" />
<file path="translations/electron_strings_km.xtb" lang="km" />
<file path="translations/electron_strings_kn.xtb" lang="kn" />
<file path="translations/electron_strings_ko.xtb" lang="ko" />
<file path="translations/electron_strings_ky.xtb" lang="ky" />
<file path="translations/electron_strings_lo.xtb" lang="lo" />
<file path="translations/electron_strings_lt.xtb" lang="lt" />
<file path="translations/electron_strings_lv.xtb" lang="lv" />
<file path="translations/electron_strings_mk.xtb" lang="mk" />
<file path="translations/electron_strings_ml.xtb" lang="ml" />
<file path="translations/electron_strings_mn.xtb" lang="mn" />
<file path="translations/electron_strings_mr.xtb" lang="mr" />
<file path="translations/electron_strings_ms.xtb" lang="ms" />
<file path="translations/electron_strings_my.xtb" lang="my" />
<file path="translations/electron_strings_ne.xtb" lang="ne" />
<file path="translations/electron_strings_nl.xtb" lang="nl" />
<file path="translations/electron_strings_no.xtb" lang="no" />
<file path="translations/electron_strings_or.xtb" lang="or" />
<file path="translations/electron_strings_pa.xtb" lang="pa" />
<file path="translations/electron_strings_pl.xtb" lang="pl" />
<file path="translations/electron_strings_pt-BR.xtb" lang="pt-BR" />
<file path="translations/electron_strings_pt-PT.xtb" lang="pt-PT" />
<file path="translations/electron_strings_ro.xtb" lang="ro" />
<file path="translations/electron_strings_ru.xtb" lang="ru" />
<file path="translations/electron_strings_si.xtb" lang="si" />
<file path="translations/electron_strings_sk.xtb" lang="sk" />
<file path="translations/electron_strings_sl.xtb" lang="sl" />
<file path="translations/electron_strings_sq.xtb" lang="sq" />
<file path="translations/electron_strings_sr-Latn.xtb" lang="sr-Latn" />
<file path="translations/electron_strings_sr.xtb" lang="sr" />
<file path="translations/electron_strings_sv.xtb" lang="sv" />
<file path="translations/electron_strings_sw.xtb" lang="sw" />
<file path="translations/electron_strings_ta.xtb" lang="ta" />
<file path="translations/electron_strings_te.xtb" lang="te" />
<file path="translations/electron_strings_th.xtb" lang="th" />
<file path="translations/electron_strings_tr.xtb" lang="tr" />
<file path="translations/electron_strings_uk.xtb" lang="uk" />
<file path="translations/electron_strings_ur.xtb" lang="ur" />
<file path="translations/electron_strings_uz.xtb" lang="uz" />
<file path="translations/electron_strings_vi.xtb" lang="vi" />
<file path="translations/electron_strings_zh-CN.xtb" lang="zh-CN" />
<file path="translations/electron_strings_zh-HK.xtb" lang="zh-HK" />
<file path="translations/electron_strings_zh-TW.xtb" lang="zh-TW" />
<file path="translations/electron_strings_zu.xtb" lang="zu" />
</translations>
<release seq="1">
<messages fallback_to_english="true">
<message name="IDS_MAC_NOTIFICATION_INLINE_REPLY_BUTTON" desc="Label for the inline reply button inside a macOS notification.">
Reply
</message>
<message name="IDS_MAC_NOTIFICATION_SHOW_BUTTON" desc="Label for the default action button inside a macOS notification.">
Show
</message>
</messages>
<includes>
<include name="IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE" file="${target_gen_dir}/shell_devtools_discovery_page.html" use_base_dir="false" type="BINDATA" />
</includes>
</release>
</grit>
</grit>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="af">
<translation id="2727175239389218057">Antwoord</translation>
<translation id="5300589172476337783">Wys</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="am">
<translation id="2727175239389218057">ምላሽ ስጥ</translation>
<translation id="5300589172476337783">አሳይ</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ar">
<translation id="2727175239389218057">الرّد</translation>
<translation id="5300589172476337783">عرض</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="as">
<translation id="2727175239389218057">প্ৰত্যুত্তৰ দিয়ক</translation>
<translation id="5300589172476337783">দেখুৱাওক</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="az">
<translation id="2727175239389218057">Cavablayın</translation>
<translation id="5300589172476337783">Göstərin</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="be">
<translation id="2727175239389218057">Адказаць</translation>
<translation id="5300589172476337783">Паказаць</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bg">
<translation id="2727175239389218057">Отговор</translation>
<translation id="5300589172476337783">Показване</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bn">
<translation id="2727175239389218057">উত্তর দিন</translation>
<translation id="5300589172476337783">দেখান</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bs">
<translation id="2727175239389218057">Odgovori</translation>
<translation id="5300589172476337783">Prikaži</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ca">
<translation id="2727175239389218057">Respon</translation>
<translation id="5300589172476337783">Mostra</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="cs">
<translation id="2727175239389218057">Odpovědět</translation>
<translation id="5300589172476337783">Zobrazit</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="cy">
<translation id="2727175239389218057">Ateb</translation>
<translation id="5300589172476337783">Arddangos</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="da">
<translation id="2727175239389218057">Svar</translation>
<translation id="5300589172476337783">Vis</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="de">
<translation id="2727175239389218057">Antworten</translation>
<translation id="5300589172476337783">Anzeigen</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="el">
<translation id="2727175239389218057">Απάντηση</translation>
<translation id="5300589172476337783">Εμφάνιση</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="en-GB">
<translation id="2727175239389218057">Reply</translation>
<translation id="5300589172476337783">Show</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="es-419">
<translation id="2727175239389218057">Responder</translation>
<translation id="5300589172476337783">Mostrar</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="es">
<translation id="2727175239389218057">Responder</translation>
<translation id="5300589172476337783">Mostrar</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="et">
<translation id="2727175239389218057">Vasta</translation>
<translation id="5300589172476337783">Kuva</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="eu">
<translation id="2727175239389218057">Erantzun</translation>
<translation id="5300589172476337783">Erakutsi</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fa">
<translation id="2727175239389218057">پاسخ دادن</translation>
<translation id="5300589172476337783">نمایش</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fi">
<translation id="2727175239389218057">Vastaa</translation>
<translation id="5300589172476337783">Näytä</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fil">
<translation id="2727175239389218057">Sumagot</translation>
<translation id="5300589172476337783">Ipakita</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fr-CA">
<translation id="2727175239389218057">Répondre</translation>
<translation id="5300589172476337783">Afficher</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fr">
<translation id="2727175239389218057">Répondre</translation>
<translation id="5300589172476337783">Afficher</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="gl">
<translation id="2727175239389218057">Responder</translation>
<translation id="5300589172476337783">Mostrar</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="gu">
<translation id="2727175239389218057">જવાબ આપો</translation>
<translation id="5300589172476337783">બતાવો</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hi">
<translation id="2727175239389218057">जवाब दें</translation>
<translation id="5300589172476337783">दिखाएं</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hr">
<translation id="2727175239389218057">Odgovori</translation>
<translation id="5300589172476337783">Prikaži</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hu">
<translation id="2727175239389218057">Válasz</translation>
<translation id="5300589172476337783">Megjelenítés</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hy">
<translation id="2727175239389218057">Պատասխանել</translation>
<translation id="5300589172476337783">Ցույց տալ</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="id">
<translation id="2727175239389218057">Balas</translation>
<translation id="5300589172476337783">Tampilkan</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="is">
<translation id="2727175239389218057">Svara</translation>
<translation id="5300589172476337783">Sýna</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="it">
<translation id="2727175239389218057">Rispondi</translation>
<translation id="5300589172476337783">Mostra</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="iw">
<translation id="2727175239389218057">מענה</translation>
<translation id="5300589172476337783">הצגה</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ja">
<translation id="2727175239389218057">返信</translation>
<translation id="5300589172476337783">表示</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ka">
<translation id="2727175239389218057">პასუხი</translation>
<translation id="5300589172476337783">ჩვენება</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="kk">
<translation id="2727175239389218057">Жауап беру</translation>
<translation id="5300589172476337783">Көрсету</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="km">
<translation id="2727175239389218057">ឆ្លើយតប</translation>
<translation id="5300589172476337783">បង្ហាញ</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="kn">
<translation id="2727175239389218057">ಪ್ರತ್ಯುತ್ತರಿಸಿ</translation>
<translation id="5300589172476337783">ತೋರಿಸಿ</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ko">
<translation id="2727175239389218057">답장</translation>
<translation id="5300589172476337783">표시</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ky">
<translation id="2727175239389218057">Жооп берүү</translation>
<translation id="5300589172476337783">Көрсөтүү</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lo">
<translation id="2727175239389218057">ຕອບກັບ</translation>
<translation id="5300589172476337783">ສະ​ແດງ​</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lt">
<translation id="2727175239389218057">Atsakyti</translation>
<translation id="5300589172476337783">Rodyti</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lv">
<translation id="2727175239389218057">Atbildēt</translation>
<translation id="5300589172476337783">Rādīt</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="mk">
<translation id="2727175239389218057">Одговори</translation>
<translation id="5300589172476337783">Прикажи</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ml">
<translation id="2727175239389218057">മറുപടി നൽകുക</translation>
<translation id="5300589172476337783">കാണിക്കുക</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="mn">
<translation id="2727175239389218057">Хариулах</translation>
<translation id="5300589172476337783">Харуулах</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="mr">
<translation id="2727175239389218057">उत्तर द्या</translation>
<translation id="5300589172476337783">दर्शवा</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ms">
<translation id="2727175239389218057">Balas</translation>
<translation id="5300589172476337783">Paparkan</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="my">
<translation id="2727175239389218057">စာပြန်ရန်</translation>
<translation id="5300589172476337783">ပြရန်</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ne">
<translation id="2727175239389218057">जवाफ दिनुहोस्</translation>
<translation id="5300589172476337783">देखाउनुहोस्</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="nl">
<translation id="2727175239389218057">Reageren</translation>
<translation id="5300589172476337783">Tonen</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="no">
<translation id="2727175239389218057">Svar</translation>
<translation id="5300589172476337783">Vis</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="or">
<translation id="2727175239389218057">ପ୍ରତ୍ୟୁତ୍ତର ଦିଅନ୍ତୁ</translation>
<translation id="5300589172476337783">ପ୍ରଦର୍ଶନ କରନ୍ତୁ</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pa">
<translation id="2727175239389218057">ਜਵਾਬ ਦਿਓ</translation>
<translation id="5300589172476337783">ਦਿਖਾਓ</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pl">
<translation id="2727175239389218057">Odpowiedz</translation>
<translation id="5300589172476337783">Pokaż</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pt-BR">
<translation id="2727175239389218057">Responder</translation>
<translation id="5300589172476337783">Mostrar</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pt-PT">
<translation id="2727175239389218057">Responder</translation>
<translation id="5300589172476337783">Mostrar</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ro">
<translation id="2727175239389218057">Răspunde</translation>
<translation id="5300589172476337783">Afișează</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ru">
<translation id="2727175239389218057">Ответить</translation>
<translation id="5300589172476337783">Показать</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="si">
<translation id="2727175239389218057">පිළිතුරු දෙන්න</translation>
<translation id="5300589172476337783">පෙන්වන්න</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sk">
<translation id="2727175239389218057">Odpovedať</translation>
<translation id="5300589172476337783">Zobraziť</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sl">
<translation id="2727175239389218057">Odgovori</translation>
<translation id="5300589172476337783">Pokaži</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sq">
<translation id="2727175239389218057">Përgjigju</translation>
<translation id="5300589172476337783">Shfaq</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sr-Latn">
<translation id="2727175239389218057">Odgovori</translation>
<translation id="5300589172476337783">Prikaži</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sr">
<translation id="2727175239389218057">Одговори</translation>
<translation id="5300589172476337783">Прикажи</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sv">
<translation id="2727175239389218057">Svara</translation>
<translation id="5300589172476337783">Visa</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sw">
<translation id="2727175239389218057">Jibu</translation>
<translation id="5300589172476337783">Onyesha</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ta">
<translation id="2727175239389218057">பதிலளி</translation>
<translation id="5300589172476337783">காண்பி</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="te">
<translation id="2727175239389218057">రిప్లయి ఇవ్వండి</translation>
<translation id="5300589172476337783">చూపించు</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="th">
<translation id="2727175239389218057">ตอบ</translation>
<translation id="5300589172476337783">แสดง</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="tr">
<translation id="2727175239389218057">Yanıtla</translation>
<translation id="5300589172476337783">Göster</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="uk">
<translation id="2727175239389218057">Відповісти</translation>
<translation id="5300589172476337783">Показати</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ur">
<translation id="2727175239389218057">جواب دیں</translation>
<translation id="5300589172476337783">دکھائیں</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="uz">
<translation id="2727175239389218057">Javob berish</translation>
<translation id="5300589172476337783">Korsatish</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="vi">
<translation id="2727175239389218057">Trả lời</translation>
<translation id="5300589172476337783">Hiển thị</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-CN">
<translation id="2727175239389218057">回复</translation>
<translation id="5300589172476337783">显示</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-HK">
<translation id="2727175239389218057">回覆</translation>
<translation id="5300589172476337783">顯示</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-TW">
<translation id="2727175239389218057">回覆</translation>
<translation id="5300589172476337783">顯示</translation>
</translationbundle>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zu">
<translation id="2727175239389218057">Phendula</translation>
<translation id="5300589172476337783">Bonisa</translation>
</translationbundle>

View File

@@ -0,0 +1,21 @@
#!/bin/sh
# Removes the codesigning keychain created by generate-identity.sh.
# Safe to run even if generate-identity.sh was never run (each step
# is guarded).
set -eo pipefail
KEYCHAIN="electron-codesign.keychain-db"
# delete-keychain also removes it from the search list
if security list-keychains -d user | grep -q "$KEYCHAIN"; then
security delete-keychain "$KEYCHAIN"
echo "Deleted keychain: $KEYCHAIN"
else
echo "Keychain not found, nothing to delete"
fi
# Clean up working directory
rm -rf "$(dirname $0)"/.working
echo "Cleanup complete"

View File

@@ -3,6 +3,8 @@
set -eo pipefail
dir="$(dirname $0)"/.working
KEYCHAIN="electron-codesign.keychain-db"
KEYCHAIN_TEMP="$(openssl rand -hex 12)"
cleanup() {
rm -rf "$dir"
@@ -18,30 +20,16 @@ mkdir -p "$dir"
# Generate Certs
openssl req -new -newkey rsa:2048 -x509 -days 7300 -nodes -config "$(dirname $0)"/codesign.cnf -extensions extended -batch -out "$dir"/certificate.cer -keyout "$dir"/certificate.key
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$dir"/certificate.cer
sudo security import "$dir"/certificate.key -A -k /Library/Keychains/System.keychain
# restart(reload) taskgated daemon
sudo pkill -f /usr/libexec/taskgated
# macOS 15+ blocks modifications to the system keychain via SIP/TCC,
# so we use a custom user-scoped keychain instead.
# Refs https://github.com/electron/electron/issues/48182
security create-keychain -p "$KEYCHAIN_TEMP" "$KEYCHAIN"
security set-keychain-settings -t 3600 -u "$KEYCHAIN"
security unlock-keychain -p "$KEYCHAIN_TEMP" "$KEYCHAIN"
# need once
sudo security authorizationdb write system.privilege.taskport allow
# need once
DevToolsSecurity -enable
security list-keychains -d user -s "$KEYCHAIN" $(security list-keychains -d user | tr -d '"')
security import "$dir"/certificate.cer -k "$KEYCHAIN" -T /usr/bin/codesign
security import "$dir"/certificate.key -k "$KEYCHAIN" -T /usr/bin/codesign -A
# openssl req -newkey rsa:2048 -nodes -keyout "$dir"/private.pem -x509 -days 1 -out "$dir"/certificate.pem -extensions extended -config "$(dirname $0)"/codesign.cnf
# openssl x509 -inform PEM -in "$dir"/certificate.pem -outform DER -out "$dir"/certificate.cer
# openssl x509 -pubkey -noout -in "$dir"/certificate.pem > "$dir"/public.key
# rm -f "$dir"/certificate.pem
# Import Certs
# security import "$dir"/certificate.cer -k $KEY_CHAIN
# security import "$dir"/private.pem -k $KEY_CHAIN
# security import "$dir"/public.key -k $KEY_CHAIN
# Generate Trust Settings
# TODO: Remove NPX
npm_config_yes=true npx ts-node "$(dirname $0)"/gen-trust.ts "$dir"/certificate.cer "$dir"/trust.xml
# Import Trust Settings
sudo security trust-settings-import -d "$dir/trust.xml"
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_TEMP" "$KEYCHAIN"

View File

@@ -2,7 +2,7 @@
set -e
valid_certs=$(security find-identity -p codesigning -v)
valid_certs=$(security find-identity -p codesigning)
if [[ $valid_certs == *"1)"* ]]; then
first_valid_cert=$(echo $valid_certs | sed 's/ \".*//' | sed 's/.* //')
echo $first_valid_cert

View File

@@ -6,6 +6,7 @@
#define ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_COCOA_NOTIFICATION_H_
#import <Foundation/Foundation.h>
#import <UserNotifications/UserNotifications.h>
#include <map>
#include <string>
@@ -14,11 +15,6 @@
namespace electron {
// NSUserNotification is deprecated; all calls should be replaced with
// UserNotifications.frameworks API
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
class CocoaNotification : public Notification {
public:
CocoaNotification(NotificationDelegate* delegate,
@@ -31,23 +27,20 @@ class CocoaNotification : public Notification {
void NotificationDisplayed();
void NotificationReplied(const std::string& reply);
void NotificationActivated();
void NotificationActivated(NSUserNotificationAction* action);
void NotificationActivated(int actionIndex);
void NotificationDismissed();
NSUserNotification* notification() const { return notification_; }
UNNotificationRequest* notification_request() const {
return notification_request_;
}
private:
void LogAction(const char* action);
void ScheduleNotification(UNMutableNotificationContent* content);
NSUserNotification* __strong notification_;
std::map<std::string, unsigned> additional_action_indices_;
unsigned action_index_;
UNNotificationRequest* __strong notification_request_;
};
// -Wdeprecated-declarations
#pragma clang diagnostic pop
} // namespace electron
#endif // ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_COCOA_NOTIFICATION_H_

View File

@@ -7,17 +7,22 @@
#include <string>
#include <utility>
#include "base/apple/foundation_util.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "chrome/common/notifications/notification_image_retainer.h"
#include "grit/electron_resources.h"
#include "shell/browser/notifications/mac/notification_presenter_mac.h"
#include "shell/browser/notifications/notification_delegate.h"
#include "shell/browser/notifications/notification_presenter.h"
#include "skia/ext/skia_utils_mac.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/gfx/image/image.h"
// NSUserNotification is deprecated; we need to use the
// UserNotifications.frameworks API instead
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#import <AppKit/AppKit.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
namespace electron {
@@ -26,101 +31,217 @@ CocoaNotification::CocoaNotification(NotificationDelegate* delegate,
: Notification(delegate, presenter) {}
CocoaNotification::~CocoaNotification() {
if (notification_)
[NSUserNotificationCenter.defaultUserNotificationCenter
removeDeliveredNotification:notification_];
if (notification_request_)
[[UNUserNotificationCenter currentNotificationCenter]
removeDeliveredNotificationsWithIdentifiers:@[
notification_request_.identifier
]];
}
void CocoaNotification::Show(const NotificationOptions& options) {
notification_ = [[NSUserNotification alloc] init];
UNMutableNotificationContent* content =
[[UNMutableNotificationContent alloc] init];
content.title = base::SysUTF16ToNSString(options.title);
content.subtitle = base::SysUTF16ToNSString(options.subtitle);
content.body = base::SysUTF16ToNSString(options.msg);
if (options.silent) {
content.sound = nil;
} else if (options.sound.empty()) {
content.sound = [UNNotificationSound defaultSound];
} else {
content.sound = [UNNotificationSound
soundNamed:base::SysUTF16ToNSString(options.sound)];
}
if (options.has_reply || options.actions.size() > 0 ||
!options.close_button_text.empty()) {
NSMutableArray* actions = [NSMutableArray array];
NSMutableString* actionString = [NSMutableString string];
if (options.has_reply) {
NSString* replyTitle =
l10n_util::GetNSString(IDS_MAC_NOTIFICATION_INLINE_REPLY_BUTTON);
NSString* replyPlaceholder =
base::SysUTF16ToNSString(options.reply_placeholder);
UNNotificationAction* replyAction = [UNTextInputNotificationAction
actionWithIdentifier:@"REPLY_ACTION"
title:replyTitle
options:UNNotificationActionOptionNone
textInputButtonTitle:replyTitle
textInputPlaceholder:replyPlaceholder];
[actionString appendFormat:@"REPLY_%@_%@", replyTitle, replyPlaceholder];
[actions addObject:replyAction];
}
int i = 0;
for (const auto& action : options.actions) {
NSString* showText =
l10n_util::GetNSString(IDS_MAC_NOTIFICATION_SHOW_BUTTON);
NSString* actionText = action.text.empty()
? showText
: base::SysUTF16ToNSString(action.text);
// Action indicies are stored in the action identifier
UNNotificationAction* notificationAction = [UNNotificationAction
actionWithIdentifier:[NSString stringWithFormat:@"ACTION_%d", i]
title:actionText
options:UNNotificationActionOptionNone];
[actionString appendFormat:@"ACTION_%d_%@", i, actionText];
[actions addObject:notificationAction];
i++;
}
if (!options.close_button_text.empty()) {
NSString* closeButtonText =
base::SysUTF16ToNSString(options.close_button_text);
UNNotificationAction* closeAction = [UNNotificationAction
actionWithIdentifier:@"CLOSE_ACTION"
title:closeButtonText
options:UNNotificationActionOptionNone];
[actionString appendFormat:@"CLOSE_%@", closeButtonText];
[actions addObject:closeAction];
i++;
}
// Categories are unique based on the actionString
NSString* categoryIdentifier =
[NSString stringWithFormat:@"CATEGORY_%lu", [actionString hash]];
// UNNotificationCategoryOptionCustomDismissAction enables the notification
// delegate to receive dismiss actions for handling
UNNotificationCategory* category = [UNNotificationCategory
categoryWithIdentifier:categoryIdentifier
actions:actions
intentIdentifiers:@[]
options:UNNotificationCategoryOptionCustomDismissAction];
UNUserNotificationCenter* center =
[UNUserNotificationCenter currentNotificationCenter];
[center getNotificationCategoriesWithCompletionHandler:^(
NSSet<UNNotificationCategory*>* _Nonnull existingCategories) {
if (![existingCategories containsObject:category]) {
NSMutableSet* updatedCategories = [existingCategories mutableCopy];
[updatedCategories addObject:category];
[center setNotificationCategories:updatedCategories];
}
}];
content.categoryIdentifier = categoryIdentifier;
}
if (!options.icon.drawsNothing()) {
gfx::Image icon = gfx::Image::CreateFrom1xBitmap(options.icon);
auto* mac_presenter = static_cast<NotificationPresenterMac*>(presenter());
mac_presenter->image_task_runner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
[](NotificationPresenterMac* mac_presenter,
gfx::Image icon) -> UNNotificationAttachment* {
base::FilePath path =
mac_presenter->image_retainer()->RegisterTemporaryImage(icon);
if (path.empty()) {
return nil;
}
NSURL* url = base::apple::FilePathToNSURL(path);
NSDictionary* attachment_options = @{
UNNotificationAttachmentOptionsTypeHintKey :
UTTypePNG.identifier
};
NSError* error = nil;
UNNotificationAttachment* attachment = [UNNotificationAttachment
attachmentWithIdentifier:[[NSUUID UUID] UUIDString]
URL:url
options:attachment_options
error:&error];
return (attachment && !error) ? attachment : nil;
},
mac_presenter, icon),
base::BindOnce(
[](base::WeakPtr<Notification> weak_self,
UNMutableNotificationContent* content,
UNNotificationAttachment* attachment) {
if (auto* notification = weak_self.get()) {
content.attachments = @[ attachment ];
auto* self = static_cast<CocoaNotification*>(notification);
self->ScheduleNotification(content);
}
},
GetWeakPtr(), content));
} else {
ScheduleNotification(content);
}
}
void CocoaNotification::ScheduleNotification(
UNMutableNotificationContent* content) {
NSString* identifier =
[NSString stringWithFormat:@"%@:notification:%@",
[[NSBundle mainBundle] bundleIdentifier],
[[NSUUID UUID] UUIDString]];
[notification_ setTitle:base::SysUTF16ToNSString(options.title)];
[notification_ setSubtitle:base::SysUTF16ToNSString(options.subtitle)];
[notification_ setInformativeText:base::SysUTF16ToNSString(options.msg)];
[notification_ setIdentifier:identifier];
UNNotificationRequest* request =
[UNNotificationRequest requestWithIdentifier:identifier
content:content
trigger:nil];
notification_request_ = request;
if (electron::debug_notifications) {
LOG(INFO) << "Notification created (" << [identifier UTF8String] << ")";
}
if (!options.icon.drawsNothing()) {
NSImage* image = skia::SkBitmapToNSImage(options.icon);
[notification_ setContentImage:image];
}
scoped_refptr<base::SequencedTaskRunner> task_runner =
base::SequencedTaskRunner::GetCurrentDefault();
auto weak_self = GetWeakPtr();
if (options.silent) {
[notification_ setSoundName:nil];
} else if (options.sound.empty()) {
[notification_ setSoundName:NSUserNotificationDefaultSoundName];
} else {
[notification_ setSoundName:base::SysUTF16ToNSString(options.sound)];
}
if (options.has_reply) {
[notification_ setHasReplyButton:true];
[notification_ setResponsePlaceholder:base::SysUTF16ToNSString(
options.reply_placeholder)];
}
// We need to explicitly set this to false if there are no
// actions, otherwise a Show button will appear by default.
if (options.actions.size() == 0)
[notification_ setHasActionButton:false];
int i = 0;
action_index_ = UINT_MAX;
NSMutableArray* additionalActions = [[NSMutableArray alloc] init];
for (const auto& action : options.actions) {
if (action.type == u"button") {
// If the notification has both a reply and actions,
// the reply takes precedence and the actions all
// become additional actions.
if (!options.has_reply && action_index_ == UINT_MAX) {
// First button observed is the displayed action
[notification_
setActionButtonTitle:base::SysUTF16ToNSString(action.text)];
action_index_ = i;
} else {
// All of the rest are appended to the list of additional actions
NSString* actionIdentifier =
[NSString stringWithFormat:@"%@Action%d", identifier, i];
NSUserNotificationAction* notificationAction = [NSUserNotificationAction
actionWithIdentifier:actionIdentifier
title:base::SysUTF16ToNSString(action.text)];
[additionalActions addObject:notificationAction];
additional_action_indices_.try_emplace(
base::SysNSStringToUTF8(actionIdentifier), i);
}
}
i++;
}
if ([additionalActions count] > 0) {
[notification_ setAdditionalActions:additionalActions];
}
if (!options.close_button_text.empty()) {
[notification_ setOtherButtonTitle:base::SysUTF16ToNSString(
options.close_button_text)];
}
[NSUserNotificationCenter.defaultUserNotificationCenter
deliverNotification:notification_];
[[UNUserNotificationCenter currentNotificationCenter]
addNotificationRequest:request
withCompletionHandler:^(NSError* _Nullable error) {
if (error) {
if (electron::debug_notifications) {
LOG(INFO) << "Error scheduling notification ("
<< [identifier UTF8String] << ") "
<< [error.localizedDescription UTF8String];
}
std::string error_description =
[error.localizedDescription UTF8String];
task_runner->PostTask(
FROM_HERE, base::BindOnce(
[](base::WeakPtr<Notification> weak_self,
std::string error_description) {
if (Notification* self = weak_self.get()) {
self->NotificationFailed(error_description);
}
},
weak_self, std::move(error_description)));
} else {
task_runner->PostTask(
FROM_HERE, base::BindOnce(
[](base::WeakPtr<Notification> weak_self) {
if (Notification* self = weak_self.get()) {
CocoaNotification* un_self =
static_cast<CocoaNotification*>(self);
un_self->NotificationDisplayed();
}
},
weak_self));
if (electron::debug_notifications) {
LOG(INFO) << "Notification scheduled (" << [identifier UTF8String]
<< ")";
}
}
}];
}
void CocoaNotification::Dismiss() {
if (notification_)
[NSUserNotificationCenter.defaultUserNotificationCenter
removeDeliveredNotification:notification_];
if (notification_request_)
[[UNUserNotificationCenter currentNotificationCenter]
removeDeliveredNotificationsWithIdentifiers:@[
notification_request_.identifier
]];
NotificationDismissed();
notification_ = nil;
notification_request_ = nil;
}
void CocoaNotification::NotificationDisplayed() {
@@ -137,27 +258,9 @@ void CocoaNotification::NotificationReplied(const std::string& reply) {
this->LogAction("replied to");
}
void CocoaNotification::NotificationActivated() {
void CocoaNotification::NotificationActivated(int actionIndex) {
if (delegate())
delegate()->NotificationAction(action_index_);
this->LogAction("button clicked");
}
void CocoaNotification::NotificationActivated(
NSUserNotificationAction* action) {
if (delegate()) {
unsigned index = action_index_;
std::string identifier = base::SysNSStringToUTF8(action.identifier);
for (const auto& it : additional_action_indices_) {
if (it.first == identifier) {
index = it.second;
break;
}
}
delegate()->NotificationAction(index);
}
delegate()->NotificationAction(actionIndex);
this->LogAction("button clicked");
}
@@ -170,8 +273,8 @@ void CocoaNotification::NotificationDismissed() {
}
void CocoaNotification::LogAction(const char* action) {
if (electron::debug_notifications && notification_) {
NSString* identifier = [notification_ valueForKey:@"identifier"];
if (electron::debug_notifications && notification_request_) {
NSString* identifier = [notification_request_ valueForKey:@"identifier"];
DCHECK(identifier);
LOG(INFO) << "Notification " << action << " (" << [identifier UTF8String]
<< ")";

View File

@@ -6,6 +6,7 @@
#define ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_NOTIFICATION_CENTER_DELEGATE_H_
#import <Foundation/Foundation.h>
#import <UserNotifications/UserNotifications.h>
#include "base/memory/raw_ptr.h"
@@ -14,7 +15,7 @@ class NotificationPresenterMac;
}
@interface NotificationCenterDelegate
: NSObject <NSUserNotificationCenterDelegate> {
: NSObject <UNUserNotificationCenterDelegate> {
@private
raw_ptr<electron::NotificationPresenterMac> presenter_;
}

View File

@@ -11,11 +11,6 @@
#include "shell/browser/notifications/mac/cocoa_notification.h"
#include "shell/browser/notifications/mac/notification_presenter_mac.h"
// NSUserNotification is deprecated; we need to use the
// UserNotifications.frameworks API instead
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@implementation NotificationCenterDelegate
- (instancetype)initWithPresenter:
@@ -28,71 +23,62 @@
return self;
}
- (void)userNotificationCenter:(NSUserNotificationCenter*)center
didDeliverNotification:(NSUserNotification*)notif {
auto* notification = presenter_->GetNotification(notif);
if (notification)
notification->NotificationDisplayed();
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
willPresentNotification:(UNNotification*)notif
withCompletionHandler:
(void (^)(UNNotificationPresentationOptions options))
completionHandler {
// Display notifications when app is in the foreground
completionHandler(UNNotificationPresentationOptionList |
UNNotificationPresentationOptionBanner |
UNNotificationPresentationOptionSound);
}
- (void)userNotificationCenter:(NSUserNotificationCenter*)center
didActivateNotification:(NSUserNotification*)notif {
auto* notification = presenter_->GetNotification(notif);
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
didReceiveNotificationResponse:(UNNotificationResponse*)response
withCompletionHandler:(void (^)())completionHandler {
auto* notification =
presenter_->GetNotification(response.notification.request);
if (electron::debug_notifications) {
LOG(INFO) << "Notification activated (" << [notif.identifier UTF8String]
<< ")";
LOG(INFO) << "Notification activated ("
<< [response.notification.request.identifier UTF8String] << ")";
}
if (notification) {
// Ref:
// https://developer.apple.com/documentation/foundation/nsusernotificationactivationtype?language=objc
if (notif.activationType ==
NSUserNotificationActivationTypeContentsClicked) {
NSString* categoryIdentifier =
response.notification.request.content.categoryIdentifier;
NSString* actionIdentifier = response.actionIdentifier;
if ([actionIdentifier
isEqualToString:UNNotificationDefaultActionIdentifier]) {
notification->NotificationClicked();
} else if (notif.activationType ==
NSUserNotificationActivationTypeActionButtonClicked) {
notification->NotificationActivated();
} else if (notif.activationType ==
NSUserNotificationActivationTypeReplied) {
notification->NotificationReplied([notif.response.string UTF8String]);
} else {
if (notif.activationType ==
NSUserNotificationActivationTypeAdditionalActionClicked) {
notification->NotificationActivated([notif additionalActivationAction]);
} else if ([actionIdentifier
isEqualToString:UNNotificationDismissActionIdentifier]) {
notification->NotificationDismissed();
} else if ([categoryIdentifier hasPrefix:@"CATEGORY_"]) {
if ([actionIdentifier isEqualToString:@"REPLY_ACTION"]) {
if ([response isKindOfClass:[UNTextInputNotificationResponse class]]) {
NSString* userText =
[(UNTextInputNotificationResponse*)response userText];
notification->NotificationReplied([userText UTF8String]);
}
} else if ([actionIdentifier hasPrefix:@"ACTION_"]) {
NSString* actionIndexString =
[actionIdentifier substringFromIndex:[@"ACTION_" length]];
int actionIndex = static_cast<int>(actionIndexString.integerValue);
notification->NotificationActivated(actionIndex);
} else if ([actionIdentifier isEqualToString:@"CLOSE_ACTION"]) {
notification->NotificationDismissed();
}
}
} else {
if (electron::debug_notifications) {
LOG(INFO) << "Could not find notification for "
<< [response.notification.request.identifier UTF8String];
}
}
}
- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center
shouldPresentNotification:(NSUserNotification*)notification {
// Display notifications even if the app is active.
return YES;
completionHandler();
}
#if !IS_MAS_BUILD()
// This undocumented method notifies us if a user closes "Alert" notifications
// https://chromium.googlesource.com/chromium/src/+/lkgr/chrome/browser/notifications/notification_platform_bridge_mac.mm
- (void)userNotificationCenter:(NSUserNotificationCenter*)center
didDismissAlert:(NSUserNotification*)notif {
auto* notification = presenter_->GetNotification(notif);
if (notification)
notification->NotificationDismissed();
}
#endif
#if !IS_MAS_BUILD()
// This undocumented method notifies us if a user closes "Banner" notifications
// https://github.com/mozilla/gecko-dev/blob/master/widget/cocoa/OSXNotificationCenter.mm
- (void)userNotificationCenter:(NSUserNotificationCenter*)center
didRemoveDeliveredNotifications:(NSArray*)notifications {
for (NSUserNotification* notif in notifications) {
auto* notification = presenter_->GetNotification(notif);
if (notification)
notification->NotificationDismissed();
}
}
#endif
@end

View File

@@ -6,36 +6,39 @@
#ifndef ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_NOTIFICATION_PRESENTER_MAC_H_
#define ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_NOTIFICATION_PRESENTER_MAC_H_
#include "chrome/common/notifications/notification_image_retainer.h"
#include "shell/browser/notifications/mac/notification_center_delegate.h"
#include "shell/browser/notifications/notification_presenter.h"
#import <UserNotifications/UserNotifications.h>
namespace electron {
class CocoaNotification;
// NSUserNotification is deprecated; all calls should be replaced with
// UserNotifications.frameworks API
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
class NotificationPresenterMac : public NotificationPresenter {
public:
CocoaNotification* GetNotification(NSUserNotification* ns_notification);
CocoaNotification* GetNotification(
UNNotificationRequest* un_notification_request);
NotificationPresenterMac();
~NotificationPresenterMac() override;
NotificationImageRetainer* image_retainer() { return image_retainer_.get(); }
scoped_refptr<base::SequencedTaskRunner> image_task_runner() {
return image_task_runner_;
}
private:
// NotificationPresenter
Notification* CreateNotificationObject(
NotificationDelegate* delegate) override;
NotificationCenterDelegate* __strong notification_center_delegate_;
std::unique_ptr<NotificationImageRetainer> image_retainer_;
scoped_refptr<base::SequencedTaskRunner> image_task_runner_;
};
// -Wdeprecated-declarations
#pragma clang diagnostic pop
} // namespace electron
#endif // ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_NOTIFICATION_PRESENTER_MAC_H_

View File

@@ -3,17 +3,13 @@
// found in the LICENSE file.
#include "base/logging.h"
#include "base/task/thread_pool.h"
#include "shell/browser/notifications/mac/notification_presenter_mac.h"
#include "shell/browser/notifications/mac/cocoa_notification.h"
#include "shell/browser/notifications/mac/notification_center_delegate.h"
// NSUserNotification is deprecated; we need to use the
// UserNotifications.frameworks API instead
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
namespace electron {
// static
@@ -22,17 +18,17 @@ std::unique_ptr<NotificationPresenter> NotificationPresenter::Create() {
}
CocoaNotification* NotificationPresenterMac::GetNotification(
NSUserNotification* ns_notification) {
UNNotificationRequest* un_notification_request) {
for (Notification* notification : notifications()) {
auto* native_notification = static_cast<CocoaNotification*>(notification);
if ([native_notification->notification().identifier
isEqual:ns_notification.identifier])
if ([native_notification->notification_request().identifier
isEqual:un_notification_request.identifier])
return native_notification;
}
if (electron::debug_notifications) {
LOG(INFO) << "Could not find notification for "
<< [ns_notification.identifier UTF8String];
<< [un_notification_request.identifier UTF8String];
}
return nullptr;
@@ -40,13 +36,43 @@ CocoaNotification* NotificationPresenterMac::GetNotification(
NotificationPresenterMac::NotificationPresenterMac()
: notification_center_delegate_(
[[NotificationCenterDelegate alloc] initWithPresenter:this]) {
NSUserNotificationCenter.defaultUserNotificationCenter.delegate =
notification_center_delegate_;
[[NotificationCenterDelegate alloc] initWithPresenter:this]),
image_retainer_(std::make_unique<NotificationImageRetainer>()),
image_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE})) {
// Delete any remaining temp files in the image folder from the previous
// sessions.
DCHECK(image_task_runner_);
auto cleanup_task = image_retainer_->GetCleanupTask();
image_task_runner_->PostTask(FROM_HERE, std::move(cleanup_task));
UNUserNotificationCenter* center =
[UNUserNotificationCenter currentNotificationCenter];
center.delegate = notification_center_delegate_;
[center
requestAuthorizationWithOptions:(UNAuthorizationOptionAlert |
UNAuthorizationOptionSound |
UNAuthorizationOptionBadge)
completionHandler:^(BOOL granted,
NSError* _Nullable error) {
if (electron::debug_notifications) {
if (error) {
LOG(INFO)
<< "Error requesting notification authorization: "
<< [error.localizedDescription UTF8String];
} else {
LOG(INFO) << "Notification authorization granted: "
<< granted;
}
}
}];
}
NotificationPresenterMac::~NotificationPresenterMac() {
NSUserNotificationCenter.defaultUserNotificationCenter.delegate = nil;
UNUserNotificationCenter.currentNotificationCenter.delegate = nil;
image_task_runner_->DeleteSoon(FROM_HERE, image_retainer_.release());
}
Notification* NotificationPresenterMac::CreateNotificationObject(

View File

@@ -56,29 +56,6 @@ ifdescribe(!process.mas)('autoUpdater module', function () {
).to.throw('Expected options object to contain a \'url\' string property in setFeedUrl call');
});
});
ifdescribe(process.platform === 'darwin' && process.arch !== 'arm64')('on Mac', function () {
it('emits an error when the application is unsigned', async () => {
const errorEvent = once(autoUpdater, 'error') as Promise<[Error]>;
autoUpdater.setFeedURL({ url: '' });
const [error] = await errorEvent;
expect(error.message).equal('Could not get code signature for running application');
});
it('does not throw if default is the serverType', () => {
// "Could not get code signature..." means the function got far enough to validate that serverType was OK.
expect(() => autoUpdater.setFeedURL({ url: '', serverType: 'default' })).to.throw('Could not get code signature for running application');
});
it('does not throw if json is the serverType', () => {
// "Could not get code signature..." means the function got far enough to validate that serverType was OK.
expect(() => autoUpdater.setFeedURL({ url: '', serverType: 'json' })).to.throw('Could not get code signature for running application');
});
it('does throw if an unknown string is the serverType', () => {
expect(() => autoUpdater.setFeedURL({ url: '', serverType: 'weow' as any })).to.throw('Expected serverType to be \'default\' or \'json\'');
});
});
});
describe('quitAndInstall', () => {

View File

@@ -7,11 +7,8 @@ import * as path from 'node:path';
const features = process._linkedBinding('electron_common_features');
const fixturesPath = path.resolve(__dirname, '..', 'fixtures');
// Re-enable codesign tests for macOS x64
// Refs https://github.com/electron/electron/issues/48182
export const shouldRunCodesignTests =
process.platform === 'darwin' &&
!(process.env.CI) &&
!process.mas &&
!features.isComponentBuild();