Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.widget.PopupWindow;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import com.atak.plugins.impl.PluginContextProvider;
import com.atak.plugins.impl.PluginLayoutInflater;
Expand Down Expand Up @@ -133,8 +134,8 @@ private void showPane() {
.setMetaValue(Pane.RELATIVE_LOCATION, Pane.Location.Default)
// pane will take up 50% of screen width in landscape mode
.setMetaValue(Pane.PREFERRED_WIDTH_RATIO, 0.5D)
// pane will take up 50% of screen height in portrait mode
.setMetaValue(Pane.PREFERRED_HEIGHT_RATIO, 0.5D)
// keep the panel close to its content height in landscape ATAK panes
.setMetaValue(Pane.PREFERRED_HEIGHT_RATIO, 0.35D)
.build();
}

Expand All @@ -149,12 +150,12 @@ private void wireChatControls(View teraView) {
final View infoButton = teraView.findViewById(R.id.tera_info);
final TextView connectionStatus = teraView.findViewById(R.id.tera_connection_status);
final ScrollView chatScroll = teraView.findViewById(R.id.tera_chat_scroll);
final TextView transcript = teraView.findViewById(R.id.tera_chat_transcript);
final LinearLayout transcript = teraView.findViewById(R.id.tera_chat_transcript);
final EditText chatInput = teraView.findViewById(R.id.tera_chat_input);
final View sendMessage = teraView.findViewById(R.id.tera_send_message);
final View voiceMessage = teraView.findViewById(R.id.tera_voice_message);
final View ttsToggle = teraView.findViewById(R.id.tera_tts_toggle);
final StringBuilder chatHistory = new StringBuilder();
final boolean[] hasMessages = new boolean[] { false };
final StringBuilder hostState = new StringBuilder();
final boolean[] ttsEnabled = new boolean[] { false };
final boolean[] listening = new boolean[] { false };
Expand Down Expand Up @@ -182,9 +183,7 @@ private void wireChatControls(View teraView) {
String endpoint = buildEndpoint(host);
JSONObject mapContext = buildMapContext();

appendChatLine(chatHistory, host.isEmpty() ? "Operator (local)" : "Operator (" + host + ")", message);
transcript.setText(chatHistory.toString());
scrollChatToBottom(chatScroll);
appendChatMessage(transcript, chatScroll, hasMessages, "Me", message, true);
chatInput.setText("");
sendMessage.setEnabled(false);
connectionStatus.setText(R.string.connection_connecting);
Expand All @@ -198,14 +197,9 @@ private void wireChatControls(View teraView) {
public void onComplete(boolean ok, String msg, JSONObject planJson) {
mainHandler.post(() -> {
sendMessage.setEnabled(true);
connectionStatus.setText(ok
? pluginContext.getString(R.string.connection_online)
: (msg.startsWith("Route signature invalid")
? "Route signature invalid - REJECTED"
: pluginContext.getString(R.string.connection_error)));
appendChatLine(chatHistory, ok ? "Agent" : "Error", msg);
transcript.setText(chatHistory.toString());
scrollChatToBottom(chatScroll);
connectionStatus.setText(statusForPlanResult(ok, msg));
appendChatMessage(transcript, chatScroll, hasMessages,
"TERA", msg, false);
if (ok && planJson != null) {
drawRoute(planJson);
}
Expand Down Expand Up @@ -554,6 +548,32 @@ private void drawRoute(JSONObject planJson) {
}
}

private String statusForPlanResult(boolean ok, String message) {
if (ok) {
return pluginContext.getString(R.string.connection_online);
}
if (message == null) {
return pluginContext.getString(R.string.connection_error);
}

String lower = message.toLowerCase(java.util.Locale.US);
if (message.startsWith("Route signature invalid")) {
return "Route signature invalid";
}
if (lower.contains("ollama")) {
return pluginContext.getString(R.string.connection_ollama_offline);
}
if (lower.contains("model providers failed") || lower.contains("model provider")) {
return pluginContext.getString(R.string.connection_model_offline);
}
if (lower.contains("health check") || lower.contains("cannot reach jetson")
|| lower.contains("jetson timed out") || lower.contains("socket")
|| lower.contains("unknownhost") || lower.contains("connectexception")) {
return pluginContext.getString(R.string.connection_error);
}
return pluginContext.getString(R.string.connection_model_error);
}

private JSONObject buildMapContext() {
try {
MapView mapView = MapView.getMapView();
Expand Down Expand Up @@ -670,10 +690,43 @@ private void scrollChatToBottom(ScrollView chatScroll) {
chatScroll.post(() -> chatScroll.fullScroll(View.FOCUS_DOWN));
}

private void appendChatLine(StringBuilder chatHistory, String sender, String message) {
if (chatHistory.length() > 0) {
chatHistory.append("\n\n");
private void appendChatMessage(LinearLayout transcript, ScrollView chatScroll,
boolean[] hasMessages, String sender,
String message, boolean outgoing) {
if (!hasMessages[0]) {
transcript.removeAllViews();
hasMessages[0] = true;
}
chatHistory.append(sender).append(": ").append(message);

LinearLayout row = new LinearLayout(pluginContext);
row.setOrientation(LinearLayout.VERTICAL);
row.setGravity(outgoing ? Gravity.RIGHT : Gravity.LEFT);
row.setPadding(0, dp(4), 0, dp(4));

TextView senderView = new TextView(pluginContext);
senderView.setText(sender);
senderView.setTextColor(Color.WHITE);
senderView.setTextSize(12);
senderView.setTypeface(null, android.graphics.Typeface.BOLD);
senderView.setGravity(outgoing ? Gravity.RIGHT : Gravity.LEFT);

TextView messageView = new TextView(pluginContext);
messageView.setText(message);
messageView.setTextColor(Color.WHITE);
messageView.setTextSize(13);
messageView.setGravity(outgoing ? Gravity.RIGHT : Gravity.LEFT);
messageView.setLineSpacing(dp(2), 1.0f);

row.addView(senderView, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
row.addView(messageView, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));

transcript.addView(row, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
scrollChatToBottom(chatScroll);
}
}
14 changes: 7 additions & 7 deletions atak/plugin/app/src/main/res/layout/main_layout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:orientation="vertical"
android:paddingLeft="11dp"
android:paddingTop="9dp"
android:paddingRight="11dp"
android:paddingBottom="11dp">
android:paddingBottom="6dp">

<TextView
android:layout_width="match_parent"
Expand Down Expand Up @@ -72,17 +72,17 @@
<ScrollView
android:id="@+id/tera_chat_scroll"
android:layout_width="match_parent"
android:layout_height="108dp"
android:layout_height="0dp"
android:layout_weight="1"
android:fadeScrollbars="false">

<TextView
<LinearLayout
android:id="@+id/tera_chat_transcript"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="top|start"
android:padding="5dp"
android:text="@string/chat_empty"
android:textSize="13sp" />
android:padding="5dp" />

</ScrollView>

Expand Down
3 changes: 3 additions & 0 deletions atak/plugin/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
<string name="connection_connecting">Connecting</string>
<string name="connection_online">Online</string>
<string name="connection_error">Connection error</string>
<string name="connection_model_error">Connected, model error</string>
<string name="connection_model_offline">Connected, model offline</string>
<string name="connection_ollama_offline">Connected, ollama offline</string>
<string name="model_local">local</string>
<string name="model_remote">remote</string>
<string name="model_hybrid">hybrid</string>
Expand Down
Loading