diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c2a9bd1..8db4785 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,6 +5,8 @@
@@ -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">
@@ -26,6 +30,8 @@
diff --git a/app/src/main/java/cfpi_fpsi/eu/titanboard/ClipboardHandler.java b/app/src/main/java/cfpi_fpsi/eu/titanboard/ClipboardHandler.java
index 3e5f036..104ccd1 100644
--- a/app/src/main/java/cfpi_fpsi/eu/titanboard/ClipboardHandler.java
+++ b/app/src/main/java/cfpi_fpsi/eu/titanboard/ClipboardHandler.java
@@ -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 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());
}
}
diff --git a/app/src/main/java/cfpi_fpsi/eu/titanboard/InputMethod.java b/app/src/main/java/cfpi_fpsi/eu/titanboard/InputMethod.java
index 81b1132..cc9c75b 100644
--- a/app/src/main/java/cfpi_fpsi/eu/titanboard/InputMethod.java
+++ b/app/src/main/java/cfpi_fpsi/eu/titanboard/InputMethod.java
@@ -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) getList());
+ mInputView.setSymbols((ArrayList) getList());
getCurrentInputConnection().setSelection(mCurrentCursorPosition
- getElementAt(0).toString().length(), mCurrentCursorPosition);
}
diff --git a/app/src/main/java/cfpi_fpsi/eu/titanboard/InputView.java b/app/src/main/java/cfpi_fpsi/eu/titanboard/InputView.java
index 34874f0..01e106e 100644
--- a/app/src/main/java/cfpi_fpsi/eu/titanboard/InputView.java
+++ b/app/src/main/java/cfpi_fpsi/eu/titanboard/InputView.java
@@ -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 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 strings) {
for (int i = 0; i < strings.size(); ++i) {
TextView tv = (TextView) mSymbolList.getChildAt(i);
diff --git a/app/src/main/java/cfpi_fpsi/eu/titanboard/PreferenceHolder.java b/app/src/main/java/cfpi_fpsi/eu/titanboard/PreferenceHolder.java
index 4098c74..e313c6a 100644
--- a/app/src/main/java/cfpi_fpsi/eu/titanboard/PreferenceHolder.java
+++ b/app/src/main/java/cfpi_fpsi/eu/titanboard/PreferenceHolder.java
@@ -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 getSelectedKeymaps() {
Set selectedKeymaps = (Set)
diff --git a/app/src/main/res/drawable/icon.xml b/app/src/main/res/drawable/icon.xml
new file mode 100644
index 0000000..efa76cb
--- /dev/null
+++ b/app/src/main/res/drawable/icon.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/icon_round.xml b/app/src/main/res/drawable/icon_round.xml
new file mode 100644
index 0000000..c75d4a6
--- /dev/null
+++ b/app/src/main/res/drawable/icon_round.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/input.xml b/app/src/main/res/layout/input.xml
index b8b1f38..ba75ffe 100644
--- a/app/src/main/res/layout/input.xml
+++ b/app/src/main/res/layout/input.xml
@@ -48,7 +48,7 @@
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 3243aae..f517acb 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -19,7 +19,6 @@
- - Test
- English
- German
- French
@@ -32,7 +31,6 @@
- - tt
- en
- de
- fr
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f448ee8..620e284 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -8,6 +8,7 @@
Floating interface
Cycling speed
+ Maximum clipboard items
Keymaps
Copyleft 🄯 Emil Kosz, 2024. License: GPLv3
@@ -22,7 +23,9 @@
floating_interface
selected_keymaps
cycle_speed
+ clipboard_items
en
500
+ 10
\ No newline at end of file
diff --git a/app/src/main/res/xml/keymaps_titan.xml b/app/src/main/res/xml/keymaps_titan.xml
index 76e84ab..22e7337 100644
--- a/app/src/main/res/xml/keymaps_titan.xml
+++ b/app/src/main/res/xml/keymaps_titan.xml
@@ -18,27 +18,6 @@
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+