New icon, preliminary clipboard functionality
This commit is contained in:
@@ -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>)
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user