Skip to content

Simplify emoji suggestion settings#451

Merged
FuJacob merged 2 commits into
mainfrom
fix/emoji-suggestion-copy
May 31, 2026
Merged

Simplify emoji suggestion settings#451
FuJacob merged 2 commits into
mainfrom
fix/emoji-suggestion-copy

Conversation

@FuJacob

@FuJacob FuJacob commented May 31, 2026

Copy link
Copy Markdown
Owner

Summary

Simplifies emoji suggestion settings by removing the Include Neutral Variant toggle and making the default emoji variant always appear after a preferred skin-tone variant. Replaces the skin tone dropdown with a horizontal row of victory-hand tone buttons, refreshes the option labels/copy, and adds an emoji picker footer that shows the configured word-accept shortcut.

Validation

  • swiftlint lint --quiet 2>&1 | tail -20 — exit 0
  • xcodebuild test -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' -only-testing:CotabbyTests/EmojiVariantResolverTests -only-testing:CotabbyTests/EmojiPickerPanelLayoutTests -only-testing:CotabbyTests/SuggestionAvailabilityEvaluatorTests CODE_SIGNING_ALLOWED=NO -derivedDataPath build/DerivedDataEmojiUxTEST SUCCEEDED, 32 tests, 0 failures
  • xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' build -derivedDataPath build/DerivedDataEmojiUxBUILD SUCCEEDED

No screenshot captured; this is a native macOS settings UI change, and the validation above covers compilation plus the changed pure behavior.

Linked issues

N/A

Risk / rollout notes

  • Existing cotabbyIncludeNeutralEmojiVariant user defaults are now ignored because the behavior is fixed: preferred tone first, default variant next.
  • The emoji picker footer intentionally uses the word-accept shortcut even when the ghost-text key hint setting is hidden, because picker instructions should remain visible.

Greptile Summary

This PR simplifies the emoji suggestion settings by removing the "Include Neutral Variant" toggle (making the default variant always follow a preferred skin-tone variant), replacing the skin-tone and gender Picker dropdowns with horizontal swatch-button rows, and adding a persistent footer to the emoji picker panel that shows the configured word-accept shortcut.

  • EmojiVariantResolver now unconditionally appends the untoned glyph after every toned glyph, replacing the old includeNeutral flag; EmojiVariantPreferences loses the includeNeutral field accordingly.
  • EmojiPickerView gains a footer bar (header + divider + list + divider + footer), and the per-row EmojiKeycap is removed in favour of a single static hint in the footer; EmojiPickerPanelLayout adds a footerHeight constant and includes it in contentSize.
  • SuggestionSettingsModel adds emojiPickerAcceptKeyLabel, which returns the word-accept label regardless of the ghost-hint toggle, so the picker instruction is always shown when a key is bound.

Confidence Score: 5/5

Safe to merge. The behavior changes are intentional and well-scoped, existing user defaults for the removed toggle are gracefully ignored, and all 32 tests pass.

All changed logic paths are covered by the updated test suite. The removals (include-neutral toggle, per-row keycap, gender/neutral binding) are clean and consistent across model, resolver, UI, and tests. The one leftover binding is inert dead code with no runtime impact.

GeneralPaneView.swift has a leftover emojiSkinToneBinding that was not removed when the Picker was replaced.

Important Files Changed

Filename Overview
Cotabby/UI/Settings/Panes/GeneralPaneView.swift Replaces skin-tone and gender Pickers with horizontal swatch rows; removes Include Neutral toggle; renames section and labels. One leftover binding (emojiSkinToneBinding) is now unreferenced.
Cotabby/Support/EmojiVariantResolver.swift Hardcodes the "include default variant" behaviour that was previously toggled via includeNeutral; applySkinTone now always appends the untoned match after the toned one.
Cotabby/UI/EmojiPickerView.swift Moves accept-key hint from per-row keycap to a persistent footer; simplifies EmojiKeycap by dropping accent-state colouring; cleans up EmojiPickerRow.
Cotabby/Models/SuggestionSettingsModel.swift Drops includeNeutralEmojiVariant property, defaults key, and setter; adds emojiPickerAcceptKeyLabel computed property that bypasses the ghost-hint toggle.
Cotabby/Support/EmojiPickerPanelLayout.swift Adds footerHeight constant and includes it (plus a second divider) in contentSize; tests updated to match.
Cotabby/App/Core/CotabbyAppEnvironment.swift Single-line change: wires emojiPickerAcceptKeyLabel instead of acceptanceHintLabel so the picker footer is unaffected by the ghost-hint toggle.
CotabbyTests/EmojiVariantResolverTests.swift Updates resolver tests: removes includeNeutral cases, verifies that a non-neutral skin tone now always yields both toned and untoned glyphs.
CotabbyTests/EmojiPickerPanelLayoutTests.swift Layout tests rewritten to use named constants instead of magic numbers; cover the new footer height in both empty and capped-row scenarios.
CotabbyTests/SuggestionAvailabilityEvaluatorTests.swift Adds a test confirming emojiPickerAcceptKeyLabel ignores the ghost-hint toggle and returns nil only when the word-accept key is cleared.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User types :smile] --> B[EmojiPickerViewModel\nmatches + selectedIndex]
    B --> C{matches empty?}
    C -- yes --> D[Content: 'Type to search'\nor 'No emoji found']
    C -- no --> E[ScrollView\nEmojiPickerRow list]
    D --> F[Footer: 'Keep typing to search']
    E --> G{acceptKeyLabel set?}
    G -- yes --> H[Footer: Press keycap to insert]
    G -- no --> I[Footer: Click an emoji to insert]

    B --> J[EmojiVariantResolver.resolve]
    J --> K[applyGender\ncollapses neutral/man/woman]
    K --> L[applySkinTone]
    L --> M{skinTone == neutral?}
    M -- yes --> N[return match unchanged]
    M -- no --> O[tonedMatch + match\nalways both]
Loading

Fix All in Codex Fix All in Claude Code

Reviews (2): Last reviewed commit: "Make People Emoji Style a swatch row mat..." | Re-trigger Greptile

Comment on lines +90 to +92
if model.matches.isEmpty {
Text("Keep typing to search")
} else if let acceptKeyLabel = model.acceptKeyLabel {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Footer copy contradicts "No emoji found" state

When the user has typed a query (e.g. :xyz) but no matches exist, the content area already shows "No emoji found". The footer unconditionally shows "Keep typing to search" in the entire matches.isEmpty branch, regardless of whether query is empty or not. A user who sees "No emoji found" above and "Keep typing to search" below gets conflicting signals — one suggests the search is done, the other suggests it might work with more input. Splitting on model.query.isEmpty would surface distinct, accurate messages for the "not started yet" vs "tried and found nothing" states.

Fix in Codex Fix in Claude Code

Replace the menu Picker with the same horizontal row of selectable emoji
swatches used for Skin Tone, so the two emoji-customization controls in
General match visually. Three swatches: person, man, woman, in
EmojiGender.allCases order.
@FuJacob FuJacob merged commit 5dc832c into main May 31, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant