From 9c2c5d6f5fd8ee9ad0191ff4452bf28feb3eba61 Mon Sep 17 00:00:00 2001 From: wchino Date: Sun, 5 Apr 2026 22:29:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E5=8A=9F=E8=83=BD=20Activity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../smsmessage/Activity/BankEditActivity.java | 134 +++++++++++++++++ .../smsmessage/Activity/BankListActivity.java | 139 ++++++++++++++++++ .../Activity/ChangePasswordActivity.java | 108 ++++++++++++++ .../smsmessage/Activity/LoginActivity.java | 120 +++++++++++++++ .../Activity/PermissionActivity.java | 138 +++++++++++++++++ 5 files changed, 639 insertions(+) create mode 100644 app/src/main/java/com/miraclegarden/smsmessage/Activity/BankEditActivity.java create mode 100644 app/src/main/java/com/miraclegarden/smsmessage/Activity/BankListActivity.java create mode 100644 app/src/main/java/com/miraclegarden/smsmessage/Activity/ChangePasswordActivity.java create mode 100644 app/src/main/java/com/miraclegarden/smsmessage/Activity/LoginActivity.java create mode 100644 app/src/main/java/com/miraclegarden/smsmessage/Activity/PermissionActivity.java diff --git a/app/src/main/java/com/miraclegarden/smsmessage/Activity/BankEditActivity.java b/app/src/main/java/com/miraclegarden/smsmessage/Activity/BankEditActivity.java new file mode 100644 index 0000000..298d477 --- /dev/null +++ b/app/src/main/java/com/miraclegarden/smsmessage/Activity/BankEditActivity.java @@ -0,0 +1,134 @@ +package com.miraclegarden.smsmessage.Activity; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Toast; + +import androidx.annotation.Nullable; + +import com.miraclegarden.library.app.MiracleGardenActivity; +import com.miraclegarden.smsmessage.databinding.ActivityBankEditBinding; +import com.miraclegarden.smsmessage.model.ApiError; +import com.miraclegarden.smsmessage.model.BankInfo; +import com.miraclegarden.smsmessage.network.ApiService; +import com.miraclegarden.smsmessage.network.TokenManager; + +public class BankEditActivity extends MiracleGardenActivity { + + private ApiService apiService; + private TokenManager tokenManager; + private String bankId; + private boolean isEditMode = false; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + tokenManager = TokenManager.getInstance(this); + if (!tokenManager.isLoggedIn()) { + startActivity(new Intent(this, LoginActivity.class)); + finish(); + return; + } + + apiService = new ApiService(this); + + initData(); + initView(); + } + + private void initData() { + bankId = getIntent().getStringExtra("bank_id"); + isEditMode = bankId != null; + + if (isEditMode) { + binding.tvTitle.setText("编辑银行"); + binding.etBankName.setText(getIntent().getStringExtra("bank_name")); + binding.etAccount.setText(getIntent().getStringExtra("account")); + binding.etRemark.setText(getIntent().getStringExtra("remark")); + } else { + binding.tvTitle.setText("添加银行"); + } + } + + private void initView() { + String username = tokenManager.getUsername(); + if (username != null) { + binding.tvUsername.setText(username); + } + + binding.backIv.setOnClickListener(v -> finish()); + binding.btnSave.setOnClickListener(v -> attemptSave()); + } + + private void attemptSave() { + String bankName = binding.etBankName.getText().toString().trim(); + String account = binding.etAccount.getText().toString().trim(); + String remark = binding.etRemark.getText().toString().trim(); + + if (TextUtils.isEmpty(bankName)) { + binding.etBankName.setError("请输入银行名称"); + binding.etBankName.requestFocus(); + return; + } + + if (TextUtils.isEmpty(account)) { + binding.etAccount.setError("请输入账户"); + binding.etAccount.requestFocus(); + return; + } + + BankInfo bankInfo = new BankInfo(bankName, account, remark); + + showLoading(true); + + if (isEditMode) { + apiService.updateBank(bankId, bankInfo, new ApiService.ApiCallback() { + @Override + public void onSuccess(BankInfo result) { + runOnUiThread(() -> { + showLoading(false); + Toast.makeText(BankEditActivity.this, "修改成功", Toast.LENGTH_SHORT).show(); + finish(); + }); + } + + @Override + public void onError(ApiError error) { + runOnUiThread(() -> { + showLoading(false); + Toast.makeText(BankEditActivity.this, + "修改失败: " + error.getMessage(), Toast.LENGTH_LONG).show(); + }); + } + }); + } else { + apiService.createBank(bankInfo, new ApiService.ApiCallback() { + @Override + public void onSuccess(BankInfo result) { + runOnUiThread(() -> { + showLoading(false); + Toast.makeText(BankEditActivity.this, "添加成功", Toast.LENGTH_SHORT).show(); + finish(); + }); + } + + @Override + public void onError(ApiError error) { + runOnUiThread(() -> { + showLoading(false); + Toast.makeText(BankEditActivity.this, + "添加失败: " + error.getMessage(), Toast.LENGTH_LONG).show(); + }); + } + }); + } + } + + private void showLoading(boolean show) { + binding.progressBar.setVisibility(show ? View.VISIBLE : View.GONE); + binding.btnSave.setEnabled(!show); + } +} diff --git a/app/src/main/java/com/miraclegarden/smsmessage/Activity/BankListActivity.java b/app/src/main/java/com/miraclegarden/smsmessage/Activity/BankListActivity.java new file mode 100644 index 0000000..9393569 --- /dev/null +++ b/app/src/main/java/com/miraclegarden/smsmessage/Activity/BankListActivity.java @@ -0,0 +1,139 @@ +package com.miraclegarden.smsmessage.Activity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.miraclegarden.library.app.MiracleGardenActivity; +import com.miraclegarden.smsmessage.R; +import com.miraclegarden.smsmessage.comm.CommonAdapter; +import com.miraclegarden.smsmessage.comm.ViewHolder; +import com.miraclegarden.smsmessage.databinding.ActivityBankListBinding; +import com.miraclegarden.smsmessage.model.ApiError; +import com.miraclegarden.smsmessage.model.BankInfo; +import com.miraclegarden.smsmessage.network.ApiService; +import com.miraclegarden.smsmessage.network.TokenManager; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; + +public class BankListActivity extends MiracleGardenActivity { + + private ApiService apiService; + private TokenManager tokenManager; + private List bankList = new ArrayList<>(); + private CommonAdapter adapter; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + tokenManager = TokenManager.getInstance(this); + if (!tokenManager.isLoggedIn()) { + startActivity(new Intent(this, LoginActivity.class)); + finish(); + return; + } + + apiService = new ApiService(this); + + initView(); + loadBankList(); + } + + private void initView() { + String username = tokenManager.getUsername(); + if (username != null) { + binding.tvUsername.setText(username); + } + + binding.backIv.setOnClickListener(v -> finish()); + + binding.recyclerview.setLayoutManager(new LinearLayoutManager(this)); + adapter = new CommonAdapter(this, R.layout.item_bank, bankList) { + @Override + public void convert(ViewHolder holder, BankInfo bankInfo, int index) { + holder.setText(R.id.tv_bank_name, bankInfo.getBankName()); + holder.setText(R.id.tv_account, bankInfo.getAccount()); + + if (bankInfo.getRemark() != null && !bankInfo.getRemark().isEmpty()) { + holder.setText(R.id.tv_remark, bankInfo.getRemark()); + holder.getView(R.id.tv_remark).setVisibility(View.VISIBLE); + } else { + holder.getView(R.id.tv_remark).setVisibility(View.GONE); + } + + String createdAt = formatTime(bankInfo.getCreatedAt()); + String updatedAt = formatTime(bankInfo.getUpdatedAt()); + holder.setText(R.id.tv_created_at, "创建: " + createdAt); + holder.setText(R.id.tv_updated_at, "更新: " + updatedAt); + } + }; + binding.recyclerview.setAdapter(adapter); + } + + private String formatTime(String isoTime) { + if (isoTime == null || isoTime.isEmpty()) { + return "--"; + } + try { + SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()); + inputFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + Date date = inputFormat.parse(isoTime); + + SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()); + outputFormat.setTimeZone(TimeZone.getDefault()); + return outputFormat.format(date); + } catch (Exception e) { + return isoTime.substring(0, Math.min(16, isoTime.length())); + } + } + + private void loadBankList() { + binding.loadingLy.setVisibility(View.VISIBLE); + binding.emptyLy.setVisibility(View.GONE); + + apiService.getBankList(new ApiService.ApiCallback>() { + @Override + public void onSuccess(List result) { + runOnUiThread(() -> { + binding.loadingLy.setVisibility(View.GONE); + bankList.clear(); + if (result != null) { + bankList.addAll(result); + } + adapter.notifyDataSetChanged(); + + if (bankList.isEmpty()) { + binding.emptyLy.setVisibility(View.VISIBLE); + } else { + binding.emptyLy.setVisibility(View.GONE); + } + }); + } + + @Override + public void onError(ApiError error) { + runOnUiThread(() -> { + binding.loadingLy.setVisibility(View.GONE); + Toast.makeText(BankListActivity.this, + "加载失败: " + error.getMessage(), Toast.LENGTH_LONG).show(); + }); + } + }); + } + + @Override + protected void onResume() { + super.onResume(); + loadBankList(); + } +} diff --git a/app/src/main/java/com/miraclegarden/smsmessage/Activity/ChangePasswordActivity.java b/app/src/main/java/com/miraclegarden/smsmessage/Activity/ChangePasswordActivity.java new file mode 100644 index 0000000..05475b6 --- /dev/null +++ b/app/src/main/java/com/miraclegarden/smsmessage/Activity/ChangePasswordActivity.java @@ -0,0 +1,108 @@ +package com.miraclegarden.smsmessage.Activity; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Toast; + +import androidx.annotation.Nullable; + +import com.miraclegarden.library.app.MiracleGardenActivity; +import com.miraclegarden.smsmessage.databinding.ActivityChangePasswordBinding; +import com.miraclegarden.smsmessage.model.ApiError; +import com.miraclegarden.smsmessage.network.ApiService; +import com.miraclegarden.smsmessage.network.TokenManager; + +/** + * 修改密码页面(首登强制修改) + */ +public class ChangePasswordActivity extends MiracleGardenActivity { + + private ApiService apiService; + private TokenManager tokenManager; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + apiService = new ApiService(this); + tokenManager = TokenManager.getInstance(this); + + initView(); + } + + private void initView() { + binding.btnSubmit.setOnClickListener(v -> attemptChangePassword()); + } + + private void attemptChangePassword() { + String oldPassword = binding.etOldPassword.getText().toString().trim(); + String newPassword = binding.etNewPassword.getText().toString().trim(); + String confirmPassword = binding.etConfirmPassword.getText().toString().trim(); + + if (TextUtils.isEmpty(oldPassword)) { + binding.etOldPassword.setError("请输入旧密码"); + binding.etOldPassword.requestFocus(); + return; + } + + if (TextUtils.isEmpty(newPassword)) { + binding.etNewPassword.setError("请输入新密码"); + binding.etNewPassword.requestFocus(); + return; + } + + if (newPassword.length() < 6) { + binding.etNewPassword.setError("新密码至少6位"); + binding.etNewPassword.requestFocus(); + return; + } + + if (!newPassword.equals(confirmPassword)) { + binding.etConfirmPassword.setError("两次输入的密码不一致"); + binding.etConfirmPassword.requestFocus(); + return; + } + + showLoading(true); + + apiService.changePassword(oldPassword, newPassword, new ApiService.ApiCallback() { + @Override + public void onSuccess(Void result) { + runOnUiThread(() -> { + showLoading(false); + tokenManager.setFirstLoginComplete(); + Toast.makeText(ChangePasswordActivity.this, "密码修改成功", Toast.LENGTH_SHORT).show(); + navigateToMain(); + }); + } + + @Override + public void onError(ApiError error) { + runOnUiThread(() -> { + showLoading(false); + Toast.makeText(ChangePasswordActivity.this, + "修改失败: " + error.getMessage(), Toast.LENGTH_LONG).show(); + }); + } + }); + } + + private void showLoading(boolean show) { + binding.progressBar.setVisibility(show ? View.VISIBLE : View.GONE); + binding.btnSubmit.setEnabled(!show); + } + + private void navigateToMain() { + Intent intent = new Intent(this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finish(); + } + + @Override + public void onBackPressed() { + Toast.makeText(this, "请先修改密码", Toast.LENGTH_SHORT).show(); + } +} diff --git a/app/src/main/java/com/miraclegarden/smsmessage/Activity/LoginActivity.java b/app/src/main/java/com/miraclegarden/smsmessage/Activity/LoginActivity.java new file mode 100644 index 0000000..73edd5a --- /dev/null +++ b/app/src/main/java/com/miraclegarden/smsmessage/Activity/LoginActivity.java @@ -0,0 +1,120 @@ +package com.miraclegarden.smsmessage.Activity; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.Toast; + +import androidx.annotation.Nullable; + +import com.miraclegarden.library.app.MiracleGardenActivity; +import com.miraclegarden.smsmessage.databinding.ActivityLoginBinding; +import com.miraclegarden.smsmessage.model.ApiError; +import com.miraclegarden.smsmessage.model.LoginResponse; +import com.miraclegarden.smsmessage.network.ApiService; +import com.miraclegarden.smsmessage.network.TokenManager; + +/** + * 登录页面 + */ +public class LoginActivity extends MiracleGardenActivity { + + private ApiService apiService; + private TokenManager tokenManager; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + apiService = new ApiService(this); + tokenManager = TokenManager.getInstance(this); + + if (tokenManager.isLoggedIn()) { + navigateToMain(); + return; + } + + initView(); + } + + private void initView() { + binding.btnLogin.setOnClickListener(v -> attemptLogin()); + } + + private void attemptLogin() { + String username = binding.etUsername.getText().toString().trim(); + String password = binding.etPassword.getText().toString().trim(); + + if (TextUtils.isEmpty(username)) { + binding.etUsername.setError("请输入用户名"); + binding.etUsername.requestFocus(); + return; + } + + if (TextUtils.isEmpty(password)) { + binding.etPassword.setError("请输入密码"); + binding.etPassword.requestFocus(); + return; + } + + showLoading(true); + + apiService.login(username, password, new ApiService.ApiCallback() { + @Override + public void onSuccess(LoginResponse result) { + runOnUiThread(() -> { + showLoading(false); + tokenManager.saveLoginData(result); + + if (result.isFirstLogin()) { + navigateToChangePassword(); + } else { + Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); + navigateToMain(); + } + }); + } + + @Override + public void onError(ApiError error) { + runOnUiThread(() -> { + showLoading(false); + String msg; + switch (error.getStatusCode()) { + case 400: + msg = "用户名和密码不能为空"; + break; + case 401: + msg = "用户名或密码错误"; + break; + case 403: + msg = "账户已被停用,请联系管理员"; + break; + default: + msg = "登录失败: " + error.getMessage(); + } + Toast.makeText(LoginActivity.this, msg, Toast.LENGTH_LONG).show(); + }); + } + }); + } + + private void showLoading(boolean show) { + binding.progressBar.setVisibility(show ? View.VISIBLE : View.GONE); + binding.btnLogin.setEnabled(!show); + } + + private void navigateToMain() { + Intent intent = new Intent(this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finish(); + } + + private void navigateToChangePassword() { + Intent intent = new Intent(this, ChangePasswordActivity.class); + startActivity(intent); + finish(); + } +} diff --git a/app/src/main/java/com/miraclegarden/smsmessage/Activity/PermissionActivity.java b/app/src/main/java/com/miraclegarden/smsmessage/Activity/PermissionActivity.java new file mode 100644 index 0000000..34d9d10 --- /dev/null +++ b/app/src/main/java/com/miraclegarden/smsmessage/Activity/PermissionActivity.java @@ -0,0 +1,138 @@ +package com.miraclegarden.smsmessage.Activity; + +import android.Manifest; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.PowerManager; +import android.provider.Settings; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + +import com.miraclegarden.library.app.MiracleGardenActivity; +import com.miraclegarden.smsmessage.databinding.ActivityPermissionBinding; +import com.miraclegarden.smsmessage.network.TokenManager; +import com.miraclegarden.smsmessage.util.OEMBackgroundHelper; + +public class PermissionActivity extends MiracleGardenActivity { + + private TokenManager tokenManager; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + tokenManager = TokenManager.getInstance(this); + if (!tokenManager.isLoggedIn()) { + startActivity(new Intent(this, LoginActivity.class)); + finish(); + return; + } + + initView(); + } + + @Override + protected void onResume() { + super.onResume(); + updatePermissionStatus(); + } + + private void initView() { + String username = tokenManager.getUsername(); + if (username != null) { + binding.tvUsername.setText(username); + } + + binding.ivBack.setOnClickListener(v -> finish()); + + binding.layoutNotificationAccess.setOnClickListener(v -> { + startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)); + }); + + binding.layoutPostNotifications.setOnClickListener(v -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) + != android.content.pm.PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, 100); + } + } + }); + + binding.layoutBattery.setOnClickListener(v -> { + requestBatteryOptimization(); + }); + + binding.btnAutostart.setOnClickListener(v -> { + OEMBackgroundHelper.openAutoStartSettings(this); + }); + + binding.btnBatteryOptimization.setOnClickListener(v -> { + OEMBackgroundHelper.requestBatteryOptimizationExemption(this); + }); + + binding.tvDeviceBrand.setText("设备: " + OEMBackgroundHelper.getManufacturer()); + } + + private void updatePermissionStatus() { + boolean notificationAccessEnabled = isNotificationListenerEnabled(); + updatePermissionItem(binding.iconNotificationAccess, binding.statusNotificationAccess, + notificationAccessEnabled, notificationAccessEnabled ? "已授权" : "未授权"); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + boolean postNotificationsGranted = ContextCompat.checkSelfPermission(this, + Manifest.permission.POST_NOTIFICATIONS) == android.content.pm.PackageManager.PERMISSION_GRANTED; + updatePermissionItem(binding.iconPostNotifications, binding.statusPostNotifications, + postNotificationsGranted, postNotificationsGranted ? "已授权" : "未授权"); + binding.layoutPostNotifications.setVisibility(View.VISIBLE); + } else { + binding.layoutPostNotifications.setVisibility(View.GONE); + } + + boolean batteryOptimized = isBatteryOptimizationEnabled(); + updatePermissionItem(binding.iconBattery, binding.statusBattery, + !batteryOptimized, batteryOptimized ? "未授权" : "已授权"); + } + + private void updatePermissionItem(ImageView icon, TextView status, boolean granted, String statusText) { + if (granted) { + icon.setImageResource(android.R.drawable.checkbox_on_background); + icon.setColorFilter(ContextCompat.getColor(this, android.R.color.holo_green_dark)); + } else { + icon.setImageResource(android.R.drawable.ic_dialog_info); + icon.setColorFilter(ContextCompat.getColor(this, android.R.color.holo_red_dark)); + } + status.setText(statusText); + } + + private boolean isNotificationListenerEnabled() { + String flat = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners"); + return flat != null && flat.contains(getPackageName()); + } + + private boolean isBatteryOptimizationEnabled() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); + return pm != null && !pm.isIgnoringBatteryOptimizations(getPackageName()); + } + return false; + } + + private void requestBatteryOptimization() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + intent.setData(Uri.parse("package:" + getPackageName())); + startActivity(intent); + } catch (Exception e) { + startActivity(new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)); + } + } + } +}