From f273eed84041b9d7950cc81701338ef0b7006e49 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 7 Oct 2026 17:48:56 +0200 Subject: [PATCH] Suppress the Cloudpinyin first-use prompt --- config/fcitx5/conf/pinyin.conf | 3 +++ default/input-methods/configure.py | 14 ++++++++++++-- shell/plugins/notifications/NotificationLogic.js | 4 +--- test/shell.d/input-method-checks.py | 13 +++++++++++++ test/shell.d/notifications-test.sh | 2 -- 5 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 config/fcitx5/conf/pinyin.conf diff --git a/config/fcitx5/conf/pinyin.conf b/config/fcitx5/conf/pinyin.conf new file mode 100644 index 00000000..590c3d43 --- /dev/null +++ b/config/fcitx5/conf/pinyin.conf @@ -0,0 +1,3 @@ +# Keep Pinyin offline without prompting to enable cloud prediction. +FirstRun=False +CloudPinyinEnabled=False diff --git a/default/input-methods/configure.py b/default/input-methods/configure.py index dc98f0ae..ab659636 100644 --- a/default/input-methods/configure.py +++ b/default/input-methods/configure.py @@ -74,7 +74,7 @@ def key_list(entries): def defaults(config_home, fresh=False): changed = False - files = ["config", "conf/quickphrase.conf", "conf/wayland.conf", "conf/xcb.conf"] + files = ["config", "conf/quickphrase.conf", "conf/wayland.conf", "conf/xcb.conf", "conf/pinyin.conf"] for name in files: target = config_home / "fcitx5" / name original = read(target) @@ -104,6 +104,16 @@ def defaults(config_home, fresh=False): additions.append(f"[{section}]\n" + "".join(f"{key}={value}\n" for key, value in entries.items())) if additions: changed |= atomic_write(target, original.rstrip() + ("\n\n" if original.strip() else "") + "\n".join(additions)) + elif name == "conf/pinyin.conf": + # Suppress the first-use cloud prompt while preserving any explicit + # cloud-prediction preference and all other existing engine settings. + if not original: + updated = shipped + elif "FirstRun" in values(original): + updated = re.sub(r"(?m)^\s*FirstRun\s*=.*$", "FirstRun=False", original) + else: + updated = "FirstRun=False\n" + original + changed |= atomic_write(target, updated) elif not target.exists() and not target.is_symlink(): changed |= atomic_write(target, shipped) return changed @@ -123,7 +133,7 @@ def activation_default(): @contextmanager def transaction(config_home, live=False): data_home = Path(os.environ.get("XDG_DATA_HOME") or str(Path.home() / ".local/share")) - paths = [config_home / "fcitx5" / name for name in ["profile", "config", "conf/quickphrase.conf", "conf/wayland.conf", "conf/xcb.conf"]] + paths = [config_home / "fcitx5" / name for name in ["profile", "config", "conf/quickphrase.conf", "conf/wayland.conf", "conf/xcb.conf", "conf/pinyin.conf"]] paths += [config_home / "fontconfig/conf.d/50-omarchy-input-method.conf", data_home / "dbus-1/services/org.fcitx.Fcitx5.service"] before = {path.resolve(): path.read_text() if path.exists() else None for path in paths} try: diff --git a/shell/plugins/notifications/NotificationLogic.js b/shell/plugins/notifications/NotificationLogic.js index e69f1e06..cabc3ac1 100644 --- a/shell/plugins/notifications/NotificationLogic.js +++ b/shell/plugins/notifications/NotificationLogic.js @@ -202,9 +202,7 @@ function snapshotOf(notification, timestamp) { glyph: glyphFromHints(n.hints), execArgv: execArgvFromHints(n.hints), actionsJson: JSON.stringify(actions), - // Pinyin's first-use cloud prediction question needs an explicit answer. - // Its normal urgency otherwise dismisses it before users can read it. - urgency: n.appName === "Pinyin" && n.appIcon === "fcitx-pinyin" ? 2 : n.urgency, + urgency: n.urgency, expireTimeout: expireTimeout, timestamp: timestamp === undefined ? Date.now() : timestamp } diff --git a/test/shell.d/input-method-checks.py b/test/shell.d/input-method-checks.py index 98b0fb14..981b0f18 100644 --- a/test/shell.d/input-method-checks.py +++ b/test/shell.d/input-method-checks.py @@ -16,6 +16,19 @@ spec.loader.exec_module(setup) class InputMethodTest(unittest.TestCase): + def test_pinyin_defaults_suppress_cloud_prompt(self): + setup.defaults(self.config, fresh=True) + pinyin = setup.values((self.config / "fcitx5/conf/pinyin.conf").read_text()) + self.assertEqual(pinyin["FirstRun"], "False") + self.assertEqual(pinyin["CloudPinyinEnabled"], "False") + + def test_pinyin_prompt_suppression_preserves_existing_preferences(self): + pinyin = self.config / "fcitx5/conf/pinyin.conf" + pinyin.parent.mkdir(parents=True) + pinyin.write_text("FirstRun=True\nCloudPinyinEnabled=True\nPageSize=7\n") + setup.defaults(self.config) + self.assertEqual(pinyin.read_text(), "FirstRun=False\nCloudPinyinEnabled=True\nPageSize=7\n") + def setUp(self): self.temporary = tempfile.TemporaryDirectory() self.addCleanup(self.temporary.cleanup) diff --git a/test/shell.d/notifications-test.sh b/test/shell.d/notifications-test.sh index ec3ad253..7d3b7494 100644 --- a/test/shell.d/notifications-test.sh +++ b/test/shell.d/notifications-test.sh @@ -275,8 +275,6 @@ assertDeepEqual(JSON.parse(notifications.snapshotOf({ actions: [ { identifier: 'default', text: 'Open' }, { identifier: 'yes', text: 'Yes' }, { identifier: 'no', text: 'No' } ]}).actionsJson), [{ identifier: 'yes', text: 'Yes' }, { identifier: 'no', text: 'No' }], 'explicit choices appear independently of the default card action') assertEqual(notifications.popupEntry({ actionsJson: '[{"identifier":"yes","text":"Yes"}]' }, 1).actionsJson, '[]', 'restored notifications do not replay actions from a dead sender') -assertEqual(notifications.snapshotOf({ appName: 'Pinyin', appIcon: 'fcitx-pinyin', urgency: 1 }).urgency, 2, 'Pinyin prompts stay visible until dismissed') -assertEqual(notifications.snapshotOf({ appName: 'Other', appIcon: 'fcitx-pinyin', urgency: 1 }).urgency, 1, 'other notification senders retain their urgency') assertDeepEqual( { id: snapshot.id,