正在改造WinBoLL主机切换对话框与按钮。。。

This commit is contained in:
2026-01-22 21:19:39 +08:00
parent 5846784940
commit d20192cb36
8 changed files with 235 additions and 14 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jan 22 12:38:42 GMT 2026 #Thu Jan 22 13:18:42 GMT 2026
stageCount=7 stageCount=7
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.15 baseVersion=15.15
publishVersion=15.15.6 publishVersion=15.15.6
buildCount=11 buildCount=15
baseBetaVersion=15.15.7 baseBetaVersion=15.15.7

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jan 22 12:38:42 GMT 2026 #Thu Jan 22 13:18:03 GMT 2026
stageCount=7 stageCount=7
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.15 baseVersion=15.15
publishVersion=15.15.6 publishVersion=15.15.6
buildCount=11 buildCount=15
baseBetaVersion=15.15.7 baseBetaVersion=15.15.7

View File

@@ -2,6 +2,7 @@ package cc.winboll.studio.libappbase;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
@@ -26,6 +27,12 @@ public class GlobalApplication extends Application {
*/ */
private static volatile boolean isDebugging = false; private static volatile boolean isDebugging = false;
// 新增WinBoLL 服务器主机地址volatile 保证多线程可见性)
private static volatile String winbollHost = null;
// 新增SP 存储相关常量(私有存储,仅当前应用可访问)
private static final String SP_NAME = "WinBoLL_SP_CONFIG";
private static final String SP_KEY_WINBOLL_HOST = "winboll_host";
/** /**
* 获取全局 Application 单例实例(外部可通过此方法获取上下文) * 获取全局 Application 单例实例(外部可通过此方法获取上下文)
* @return GlobalApplication 单例(未初始化时返回 null需确保配置 AndroidManifest * @return GlobalApplication 单例(未初始化时返回 null需确保配置 AndroidManifest
@@ -76,6 +83,37 @@ public class GlobalApplication extends Application {
return isDebugging; return isDebugging;
} }
// 新增:设置 WinBoLL 服务器主机地址(同时保存到 SP 持久化)
public static void setWinbollHost(String host) {
if (sInstance == null) {
LogUtils.e(TAG, "setWinbollHost: 应用未初始化,设置失败");
return;
}
// 更新内存中的字段
winbollHost = host;
// 保存到 SP 持久化(私有模式,安全)
SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().putString(SP_KEY_WINBOLL_HOST, host).apply();
LogUtils.d(TAG, "setWinbollHost: 服务器地址已设置并持久化host=" + host);
}
// 新增:获取 WinBoLL 服务器主机地址(优先内存,内存为空则从 SP 读取)
public static String getWinbollHost() {
if (winbollHost != null) {
// 内存中存在,直接返回(提高效率)
return winbollHost;
}
if (sInstance == null) {
LogUtils.e(TAG, "getWinbollHost: 应用未初始化,获取失败");
return null;
}
// 内存中不存在,从 SP 读取并更新到内存
SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
winbollHost = sp.getString(SP_KEY_WINBOLL_HOST, null);
LogUtils.d(TAG, "getWinbollHost: 从 SP 读取服务器地址host=" + winbollHost);
return winbollHost;
}
/** /**
* 应用启动时初始化(仅执行一次) * 应用启动时初始化(仅执行一次)
* 初始化核心框架、恢复调试状态、配置全局异常处理等 * 初始化核心框架、恢复调试状态、配置全局异常处理等
@@ -86,11 +124,12 @@ public class GlobalApplication extends Application {
// 初始化单例实例(确保在所有初始化操作前完成) // 初始化单例实例(确保在所有初始化操作前完成)
sInstance = this; sInstance = this;
// 初始化基础组件日志、崩溃处理、Toast // 初始化基础组件日志、崩溃处理、Toast
initCoreComponents(); initCoreComponents();
// 恢复/初始化调试模式状态(从本地文件读取,无文件则默认关闭调试) // 恢复/初始化调试模式状态(从本地文件读取,无文件则默认关闭调试)
restoreDebugStatus(); restoreDebugStatus();
// 新增:初始化服务器地址(从 SP 读取到内存,提高后续访问效率)
initWinbollHost();
LogUtils.d(TAG, "GlobalApplication 初始化完成,单例实例已创建"); LogUtils.d(TAG, "GlobalApplication 初始化完成,单例实例已创建");
} }
@@ -131,6 +170,11 @@ public class GlobalApplication extends Application {
} }
} }
// 新增:初始化服务器地址(应用启动时从 SP 读取到内存)
private void initWinbollHost() {
getWinbollHost(); // 触发从 SP 读取并更新内存
}
/** /**
* 获取应用名称(从 AndroidManifest.xml 的 android:label 读取) * 获取应用名称(从 AndroidManifest.xml 的 android:label 读取)
* @param context 上下文(建议传入 Application 上下文,避免内存泄漏) * @param context 上下文(建议传入 Application 上下文,避免内存泄漏)
@@ -170,7 +214,6 @@ public class GlobalApplication extends Application {
// 释放单例引用(可选,避免内存泄漏风险) // 释放单例引用(可选,避免内存泄漏风险)
sInstance = null; sInstance = null;
LogUtils.d(TAG, "GlobalApplication 终止,单例实例已释放"); LogUtils.d(TAG, "GlobalApplication 终止,单例实例已释放");
} }
} }

View File

@@ -0,0 +1,99 @@
package cc.winboll.studio.libappbase.dialogs;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.R;
import cc.winboll.studio.libappbase.ToastUtils;
/**
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @Date 2026/01/22 20:59
* @Describe WinBoLL服务器地址设置对话框调试模式专用
*/
public class DebugHostDialog extends Dialog implements View.OnClickListener {
public static final String TAG = "DebugHostDialog";
private Context mContext;
private EditText etHostInput;
private Button btnConfirm;
private Button btnCancel;
// 构造方法(适配默认样式)
public DebugHostDialog(Context context) {
super(context, R.style.DialogStyle);
this.mContext = context;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_debug_host); // 绑定XML布局
setCancelable(true); // 点击外部可关闭
initView();
initData();
LogUtils.d(TAG, "DebugHostDialog 初始化完成");
}
// 初始化视图
private void initView() {
etHostInput = findViewById(R.id.et_host_input);
btnConfirm = findViewById(R.id.btn_confirm);
btnCancel = findViewById(R.id.btn_cancel);
// 绑定点击事件
btnConfirm.setOnClickListener(this);
btnCancel.setOnClickListener(this);
}
// 初始化数据(显示当前已保存的地址)
private void initData() {
String currentHost = GlobalApplication.getWinbollHost();
if (!TextUtils.isEmpty(currentHost)) {
etHostInput.setText(currentHost);
etHostInput.setSelection(currentHost.length()); // 光标定位到末尾
LogUtils.d(TAG, "当前已保存的服务器地址:" + currentHost);
}
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btn_confirm) {
handleConfirm(); // 确认设置
} else if (id == R.id.btn_cancel) {
dismiss(); // 取消对话框
}
}
// 处理确认设置逻辑
private void handleConfirm() {
String inputHost = etHostInput.getText().toString().trim();
if (TextUtils.isEmpty(inputHost)) {
ToastUtils.show("服务器地址不能为空");
LogUtils.w(TAG, "设置失败:地址为空");
return;
}
// 简单校验URL格式避免明显错误
if (!inputHost.startsWith("http://") && !inputHost.startsWith("https://")) {
ToastUtils.show("地址需以http://或https://开头");
LogUtils.w(TAG, "设置失败地址格式错误input=" + inputHost);
return;
}
// 保存地址到SP+内存
GlobalApplication.setWinbollHost(inputHost);
ToastUtils.show("服务器地址设置成功");
LogUtils.d(TAG, "服务器地址设置成功:" + inputHost);
dismiss(); // 关闭对话框
}
}

View File

@@ -116,7 +116,8 @@ public class AboutView extends LinearLayout {
// LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); // LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成");
// } // }
// 1. 新增视图绑定属性(加在原有视图属性后面) // 1. 新增视图绑定属性(加在原有视图属性后面)
private ImageButton ibSigngetdialog; private ImageButton ibSigngetDialog;
private ImageButton ibWinBoLLHostDialog;
// 2. 完善initViewFromXml方法新增按钮绑定 // 2. 完善initViewFromXml方法新增按钮绑定
private void initViewFromXml() { private void initViewFromXml() {
@@ -125,14 +126,15 @@ public class AboutView extends LinearLayout {
tvAppNameVersion = findViewById(R.id.tv_app_name_version); tvAppNameVersion = findViewById(R.id.tv_app_name_version);
tvAppDesc = findViewById(R.id.tv_app_desc); tvAppDesc = findViewById(R.id.tv_app_desc);
llFunctionContainer = findViewById(R.id.ll_function_container); llFunctionContainer = findViewById(R.id.ll_function_container);
ibSigngetdialog = findViewById(R.id.ib_signgetdialog); // 新增按钮绑定 ibSigngetDialog = findViewById(R.id.ib_signgetdialog); // 新增按钮绑定
ibWinBoLLHostDialog = findViewById(R.id.ib_winbollhostdialog); // 新增按钮绑定
setBtnClickListener(); // 新增绑定点击事件 setBtnClickListener(); // 新增绑定点击事件
LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成"); LogUtils.d(TAG, "initViewFromXml 布局加载+视图绑定完成");
} }
// 3. 新增按钮点击事件方法放在initViewFromXml下面即可 // 3. 新增按钮点击事件方法放在initViewFromXml下面即可
private void setBtnClickListener() { private void setBtnClickListener() {
ibSigngetdialog.setOnClickListener(new OnClickListener() { ibSigngetDialog.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d(TAG, "签名获取按钮点击弹出SignGetDialog"); LogUtils.d(TAG, "签名获取按钮点击弹出SignGetDialog");

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#ff000000"
android:pathData="M14,12H10V10H14M14,16H10V14H14M20,8H17.19C16.74,7.22 16.12,6.55 15.37,6.04L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.04,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6.04C7.88,6.55 7.26,7.22 6.81,8H4V10H6.09C6.04,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.04,15.67 6.09,16H4V18H6.81C7.85,19.79 9.78,21 12,21C14.22,21 16.15,19.79 17.19,18H20V16H17.91C17.96,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.96,10.33 17.91,10H20V8Z"/>
</vector>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:background="#FFFFFF">
<!-- 标题 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="设置服务器地址"
android:textSize="16sp"
android:textColor="#212121"
android:textStyle="bold"
android:layout_marginBottom="16dp"/>
<!-- 地址输入框 -->
<EditText
android:id="@+id/et_host_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入服务器地址如http://localhost:8080"
android:textSize="14sp"
android:inputType="textUri"
android:padding="8dp"
android:background="@android:drawable/edit_text"
android:layout_marginBottom="16dp"/>
<!-- 按钮容器 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="end">
<!-- 取消按钮 -->
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消"
android:textSize="14sp"
android:layout_marginRight="8dp"/>
<!-- 确认按钮 -->
<Button
android:id="@+id/btn_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确认"
android:textSize="14sp"
android:backgroundTint="#2196F3"
android:textColor="#FFFFFF"/>
</LinearLayout>
</LinearLayout>

View File

@@ -56,8 +56,14 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<ImageButton <ImageButton
android:layout_width="wrap_content" android:layout_width="80dp"
android:layout_height="wrap_content" android:layout_height="80dp"
android:src="@drawable/ic_home"
android:id="@+id/ib_winbollhostdialog"/>
<ImageButton
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ic_key" android:src="@drawable/ic_key"
android:id="@+id/ib_signgetdialog"/> android:id="@+id/ib_signgetdialog"/>