use linear layout instead of tab host for emoji strip

This commit is contained in:
Helium314 2024-01-07 13:36:57 +01:00
parent f0410fd783
commit c80b92dbdc
5 changed files with 42 additions and 159 deletions

View file

@ -1,58 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
* modified
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
*/
package org.dslul.openboard.inputmethod.compat;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TabHost;
/*
* Custom version of {@link TabHost} that triggers its {@link TabHost.OnTabChangeListener} when
* a tab is reselected. It is hacky but it avoids importing material widgets lib.
* See https://github.com/aosp-mirror/platform_frameworks_base/blob/8551ec363dcd7c2d7c82c45e89db4922156766ab/core/java/android/widget/TabHost.java#L428
*/
public class TabHostCompat extends TabHost implements TabHost.OnTabChangeListener {
private boolean mFireOnTabChangeListenerOnReselection;
private OnTabChangeListener mOnTabChangeListener;
public TabHostCompat(Context context) {
super(context);
}
public TabHostCompat(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setOnTabChangedListener(OnTabChangeListener l) {
super.setOnTabChangedListener(l != null ? this : null);
mOnTabChangeListener = l;
}
@Override
public void setCurrentTab(int index) {
super.setCurrentTab(index);
if (index < 0 || index >= getTabWidget().getTabCount()) {
return;
}
if (mOnTabChangeListener != null) {
if (getCurrentTab() != index || mFireOnTabChangeListenerOnReselection) {
mOnTabChangeListener.onTabChanged(getCurrentTabTag());
}
}
}
@Override
public void onTabChanged(String s) {
// Ignored
}
public void setFireOnTabChangeListenerOnReselection(boolean whether) {
mFireOnTabChangeListenerOnReselection = whether;
}
}

View file

@ -31,7 +31,6 @@ import org.dslul.openboard.inputmethod.latin.LatinIME;
import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.RichInputMethodManager; import org.dslul.openboard.inputmethod.latin.RichInputMethodManager;
import org.dslul.openboard.inputmethod.latin.WordComposer; import org.dslul.openboard.inputmethod.latin.WordComposer;
import org.dslul.openboard.inputmethod.latin.define.ProductionFlags;
import org.dslul.openboard.inputmethod.latin.settings.Settings; import org.dslul.openboard.inputmethod.latin.settings.Settings;
import org.dslul.openboard.inputmethod.latin.settings.SettingsValues; import org.dslul.openboard.inputmethod.latin.settings.SettingsValues;
import org.dslul.openboard.inputmethod.latin.utils.CapsModeUtils; import org.dslul.openboard.inputmethod.latin.utils.CapsModeUtils;
@ -549,8 +548,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
} }
} }
public View onCreateInputView(@NonNull Context displayContext, @SuppressLint("InflateParams")
final boolean isHardwareAcceleratedDrawingEnabled) { public View onCreateInputView(@NonNull Context displayContext, final boolean isHardwareAcceleratedDrawingEnabled) {
if (mKeyboardView != null) { if (mKeyboardView != null) {
mKeyboardView.closing(); mKeyboardView.closing();
} }
@ -573,9 +572,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mEmojiTabStripView = mCurrentInputView.findViewById(R.id.emoji_tab_strip); mEmojiTabStripView = mCurrentInputView.findViewById(R.id.emoji_tab_strip);
mClipboardStripView = mCurrentInputView.findViewById(R.id.clipboard_strip); mClipboardStripView = mCurrentInputView.findViewById(R.id.clipboard_strip);
mSuggestionStripView = mCurrentInputView.findViewById(R.id.suggestion_strip_view); mSuggestionStripView = mCurrentInputView.findViewById(R.id.suggestion_strip_view);
// todo: try delaying, it's not needed at this point
// but when initializing right before showing, selected emoji category is not colored correctly
mEmojiPalettesView.initialize();
return mCurrentInputView; return mCurrentInputView;
} }

View file

@ -12,21 +12,17 @@ import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabWidget;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import org.dslul.openboard.inputmethod.compat.TabHostCompat;
import org.dslul.openboard.inputmethod.keyboard.Key; import org.dslul.openboard.inputmethod.keyboard.Key;
import org.dslul.openboard.inputmethod.keyboard.KeyboardActionListener; import org.dslul.openboard.inputmethod.keyboard.KeyboardActionListener;
import org.dslul.openboard.inputmethod.keyboard.KeyboardLayoutSet; import org.dslul.openboard.inputmethod.keyboard.KeyboardLayoutSet;
@ -61,8 +57,7 @@ import static org.dslul.openboard.inputmethod.latin.common.Constants.NOT_A_COORD
* Because of the above reasons, this class doesn't extend {@link KeyboardView}. * Because of the above reasons, this class doesn't extend {@link KeyboardView}.
*/ */
public final class EmojiPalettesView extends LinearLayout public final class EmojiPalettesView extends LinearLayout
implements OnTabChangeListener, View.OnClickListener, View.OnTouchListener, implements View.OnClickListener, View.OnTouchListener, OnKeyEventListener {
OnKeyEventListener {
private boolean initialized = false; private boolean initialized = false;
private final int mFunctionalKeyBackgroundId; private final int mFunctionalKeyBackgroundId;
private final Drawable mSpacebarBackground; private final Drawable mSpacebarBackground;
@ -81,7 +76,7 @@ public final class EmojiPalettesView extends LinearLayout
private View mSpacebar; private View mSpacebar;
// TODO: Remove this workaround. // TODO: Remove this workaround.
private View mSpacebarIcon; private View mSpacebarIcon;
private TabHostCompat mTabHost; private LinearLayout mTabStrip;
private RecyclerView mEmojiRecyclerView; private RecyclerView mEmojiRecyclerView;
private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView; private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView;
@ -123,7 +118,7 @@ public final class EmojiPalettesView extends LinearLayout
R.styleable.EmojiPalettesView_categoryIndicatorDrawable, 0); R.styleable.EmojiPalettesView_categoryIndicatorDrawable, 0);
mCategoryIndicatorBackgroundResId = emojiPalettesViewAttr.getResourceId( mCategoryIndicatorBackgroundResId = emojiPalettesViewAttr.getResourceId(
R.styleable.EmojiPalettesView_categoryIndicatorBackground, 0); R.styleable.EmojiPalettesView_categoryIndicatorBackground, 0);
mCategoryPageIndicatorColor = emojiPalettesViewAttr.getColor( mCategoryPageIndicatorColor = emojiPalettesViewAttr.getColor( // todo: remove this and related attr
R.styleable.EmojiPalettesView_categoryPageIndicatorColor, 0); R.styleable.EmojiPalettesView_categoryPageIndicatorColor, 0);
emojiPalettesViewAttr.recycle(); emojiPalettesViewAttr.recycle();
mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener(); mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener();
@ -142,30 +137,35 @@ public final class EmojiPalettesView extends LinearLayout
setMeasuredDimension(width, height); setMeasuredDimension(width, height);
} }
private void addTab(final TabHost host, final int categoryId) { // todo (maybe): bring back the holo indicator thing?
final String tabId = EmojiCategory.getCategoryName(categoryId, 0 /* categoryPageId */); // just some 2 dp high strip
final TabHost.TabSpec tspec = host.newTabSpec(tabId); // would probably need a vertical linear layout
tspec.setContent(R.id.emoji_keyboard_dummy); // better not, would complicate stuff again
final ImageView iconView = (ImageView) LayoutInflater.from(getContext()).inflate( // when decided to definitely not bring it back:
R.layout.emoji_keyboard_tab_icon, null); // remove mCategoryIndicatorEnabled, mCategoryIndicatorDrawableResId, mCategoryIndicatorBackgroundResId
// and the attrs categoryIndicatorDrawable, categoryIndicatorEnabled, categoryIndicatorBackground (and the connected drawables)
private void addTab(final LinearLayout host, final int categoryId) {
final ImageView iconView = new ImageView(getContext());
mColors.setBackground(iconView, ColorType.EMOJI_CATEGORY_BACKGROUND); mColors.setBackground(iconView, ColorType.EMOJI_CATEGORY_BACKGROUND);
mColors.setColor(iconView, ColorType.EMOJI_CATEGORY); mColors.setColor(iconView, ColorType.EMOJI_CATEGORY);
iconView.setScaleType(ImageView.ScaleType.CENTER);
iconView.setImageResource(mEmojiCategory.getCategoryTabIcon(categoryId)); iconView.setImageResource(mEmojiCategory.getCategoryTabIcon(categoryId));
iconView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId)); iconView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId));
tspec.setIndicator(iconView); iconView.setTag((long) categoryId); // use long for simple difference to int used for key codes
host.addTab(tspec); host.addView(iconView);
iconView.setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
iconView.setOnClickListener(this);
} }
public void initialize() { // needs to be delayed for access to EmojiTabStrip, which is not a child of this view public void initialize() { // needs to be delayed for access to EmojiTabStrip, which is not a child of this view
if (initialized) return; if (initialized) return;
mEmojiCategory.initialize(); mEmojiCategory.initialize();
mTabHost = KeyboardSwitcher.getInstance().getEmojiTabStrip().findViewById(R.id.emoji_category_tabhost); mTabStrip = (LinearLayout) KeyboardSwitcher.getInstance().getEmojiTabStrip();
mTabHost.setup();
for (final EmojiCategory.CategoryProperties properties : mEmojiCategory.getShownCategories()) { for (final EmojiCategory.CategoryProperties properties : mEmojiCategory.getShownCategories()) {
addTab(mTabHost, properties.mCategoryId); addTab(mTabStrip, properties.mCategoryId);
} }
mTabHost.setOnTabChangedListener(this); // mTabStrip.setOnTabChangedListener(this); // now onClickListener
final TabWidget tabWidget = mTabHost.getTabWidget(); /* final TabWidget tabWidget = mTabStrip.getTabWidget();
tabWidget.setStripEnabled(mCategoryIndicatorEnabled); tabWidget.setStripEnabled(mCategoryIndicatorEnabled);
if (mCategoryIndicatorEnabled) { if (mCategoryIndicatorEnabled) {
// On TabWidget's strip, what looks like an indicator is actually a background. // On TabWidget's strip, what looks like an indicator is actually a background.
@ -175,7 +175,7 @@ public final class EmojiPalettesView extends LinearLayout
tabWidget.setRightStripDrawable(mCategoryIndicatorBackgroundResId); tabWidget.setRightStripDrawable(mCategoryIndicatorBackgroundResId);
tabWidget.setBackgroundColor(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED)); tabWidget.setBackgroundColor(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED));
} }
*/
mEmojiPalettesAdapter = new EmojiPalettesAdapter(mEmojiCategory, this); mEmojiPalettesAdapter = new EmojiPalettesAdapter(mEmojiCategory, this);
mEmojiRecyclerView = findViewById(R.id.emoji_keyboard_list); mEmojiRecyclerView = findViewById(R.id.emoji_keyboard_list);
@ -214,12 +214,9 @@ public final class EmojiPalettesView extends LinearLayout
mEmojiLayoutParams.setEmojiListProperties(mEmojiRecyclerView); mEmojiLayoutParams.setEmojiListProperties(mEmojiRecyclerView);
mEmojiCategoryPageIndicatorView = findViewById(R.id.emoji_category_page_id_view); mEmojiCategoryPageIndicatorView = findViewById(R.id.emoji_category_page_id_view);
mEmojiCategoryPageIndicatorView.setColors(mCategoryPageIndicatorColor, mColors.get(ColorType.EMOJI_CATEGORY_BACKGROUND));
mEmojiLayoutParams.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView); mEmojiLayoutParams.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView);
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true); setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true);
// Enable reselection after the first setCurrentCategoryAndPageId() init call
mTabHost.setFireOnTabChangeListenerOnReselection(true);
// deleteKey depends only on OnTouchListener. // deleteKey depends only on OnTouchListener.
mDeleteKey = findViewById(R.id.key_delete); mDeleteKey = findViewById(R.id.key_delete);
@ -264,21 +261,6 @@ public final class EmojiPalettesView extends LinearLayout
return super.dispatchTouchEvent(ev); return super.dispatchTouchEvent(ev);
} }
@Override
public void onTabChanged(final String tabId) {
AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
Constants.CODE_UNSPECIFIED, this);
final int categoryId = mEmojiCategory.getCategoryId(tabId);
if (categoryId != mEmojiCategory.getCurrentCategoryId()) {
setCurrentCategoryAndPageId(categoryId, 0, false /* force */);
updateEmojiCategoryPageIdView();
}
if (mCurrentTab != null)
mColors.setColor(mCurrentTab, ColorType.EMOJI_CATEGORY);
mCurrentTab = (ImageView) mTabHost.getCurrentTabView();
mColors.setColor(mCurrentTab, ColorType.EMOJI_CATEGORY_SELECTED);
}
/** /**
* Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnTouchListener} * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnTouchListener}
* interface to handle touch events from View-based elements such as the space bar. * interface to handle touch events from View-based elements such as the space bar.
@ -311,6 +293,14 @@ public final class EmojiPalettesView extends LinearLayout
@Override @Override
public void onClick(View v) { public void onClick(View v) {
final Object tag = v.getTag(); final Object tag = v.getTag();
if (tag instanceof Long) {
AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(Constants.CODE_UNSPECIFIED, this);
final int categoryId = ((Long) tag).intValue();
if (categoryId != mEmojiCategory.getCurrentCategoryId()) {
setCurrentCategoryAndPageId(categoryId, 0, false);
updateEmojiCategoryPageIdView();
}
}
if (!(tag instanceof Integer)) { if (!(tag instanceof Integer)) {
return; return;
} }
@ -402,8 +392,7 @@ public final class EmojiPalettesView extends LinearLayout
mEmojiCategory.getCurrentCategoryPageId(), 0.0f); mEmojiCategory.getCurrentCategoryPageId(), 0.0f);
} }
private void setCurrentCategoryAndPageId(final int categoryId, final int categoryPageId, private void setCurrentCategoryAndPageId(final int categoryId, final int categoryPageId, final boolean force) {
final boolean force) {
final int oldCategoryId = mEmojiCategory.getCurrentCategoryId(); final int oldCategoryId = mEmojiCategory.getCurrentCategoryId();
final int oldCategoryPageId = mEmojiCategory.getCurrentCategoryPageId(); final int oldCategoryPageId = mEmojiCategory.getCurrentCategoryPageId();
@ -421,10 +410,13 @@ public final class EmojiPalettesView extends LinearLayout
mEmojiRecyclerView.scrollToPosition(categoryPageId); mEmojiRecyclerView.scrollToPosition(categoryPageId);
} }
final int newTabId = mEmojiCategory.getTabIdFromCategoryId(categoryId); final View old = mTabStrip.findViewWithTag((long) oldCategoryId);
if (force || mTabHost.getCurrentTab() != newTabId) { final View current = mTabStrip.findViewWithTag((long) categoryId);
mTabHost.setCurrentTab(newTabId);
} if (old instanceof ImageView)
Settings.getInstance().getCurrent().mColors.setColor((ImageView) old, ColorType.EMOJI_CATEGORY);
if (current instanceof ImageView)
Settings.getInstance().getCurrent().mColors.setColor((ImageView) current, ColorType.EMOJI_CATEGORY_SELECTED);
} }
private static class DeleteKeyOnTouchListener implements OnTouchListener { private static class DeleteKeyOnTouchListener implements OnTouchListener {

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 The Android Open Source Project
SPDX-License-Identifier: Apache-2.0
-->
<!-- Note: contentDescription will be added programatically in {@link EmojiPalettesView}. -->
<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
We just need to ignore the system's audio and haptic feedback settings. -->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dip"
android:layout_weight="1.0"
android:layout_height="wrap_content"
android:gravity="center"
android:scaleType="center"
android:contentDescription="@null"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
/>

View file

@ -23,35 +23,7 @@
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
style="?attr/suggestionStripViewStyle" style="?attr/suggestionStripViewStyle" />
>
<org.dslul.openboard.inputmethod.compat.TabHostCompat
android:id="@+id/emoji_category_tabhost"
android:layout_width="0dip"
android:layout_weight="87.5"
android:layout_height="match_parent"
>
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dip"
android:layout_height="0dip"
>
<!-- Empty placeholder that TabHost requires. But we don't use it to actually
display anything. We monitor the tab changes and change the ViewPager.
Similarly the ViewPager swipes are intercepted and passed to the TabHost. -->
<View
android:id="@+id/emoji_keyboard_dummy"
android:layout_width="0dip"
android:layout_height="0dip"
android:visibility="gone" />
</FrameLayout>
</org.dslul.openboard.inputmethod.compat.TabHostCompat>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/clipboard_strip" android:id="@+id/clipboard_strip"
android:orientation="horizontal" android:orientation="horizontal"