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.
This commit is contained in:
Developer-Ecosystem-Engineering
2025-07-17 12:49:22 -07:00
committed by Keeley Hammond
parent 57a6e43025
commit ed27a77558
90 changed files with 923 additions and 196 deletions

View File

@@ -322,6 +322,10 @@ grit("resources") {
"electron_resources.pak",
]
foreach(locale, all_chrome_locales) {
outputs += [ "electron_strings_$locale.pak" ]
}
# Mojo manifest overlays are generated.
grit_flags = [
"-E",
@@ -618,6 +622,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

@@ -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,19 @@ 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);
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

@@ -10,14 +10,14 @@
#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 "grit/electron_resources.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"
// 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>
namespace electron {
@@ -26,101 +26,185 @@ 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.icon.drawsNothing()) {
NSImage* image = skia::SkBitmapToNSImage(options.icon);
NSData* imageData =
[[NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]]
representationUsingType:NSBitmapImageFileTypePNG
properties:@{}];
NSString* tempFilePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:[NSString
stringWithFormat:@"%@_icon.png",
[[NSUUID UUID]
UUIDString]]];
if ([imageData writeToFile:tempFilePath atomically:YES]) {
NSError* error = nil;
UNNotificationAttachment* attachment = [UNNotificationAttachment
attachmentWithIdentifier:@"image"
URL:[NSURL fileURLWithPath:tempFilePath]
options:nil
error:&error];
if (attachment && !error) {
content.attachments = @[ attachment ];
}
}
}
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;
}
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];
}
} 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 +221,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 +236,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

@@ -9,18 +9,16 @@
#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;
@@ -33,9 +31,6 @@ class NotificationPresenterMac : public NotificationPresenter {
NotificationCenterDelegate* __strong notification_center_delegate_;
};
// -Wdeprecated-declarations
#pragma clang diagnostic pop
} // namespace electron
#endif // ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_NOTIFICATION_PRESENTER_MAC_H_

View File

@@ -9,11 +9,6 @@
#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 +17,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;
@@ -41,12 +36,32 @@ CocoaNotification* NotificationPresenterMac::GetNotification(
NotificationPresenterMac::NotificationPresenterMac()
: notification_center_delegate_(
[[NotificationCenterDelegate alloc] initWithPresenter:this]) {
NSUserNotificationCenter.defaultUserNotificationCenter.delegate =
notification_center_delegate_;
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;
}
Notification* NotificationPresenterMac::CreateNotificationObject(