Files
DragonTCP/android/src/com/dragontcp/client/LogActivity.java
T
2026-08-16 16:10:38 -03:00

206 lines
7.3 KiB
Java

package com.dragontcp.client;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
public class LogActivity extends Activity {
private static final int BG = Color.rgb(11, 15, 20);
private static final int CARD = Color.rgb(22, 28, 36);
private static final int BORDER = Color.rgb(43, 53, 66);
private static final int TEXT = Color.rgb(244, 247, 251);
private static final int MUTED = Color.rgb(139, 151, 168);
private static final int LOG_BG = Color.rgb(7, 10, 14);
private static final int LOG_TEXT = Color.rgb(179, 194, 214);
private TextView logText;
private ScrollView logScroll;
private final AppLog.Listener logListener = line -> runOnUiThread(() -> appendLogLine(line));
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
forceDarkSystemUi();
buildUi();
}
@Override
protected void onStart() {
super.onStart();
logText.setText(AppLog.history());
AppLog.addListener(logListener);
logScroll.post(this::scrollLogToBottom);
}
@Override
protected void onStop() {
AppLog.removeListener(logListener);
super.onStop();
}
private void forceDarkSystemUi() {
Window w = getWindow();
w.setStatusBarColor(BG);
w.setNavigationBarColor(Color.rgb(7, 10, 14));
if (Build.VERSION.SDK_INT >= 26) w.getDecorView().setSystemUiVisibility(0);
}
private void buildUi() {
LinearLayout root = new LinearLayout(this);
root.setOrientation(LinearLayout.VERTICAL);
root.setBackgroundColor(BG);
root.setPadding(dp(16), dp(14), dp(16), dp(12));
LinearLayout header = new LinearLayout(this);
header.setOrientation(LinearLayout.HORIZONTAL);
header.setGravity(Gravity.CENTER_VERTICAL);
header.setPadding(dp(2), dp(2), dp(2), dp(12));
LinearLayout heading = new LinearLayout(this);
heading.setOrientation(LinearLayout.VERTICAL);
TextView title = text("Logs", 25, TEXT, true);
TextView subtitle = text("DragonTCP Lite", 12, MUTED, false);
subtitle.setPadding(0, dp(2), 0, 0);
heading.addView(title);
heading.addView(subtitle);
header.addView(heading, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f));
Button back = smallButton("BACK");
Button clear = smallButton("CLEAR");
LinearLayout.LayoutParams bp = new LinearLayout.LayoutParams(dp(76), dp(42));
bp.setMarginEnd(dp(8));
header.addView(back, bp);
header.addView(clear, new LinearLayout.LayoutParams(dp(82), dp(42)));
root.addView(header);
LinearLayout panel = new LinearLayout(this);
panel.setOrientation(LinearLayout.VERTICAL);
panel.setPadding(dp(10), dp(10), dp(10), dp(10));
panel.setBackground(roundRect(CARD, 16, BORDER, 1));
logScroll = new ScrollView(this);
logScroll.setFillViewport(true);
logScroll.setFocusable(false);
logScroll.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS);
logScroll.setBackground(roundRect(LOG_BG, 11, Color.rgb(30, 38, 49), 1));
logText = new TextView(this);
logText.setTextSize(12f);
logText.setTextColor(LOG_TEXT);
logText.setTypeface(Typeface.MONOSPACE);
logText.setTextIsSelectable(true);
logText.setPadding(dp(11), dp(10), dp(11), dp(10));
logText.setLineSpacing(0, 1.10f);
logScroll.addView(logText, new ScrollView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
panel.addView(logScroll, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
0,
1f
));
root.addView(panel, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
0,
1f
));
back.setOnClickListener(v -> finish());
clear.setOnClickListener(v -> {
AppLog.clear();
logText.setText("");
logScroll.scrollTo(0, 0);
});
setContentView(root);
applyInsets(root, dp(16), dp(14), dp(16), dp(12));
}
private void appendLogLine(String line) {
View child = logScroll.getChildAt(0);
int contentHeight = child == null ? 0 : child.getHeight();
int maxScroll = Math.max(0, contentHeight - logScroll.getHeight());
boolean follow = maxScroll - logScroll.getScrollY() < dp(48);
logText.append(line + "\n");
if (follow) logScroll.post(this::scrollLogToBottom);
}
private void scrollLogToBottom() {
View child = logScroll.getChildAt(0);
if (child == null) return;
int y = Math.max(0, child.getHeight() - logScroll.getHeight());
logScroll.scrollTo(0, y);
}
private TextView text(String value, float size, int color, boolean bold) {
TextView t = new TextView(this);
t.setText(value);
t.setTextSize(size);
t.setTextColor(color);
if (bold) t.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
return t;
}
private Button smallButton(String value) {
Button b = new Button(this);
b.setText(value);
b.setAllCaps(false);
b.setTextSize(11);
b.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
b.setTextColor(TEXT);
b.setBackground(roundRect(Color.rgb(32, 40, 51), 10, BORDER, 1));
return b;
}
private GradientDrawable roundRect(int color, int radiusDp, int strokeColor, int strokeDp) {
GradientDrawable d = new GradientDrawable();
d.setColor(color);
d.setCornerRadius(dp(radiusDp));
if (strokeDp > 0) d.setStroke(dp(strokeDp), strokeColor);
return d;
}
private int dp(int value) {
return Math.round(value * getResources().getDisplayMetrics().density);
}
/**
* Pads the root by the system bar insets. Required from API 35, where the
* activity is laid out edge to edge and would otherwise draw under the
* status and navigation bars.
*/
private void applyInsets(final View root, final int l, final int t, final int r, final int b) {
root.setOnApplyWindowInsetsListener((v, insets) -> {
int top, bottom, left, right;
if (Build.VERSION.SDK_INT >= 30) {
android.graphics.Insets bars = insets.getInsets(WindowInsets.Type.systemBars());
top = bars.top; bottom = bars.bottom; left = bars.left; right = bars.right;
} else {
top = insets.getSystemWindowInsetTop();
bottom = insets.getSystemWindowInsetBottom();
left = insets.getSystemWindowInsetLeft();
right = insets.getSystemWindowInsetRight();
}
v.setPadding(l + left, t + top, r + right, b + bottom);
return insets;
});
root.requestApplyInsets();
}
}