[FEAT] 主控台 UI 全面翻新 (Console UI Overhaul)
1. MainActivity.java:重構按鈕點擊邏輯,改用 Lambda 取代匿名 Runnable;新增 activeLoginDialog 追蹤機制,登入成功後自動關閉對話框並呼叫 updateLoginStatus();新增頂部登入/登出狀態按鈕 (btnStatusAction) 切換邏輯。 2. activity_main.xml:全面翻新 UI 佈局,導入卡片式分組選單、現代化 Header 區塊(含 Logo、版本號、機台狀態)、功能按鈕網格排版,以及底部版權列。 3. colors.xml:建立完整 Material 3 色彩系統,包含 primary/secondary/surface/background 色階,以及 success/warning/error/info 四種語意狀態色;調整 black 為深灰 (#272727)。 4. dimens.xml:新增 welcome 標題、Header Logo、選單按鈕圖示及間距等全套尺寸規格變數。 5. 新增三個 Drawable 資源:bg_button_primary.xml (主要按鈕樣式)、bg_button_outline.xml (外框按鈕樣式)、bg_input_modern.xml (現代化輸入框背景)。 6. 新增 values-sw720dp/dimens.xml:針對 720dp 以上大螢幕(10吋機台)的適配尺寸規格。 7. 新增主控台各功能示意圖資源(drawable/*.png):binding_machine、card_reader_checkout、card_reader_reboot、cargo_lane_management、product_list、reboot_app、sales_page、scanner_test、system_settings、taiwan_star_tech_logo、view_log_records、vending_machine_scenario_v1/v2。 8. app/build.gradle:verPatch 從 1 升至 6,對應本次多功能迭代開發。 9. dialog_admin_login.xml:新增獨立的管理員登入對話框佈局。
@ -10,7 +10,7 @@ plugins {
|
||||
// =========================================================================
|
||||
def verMajor = 10
|
||||
def verMinor = 1
|
||||
def verPatch = 1
|
||||
def verPatch = 6
|
||||
|
||||
android {
|
||||
namespace 'com.unibuy.smartdevice'
|
||||
|
||||
@ -17,8 +17,11 @@ import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.graphics.Insets;
|
||||
@ -69,6 +72,8 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
return this.getClass();
|
||||
}
|
||||
|
||||
private AlertDialog activeLoginDialog;
|
||||
|
||||
@Override
|
||||
protected HandlerMain setHandlerMain() {
|
||||
return new ToastHandlerMain(getCtx(), getLogs()) {
|
||||
@ -76,6 +81,11 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
public void execute(Context context, int commandCode, String message) {
|
||||
super.execute(context, commandCode, message);
|
||||
if ("登入成功".equals(message)) {
|
||||
updateLoginStatus();
|
||||
if (activeLoginDialog != null && activeLoginDialog.isShowing()) {
|
||||
activeLoginDialog.dismiss();
|
||||
activeLoginDialog = null;
|
||||
}
|
||||
if (pendingAction != null) {
|
||||
pendingAction.run();
|
||||
pendingAction = null;
|
||||
@ -111,79 +121,66 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
// ---- 環境尺寸設定 ----
|
||||
|
||||
initialData();
|
||||
updateLoginStatus();
|
||||
|
||||
binding.btnStatusAction.setOnClickListener(v -> {
|
||||
if (MyApp.getInstance().getSuAccess().isEmpty()) {
|
||||
showLoginDialog(getCtx(), this::updateLoginStatus);
|
||||
} else {
|
||||
MyApp.getInstance().setSuAccess("");
|
||||
updateLoginStatus();
|
||||
Toast.makeText(getCtx(), "已登出後台權限", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
binding.buttonGotoSetting.setOnClickListener(v -> {
|
||||
pendingAction = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getTools().gotoActivity(SettingActivity.class);
|
||||
}
|
||||
};
|
||||
Runnable action = () -> getTools().gotoActivity(SettingActivity.class);
|
||||
if (!MyApp.getInstance().getMachine().getMachineID().isEmpty()) {
|
||||
if (MyApp.getInstance().getSuAccess().isEmpty()) {
|
||||
showLoginDialog(getCtx());
|
||||
showLoginDialog(getCtx(), action);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pendingAction.run();
|
||||
pendingAction = null;
|
||||
action.run();
|
||||
});
|
||||
|
||||
binding.buttonGotoSystemSet.setOnClickListener(v -> {
|
||||
pendingAction = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getTools().gotoActivity(SystemSetActivity.class);
|
||||
}
|
||||
};
|
||||
Runnable action = () -> getTools().gotoActivity(SystemSetActivity.class);
|
||||
if (MyApp.getInstance().getMachine().getMachineID().isEmpty()) {
|
||||
getHandlerMain().start("MainActivity", "@先綁定機器");
|
||||
return;
|
||||
}
|
||||
if (MyApp.getInstance().getSuAccess().isEmpty()) {
|
||||
showLoginDialog(getCtx());
|
||||
showLoginDialog(getCtx(), action);
|
||||
return;
|
||||
}
|
||||
pendingAction.run();
|
||||
pendingAction = null;
|
||||
action.run();
|
||||
});
|
||||
|
||||
binding.buttonGotoProductList.setOnClickListener(v -> {
|
||||
pendingAction = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getTools().gotoActivity(ProductListActivity.class);
|
||||
}
|
||||
};
|
||||
Runnable action = () -> getTools().gotoActivity(ProductListActivity.class);
|
||||
if (MyApp.getInstance().getMachine().getMachineID().isEmpty()) {
|
||||
getHandlerMain().start("MainActivity", "@先綁定機器");
|
||||
return;
|
||||
}
|
||||
if (MyApp.getInstance().getSuAccess().isEmpty()) {
|
||||
showLoginDialog(getCtx());
|
||||
showLoginDialog(getCtx(), action);
|
||||
return;
|
||||
}
|
||||
pendingAction.run();
|
||||
pendingAction = null;
|
||||
action.run();
|
||||
});
|
||||
|
||||
binding.buttonGotoSlotList.setOnClickListener(v -> {
|
||||
pendingAction = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getTools().gotoActivity(VmcSlotListActivity.class);
|
||||
}
|
||||
};
|
||||
Runnable action = () -> getTools().gotoActivity(VmcSlotListActivity.class);
|
||||
if (MyApp.getInstance().getMachine().getMachineID().isEmpty()) {
|
||||
getHandlerMain().start("MainActivity", "@先綁定機器");
|
||||
return;
|
||||
}
|
||||
if (MyApp.getInstance().getSuAccess().isEmpty()) {
|
||||
showLoginDialog(getCtx());
|
||||
showLoginDialog(getCtx(), action);
|
||||
return;
|
||||
}
|
||||
pendingAction.run();
|
||||
pendingAction = null;
|
||||
action.run();
|
||||
});
|
||||
|
||||
binding.buttonGotoShoppingPlatform.setOnClickListener(v -> {
|
||||
@ -247,17 +244,18 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
});
|
||||
|
||||
binding.buttonGotoXyshjTest.setOnClickListener(v -> {
|
||||
Runnable action = () -> getTools().gotoActivity(XyshjTestActivity.class);
|
||||
if (MyApp.getInstance().getMachine().getMachineID().isEmpty()) {
|
||||
getHandlerMain().start("MainActivity", "@先綁定機器");
|
||||
return;
|
||||
}
|
||||
|
||||
if (MyApp.getInstance().getSuAccess().isEmpty()) {
|
||||
showLoginDialog(getCtx());
|
||||
showLoginDialog(getCtx(), action);
|
||||
return;
|
||||
}
|
||||
|
||||
getTools().gotoActivity(XyshjTestActivity.class);
|
||||
action.run();
|
||||
});
|
||||
|
||||
binding.buttonresetapp.setOnClickListener(v -> {
|
||||
@ -265,12 +263,15 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
ReSetAPP();
|
||||
});
|
||||
|
||||
binding.buttonOpenSystemSettings.setOnClickListener(v -> {
|
||||
// 開啟 Android 系統設定
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
binding.buttonGotoAndroidSettings.setOnClickListener(v -> {
|
||||
try {
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(getCtx(), "無法開啟安卓設定頁", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static class ButtonQrCodeTestOnClick extends HandlerMainSchedulerOnClick {
|
||||
@ -476,10 +477,16 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
}
|
||||
|
||||
private void initialData() {
|
||||
if (MyApp.getInstance().getMachine() != null || MyApp.getInstance().getMachine().getMachineID().isEmpty()) {
|
||||
if (MyApp.getInstance().getMachine() != null && MyApp.getInstance().getMachine().getMachineID().isEmpty()) {
|
||||
SettingsDao settingsDao = new SettingsDao(this);
|
||||
SettingStructure setting = settingsDao.getOne(MyApp.getInstance().getMachine().getClass().getSimpleName());
|
||||
MyApp.getInstance().getMachine().setMachineID(setting.getData(1));
|
||||
if (setting != null && setting.getDataCount() >= 2) {
|
||||
MyApp.getInstance().getMachine().setApiKey(setting.getData(0));
|
||||
MyApp.getInstance().getMachine().setMachineID(setting.getData(1));
|
||||
if (setting.getDataCount() >= 3 && setting.getData(2) != null && !setting.getData(2).isEmpty()) {
|
||||
MyApp.getInstance().getMachine().setMqttEnv(setting.getData(2));
|
||||
}
|
||||
}
|
||||
settingsDao.close();
|
||||
}
|
||||
}
|
||||
@ -518,88 +525,94 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
}
|
||||
|
||||
public void showLoginDialog(Context context) {
|
||||
// 創建一個垂直的 LinearLayout
|
||||
LinearLayout layout = new LinearLayout(context);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
layout.setPadding(50, 20, 50, 10);
|
||||
showLoginDialog(context, null);
|
||||
}
|
||||
|
||||
// 帳號輸入框
|
||||
final EditText accessInput = new EditText(context);
|
||||
accessInput.setHint("帳號");
|
||||
layout.addView(accessInput);
|
||||
public void showLoginDialog(Context context, Runnable onSuccess) {
|
||||
// 使用 LayoutInflater 載入自訂佈局
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.dialog_admin_login, null);
|
||||
|
||||
final EditText accessInput = view.findViewById(R.id.etAccess);
|
||||
final EditText passwordInput = view.findViewById(R.id.etPassword);
|
||||
final CheckBox rememberAccountCb = view.findViewById(R.id.cbRemember);
|
||||
androidx.appcompat.widget.AppCompatButton positiveButton = view.findViewById(R.id.btnLogin);
|
||||
androidx.appcompat.widget.AppCompatButton negativeButton = view.findViewById(R.id.btnCancel);
|
||||
|
||||
getTools().setImmHideByFocusChange(accessInput);
|
||||
getTools().setImmOpenByFocusChange(accessInput);
|
||||
|
||||
// 密碼輸入框
|
||||
final EditText passwordInput = new EditText(context);
|
||||
passwordInput.setHint("密碼");
|
||||
passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
layout.addView(passwordInput);
|
||||
|
||||
getTools().setImmHideByFocusChange(passwordInput);
|
||||
|
||||
// 讀取紀錄的帳號
|
||||
android.content.SharedPreferences prefs = context.getSharedPreferences("LoginPrefs", Context.MODE_PRIVATE);
|
||||
String savedAccount = prefs.getString("saved_account", "");
|
||||
if (!savedAccount.isEmpty()) {
|
||||
accessInput.setText(savedAccount);
|
||||
}
|
||||
rememberAccountCb.setChecked(!savedAccount.isEmpty()); // 如果有存過帳號,預設打勾
|
||||
|
||||
// 建立對話框
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
.setTitle("登入")
|
||||
.setView(layout)
|
||||
.setPositiveButton("登入", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String access = accessInput.getText().toString().trim();
|
||||
String password = passwordInput.getText().toString().trim();
|
||||
.setView(view)
|
||||
.create();
|
||||
activeLoginDialog = dialog;
|
||||
|
||||
if (access.isEmpty() || password.isEmpty()) {
|
||||
Toast.makeText(context, "請輸入帳號和密碼", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(context, "正在驗證登入...", Toast.LENGTH_SHORT).show();
|
||||
starCloudAPI.login(access, password);
|
||||
}
|
||||
// 設定對話框視窗背景為透明,以便呈現圓角設計
|
||||
if (dialog.getWindow() != null) {
|
||||
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
||||
}
|
||||
|
||||
getTools().hideSystemBars((Activity) getCtx());
|
||||
}
|
||||
})
|
||||
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
getTools().hideSystemBars((Activity) getCtx());
|
||||
dialog.dismiss();
|
||||
}
|
||||
}).create();
|
||||
// 設定點擊事件
|
||||
positiveButton.setOnClickListener(v -> {
|
||||
String access = accessInput.getText().toString().trim();
|
||||
String password = passwordInput.getText().toString().trim();
|
||||
|
||||
// 🛠️ Debug Backdoor: 長按對話框標題 3 秒跳過登入
|
||||
dialog.setOnShowListener(d -> {
|
||||
int titleId = context.getResources().getIdentifier("alertTitle", "id", "android");
|
||||
View titleView = dialog.findViewById(titleId);
|
||||
if (titleView != null) {
|
||||
final Handler titleHandler = new Handler();
|
||||
final Runnable titleRunnable = () -> {
|
||||
Toast.makeText(context, "🛠️ Debug Mode: 跳過登入", Toast.LENGTH_SHORT).show();
|
||||
MyApp.getInstance().setSuAccess("DEBUG_MODE");
|
||||
if (pendingAction != null) {
|
||||
pendingAction.run();
|
||||
pendingAction = null;
|
||||
}
|
||||
dialog.dismiss();
|
||||
};
|
||||
|
||||
titleView.setOnTouchListener((v, event) -> {
|
||||
switch (event.getAction()) {
|
||||
case android.view.MotionEvent.ACTION_DOWN:
|
||||
titleHandler.postDelayed(titleRunnable, 2000); // 2秒
|
||||
break;
|
||||
case android.view.MotionEvent.ACTION_UP:
|
||||
case android.view.MotionEvent.ACTION_CANCEL:
|
||||
titleHandler.removeCallbacks(titleRunnable);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (access.isEmpty() || password.isEmpty()) {
|
||||
Toast.makeText(context, "請輸入帳號和密碼", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(context, "正在驗證登入...", Toast.LENGTH_SHORT).show();
|
||||
|
||||
// 為了處理 StarCloudAPI 登入成功後的回調
|
||||
// 我們重新設計 handlerMain 讓它能夠在 onSuccess 回調中跑 pendingAction
|
||||
pendingAction = onSuccess;
|
||||
starCloudAPI.login(access, password);
|
||||
|
||||
if (rememberAccountCb.isChecked()) {
|
||||
prefs.edit().putString("saved_account", access).apply();
|
||||
} else {
|
||||
prefs.edit().remove("saved_account").apply();
|
||||
}
|
||||
// 🛠️ 關鍵優化:不再此處立即 dismiss(),改由 API 回報成功時關閉
|
||||
}
|
||||
getTools().hideSystemBars((Activity) getCtx());
|
||||
});
|
||||
|
||||
negativeButton.setOnClickListener(v -> {
|
||||
getTools().hideSystemBars((Activity) getCtx());
|
||||
dialog.dismiss();
|
||||
activeLoginDialog = null;
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新右上角登入狀態顯示
|
||||
*/
|
||||
private void updateLoginStatus() {
|
||||
String suAccess = MyApp.getInstance().getSuAccess();
|
||||
if (suAccess.isEmpty()) {
|
||||
binding.tvWelcomeTitle.setText("歡迎使用 AAT\n智能販賣機系統");
|
||||
binding.tvWelcomeHint.setText("請點擊右上角登入帳號");
|
||||
binding.btnStatusAction.setText("登入");
|
||||
binding.btnStatusAction.setBackgroundTintList(android.content.res.ColorStateList.valueOf(getResources().getColor(R.color.primary)));
|
||||
} else {
|
||||
binding.tvWelcomeTitle.setText("歡迎使用 AAT\n" + suAccess);
|
||||
binding.tvWelcomeHint.setText("請點擊下方按鈕操作");
|
||||
binding.btnStatusAction.setText("登出");
|
||||
binding.btnStatusAction.setBackgroundTintList(android.content.res.ColorStateList.valueOf(getResources().getColor(R.color.error)));
|
||||
}
|
||||
}
|
||||
|
||||
private void enterShoppingPlatform() {
|
||||
MyApp.getInstance().setSuAccess("");
|
||||
getTools().gotoActivity(FontendActivity.class);
|
||||
@ -634,15 +647,15 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
super.onStart();
|
||||
|
||||
if (MyApp.getInstance().getMachine().getMachineID().isEmpty()) {
|
||||
binding.buttonGotoSystemSet.setVisibility(View.GONE);
|
||||
binding.buttonGotoProductList.setVisibility(View.GONE);
|
||||
binding.buttonGotoSlotList.setVisibility(View.GONE);
|
||||
binding.buttonGotoShoppingPlatform.setVisibility(View.GONE);
|
||||
binding.wrapButtonGotoSystemSet.setVisibility(View.GONE);
|
||||
binding.wrapButtonGotoProductList.setVisibility(View.GONE);
|
||||
binding.wrapButtonGotoSlotList.setVisibility(View.GONE);
|
||||
binding.wrapButtonGotoShoppingPlatform.setVisibility(View.GONE);
|
||||
} else {
|
||||
binding.buttonGotoSystemSet.setVisibility(View.VISIBLE);
|
||||
binding.buttonGotoProductList.setVisibility(View.VISIBLE);
|
||||
binding.buttonGotoSlotList.setVisibility(View.VISIBLE);
|
||||
binding.buttonGotoShoppingPlatform.setVisibility(View.VISIBLE);
|
||||
binding.wrapButtonGotoSystemSet.setVisibility(View.VISIBLE);
|
||||
binding.wrapButtonGotoProductList.setVisibility(View.VISIBLE);
|
||||
binding.wrapButtonGotoSlotList.setVisibility(View.VISIBLE);
|
||||
binding.wrapButtonGotoShoppingPlatform.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
app/src/main/res/drawable/bg_button_outline.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<!-- 背景透明 -->
|
||||
<solid android:color="@color/transparent" />
|
||||
<!-- 外框線設定 -->
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="@color/outline" />
|
||||
<!-- 圓角設定 (與輸入框 bg_input_modern 的 12dp 圓角一致) -->
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
||||
8
app/src/main/res/drawable/bg_button_primary.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<!-- 主色背景 -->
|
||||
<solid android:color="@color/primary" />
|
||||
<!-- 圓角設定 (與輸入框 bg_input_modern 的 12dp 圓角一致) -->
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
||||
11
app/src/main/res/drawable/bg_input_modern.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/surface" />
|
||||
<stroke android:width="1.5dp" android:color="@color/outlineVariant" />
|
||||
<corners android:radius="12dp" />
|
||||
<padding
|
||||
android:left="16dp"
|
||||
android:top="12dp"
|
||||
android:right="16dp"
|
||||
android:bottom="12dp" />
|
||||
</shape>
|
||||
BIN
app/src/main/res/drawable/binding_machine.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
app/src/main/res/drawable/card_reader_checkout.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
app/src/main/res/drawable/card_reader_reboot.png
Normal file
|
After Width: | Height: | Size: 162 KiB |
BIN
app/src/main/res/drawable/cargo_lane_management.png
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
app/src/main/res/drawable/product_list.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
app/src/main/res/drawable/reboot_app.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
app/src/main/res/drawable/sales_page.png
Normal file
|
After Width: | Height: | Size: 151 KiB |
BIN
app/src/main/res/drawable/scanner_test.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
app/src/main/res/drawable/system_settings.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
app/src/main/res/drawable/taiwan_star_tech_logo.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 3.8 MiB |
BIN
app/src/main/res/drawable/view_log_records.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
114
app/src/main/res/layout/dialog_admin_login.xml
Normal file
@ -0,0 +1,114 @@
|
||||
<?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="36dp"
|
||||
android:background="@color/surface">
|
||||
|
||||
<!-- 標題 -->
|
||||
<TextView
|
||||
android:id="@+id/tvTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="登入後台管理帳號"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/onSurface"
|
||||
android:layout_marginBottom="24dp" />
|
||||
|
||||
<!-- 帳號標籤 -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="管理員帳號"
|
||||
android:textSize="22sp"
|
||||
android:textColor="@color/onSurfaceVariant"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginStart="4dp" />
|
||||
|
||||
<!-- 帳號輸入框 -->
|
||||
<EditText
|
||||
android:id="@+id/etAccess"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="請輸入帳號"
|
||||
android:textSize="24sp"
|
||||
android:background="@drawable/bg_input_modern"
|
||||
android:singleLine="true"
|
||||
android:padding="16dp"
|
||||
android:layout_marginBottom="24dp" />
|
||||
|
||||
<!-- 密碼標籤 -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="管理員密碼"
|
||||
android:textSize="22sp"
|
||||
android:textColor="@color/onSurfaceVariant"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginStart="4dp" />
|
||||
|
||||
<!-- 密碼輸入框 -->
|
||||
<EditText
|
||||
android:id="@+id/etPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="請輸入密碼"
|
||||
android:textSize="24sp"
|
||||
android:background="@drawable/bg_input_modern"
|
||||
android:inputType="textPassword"
|
||||
android:singleLine="true"
|
||||
android:padding="16dp"
|
||||
android:layout_marginBottom="20dp" />
|
||||
|
||||
<!-- 記住帳號 -->
|
||||
<CheckBox
|
||||
android:id="@+id/cbRemember"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="記住帳號"
|
||||
android:textSize="22sp"
|
||||
android:textColor="@color/onSurfaceVariant"
|
||||
android:layout_marginBottom="28dp" />
|
||||
|
||||
<!-- 按鈕區塊 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- 取消按鈕 -->
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btnCancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_button_outline"
|
||||
android:text="取消"
|
||||
android:textSize="22sp"
|
||||
android:textColor="@color/outline"
|
||||
android:paddingStart="40dp"
|
||||
android:paddingEnd="40dp"
|
||||
android:paddingTop="14dp"
|
||||
android:paddingBottom="14dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:textAllCaps="false" />
|
||||
|
||||
<!-- 登入按鈕 -->
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btnLogin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_button_primary"
|
||||
android:text="登入"
|
||||
android:textSize="22sp"
|
||||
android:textColor="@color/white"
|
||||
android:paddingStart="40dp"
|
||||
android:paddingEnd="40dp"
|
||||
android:paddingTop="14dp"
|
||||
android:paddingBottom="14dp"
|
||||
android:textAllCaps="false" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
25
app/src/main/res/values-sw720dp/dimens.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Default screen margins for large screens -->
|
||||
<dimen name="activity_horizontal_margin">24dp</dimen>
|
||||
<dimen name="activity_vertical_margin">24dp</dimen>
|
||||
<dimen name="fab_margin">24dp</dimen>
|
||||
<dimen name="bottom_nav_icon_size">68dp</dimen>
|
||||
<dimen name="bottom_navigation_height">165dp</dimen>
|
||||
|
||||
<!-- 歡迎標題與登入區 (放大約 1.5 倍) -->
|
||||
<dimen name="welcome_title_text_size">26sp</dimen>
|
||||
<dimen name="welcome_hint_text_size">22sp</dimen>
|
||||
<dimen name="login_btn_text_size">28sp</dimen>
|
||||
<dimen name="header_logo_width">360dp</dimen>
|
||||
<dimen name="header_logo_height">255dp</dimen>
|
||||
|
||||
<!-- 群組標題 (放大約 1.5 倍) -->
|
||||
<dimen name="group_title_text_size">26sp</dimen>
|
||||
|
||||
<!-- 選單功能按鈕 (放大約 1.5 倍) -->
|
||||
<dimen name="menu_btn_text_size">26sp</dimen>
|
||||
<dimen name="menu_btn_icon_size">108dp</dimen>
|
||||
<dimen name="menu_btn_inset">12dp</dimen>
|
||||
<dimen name="menu_btn_corner_radius">24dp</dimen>
|
||||
</resources>
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="black">#272727</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="red">#FFFF0000</color>
|
||||
<color name="light_gray">#FFA9A9A9</color>
|
||||
@ -8,4 +8,57 @@
|
||||
<color name="transparent_black">#AA000000</color>
|
||||
<color name="transparent_white">#80FFFFFF</color>
|
||||
<color name="transparent">#00000000</color>
|
||||
|
||||
<!-- 全域系統色彩系統 (Material 3 標準色系 - 沉穩藍視角) -->
|
||||
<!-- Primary 主色 (#005DAD) -->
|
||||
<color name="primary">#005DAD</color>
|
||||
<color name="onPrimary">#FFFFFF</color>
|
||||
<color name="primaryContainer">#D1E4FF</color>
|
||||
<color name="onPrimaryContainer">#001D36</color>
|
||||
|
||||
<!-- Secondary 次色 (藍灰色調) -->
|
||||
<color name="secondary">#535F70</color>
|
||||
<color name="onSecondary">#FFFFFF</color>
|
||||
<color name="secondaryContainer">#D7E3F7</color>
|
||||
<color name="onSecondaryContainer">#101C2B</color>
|
||||
|
||||
<!-- Semantic: Success 成功狀態 -->
|
||||
<color name="success">#2E7D32</color>
|
||||
<color name="onSuccess">#FFFFFF</color>
|
||||
<color name="successContainer">#C8E6C9</color>
|
||||
<color name="onSuccessContainer">#003300</color>
|
||||
|
||||
<!-- Semantic: Warning 警告狀態 -->
|
||||
<color name="warning">#EF6C00</color>
|
||||
<color name="onWarning">#FFFFFF</color>
|
||||
<color name="warningContainer">#FFE0B2</color>
|
||||
<color name="onWarningContainer">#4A2600</color>
|
||||
|
||||
<!-- Semantic: Error / Dangerous 錯誤與危險狀態 -->
|
||||
<color name="error">#BA1A1A</color>
|
||||
<color name="onError">#FFFFFF</color>
|
||||
<color name="errorContainer">#FFDAD6</color>
|
||||
<color name="onErrorContainer">#410002</color>
|
||||
|
||||
<!-- Semantic: Info 提示狀態 -->
|
||||
<color name="info">#00639B</color>
|
||||
<color name="onInfo">#FFFFFF</color>
|
||||
<color name="infoContainer">#D1E4FF</color>
|
||||
<color name="onInfoContainer">#001D35</color>
|
||||
|
||||
<!-- Background & Surface 背景與表面 (調整為微冷調白) -->
|
||||
<color name="paperColor">#F5F7FA</color>
|
||||
|
||||
<color name="surface">#F8F9FF</color>
|
||||
<color name="onSurface">#191C1E</color>
|
||||
<color name="surfaceVariant">#DFE2EB</color>
|
||||
<color name="onSurfaceVariant">#43474E</color>
|
||||
|
||||
<color name="background">#F8F9FF</color>
|
||||
<color name="onBackground">#191C1E</color>
|
||||
|
||||
<!-- Outlines & Dividers 邊框與分隔線 -->
|
||||
<color name="outline">#73777F</color>
|
||||
<color name="outlineVariant">#C3C7CF</color>
|
||||
<color name="divider">#DFE2EB</color>
|
||||
</resources>
|
||||
@ -5,4 +5,20 @@
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
<dimen name="bottom_nav_icon_size">45dp</dimen>
|
||||
<dimen name="bottom_navigation_height">110dp</dimen>
|
||||
|
||||
<!-- 歡迎標題與登入區 -->
|
||||
<dimen name="welcome_title_text_size">18sp</dimen>
|
||||
<dimen name="welcome_hint_text_size">16sp</dimen>
|
||||
<dimen name="login_btn_text_size">20sp</dimen>
|
||||
<dimen name="header_logo_width">240dp</dimen>
|
||||
<dimen name="header_logo_height">170dp</dimen>
|
||||
|
||||
<!-- 群組標題 -->
|
||||
<dimen name="group_title_text_size">18sp</dimen>
|
||||
|
||||
<!-- 選單功能按鈕 -->
|
||||
<dimen name="menu_btn_text_size">18sp</dimen>
|
||||
<dimen name="menu_btn_icon_size">72dp</dimen>
|
||||
<dimen name="menu_btn_inset">8dp</dimen>
|
||||
<dimen name="menu_btn_corner_radius">16dp</dimen>
|
||||
</resources>
|
||||