Skip to content

Commit

Permalink
bug fixes. new icon. suggest recent content.
Browse files Browse the repository at this point in the history
setting now toggles suggestions.
  • Loading branch information
codokie committed Apr 9, 2024
1 parent 9987154 commit 7ce9d9f
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class ClipboardHistoryManager(

private lateinit var clipboardManager: ClipboardManager
private var onHistoryChangeListener: OnHistoryChangeListener? = null
private var recentEntry: String = ""
private var recentTimestamp: Long = 0L
private var suggestionPicked: Boolean = false;

fun onCreate() {
clipboardManager = latinIME.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
Expand Down Expand Up @@ -90,7 +93,9 @@ class ClipboardHistoryManager(
if (onHistoryChangeListener != null) {
onHistoryChangeListener?.onClipboardHistoryEntriesRemoved(pos, count)
}
latinIME.setNeutralSuggestionStrip() // get rid of any clipboard suggestion
if (latinIME.mSettings.current.mSuggestClipboardContent) {
latinIME.setNeutralSuggestionStrip() // get rid of any clipboard suggestion
}
}

fun canRemove(index: Int) = index in 0 until historyEntries.size && !historyEntries[index].isPinned
Expand Down Expand Up @@ -137,6 +142,27 @@ class ClipboardHistoryManager(
return clipData.getItemAt(0)?.coerceToText(latinIME) ?: ""
}

fun retrieveRecentClipboardContent(updateEntry: Boolean): String {
val maxClipRetentionTime: Long =
latinIME.mSettings.current.mClipboardHistoryRetentionTime * 60000L
val clipContent = retrieveClipboardContent().toString()
val now = System.currentTimeMillis()
val isNewEntry = recentEntry != clipContent
val isRecent = (now - recentTimestamp) < maxClipRetentionTime
return if (isNewEntry || isRecent && !suggestionPicked || maxClipRetentionTime == 0L) {
if (updateEntry && isNewEntry) {
suggestionPicked = false
recentEntry = clipContent
recentTimestamp = now
}
clipContent
} else "" // empty string indicating clipboard is empty, not recent
}

fun markSuggestionAsPicked() {
suggestionPicked = true
}

// pinned clips are stored in default shared preferences, not in device protected preferences!
private fun loadPinnedClips() {
val pinnedClipString = Settings.readPinnedClipString(latinIME)
Expand Down
46 changes: 29 additions & 17 deletions app/src/main/java/helium314/keyboard/latin/LatinIME.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import helium314.keyboard.latin.common.Constants;
import helium314.keyboard.latin.common.CoordinateUtils;
import helium314.keyboard.latin.common.InputPointers;
import helium314.keyboard.latin.common.StringUtilsKt;
import helium314.keyboard.latin.common.ViewOutlineProviderUtilsKt;
import helium314.keyboard.latin.define.DebugFlags;
import helium314.keyboard.latin.define.ProductionFlags;
Expand All @@ -78,6 +79,7 @@
import helium314.keyboard.latin.utils.ColorUtilKt;
import helium314.keyboard.latin.utils.InlineAutofillUtils;
import helium314.keyboard.latin.utils.InputMethodPickerKt;
import helium314.keyboard.latin.utils.InputTypeUtils;
import helium314.keyboard.latin.utils.JniUtils;
import helium314.keyboard.latin.utils.LeakGuardHandlerWrapper;
import helium314.keyboard.latin.utils.Log;
Expand Down Expand Up @@ -313,7 +315,9 @@ public void postResumeSuggestions(final boolean shouldDelay) {
if (latinIme == null) {
return;
}
if (!latinIme.mSettings.getCurrent().isSuggestionsEnabledPerUserSettings()) {
if (!latinIme.mSettings.getCurrent().isSuggestionsEnabledPerUserSettings()
&& (!latinIme.mSettings.getCurrent().mSuggestClipboardContent
|| latinIme.mClipboardHistoryManager.retrieveRecentClipboardContent(false).isEmpty())) {
return;
}
removeMessages(MSG_RESUME_SUGGESTIONS);
Expand Down Expand Up @@ -1020,8 +1024,9 @@ void onStartInputViewInternal(final EditorInfo editorInfo, final boolean restart
// Space state must be updated before calling updateShiftState
switcher.requestUpdatingShiftState(getCurrentAutoCapsState(), getCurrentRecapitalizeState());
}
if (mSuggestionStripView != null) {
mSuggestionStripView.refreshStripView();
// This will remove old "stuck" inline suggestions
if (hasSuggestionStripView()) {
mSuggestionStripView.setInlineSuggestionsView(null);
}
// This will set the punctuation suggestions if next word suggestion is off;
// otherwise it will clear the suggestion strip.
Expand Down Expand Up @@ -1586,10 +1591,8 @@ private void setSuggestedWords(final SuggestedWords suggestedWords) {
final boolean isEmptyApplicationSpecifiedCompletions =
currentSettingsValues.isApplicationSpecifiedCompletionsOn()
&& suggestedWords.isEmpty();
final boolean isClipboardSuggestion = (suggestedWords.size() == 1
&& suggestedWords.getInfo(0).isKindOf(SuggestedWordInfo.KIND_CLIPBOARD));
final boolean noSuggestionsFromDictionaries = suggestedWords.isEmpty()
|| isClipboardSuggestion
|| suggestedWords.isClipboardSuggestion()
|| suggestedWords.isPunctuationSuggestions()
|| isEmptyApplicationSpecifiedCompletions;

Expand Down Expand Up @@ -1638,29 +1641,38 @@ public void pickSuggestionManually(final SuggestedWordInfo suggestionInfo) {
updateStateAfterInputTransaction(completeInputTransaction);
}

// Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener}
// interface
@Override
public void onClipboardSuggestionRemoved(String clipContent){
if (mSettings.getCurrent().mClipboardHistoryEnabled) {
mClipboardHistoryManager.removeEntry(clipContent);
}
}

// This will show a suggestion of the primary clipboard if present.
@Override
public void onClipboardSuggestionPicked(){
mClipboardHistoryManager.markSuggestionAsPicked();
}

// This will show a suggestion of the primary clipboard
// if there is one and the setting is enabled.
// Otherwise, an empty suggestion strip (if prediction is enabled)
// or punctuation suggestions (if it's disabled) will be shown.
@Override
public void setNeutralSuggestionStrip() {
if (mSuggestionStripView != null && mSuggestionStripView.isInlineAutofillSuggestionsVisible()) return;
final SettingsValues currentSettings = mSettings.getCurrent();
final String clipContent = mClipboardHistoryManager.retrieveClipboardContent().toString();
if (!clipContent.isEmpty()) {
EditorInfo editorInfo = getCurrentInputEditorInfo();
int inputType = (editorInfo != null) ? editorInfo.inputType : InputType.TYPE_NULL;
setSuggestedWords(mInputLogic.getClipboardSuggestion(clipContent, inputType));
return;
if (currentSettings.mSuggestClipboardContent) {
final String clipContent = mClipboardHistoryManager.retrieveRecentClipboardContent(true);
if (!clipContent.isEmpty()) {
EditorInfo editorInfo = getCurrentInputEditorInfo();
int inputType = (editorInfo != null) ? editorInfo.inputType : InputType.TYPE_NULL;
// make sure content that is not a number is not suggested in a number input type
if (!InputTypeUtils.isNumberInputType(inputType) || StringUtilsKt.isValidNumber(clipContent)) {
setSuggestedWords(mInputLogic.getClipboardSuggestion(clipContent, inputType));
return;
}
}
}
else if (!currentSettings.mBigramPredictionEnabled) {
if (!currentSettings.mBigramPredictionEnabled) {
setSuggestedWords(currentSettings.mSpacingAndPunctuations.mSuggestPuncList);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ public boolean isPunctuationSuggestions() {
return false;
}

/**
* The predicator to tell whether this object represents a clipboard suggestion.
* @return false if this object doesn't represent a clipboard suggestion
*/
public boolean isClipboardSuggestion(){
return !isEmpty() && getInfo(0).isKindOf(SuggestedWordInfo.KIND_CLIPBOARD);
}

@Override
public String toString() {
// Pretty-print method to help debug
Expand Down
10 changes: 5 additions & 5 deletions app/src/main/java/helium314/keyboard/latin/common/Colors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
AUTOFILL_BACKGROUND_CHIP, GESTURE_PREVIEW, POPUP_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW -> adjustedBackground
TOOL_BAR_EXPAND_KEY_BACKGROUND -> if (!isNight) accent else doubleAdjustedBackground
GESTURE_TRAIL -> gesture
KEY_TEXT, SUGGESTION_AUTO_CORRECT, REMOVE_SUGGESTION_ICON,
KEY_TEXT, SUGGESTION_AUTO_CORRECT, SUGGESTION_ICONS,
KEY_ICON, ONE_HANDED_MODE_BUTTON, EMOJI_CATEGORY, TOOL_BAR_KEY, FUNCTIONAL_KEY_TEXT -> keyText
KEY_HINT_TEXT -> keyHintText
SPACE_BAR_TEXT -> spaceBarText
Expand Down Expand Up @@ -322,7 +322,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override

private fun getColorFilter(color: ColorType): ColorFilter? = when (color) {
EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter
REMOVE_SUGGESTION_ICON, EMOJI_CATEGORY, KEY_TEXT,
SUGGESTION_ICONS, EMOJI_CATEGORY, KEY_TEXT,
KEY_ICON, ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> keyTextFilter
KEY_PREVIEW -> adjustedBackgroundFilter
ACTION_KEY_ICON -> actionKeyIconColorFilter
Expand Down Expand Up @@ -468,7 +468,7 @@ class DefaultColors (
GESTURE_PREVIEW, POPUP_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW -> adjustedBackground
TOOL_BAR_EXPAND_KEY_BACKGROUND -> doubleAdjustedBackground
GESTURE_TRAIL -> gesture
KEY_TEXT, REMOVE_SUGGESTION_ICON, FUNCTIONAL_KEY_TEXT, KEY_ICON -> keyText
KEY_TEXT, SUGGESTION_ICONS, FUNCTIONAL_KEY_TEXT, KEY_ICON -> keyText
KEY_HINT_TEXT -> keyHintText
SPACE_BAR_TEXT -> spaceBarText
FUNCTIONAL_KEY_BACKGROUND -> functionalKey
Expand Down Expand Up @@ -539,7 +539,7 @@ class DefaultColors (
private fun getColorFilter(color: ColorType): ColorFilter? = when (color) {
EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter
KEY_TEXT, KEY_ICON -> keyTextFilter
REMOVE_SUGGESTION_ICON, EMOJI_CATEGORY, ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> suggestionTextFilter
SUGGESTION_ICONS, EMOJI_CATEGORY, ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> suggestionTextFilter
KEY_PREVIEW -> adjustedBackgroundFilter
ACTION_KEY_ICON -> actionKeyIconColorFilter
else -> colorFilter(get(color)) // create color filter (not great for performance, so the frequently used filters should be stored)
Expand Down Expand Up @@ -649,7 +649,7 @@ enum class ColorType {
SPACE_BAR_BACKGROUND,
SPACE_BAR_TEXT,
ONE_HANDED_MODE_BUTTON,
REMOVE_SUGGESTION_ICON,
SUGGESTION_ICONS,
STRIP_BACKGROUND,
SUGGESTED_WORD,
SUGGESTION_AUTO_CORRECT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ fun String.splitOnFirstSpacesOnly(): List<String> {
return out
}

fun String.isValidNumber(): Boolean {
return this.toDoubleOrNull() != null
}

fun isEmoji(c: Int): Boolean = mightBeEmoji(c) && isEmoji(newSingleCodePointString(c))

fun isEmoji(s: String): Boolean = mightBeEmoji(s) && s.matches(emoRegex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ final class SuggestionStripLayoutHelper {
private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2;
private static final int PUNCTUATIONS_IN_STRIP = 5;
private static final float MIN_TEXT_XSCALE = 0.70f;
private static final CharSequence CLIPBOARD_ICON = "\uD83D\uDCCB";
private static final CharSequence PASSWORD_MASK = "********";

public final int mPadding;
Expand Down Expand Up @@ -84,6 +83,8 @@ final class SuggestionStripLayoutHelper {
private final float mCenterSuggestionWeight;
private final int mCenterPositionInStrip;
private final int mTypedWordPositionWhenAutocorrect;
private final int mSuggestionTextPadding;
private final Drawable mClipboardIcon;
private final Drawable mMoreSuggestionsHint;
private static final String MORE_SUGGESTIONS_HINT = "…";

Expand Down Expand Up @@ -139,6 +140,11 @@ public SuggestionStripLayoutHelper(final Context context, final AttributeSet att
R.styleable.SuggestionStripView_minMoreSuggestionsWidth, 1.0f);
a.recycle();

final TypedArray keyboardAttr = context.obtainStyledAttributes(attrs, R.styleable.Keyboard, defStyle, R.style.SuggestionStripView);
mClipboardIcon = keyboardAttr.getDrawable(R.styleable.Keyboard_iconClipboardNormalKey);
keyboardAttr.recycle();

mSuggestionTextPadding = context.getResources().getDimensionPixelSize(R.dimen.config_suggestion_text_horizontal_padding);
mMoreSuggestionsHint = getMoreSuggestionsHint(res,
res.getDimension(R.dimen.config_more_suggestions_hint_text_size),
colorMoreSuggestionsHint);
Expand Down Expand Up @@ -193,15 +199,9 @@ private CharSequence getStyledSuggestedWord(final SuggestedWords suggestedWords,
return null;
}
final String word = suggestedWords.getLabel(indexInSuggestedWords);
if (!suggestedWords.isEmpty() && suggestedWords.getInfo(0).isKindOf(SuggestedWordInfo.KIND_CLIPBOARD)) {
// Replace the clipboard content with an icon if "Suggest clipboard content" setting is off
if (!Settings.getInstance().getCurrent().mSuggestClipboardContent)
return CLIPBOARD_ICON;
// If input type of the editor is that of a password, make sure the content is redacted
if (suggestedWords.mInputStyle == SuggestedWords.INPUT_STYLE_PASSWORD)
return TextUtils.concat(CLIPBOARD_ICON, "\t", PASSWORD_MASK);
// Otherwise, append clipboard icon and padding to the beginning of the content
return TextUtils.concat(CLIPBOARD_ICON, "\t", word);
// If input type of the editor is that of a password, make sure the content is redacted
if (suggestedWords.mInputStyle == SuggestedWords.INPUT_STYLE_PASSWORD) {
return PASSWORD_MASK;
}
// TODO: don't use the index to decide whether this is the auto-correction/typed word, as
// this is brittle
Expand Down Expand Up @@ -351,14 +351,27 @@ public int layoutAndReturnStartIndexOfMoreSuggestions(
final int stripWidth = stripView.getWidth();
final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, stripWidth);
if (wordCountToShow == 1 || getTextScaleX(centerWordView.getText(), centerWidth,
centerWordView.getPaint()) < MIN_TEXT_XSCALE) {
centerWordView.getPaint()) < MIN_TEXT_XSCALE || suggestedWords.isClipboardSuggestion()) {
// Layout only the most relevant suggested word at the center of the suggestion strip
// by consolidating all slots in the strip.
final int countInStrip = 1;
mMoreSuggestionsAvailable = (wordCountToShow > countInStrip);
layoutWord(context, mCenterPositionInStrip, stripWidth - mPadding);
final int layoutWidth;
final float layoutWeight;
if (suggestedWords.isClipboardSuggestion()) {
Settings.getInstance().getCurrent().mColors.setColor(mClipboardIcon, ColorType.SUGGESTION_ICONS);
centerWordView.setCompoundDrawablesWithIntrinsicBounds(mClipboardIcon, null, null, null);
centerWordView.setCompoundDrawablePadding(mSuggestionTextPadding);
centerWordView.setEllipsize(TextUtils.TruncateAt.END);
layoutWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutWeight = 0.0f;
} else {
layoutWidth = 0;
layoutWeight = 1.0f;
}
stripView.addView(centerWordView);
setLayoutWeight(centerWordView, 1.0f, ViewGroup.LayoutParams.MATCH_PARENT);
setLayoutWeightAndSize(centerWordView, layoutWeight, layoutWidth, ViewGroup.LayoutParams.MATCH_PARENT);
if (SuggestionStripView.DEBUG_SUGGESTIONS) {
layoutDebugInfo(mCenterPositionInStrip, placerView, stripWidth);
}
Expand All @@ -381,7 +394,7 @@ public int layoutAndReturnStartIndexOfMoreSuggestions(
final int width = getSuggestionWidth(positionInStrip, stripWidth);
final TextView wordView = layoutWord(context, positionInStrip, width);
stripView.addView(wordView);
setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), ViewGroup.LayoutParams.MATCH_PARENT);
setLayoutWeightAndSize(wordView, getSuggestionWeight(positionInStrip), 0, ViewGroup.LayoutParams.MATCH_PARENT);
x += wordView.getMeasuredWidth();

if (SuggestionStripView.DEBUG_SUGGESTIONS) {
Expand Down Expand Up @@ -522,17 +535,17 @@ private int layoutPunctuationsAndReturnStartIndexOfMoreSuggestions(
wordView.setCompoundDrawables(null, null, null, null);
wordView.setTextColor(mColorAutoCorrect);
stripView.addView(wordView);
setLayoutWeight(wordView, 1.0f, mSuggestionsStripHeight);
setLayoutWeightAndSize(wordView, 1.0f, 0, mSuggestionsStripHeight);
}
mMoreSuggestionsAvailable = (punctuationSuggestions.size() > countInStrip);
return countInStrip;
}

static void setLayoutWeight(final View v, final float weight, final int height) {
static void setLayoutWeightAndSize(final View v, final float weight, final int width, final int height) {
final ViewGroup.LayoutParams lp = v.getLayoutParams();
if (lp instanceof final LinearLayout.LayoutParams llp) {
llp.weight = weight;
llp.width = 0;
llp.width = width;
llp.height = height;
}
}
Expand Down
Loading

0 comments on commit 7ce9d9f

Please sign in to comment.