New icon, preliminary clipboard functionality

This commit is contained in:
2024-11-01 17:15:56 +01:00
parent ec3e21d8cf
commit ff9d115306
12 changed files with 173 additions and 51 deletions
+6
View File
@@ -5,6 +5,8 @@
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:roundIcon="@drawable/icon_round"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:supportsRtl="true"
tools:targetApi="31">
@@ -12,6 +14,8 @@
android:name=".InputMethod"
android:directBootAware="true"
android:exported="false"
android:roundIcon="@drawable/icon_round"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
@@ -26,6 +30,8 @@
<activity
android:name=".PreferenceActivity"
android:exported="false"
android:roundIcon="@drawable/icon_round"
android:icon="@drawable/icon"
android:label="@string/preferences_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -25,21 +25,36 @@ import android.content.ClipboardManager;
import android.content.Context;
import android.os.Build;
import java.util.ArrayDeque;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class ClipboardHandler implements ClipboardManager.OnPrimaryClipChangedListener {
private final InputMethod mInputMethod;
private final ClipboardManager mClipboardManager;
private ClipData mCurrentClip;
private ArrayDeque<ClipData> mClips = new ArrayDeque<>();
public ClipboardHandler(Context ctx) {
mClipboardManager = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE);
public ClipboardHandler(Context context) {
mInputMethod = (InputMethod) context;
mClipboardManager = (ClipboardManager) mInputMethod.getSystemService(Context.CLIPBOARD_SERVICE);
mClipboardManager.addPrimaryClipChangedListener(this);
}
@Override
public void onPrimaryClipChanged() {
mCurrentClip = mClipboardManager.getPrimaryClip();
}
// The callback can be launched several times, so we have to check if it isn't the same
// clipboard data.
if (mClips.peekFirst() != null) {
if (mClips.peekFirst().equals(mClipboardManager.getPrimaryClip())) {
return;
}
}
public ClipData getCurrentClip() {
return mCurrentClip;
mClips.addFirst(mClipboardManager.getPrimaryClip());
if (mClips.size() > mInputMethod.mPreferenceHolder.getMaxClipboardItems()) {
mClips.removeLast();
}
mInputMethod.mInputView.setClips(mClips.toArray());
}
}
@@ -46,7 +46,7 @@ public class InputMethod extends InputMethodService {
public KeymapManager mKeymapManager;
public PreferenceHolder mPreferenceHolder;
private ClipboardHandler mClipboardHandler;
private InputView mInputView;
public InputView mInputView;
private int mCurrentCursorPosition;
private Handler mHandler;
private Cycler mSymbolCycler;
@@ -186,7 +186,7 @@ public class InputMethod extends InputMethodService {
@Override
public void onFirstCycle() {
mInputView.setSymbolsVisible(true);
mInputView.prepareSymbols((ArrayList<String>) getList());
mInputView.setSymbols((ArrayList<String>) getList());
getCurrentInputConnection().setSelection(mCurrentCursorPosition
- getElementAt(0).toString().length(), mCurrentCursorPosition);
}
@@ -19,6 +19,8 @@
package cfpi_fpsi.eu.titanboard;
import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.graphics.Paint;
@@ -31,6 +33,7 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayDeque;
import java.util.ArrayList;
// TODO: programmatically scroll if current selected symbol is outside the visible space of the
@@ -41,9 +44,8 @@ public class InputView extends RelativeLayout {
private final LinearLayout.LayoutParams mSymbolLayout;
private final LinearLayout.LayoutParams mCandidateLayout;
private LinearLayout mSymbolList;
private LinearLayout mCandidateList;
private LinearLayout mClipsList;
private Button mStateButton;
private Button mClipboardButton;
public InputView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
@@ -70,12 +72,8 @@ public class InputView extends RelativeLayout {
protected void onFinishInflate() {
super.onFinishInflate();
mSymbolList = findViewById(R.id.symbol_list);
mCandidateList = findViewById(R.id.candidate_list);
mClipsList = findViewById(R.id.clip_list);
mStateButton = findViewById(R.id.state_button);
mClipboardButton = (Button) inflate(this.getContext(), R.layout.candidate, null);
mClipboardButton.setTag(0);
mClipboardButton.setLayoutParams(mCandidateLayout);
mCandidateList.addView(mClipboardButton);
mStateButton.setOnClickListener(button -> {
MetaKeyManager metaManager = mInputMethod.mMetaKeyManager;
@@ -136,18 +134,30 @@ public class InputView extends RelativeLayout {
mStateButton.setText(keymapManager.getCurrentKeymap().getCode());
}
public void setSymbolsVisible(boolean state) {
findViewById(R.id.symbol_list_container).setVisibility(state ? VISIBLE : GONE);
findViewById(R.id.candidate_list_container).setVisibility(state ? GONE : VISIBLE);
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void setClips(Object[] clips) {
for (int i = 0; i < clips.length; ++i) {
Button b = (Button) mClipsList.getChildAt(i);
ClipData clip = (ClipData) clips[i];
if (b == null) {
b = (Button) inflate(this.getContext(), R.layout.candidate, null);
b.setTag(i);
b.setLayoutParams(mCandidateLayout);
mClipsList.addView(b);
}
ClipData.Item item = clip.getItemAt(0);
b.setText(item.coerceToText(this.getContext()).toString());
}
}
/**
* Prepares the CyclerView for the display of given strings, creating additional TextViews if
* necessary, and hiding unnecessary ones.
*
* @param strings the strings to be displayed in the CyclerView
*/
public void prepareSymbols(ArrayList<String> strings) {
public void setSymbolsVisible(boolean state) {
findViewById(R.id.symbol_list_container).setVisibility(state ? VISIBLE : GONE);
findViewById(R.id.clip_list_container).setVisibility(state ? GONE : VISIBLE);
}
public void setSymbols(ArrayList<String> strings) {
for (int i = 0; i < strings.size(); ++i) {
TextView tv = (TextView) mSymbolList.getChildAt(i);
@@ -67,6 +67,12 @@ public class PreferenceHolder implements SharedPreferences.OnSharedPreferenceCha
mContext.getString(R.string.cycle_speed_default)));
}
public int getMaxClipboardItems() {
return Integer.parseInt((String)
getOrDefault(mContext.getString(R.string.preferences_key_clipboard_max_items),
mContext.getString(R.string.clipboard_max_items_default)));
}
@SuppressWarnings("unchecked")
public ArrayList<String> getSelectedKeymaps() {
Set<String> selectedKeymaps = (Set<String>)
+49
View File
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for the Unihertz Titan/physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
~
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background-->
<item>
<shape android:shape="rectangle">
<solid android:color="#333" />
</shape>
</item>
<!-- The stem of the T-->
<item>
<inset android:insetLeft="40%"
android:insetRight="40%"
android:insetTop="25%"
android:insetBottom="20%">
<shape android:shape="rectangle">
<solid android:color="#FFF"/>
</shape>
</inset>
</item>
<!-- The top of the T-->
<item>
<inset android:insetLeft="20%"
android:insetRight="20%"
android:insetTop="25%"
android:insetBottom="65%">
<shape android:shape="rectangle">
<solid android:color="#FFF"/>
</shape>
</inset>
</item>
</layer-list>
+49
View File
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ An input method for the Unihertz Titan/physical keyboard phones
~ Copyright (C) 2024 Emil Kosz
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
~
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background-->
<item>
<shape android:shape="oval">
<solid android:color="#333" />
</shape>
</item>
<!-- The stem of the T-->
<item>
<inset android:insetLeft="40%"
android:insetRight="40%"
android:insetTop="25%"
android:insetBottom="20%">
<shape android:shape="rectangle">
<solid android:color="#FFF"/>
</shape>
</inset>
</item>
<!-- The top of the T-->
<item>
<inset android:insetLeft="20%"
android:insetRight="20%"
android:insetTop="25%"
android:insetBottom="65%">
<shape android:shape="rectangle">
<solid android:color="#FFF"/>
</shape>
</inset>
</item>
</layer-list>
+2 -2
View File
@@ -48,7 +48,7 @@
</HorizontalScrollView>
<HorizontalScrollView
android:id="@+id/candidate_list_container"
android:id="@+id/clip_list_container"
android:layout_width="match_parent"
android:layout_height="@dimen/container_height"
android:layout_alignTop="@id/state_button"
@@ -59,7 +59,7 @@
android:layout_toLeftOf="@id/state_button">
<LinearLayout
android:id="@+id/candidate_list"
android:id="@+id/clip_list"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" />
-2
View File
@@ -19,7 +19,6 @@
<resources>
<string-array name="preferences_keymap_labels">
<item>Test</item>
<item>English</item>
<item>German</item>
<item>French</item>
@@ -32,7 +31,6 @@
</string-array>
<string-array name="preferences_keymaps">
<item>tt</item>
<item>en</item>
<item>de</item>
<item>fr</item>
+3
View File
@@ -8,6 +8,7 @@
<string name="preferences_label_floating_interface">Floating interface</string>
<string name="preferences_label_cycle_speed">Cycling speed</string>
<string name="preferences_label_clipboard_max_items">Maximum clipboard items</string>
<string name="preferences_label_keymaps">Keymaps</string>
<string name="preferences_label_copyright_info">Copyleft 🄯 Emil Kosz, 2024. License: GPLv3</string>
@@ -22,7 +23,9 @@
<string name="preferences_key_floating_interface">floating_interface</string>
<string name="preferences_key_keymaps">selected_keymaps</string>
<string name="preferences_key_cycle_speed">cycle_speed</string>
<string name="preferences_key_clipboard_max_items">clipboard_items</string>
<string name="keymap_default">en</string>
<string name="cycle_speed_default">500</string>
<string name="clipboard_max_items_default">10</string>
</resources>
-21
View File
@@ -18,27 +18,6 @@
-->
<device-keymap-list>
<!-- Test keymap -->
<keymap
name="tt"
latched-name="Tt"
locked-name="TT">
<key code="29">
<base value="a" />
<base value="b" />
<base value="c" />
<base value="d" />
<base value="e" />
<base value="f" />
<base value="g" />
<base value="h" />
<base value="i" />
<base value="j" />
<base value="k" />
<base value="l" />
<base value="o" />
</key>
</keymap>
<!-- English -->
<keymap
name="en"
+7
View File
@@ -31,6 +31,13 @@
android:key="@string/preferences_key_cycle_speed"
android:summary="@string/preferences_summary_cycle_speed"
android:title="@string/preferences_label_cycle_speed" />
<EditTextPreference
android:defaultValue="@string/clipboard_max_items_default"
android:inputType="number|numberSigned"
android:key="@string/preferences_key_clipboard_max_items"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/preferences_label_clipboard_max_items" />
<MultiSelectListPreference
android:defaultValue="@array/preferences_keymap_defaults"
android:entries="@array/preferences_keymap_labels"