Repository navigation
feat(snippet): add system-wide text snippet expansion with configurable prefix (#1743) - #1756
Open
Balajitechlabs wants to merge 8 commits into
Open
Balajitechlabs wants to merge 8 commits into
Balajitechlabs wants to merge 8 commits into
Conversation
Balajitechlabs
force-pushed
the
feature/snippet
branch
from
November 11, 2026 14:45
32436c8 to
715370c
Compare
Balajitechlabs
force-pushed
the
feature/snippet
branch
from
November 11, 2026 17:16
bc82adb to
f0ebe92
Compare
sameerasw
requested changes
Nov 12, 2026
sameerasw
left a comment
Owner
There was a problem hiding this comment.
@Balajitechlabs please address these.
Bugs
- Short keywords block longer ones in symbol mode. Expansion fires the moment the text ends with
;app, so a;applesnippet can never be typed. Sorting longest-first doesn't help, because the check runs on every character. Prefix mode needs a terminator (space or punctuation after the keyword), or a check that no longer keyword still starts with what's been typed. - The
//prefix breaks URLs. Typinghttps://app…expands the defaultappsnippet in the middle of a URL.:has the same problem with emoji shortcodes and times like10:email. Drop//or require a word boundary before the prefix. - Trailing-space mode plus the default snippets expands everyday words. With prefix "␣", typing "email " or "app " in normal sentences turns them into the snippet text.
- The 250ms
isUpdatingTextlock swallows fast typing. Text-changed events in that window are dropped, so a second trigger typed quickly never expands. The lock should ignore only the event caused by its own replacement, for example by comparing against the text it just set. ACTION_SET_TEXTreplaces the whole field. That wipes formatting, breaks the app's undo history and any half-typed word in the keyboard, and many apps ignore it entirely (Chrome/WebView, Compose text fields, Google Docs). The PR calls this "system-wide", but in practice it works in plain text boxes only.- Hint text gets treated as typed text. In an empty field,
source.textcan return the hint and there's noisShowingHintTextcheck. Whensource.textis null, the fallbackevent.textdoesn't match the cursor position fromtextSelectionEnd. - Possible double expansion. With both the Essentials keyboard and the accessibility service active, both run expansion on the same input. It may work by luck of event timing, but neither side knows about the other.
- Bad default snippets.
hello@example.comand the repo link are placeholders that ship to every user. Defaults should be empty, or at most the shrug.
Performance and privacy
- JSON parsed on every keystroke.
getTextSnippets()decodes the stored snippet list (gson) on every keystroke in the keyboard and on every text-changed event in every app. The parsed list should be cached and refreshed when the setting changes. - Every app's typing now reaches the service. Text-changed events are always turned on for the whole accessibility service, even when snippets are off, so the service gets an event for every character typed anywhere. They should only be turned on while the feature is on. This also affects the accessibility disclosure for Play.
- The event type is turned on twice, in
accessibility_service_config.xmland again at runtime viaeventTypes or. One is enough, and the runtime one is the version to keep.
Unnecessary or noisy
- Two entry points. There's a separate "Text Snippets" entry in the feature list (
FeatureRegistry) and a toggle inside Keyboard settings. Pick one; it belongs under Keyboard. SnippetCardItemis added to the sharedSelectionCardItem.ktwith about 90 lines of imports and code for one screen. It should live with the snippets screen, or reuse an existing list item.- Leftover parameters:
contextinsetTextSnippetsEnabled(enabled, context)isn't used, and neither isscopeinSnippetExpansionHandler. - Screen state in the shared ViewModel.
editingSnippetandisAddSnippetSheetVisibleare UI state for one screen but sit in the already hugeMainViewModel. Localrememberstate would do. - Comments. KDoc paragraphs and section comments like
// Text Snippets Containerand// Trigger Prefix Hero Card with Wide Action Buttongo against the repo's no-comment style. - Long fully-qualified names inline (
com.sameerasw.essentials.ui.core.sheets.PermissionsBottomSheet, etc.) instead of imports. - Oversized PR. The size checkbox (under ~1,000 lines) is left unchecked and the PR is over it. The UI file alone is 347 lines.
Smaller things
- No keyword validation for duplicates, spaces, or a keyword that contains the prefix.
- Snippet IDs use
System.currentTimeMillis(), which works but is fragile. A UUID would be safer. - List item corners.
SnippetCardItemusesextraSmalland 8dp corners rather than the app's 24dp outer / 4dp inner shape for grouped items. - New strings are only in
values/strings.xml, which is fine if Crowdin fills in the other locales.
…rmance, and UI conventions (#1743)
Collaborator
Author
|
Addressed all feedback |
Balajitechlabs
marked this pull request as ready for review
November 13, 2026 17:13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked issue
Closes #1743
Description
Adds a system-wide text snippet expansion engine with user-configurable trigger prefixes (
;,:,@@,//, or trailing space expansion).What this PR changes and why:
System-Wide Accessibility Service Integration:
SnippetExpansionHandlerinsideScreenOffAccessibilityServicelistening toTYPE_VIEW_TEXT_CHANGEDand executing replacements viaACTION_SET_TEXT.EssentialsInputMethodServicefallback expansion for the app's built-in keyboard.UI & Repository Conventions (Refined with Maintainer Feedback):
RoundedCardContainer(spacing = 2.dp)under Keyboard Settings withrounded_edit_note_24(text cursor icon).EssentialsBottomSheet.StackedActionCardwith a wide thick action button ([ ✎ Change ]) that opens a bottom sheet with preset prefix choices (;,:,@@,//,␣).SnippetCardItemtoSelectionCardItem.ktusing theme-adaptive Material You colors (secondaryContainer/onSecondaryContainer) for guaranteed high contrast in both dark and light modes, resilient text weights (weight(1f, fill = false)) so long shortcuts/labels never break layout, multi-line content previews, and trailing delete buttons with haptics.ACCESSIBILITYpermission with automaticPermissionsBottomSheetprompt.strings.xml.Type of change
UI changes
RoundedCardContainer).StackedActionCardfor prefix trigger selection andSnippetCardItemfor saved shortcuts.EssentialsBottomSheet).EssentialsBottomSheet).(Screenshots attached)
Checklist
approvedand assigned to me.develop../gradlew assembleDebugand./gradlew testDebugUnitTestpass.