mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
1 Commits
fix/codesi
...
trash-erro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db4db1f722 |
@@ -191,18 +191,12 @@ jobs:
|
||||
run: |
|
||||
cd src/out/Default
|
||||
unzip -:o dist.zip
|
||||
- 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: 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: Run Electron Tests
|
||||
shell: bash
|
||||
|
||||
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
@@ -51,6 +51,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v3.29.5
|
||||
uses: github/codeql-action/upload-sarif@6bc82e05fd0ea64601dd4b465378bbcf57de0314 # v3.29.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
23
BUILD.gn
23
BUILD.gn
@@ -321,33 +321,12 @@ 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" ]
|
||||
|
||||
@@ -471,7 +450,6 @@ 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",
|
||||
@@ -640,7 +618,6 @@ source_set("electron_lib") {
|
||||
"SecurityInterface.framework",
|
||||
"ServiceManagement.framework",
|
||||
"StoreKit.framework",
|
||||
"UserNotifications.framework",
|
||||
]
|
||||
|
||||
weak_frameworks = [ "QuickLookThumbnailing.framework" ]
|
||||
|
||||
@@ -183,7 +183,6 @@ 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_",
|
||||
@@ -200,7 +199,6 @@ 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",
|
||||
|
||||
@@ -9,189 +9,10 @@
|
||||
<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>
|
||||
<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>
|
||||
<release seq="1" allow_pseudo="false">
|
||||
<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>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="af">
|
||||
<translation id="2727175239389218057">Antwoord</translation>
|
||||
<translation id="5300589172476337783">Wys</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="am">
|
||||
<translation id="2727175239389218057">ምላሽ ስጥ</translation>
|
||||
<translation id="5300589172476337783">አሳይ</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ar">
|
||||
<translation id="2727175239389218057">الرّد</translation>
|
||||
<translation id="5300589172476337783">عرض</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="as">
|
||||
<translation id="2727175239389218057">প্ৰত্যুত্তৰ দিয়ক</translation>
|
||||
<translation id="5300589172476337783">দেখুৱাওক</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="az">
|
||||
<translation id="2727175239389218057">Cavablayın</translation>
|
||||
<translation id="5300589172476337783">Göstərin</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="be">
|
||||
<translation id="2727175239389218057">Адказаць</translation>
|
||||
<translation id="5300589172476337783">Паказаць</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="bg">
|
||||
<translation id="2727175239389218057">Отговор</translation>
|
||||
<translation id="5300589172476337783">Показване</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="bn">
|
||||
<translation id="2727175239389218057">উত্তর দিন</translation>
|
||||
<translation id="5300589172476337783">দেখান</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="bs">
|
||||
<translation id="2727175239389218057">Odgovori</translation>
|
||||
<translation id="5300589172476337783">Prikaži</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ca">
|
||||
<translation id="2727175239389218057">Respon</translation>
|
||||
<translation id="5300589172476337783">Mostra</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="cs">
|
||||
<translation id="2727175239389218057">Odpovědět</translation>
|
||||
<translation id="5300589172476337783">Zobrazit</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="cy">
|
||||
<translation id="2727175239389218057">Ateb</translation>
|
||||
<translation id="5300589172476337783">Arddangos</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="da">
|
||||
<translation id="2727175239389218057">Svar</translation>
|
||||
<translation id="5300589172476337783">Vis</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="de">
|
||||
<translation id="2727175239389218057">Antworten</translation>
|
||||
<translation id="5300589172476337783">Anzeigen</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="el">
|
||||
<translation id="2727175239389218057">Απάντηση</translation>
|
||||
<translation id="5300589172476337783">Εμφάνιση</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="en-GB">
|
||||
<translation id="2727175239389218057">Reply</translation>
|
||||
<translation id="5300589172476337783">Show</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="es-419">
|
||||
<translation id="2727175239389218057">Responder</translation>
|
||||
<translation id="5300589172476337783">Mostrar</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="es">
|
||||
<translation id="2727175239389218057">Responder</translation>
|
||||
<translation id="5300589172476337783">Mostrar</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="et">
|
||||
<translation id="2727175239389218057">Vasta</translation>
|
||||
<translation id="5300589172476337783">Kuva</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="eu">
|
||||
<translation id="2727175239389218057">Erantzun</translation>
|
||||
<translation id="5300589172476337783">Erakutsi</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="fa">
|
||||
<translation id="2727175239389218057">پاسخ دادن</translation>
|
||||
<translation id="5300589172476337783">نمایش</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="fi">
|
||||
<translation id="2727175239389218057">Vastaa</translation>
|
||||
<translation id="5300589172476337783">Näytä</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="fil">
|
||||
<translation id="2727175239389218057">Sumagot</translation>
|
||||
<translation id="5300589172476337783">Ipakita</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="fr-CA">
|
||||
<translation id="2727175239389218057">Répondre</translation>
|
||||
<translation id="5300589172476337783">Afficher</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="fr">
|
||||
<translation id="2727175239389218057">Répondre</translation>
|
||||
<translation id="5300589172476337783">Afficher</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="gl">
|
||||
<translation id="2727175239389218057">Responder</translation>
|
||||
<translation id="5300589172476337783">Mostrar</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="gu">
|
||||
<translation id="2727175239389218057">જવાબ આપો</translation>
|
||||
<translation id="5300589172476337783">બતાવો</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="hi">
|
||||
<translation id="2727175239389218057">जवाब दें</translation>
|
||||
<translation id="5300589172476337783">दिखाएं</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="hr">
|
||||
<translation id="2727175239389218057">Odgovori</translation>
|
||||
<translation id="5300589172476337783">Prikaži</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="hu">
|
||||
<translation id="2727175239389218057">Válasz</translation>
|
||||
<translation id="5300589172476337783">Megjelenítés</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="hy">
|
||||
<translation id="2727175239389218057">Պատասխանել</translation>
|
||||
<translation id="5300589172476337783">Ցույց տալ</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="id">
|
||||
<translation id="2727175239389218057">Balas</translation>
|
||||
<translation id="5300589172476337783">Tampilkan</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="is">
|
||||
<translation id="2727175239389218057">Svara</translation>
|
||||
<translation id="5300589172476337783">Sýna</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="it">
|
||||
<translation id="2727175239389218057">Rispondi</translation>
|
||||
<translation id="5300589172476337783">Mostra</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="iw">
|
||||
<translation id="2727175239389218057">מענה</translation>
|
||||
<translation id="5300589172476337783">הצגה</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ja">
|
||||
<translation id="2727175239389218057">返信</translation>
|
||||
<translation id="5300589172476337783">表示</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ka">
|
||||
<translation id="2727175239389218057">პასუხი</translation>
|
||||
<translation id="5300589172476337783">ჩვენება</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="kk">
|
||||
<translation id="2727175239389218057">Жауап беру</translation>
|
||||
<translation id="5300589172476337783">Көрсету</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="km">
|
||||
<translation id="2727175239389218057">ឆ្លើយតប</translation>
|
||||
<translation id="5300589172476337783">បង្ហាញ</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="kn">
|
||||
<translation id="2727175239389218057">ಪ್ರತ್ಯುತ್ತರಿಸಿ</translation>
|
||||
<translation id="5300589172476337783">ತೋರಿಸಿ</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ko">
|
||||
<translation id="2727175239389218057">답장</translation>
|
||||
<translation id="5300589172476337783">표시</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ky">
|
||||
<translation id="2727175239389218057">Жооп берүү</translation>
|
||||
<translation id="5300589172476337783">Көрсөтүү</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="lo">
|
||||
<translation id="2727175239389218057">ຕອບກັບ</translation>
|
||||
<translation id="5300589172476337783">ສະແດງ</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="lt">
|
||||
<translation id="2727175239389218057">Atsakyti</translation>
|
||||
<translation id="5300589172476337783">Rodyti</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="lv">
|
||||
<translation id="2727175239389218057">Atbildēt</translation>
|
||||
<translation id="5300589172476337783">Rādīt</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="mk">
|
||||
<translation id="2727175239389218057">Одговори</translation>
|
||||
<translation id="5300589172476337783">Прикажи</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ml">
|
||||
<translation id="2727175239389218057">മറുപടി നൽകുക</translation>
|
||||
<translation id="5300589172476337783">കാണിക്കുക</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="mn">
|
||||
<translation id="2727175239389218057">Хариулах</translation>
|
||||
<translation id="5300589172476337783">Харуулах</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="mr">
|
||||
<translation id="2727175239389218057">उत्तर द्या</translation>
|
||||
<translation id="5300589172476337783">दर्शवा</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ms">
|
||||
<translation id="2727175239389218057">Balas</translation>
|
||||
<translation id="5300589172476337783">Paparkan</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="my">
|
||||
<translation id="2727175239389218057">စာပြန်ရန်</translation>
|
||||
<translation id="5300589172476337783">ပြရန်</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ne">
|
||||
<translation id="2727175239389218057">जवाफ दिनुहोस्</translation>
|
||||
<translation id="5300589172476337783">देखाउनुहोस्</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="nl">
|
||||
<translation id="2727175239389218057">Reageren</translation>
|
||||
<translation id="5300589172476337783">Tonen</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="no">
|
||||
<translation id="2727175239389218057">Svar</translation>
|
||||
<translation id="5300589172476337783">Vis</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="or">
|
||||
<translation id="2727175239389218057">ପ୍ରତ୍ୟୁତ୍ତର ଦିଅନ୍ତୁ</translation>
|
||||
<translation id="5300589172476337783">ପ୍ରଦର୍ଶନ କରନ୍ତୁ</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="pa">
|
||||
<translation id="2727175239389218057">ਜਵਾਬ ਦਿਓ</translation>
|
||||
<translation id="5300589172476337783">ਦਿਖਾਓ</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="pl">
|
||||
<translation id="2727175239389218057">Odpowiedz</translation>
|
||||
<translation id="5300589172476337783">Pokaż</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="pt-BR">
|
||||
<translation id="2727175239389218057">Responder</translation>
|
||||
<translation id="5300589172476337783">Mostrar</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="pt-PT">
|
||||
<translation id="2727175239389218057">Responder</translation>
|
||||
<translation id="5300589172476337783">Mostrar</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ro">
|
||||
<translation id="2727175239389218057">Răspunde</translation>
|
||||
<translation id="5300589172476337783">Afișează</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ru">
|
||||
<translation id="2727175239389218057">Ответить</translation>
|
||||
<translation id="5300589172476337783">Показать</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="si">
|
||||
<translation id="2727175239389218057">පිළිතුරු දෙන්න</translation>
|
||||
<translation id="5300589172476337783">පෙන්වන්න</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="sk">
|
||||
<translation id="2727175239389218057">Odpovedať</translation>
|
||||
<translation id="5300589172476337783">Zobraziť</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="sl">
|
||||
<translation id="2727175239389218057">Odgovori</translation>
|
||||
<translation id="5300589172476337783">Pokaži</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="sq">
|
||||
<translation id="2727175239389218057">Përgjigju</translation>
|
||||
<translation id="5300589172476337783">Shfaq</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="sr-Latn">
|
||||
<translation id="2727175239389218057">Odgovori</translation>
|
||||
<translation id="5300589172476337783">Prikaži</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="sr">
|
||||
<translation id="2727175239389218057">Одговори</translation>
|
||||
<translation id="5300589172476337783">Прикажи</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="sv">
|
||||
<translation id="2727175239389218057">Svara</translation>
|
||||
<translation id="5300589172476337783">Visa</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="sw">
|
||||
<translation id="2727175239389218057">Jibu</translation>
|
||||
<translation id="5300589172476337783">Onyesha</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ta">
|
||||
<translation id="2727175239389218057">பதிலளி</translation>
|
||||
<translation id="5300589172476337783">காண்பி</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="te">
|
||||
<translation id="2727175239389218057">రిప్లయి ఇవ్వండి</translation>
|
||||
<translation id="5300589172476337783">చూపించు</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="th">
|
||||
<translation id="2727175239389218057">ตอบ</translation>
|
||||
<translation id="5300589172476337783">แสดง</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="tr">
|
||||
<translation id="2727175239389218057">Yanıtla</translation>
|
||||
<translation id="5300589172476337783">Göster</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="uk">
|
||||
<translation id="2727175239389218057">Відповісти</translation>
|
||||
<translation id="5300589172476337783">Показати</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="ur">
|
||||
<translation id="2727175239389218057">جواب دیں</translation>
|
||||
<translation id="5300589172476337783">دکھائیں</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="uz">
|
||||
<translation id="2727175239389218057">Javob berish</translation>
|
||||
<translation id="5300589172476337783">Ko‘rsatish</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="vi">
|
||||
<translation id="2727175239389218057">Trả lời</translation>
|
||||
<translation id="5300589172476337783">Hiển thị</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="zh-CN">
|
||||
<translation id="2727175239389218057">回复</translation>
|
||||
<translation id="5300589172476337783">显示</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="zh-HK">
|
||||
<translation id="2727175239389218057">回覆</translation>
|
||||
<translation id="5300589172476337783">顯示</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="zh-TW">
|
||||
<translation id="2727175239389218057">回覆</translation>
|
||||
<translation id="5300589172476337783">顯示</translation>
|
||||
</translationbundle>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE translationbundle>
|
||||
<translationbundle lang="zu">
|
||||
<translation id="2727175239389218057">Phendula</translation>
|
||||
<translation id="5300589172476337783">Bonisa</translation>
|
||||
</translationbundle>
|
||||
@@ -94,45 +94,18 @@ The `desktopCapturer` module has the following methods:
|
||||
Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`DesktopCapturerSource`](structures/desktop-capturer-source.md) objects, each `DesktopCapturerSource` represents a screen or an individual window that can be captured.
|
||||
|
||||
> [!NOTE]
|
||||
|
||||
> * Capturing audio requires `NSAudioCaptureUsageDescription` Info.plist key on macOS 14.2 Sonoma and higher - [read more](#macos-versions-142-or-higher).
|
||||
> * Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher, which can detected by [`systemPreferences.getMediaAccessStatus`][].
|
||||
> Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher,
|
||||
> which can detected by [`systemPreferences.getMediaAccessStatus`][].
|
||||
|
||||
[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia
|
||||
[`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-windows-macos
|
||||
|
||||
## Caveats
|
||||
|
||||
### Linux
|
||||
|
||||
`desktopCapturer.getSources(options)` only returns a single source on Linux when using Pipewire.
|
||||
|
||||
PipeWire supports a single capture for both screens and windows. If you request the window and screen type, the selected source will be returned as a window capture.
|
||||
|
||||
---
|
||||
`navigator.mediaDevices.getUserMedia` does not work on macOS for audio capture due to a fundamental limitation whereby apps that want to access the system's audio require a [signed kernel extension](https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/KernelExtensions/KernelExtensions.html). Chromium, and by extension Electron, does not provide this.
|
||||
|
||||
### MacOS versions 14.2 or higher
|
||||
|
||||
`NSAudioCaptureUsageDescription` Info.plist key must be added in-order for audio to be captured by `desktopCapturer`. If instead you are running electron from another program like a terminal or IDE then that parent program must contain the Info.plist key.
|
||||
|
||||
This is in order to facillitate use of Apple's new [CoreAudio Tap API](https://developer.apple.com/documentation/CoreAudio/capturing-system-audio-with-core-audio-taps#Configure-the-sample-code-project) by Chromium.
|
||||
|
||||
> [!WARNING]
|
||||
> Failure of `desktopCapturer` to start an audio stream due to `NSAudioCaptureUsageDescription` permission not present will still create a dead audio stream however no warnings or errors are displayed.
|
||||
|
||||
As of electron `v39.0.0-beta.4` Chromium [made Apple's new `CoreAudio Tap API` the default](https://source.chromium.org/chromium/chromium/src/+/ad17e8f8b93d5f34891b06085d373a668918255e) for desktop audio capture. There is no fallback to the older `Screen & System Audio Recording` permissions system even if [CoreAudio Tap API](https://developer.apple.com/documentation/CoreAudio/capturing-system-audio-with-core-audio-taps) stream creation fails.
|
||||
|
||||
If you need to continue using `Screen & System Audio Recording` permissions for `desktopCapturer` on macOS versions 14.2 and later, you can apply a chromium feature flag to force use of that older permissions system:
|
||||
|
||||
```js
|
||||
// main.js (right beneath your require/import statments)
|
||||
app.commandLine.appendSwitch('disable-features', 'MacCatapLoopbackAudioForScreenShare')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### MacOS versions 12.7.6 or lower
|
||||
|
||||
`navigator.mediaDevices.getUserMedia` does not work on macOS versions 12.7.6 and prior for audio capture due to a fundamental limitation whereby apps that want to access the system's audio require a [signed kernel extension](https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/KernelExtensions/KernelExtensions.html). Chromium, and by extension Electron, does not provide this. Only in macOS 13 and onwards does Apple provide APIs to capture desktop audio without the need for a signed kernel extension.
|
||||
|
||||
It is possible to circumvent this limitation by capturing system audio with another macOS app like [BlackHole](https://existential.audio/blackhole/) or [Soundflower](https://rogueamoeba.com/freebies/soundflower/) and passing it through a virtual audio input device. This virtual device can then be queried with `navigator.mediaDevices.getUserMedia`.
|
||||
It is possible to circumvent this limitation by capturing system audio with another macOS app like Soundflower and passing it through a virtual audio input device. This virtual device can then be queried with `navigator.mediaDevices.getUserMedia`.
|
||||
|
||||
@@ -76,22 +76,6 @@ webContents.setWindowOpenHandler((details) => {
|
||||
})
|
||||
```
|
||||
|
||||
### Behavior Changed: `NSAudioCaptureUsageDescription` should be included in your app's Info.plist file to use `desktopCapturer` (🍏 macOS ≥14.2)
|
||||
|
||||
Per [Chromium update](https://source.chromium.org/chromium/chromium/src/+/ad17e8f8b93d5f34891b06085d373a668918255e) which enables Apple's newer [CoreAudio Tap API](https://developer.apple.com/documentation/CoreAudio/capturing-system-audio-with-core-audio-taps#Configure-the-sample-code-project) by default, you now must have `NSAudioCaptureUsageDescription` defined in your `Info.plist` to use `desktopCapturer`.
|
||||
|
||||
Electron's `desktopCapturer` will create a dead audio stream if the new permission is absent however no errors or warnings will occur. This is partially a side-effect of Chromium not falling back to the older `Screen & System Audio Recording` permissions system if the new system fails.
|
||||
|
||||
To restore previous behavior:
|
||||
|
||||
```js
|
||||
// main.js (right beneath your require/import statments)
|
||||
app.commandLine.appendSwitch(
|
||||
'disable-features',
|
||||
'MacCatapLoopbackAudioForScreenShare'
|
||||
)
|
||||
```
|
||||
|
||||
### Behavior Changed: shared texture OSR `paint` event data structure
|
||||
|
||||
When using shared texture offscreen rendering feature, the `paint` event now emits a more structured object.
|
||||
|
||||
@@ -200,7 +200,7 @@ macOS has a number of platform-specific menu roles available. Many of these map
|
||||
|
||||
* `recentDocuments` - The submenu is an "Open Recent" menu.
|
||||
* `clearRecentDocuments` - Map to the [`clearRecentDocuments`](https://developer.apple.com/documentation/appkit/nsdocumentcontroller/clearrecentdocuments(_:)) action.
|
||||
* `shareMenu` - The submenu is [share menu](../api/share-menu.md). The `sharingItem` property must also be set to indicate the item to share.
|
||||
* `shareMenu` - The submenu is [share menu][ShareMenu]. The `sharingItem` property must also be set to indicate the item to share.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> When specifying a `role` on macOS, `label` and `accelerator` are the only
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/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"
|
||||
@@ -3,8 +3,6 @@
|
||||
set -eo pipefail
|
||||
|
||||
dir="$(dirname $0)"/.working
|
||||
KEYCHAIN="electron-codesign.keychain-db"
|
||||
KEYCHAIN_TEMP="$(openssl rand -hex 12)"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$dir"
|
||||
@@ -20,16 +18,30 @@ 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
|
||||
|
||||
# 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"
|
||||
# restart(reload) taskgated daemon
|
||||
sudo pkill -f /usr/libexec/taskgated
|
||||
|
||||
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
|
||||
# need once
|
||||
sudo security authorizationdb write system.privilege.taskport allow
|
||||
# need once
|
||||
DevToolsSecurity -enable
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_TEMP" "$KEYCHAIN"
|
||||
# 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"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
valid_certs=$(security find-identity -p codesigning)
|
||||
valid_certs=$(security find-identity -p codesigning -v)
|
||||
if [[ $valid_certs == *"1)"* ]]; then
|
||||
first_valid_cert=$(echo $valid_certs | sed 's/ \".*//' | sed 's/.* //')
|
||||
echo $first_valid_cert
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "shell/browser/web_contents_permission_helper.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "third_party/blink/public/common/features_generated.h"
|
||||
#include "third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "url/origin.h"
|
||||
@@ -444,28 +443,6 @@ class FileSystemAccessPermissionContext::PermissionGrantImpl
|
||||
}
|
||||
}
|
||||
|
||||
// Downgrades the in-memory read permission grant for the `path` if it exist
|
||||
// in `grants`. This is different from
|
||||
// ChromeFileSystemAccessPermissionContext::RevokeGrant in that this method
|
||||
// does not reset the persisted permission state.
|
||||
static void DowngradeReadGrantInMemory(
|
||||
std::map<base::FilePath, PermissionGrantImpl*>& grants,
|
||||
const content::PathInfo& path) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
auto entry_it = std::ranges::find_if(grants, [&path](const auto& entry) {
|
||||
return entry.first == path.path;
|
||||
});
|
||||
if (entry_it == grants.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK_EQ(entry_it->second->GetActivePermissionStatus(),
|
||||
PermissionStatus::GRANTED);
|
||||
auto* const grant_impl = entry_it->second;
|
||||
grant_impl->SetStatus(PermissionStatus::DENIED);
|
||||
}
|
||||
|
||||
protected:
|
||||
~PermissionGrantImpl() override {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
@@ -518,10 +495,6 @@ struct FileSystemAccessPermissionContext::OriginState {
|
||||
// PermissionGrantDestroyed().
|
||||
std::map<base::FilePath, PermissionGrantImpl*> read_grants;
|
||||
std::map<base::FilePath, PermissionGrantImpl*> write_grants;
|
||||
|
||||
// Stores paths whose read grants have been downgraded to ASK after a
|
||||
// remove() call and are eligible for restoration.
|
||||
std::set<base::FilePath> downgraded_read_paths;
|
||||
};
|
||||
|
||||
FileSystemAccessPermissionContext::FileSystemAccessPermissionContext(
|
||||
@@ -985,68 +958,15 @@ void FileSystemAccessPermissionContext::NotifyEntryMoved(
|
||||
PermissionGrantImpl::UpdateGrantPath(it->second.read_grants, old_path,
|
||||
new_path, allow_overwrite);
|
||||
}
|
||||
|
||||
if (base::FeatureList::IsEnabled(
|
||||
blink::features::kFileSystemAccessRevokeReadOnRemove)) {
|
||||
MaybeRestoreReadPermission(origin, new_path.path);
|
||||
}
|
||||
}
|
||||
|
||||
void FileSystemAccessPermissionContext::NotifyEntryModified(
|
||||
const url::Origin& origin,
|
||||
const content::PathInfo& path) {
|
||||
CHECK(base::FeatureList::IsEnabled(
|
||||
blink::features::kFileSystemAccessRevokeReadOnRemove));
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
|
||||
MaybeRestoreReadPermission(origin, path.path);
|
||||
}
|
||||
|
||||
void FileSystemAccessPermissionContext::MaybeRestoreReadPermission(
|
||||
const url::Origin& origin,
|
||||
const base::FilePath& path) {
|
||||
auto it = active_permissions_map_.find(origin);
|
||||
if (it == active_permissions_map_.end()) {
|
||||
return;
|
||||
}
|
||||
OriginState& origin_state = it->second;
|
||||
|
||||
// Return early if the path was not previously downgraded.
|
||||
if (origin_state.downgraded_read_paths.find(path) ==
|
||||
origin_state.downgraded_read_paths.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
origin_state.downgraded_read_paths.erase(path);
|
||||
|
||||
// Set the grant's status back to GRANTED if it was previously downgraded.
|
||||
auto grant_it = origin_state.read_grants.find(path);
|
||||
// Exclude the case where the path does not exist in the read_grants map.
|
||||
if (grant_it != origin_state.read_grants.end())
|
||||
grant_it->second->SetStatus(PermissionStatus::GRANTED);
|
||||
}
|
||||
const content::PathInfo& path) {}
|
||||
|
||||
void FileSystemAccessPermissionContext::NotifyEntryRemoved(
|
||||
const url::Origin& origin,
|
||||
const content::PathInfo& path) {
|
||||
CHECK(base::FeatureList::IsEnabled(
|
||||
blink::features::kFileSystemAccessRevokeReadOnRemove));
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
|
||||
if (AncestorHasActivePermission(origin, path.path, GrantType::kRead)) {
|
||||
// If `path` has an active read grant inherited from its ancestor, don't
|
||||
// downgrade its permission, as it will still get ancestor grant by default.
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = active_permissions_map_.find(origin);
|
||||
if (it != active_permissions_map_.end()) {
|
||||
PermissionGrantImpl::DowngradeReadGrantInMemory(it->second.read_grants,
|
||||
path);
|
||||
// Marks the path as downgraded so that it can be restored later.
|
||||
it->second.downgraded_read_paths.insert(path.path);
|
||||
}
|
||||
}
|
||||
const content::PathInfo& path) {}
|
||||
|
||||
void FileSystemAccessPermissionContext::OnFileCreatedFromShowSaveFilePicker(
|
||||
const GURL& file_picker_binding_context,
|
||||
|
||||
@@ -140,11 +140,6 @@ class FileSystemAccessPermissionContext
|
||||
|
||||
void PermissionGrantDestroyed(PermissionGrantImpl* grant);
|
||||
|
||||
// Restores the read permission for `path` if it was previously downgraded,
|
||||
// e.g. by a `remove()` call.
|
||||
void MaybeRestoreReadPermission(const url::Origin& origin,
|
||||
const base::FilePath& path);
|
||||
|
||||
void CheckShouldBlockAccessToPathAndReply(
|
||||
base::FilePath path,
|
||||
HandleType handle_type,
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#define ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_COCOA_NOTIFICATION_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -15,6 +14,11 @@
|
||||
|
||||
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,
|
||||
@@ -27,20 +31,23 @@ class CocoaNotification : public Notification {
|
||||
|
||||
void NotificationDisplayed();
|
||||
void NotificationReplied(const std::string& reply);
|
||||
void NotificationActivated(int actionIndex);
|
||||
void NotificationActivated();
|
||||
void NotificationActivated(NSUserNotificationAction* action);
|
||||
void NotificationDismissed();
|
||||
|
||||
UNNotificationRequest* notification_request() const {
|
||||
return notification_request_;
|
||||
}
|
||||
NSUserNotification* notification() const { return notification_; }
|
||||
|
||||
private:
|
||||
void LogAction(const char* action);
|
||||
void ScheduleNotification(UNMutableNotificationContent* content);
|
||||
|
||||
UNNotificationRequest* __strong notification_request_;
|
||||
NSUserNotification* __strong notification_;
|
||||
std::map<std::string, unsigned> additional_action_indices_;
|
||||
unsigned action_index_;
|
||||
};
|
||||
|
||||
// -Wdeprecated-declarations
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_COCOA_NOTIFICATION_H_
|
||||
|
||||
@@ -7,22 +7,17 @@
|
||||
#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"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.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 {
|
||||
|
||||
@@ -31,217 +26,101 @@ CocoaNotification::CocoaNotification(NotificationDelegate* delegate,
|
||||
: Notification(delegate, presenter) {}
|
||||
|
||||
CocoaNotification::~CocoaNotification() {
|
||||
if (notification_request_)
|
||||
[[UNUserNotificationCenter currentNotificationCenter]
|
||||
removeDeliveredNotificationsWithIdentifiers:@[
|
||||
notification_request_.identifier
|
||||
]];
|
||||
if (notification_)
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter
|
||||
removeDeliveredNotification:notification_];
|
||||
}
|
||||
|
||||
void CocoaNotification::Show(const NotificationOptions& options) {
|
||||
UNMutableNotificationContent* content =
|
||||
[[UNMutableNotificationContent alloc] init];
|
||||
notification_ = [[NSUserNotification 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]];
|
||||
|
||||
UNNotificationRequest* request =
|
||||
[UNNotificationRequest requestWithIdentifier:identifier
|
||||
content:content
|
||||
trigger:nil];
|
||||
[notification_ setTitle:base::SysUTF16ToNSString(options.title)];
|
||||
[notification_ setSubtitle:base::SysUTF16ToNSString(options.subtitle)];
|
||||
[notification_ setInformativeText:base::SysUTF16ToNSString(options.msg)];
|
||||
[notification_ setIdentifier:identifier];
|
||||
|
||||
notification_request_ = request;
|
||||
if (electron::debug_notifications) {
|
||||
LOG(INFO) << "Notification created (" << [identifier UTF8String] << ")";
|
||||
}
|
||||
|
||||
scoped_refptr<base::SequencedTaskRunner> task_runner =
|
||||
base::SequencedTaskRunner::GetCurrentDefault();
|
||||
auto weak_self = GetWeakPtr();
|
||||
if (!options.icon.drawsNothing()) {
|
||||
NSImage* image = skia::SkBitmapToNSImage(options.icon);
|
||||
[notification_ setContentImage:image];
|
||||
}
|
||||
|
||||
[[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]
|
||||
<< ")";
|
||||
}
|
||||
}
|
||||
}];
|
||||
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_];
|
||||
}
|
||||
|
||||
void CocoaNotification::Dismiss() {
|
||||
if (notification_request_)
|
||||
[[UNUserNotificationCenter currentNotificationCenter]
|
||||
removeDeliveredNotificationsWithIdentifiers:@[
|
||||
notification_request_.identifier
|
||||
]];
|
||||
if (notification_)
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter
|
||||
removeDeliveredNotification:notification_];
|
||||
|
||||
NotificationDismissed();
|
||||
|
||||
notification_request_ = nil;
|
||||
notification_ = nil;
|
||||
}
|
||||
|
||||
void CocoaNotification::NotificationDisplayed() {
|
||||
@@ -258,9 +137,27 @@ void CocoaNotification::NotificationReplied(const std::string& reply) {
|
||||
this->LogAction("replied to");
|
||||
}
|
||||
|
||||
void CocoaNotification::NotificationActivated(int actionIndex) {
|
||||
void CocoaNotification::NotificationActivated() {
|
||||
if (delegate())
|
||||
delegate()->NotificationAction(actionIndex);
|
||||
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);
|
||||
}
|
||||
|
||||
this->LogAction("button clicked");
|
||||
}
|
||||
@@ -273,8 +170,8 @@ void CocoaNotification::NotificationDismissed() {
|
||||
}
|
||||
|
||||
void CocoaNotification::LogAction(const char* action) {
|
||||
if (electron::debug_notifications && notification_request_) {
|
||||
NSString* identifier = [notification_request_ valueForKey:@"identifier"];
|
||||
if (electron::debug_notifications && notification_) {
|
||||
NSString* identifier = [notification_ valueForKey:@"identifier"];
|
||||
DCHECK(identifier);
|
||||
LOG(INFO) << "Notification " << action << " (" << [identifier UTF8String]
|
||||
<< ")";
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#define ELECTRON_SHELL_BROWSER_NOTIFICATIONS_MAC_NOTIFICATION_CENTER_DELEGATE_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
|
||||
@@ -15,7 +14,7 @@ class NotificationPresenterMac;
|
||||
}
|
||||
|
||||
@interface NotificationCenterDelegate
|
||||
: NSObject <UNUserNotificationCenterDelegate> {
|
||||
: NSObject <NSUserNotificationCenterDelegate> {
|
||||
@private
|
||||
raw_ptr<electron::NotificationPresenterMac> presenter_;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
#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:
|
||||
@@ -23,62 +28,71 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (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
|
||||
didDeliverNotification:(NSUserNotification*)notif {
|
||||
auto* notification = presenter_->GetNotification(notif);
|
||||
if (notification)
|
||||
notification->NotificationDisplayed();
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
|
||||
didReceiveNotificationResponse:(UNNotificationResponse*)response
|
||||
withCompletionHandler:(void (^)())completionHandler {
|
||||
auto* notification =
|
||||
presenter_->GetNotification(response.notification.request);
|
||||
- (void)userNotificationCenter:(NSUserNotificationCenter*)center
|
||||
didActivateNotification:(NSUserNotification*)notif {
|
||||
auto* notification = presenter_->GetNotification(notif);
|
||||
|
||||
if (electron::debug_notifications) {
|
||||
LOG(INFO) << "Notification activated ("
|
||||
<< [response.notification.request.identifier UTF8String] << ")";
|
||||
LOG(INFO) << "Notification activated (" << [notif.identifier UTF8String]
|
||||
<< ")";
|
||||
}
|
||||
|
||||
if (notification) {
|
||||
NSString* categoryIdentifier =
|
||||
response.notification.request.content.categoryIdentifier;
|
||||
NSString* actionIdentifier = response.actionIdentifier;
|
||||
if ([actionIdentifier
|
||||
isEqualToString:UNNotificationDefaultActionIdentifier]) {
|
||||
// Ref:
|
||||
// https://developer.apple.com/documentation/foundation/nsusernotificationactivationtype?language=objc
|
||||
if (notif.activationType ==
|
||||
NSUserNotificationActivationTypeContentsClicked) {
|
||||
notification->NotificationClicked();
|
||||
} 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 (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 (electron::debug_notifications) {
|
||||
LOG(INFO) << "Could not find notification for "
|
||||
<< [response.notification.request.identifier UTF8String];
|
||||
}
|
||||
}
|
||||
|
||||
completionHandler();
|
||||
}
|
||||
|
||||
- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center
|
||||
shouldPresentNotification:(NSUserNotification*)notification {
|
||||
// Display notifications even if the app is active.
|
||||
return YES;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@@ -6,39 +6,36 @@
|
||||
#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(
|
||||
UNNotificationRequest* un_notification_request);
|
||||
CocoaNotification* GetNotification(NSUserNotification* ns_notification);
|
||||
|
||||
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_
|
||||
|
||||
@@ -3,13 +3,17 @@
|
||||
// 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
|
||||
@@ -18,17 +22,17 @@ std::unique_ptr<NotificationPresenter> NotificationPresenter::Create() {
|
||||
}
|
||||
|
||||
CocoaNotification* NotificationPresenterMac::GetNotification(
|
||||
UNNotificationRequest* un_notification_request) {
|
||||
NSUserNotification* ns_notification) {
|
||||
for (Notification* notification : notifications()) {
|
||||
auto* native_notification = static_cast<CocoaNotification*>(notification);
|
||||
if ([native_notification->notification_request().identifier
|
||||
isEqual:un_notification_request.identifier])
|
||||
if ([native_notification->notification().identifier
|
||||
isEqual:ns_notification.identifier])
|
||||
return native_notification;
|
||||
}
|
||||
|
||||
if (electron::debug_notifications) {
|
||||
LOG(INFO) << "Could not find notification for "
|
||||
<< [un_notification_request.identifier UTF8String];
|
||||
<< [ns_notification.identifier UTF8String];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -36,43 +40,13 @@ CocoaNotification* NotificationPresenterMac::GetNotification(
|
||||
|
||||
NotificationPresenterMac::NotificationPresenterMac()
|
||||
: 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;
|
||||
}
|
||||
}
|
||||
}];
|
||||
[[NotificationCenterDelegate alloc] initWithPresenter:this]) {
|
||||
NSUserNotificationCenter.defaultUserNotificationCenter.delegate =
|
||||
notification_center_delegate_;
|
||||
}
|
||||
|
||||
NotificationPresenterMac::~NotificationPresenterMac() {
|
||||
UNUserNotificationCenter.currentNotificationCenter.delegate = nil;
|
||||
image_task_runner_->DeleteSoon(FROM_HERE, image_retainer_.release());
|
||||
NSUserNotificationCenter.defaultUserNotificationCenter.delegate = nil;
|
||||
}
|
||||
|
||||
Notification* NotificationPresenterMac::CreateNotificationObject(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user