package com.example.suyzeko.fragment;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Handler;
import android.os.IBinder;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;
import com.example.suyzeko.MainActivity;
import com.example.suyzeko.activitys.ledPanel.sixRoads.DeviceDetailsActivity;
import com.example.suyzeko.activitys.ledPanel.twoRoads.PhototherapyBoardTwoActivity;
import com.example.suyzeko.R;
import com.example.suyzeko.SelectDeviceActivity;
import com.example.suyzeko.activitys.therapyHelmet.fourZones.TherapyHelmetFourActivity;
import com.example.suyzeko.activitys.therapyHelmet.nineteenZones.TherapyHelmetNineteenActivity;
import com.example.suyzeko.entity.Device;
import com.example.suyzeko.entity.DeviceClass;
import com.example.suyzeko.service.BluetoothService;
import com.example.suyzeko.utils.BannerAdapter;
import com.example.suyzeko.utils.DeviceUtils;
import com.example.suyzeko.utils.RetrofitAPI;
import com.example.suyzeko.utils.RetrofitClient;
import com.google.android.flexbox.FlexboxLayout;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class DashboardFragment extends Fragment{
private ViewPager2 viewPager;
private FlexboxLayout flexboxContainer;
private int buttonCount = 0;
private View maskView; // 遮罩层视图
private PopupWindow popupWindow;
private final Handler autoScrollHandler = new Handler();
private ImageButton btnAdd;
private TextView textView;
private BluetoothService bluetoothService; // 蓝牙后台服务实例
private final Runnable autoScrollRunnable = new Runnable() {
@Override
public void run() {
if (viewPager != null) {
int currentItem = viewPager.getCurrentItem();
viewPager.setCurrentItem(currentItem + 1, true);
autoScrollHandler.postDelayed(this, 3000); // 3秒切换一次
}
}
};
private boolean isBound = false;
private float flexBasisPercent = 0.4f;
private int buttonHeight = 90;
/**
* 服务连接回调
*/
private final ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
BluetoothService.LocalBinder binder = (BluetoothService.LocalBinder) service;
bluetoothService = binder.getService();
isBound = true;
registerReceivers(); // 注册广播接收器
} catch (SecurityException e) {
throw new RuntimeException(e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_dashboard, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (DeviceUtils.isTablet(requireActivity())) {
flexBasisPercent = 0.22f;
buttonHeight = 110;
} else {
// 手机设备
}
viewPager = view.findViewById(R.id.viewPager);
textView = view.findViewById(R.id.device_num);
// 示例图片列表
List<Integer> images = Arrays.asList(
R.drawable.ontc,
R.drawable.offtc
);
// 绑定服务
if (bluetoothService != null){
Intent intentBlue = new Intent(getActivity(), BluetoothService.class);
bluetoothService.bindService(intentBlue, connection, Context.BIND_AUTO_CREATE);
}
// 初始化适配器并绑定
BannerAdapter adapter = new BannerAdapter(images);
viewPager.setAdapter(adapter);
// 设置初始位置(从中间开始,支持向左滑动)
viewPager.setCurrentItem(Integer.MAX_VALUE / 2, false);
// 自动轮播
autoScrollHandler.postDelayed(autoScrollRunnable, 3000);
// 页面切换监听(可选)
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
// 可以在此处理指示器逻辑
}
});
flexboxContainer = view.findViewById(R.id.flexbox_container);
// 初始化检查:如果没有按钮,显示添加按钮
checkAndShowAddButton();
// 获取加号按钮
btnAdd = view.findViewById(R.id.add_image_button);
// 设置点击事件
btnAdd.setOnClickListener(this::showPopupMenu);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnJumpToActivityListener) {
onJumpToActivityListener = (OnJumpToActivityListener) context;
} else {
throw new RuntimeException("宿主 Activity 需实现 OnJumpToActivityListener");
}
}
@Override
public void onResume(){
super.onResume();
loadActivity();
updateConnectionStatus();
}
@Override
public void onDestroyView() {
super.onDestroyView();
autoScrollHandler.removeCallbacks(autoScrollRunnable); // 防止内存泄漏
// 确保 Fragment 销毁时移除遮罩
removeMask();
super.onDestroy();
}
/**
* 显示/隐藏"添加按钮"的逻辑
*/
private void checkAndShowAddButton() {
if (buttonCount == 0) {
// 创建"添加按钮"
Button addButton = new Button(requireContext());
addButton.setTextColor(Color.parseColor("#2A2A2A"));
addButton.setBackgroundResource(R.drawable.button_style); // 可自定义样式
addButton.setText(getString(R.string.add));
// 布局参数
FlexboxLayout.LayoutParams params = new FlexboxLayout.LayoutParams(
FlexboxLayout.LayoutParams.WRAP_CONTENT,
FlexboxLayout.LayoutParams.WRAP_CONTENT
);
params.setFlexBasisPercent(flexBasisPercent);
params.setHeight(dpToPx(buttonHeight));
params.setMargins(32, 16, 32, 16);
// 点击事件:开始添加普通按钮
addButton.setOnClickListener(v -> {
onJumpToActivityListener.jumpToActivityAndClose();// 跳转到搜索设备页面
// navigateToNewActivity();
});
buttonCount++;
flexboxContainer.addView(addButton, params);
}
}
private List<Device> deviceLists;
/**
* 添加动态按钮的方法
* @param deviceList
*/
public void addNewButton(List<Device> deviceList) {
for (Device device:deviceList){
int flag = 0;
if(deviceLists != null){
for (Device device1:deviceLists){
if (device1.getDeviceMac().equals(device.getDeviceMac())) {
flag = 1;
break;
}
}
}
if (flag == 1){
continue;
}
buttonCount++;
DeviceClass deviceTypeResources = getDeviceTypeResources(device.getDeviceClassCode());
Button newButton = new Button(requireContext());
newButton.setTag(device);
newButton.post(() -> {
// 获取按钮实际宽高(单位:像素)
int buttonWidth = newButton.getWidth();
int buttonHeight = newButton.getHeight();
// 动态计算文字大小(示例:按钮宽度的 1/6)
float textSizePx = buttonWidth / 20f;
// 转换为 sp 单位(更符合用户习惯)
float textSizeSp = pxToSp(textSizePx);
// 设置文字大小
newButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeSp);
});
// 创建状态图标层叠Drawable
Drawable statusIcon = createStatusIcon(device);
newButton.setText(device.getDeviceName());
// 获取设备类型对应的图标资源
Drawable icon = ContextCompat.getDrawable(requireContext(), deviceTypeResources.getIconRes());
// 计算按钮实际高度(从布局参数获取)
int buttonHeightPx = dpToPx(buttonHeight); // 需与布局中params.setHeight(dpToPx(90))一致
// 设置图标尺寸为按钮高度的60%(按需调整比例)
int iconSize = (int) (buttonHeightPx * 0.6);
if (icon != null) {
// 保持图标宽高比
float aspectRatio = (float) icon.getIntrinsicWidth() / icon.getIntrinsicHeight();
int scaledWidth = (int) (iconSize * aspectRatio);
icon.setBounds(0, 0, scaledWidth, iconSize); // 设置绘制区域
}
// 设置图标到按钮左侧
newButton.setCompoundDrawables(statusIcon, icon, null, null);
newButton.setCompoundDrawablePadding(8);
newButton.setBackgroundResource(R.drawable.button_style);
newButton.setTextColor(Color.parseColor("#2A2A2A"));
// 布局参数(与之前相同)
FlexboxLayout.LayoutParams params = new FlexboxLayout.LayoutParams(
FlexboxLayout.LayoutParams.WRAP_CONTENT,
FlexboxLayout.LayoutParams.WRAP_CONTENT
);
params.setFlexBasisPercent(flexBasisPercent);
params.setHeight(dpToPx(buttonHeight));
params.setMargins(32, 16, 32, 16);
// 点击事件
newButton.setOnClickListener(v -> {
if (bluetoothService != null && bluetoothService.getConnectedDevice() != null){
if(device.getDeviceMac().equals(bluetoothService.getMACAddress())){
navigateToNewDeviceDetailsActivity(device);
}else {
new AlertDialog.Builder(getContext())
.setTitle("Device not connected")
.setMessage("Do you want to redirect to the device connection page")
// 确认按钮
.setPositiveButton(getString(R.string.OK), (dialog, which) -> {
onJumpToActivityListener.jumpToActivityAndClose(); // 跳转到搜索设备页面
})
// 取消按钮
.setNegativeButton(getString(R.string.Cancel), (dialog, which) -> {
dialog.dismiss();
})
.show();
}
}else {
new AlertDialog.Builder(getContext())
.setTitle("Device not connected")
.setMessage("Do you want to redirect to the device connection page")
// 确认按钮
.setPositiveButton(getString(R.string.OK), (dialog, which) -> {
onJumpToActivityListener.jumpToActivityAndClose(); // 跳转到搜索设备页面
})
// 取消按钮
.setNegativeButton(getString(R.string.Cancel), (dialog, which) -> {
dialog.dismiss();
})
.show();
}
});
// // 长按删除(增加删除后的检查)
// newButton.setOnLongClickListener(v -> {
// flexboxContainer.removeView(v);
// buttonCount--;
// checkAndShowAddButton(); // 删除后检查是否需要恢复"添加按钮"
// return true;
// });
// 将新按钮添加到第一个
flexboxContainer.addView(newButton, 0, params);
// --- 关键修改:强制刷新父容器和滚动视图 ---
flexboxContainer.post(new Runnable() {
@Override
public void run() {
flexboxContainer.requestLayout();
// 触发 NestedScrollView 重新计算滚动范围
ViewParent parent = flexboxContainer.getParent();
if (parent instanceof ViewGroup) {
((ViewGroup) parent).requestLayout();
}
}
});
}
textView.setText(String.valueOf(buttonCount-1));
}
public void updateConnectionStatus() {
for (int i = 0; i < flexboxContainer.getChildCount() - 1; i++) {
View view = flexboxContainer.getChildAt(i);
if (view instanceof Button) {
Button btn = (Button) view;
Device device = (Device) btn.getTag();
Drawable newStatus = createStatusIcon(device);
DeviceClass deviceTypeResources = getDeviceTypeResources(device.getDeviceClassCode());
// 获取设备类型对应的图标资源
Drawable icon = ContextCompat.getDrawable(requireContext(), deviceTypeResources.getIconRes());
// 计算按钮实际高度(从布局参数获取)
int buttonHeightPx = dpToPx(buttonHeight);
// 设置图标尺寸为按钮高度的60%(按需调整比例)
int iconSize = (int) (buttonHeightPx * 0.6);
if (icon != null) {
// 保持图标宽高比
float aspectRatio = (float) icon.getIntrinsicWidth() / icon.getIntrinsicHeight();
int scaledWidth = (int) (iconSize * aspectRatio);
icon.setBounds(0, 0, scaledWidth, iconSize); // 设置绘制区域
}
// 设置图标到按钮左侧
btn.setCompoundDrawables(newStatus, icon, null, null);
btn.postInvalidate(); // 线程安全刷新
}
}
}
public void updateUnConnectionStatus() {
for (int i = 0; i < flexboxContainer.getChildCount() - 1; i++) {
View view = flexboxContainer.getChildAt(i);
if (view instanceof Button) {
Button btn = (Button) view;
Device device = (Device) btn.getTag();
if(bluetoothService!= null && device.getDeviceMac().equals(bluetoothService.getMACAddress())){
bluetoothService.disconnect();
Drawable newStatus = createStatusIcon(device);
DeviceClass deviceTypeResources = getDeviceTypeResources(device.getDeviceClassCode());
// 获取设备类型对应的图标资源
Drawable icon = ContextCompat.getDrawable(requireContext(), deviceTypeResources.getIconRes());
// 计算按钮实际高度(从布局参数获取)
int buttonHeightPx = dpToPx(buttonHeight);
// 设置图标尺寸为按钮高度的60%(按需调整比例)
int iconSize = (int) (buttonHeightPx * 0.6);
if (icon != null) {
// 保持图标宽高比
float aspectRatio = (float) icon.getIntrinsicWidth() / icon.getIntrinsicHeight();
int scaledWidth = (int) (iconSize * aspectRatio);
icon.setBounds(0, 0, scaledWidth, iconSize); // 设置绘制区域
}
// 设置图标到按钮左侧
btn.setCompoundDrawables(newStatus, icon, null, null);
btn.postInvalidate(); // 线程安全刷新
}
}
}
}
private Drawable createStatusIcon(Device device) {
// 获取状态图标资源
int statusRes = isDeviceConnected(device) ?
R.drawable.ic_connected_green_round : R.drawable.ic_disconnected_hui_round;
// 创建缩放后的状态图标
Drawable statusIcon = ContextCompat.getDrawable(requireContext(), statusRes);
int statusSize = dpToPx(12); // 状态图标尺寸
if (statusIcon != null) {
statusIcon.setBounds(0, 0, statusSize, statusSize);
}
return statusIcon;
}
private boolean isDeviceConnected(Device device) {
return bluetoothService != null &&
bluetoothService.getConnectedDevice() != null &&
device.getDeviceMac().equals(bluetoothService.getMACAddress());
}
/**
* 定义类型映射关系
* @param
* @return
*/
private DeviceClass getDeviceTypeResources(String deviceClassCode) {
DeviceClass deviceClass;
if(deviceClassCode.equals("5A A5 01 01")){
deviceClass = new DeviceClass(0,R.drawable.up_down_black, "ELEVATING WHIRLING LED PANEL");
}else if(deviceClassCode.equals("5A A5 02 02")){
deviceClass = new DeviceClass(1,R.drawable.ontc, "红光床");
}else {
deviceClass = new DeviceClass(2,R.drawable.up_down_black, "ELEVATING WHIRLING LED PANEL");
}
return deviceClass;
}
/**
* 弹出菜单
* @param anchorView
*/
public void showPopupMenu(View anchorView) {
// 初始化布局
View popupView = LayoutInflater.from(requireContext()).inflate(R.layout.menu_popup_layout, null);
// 创建 PopupWindow
popupWindow = new PopupWindow(
popupView,
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
true
);
// 设置背景和动画
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupWindow.setElevation(8); // 阴影效果
popupWindow.setAnimationStyle(R.style.PopupAnimation); // 自定义动画
// 处理菜单项点击
popupView.findViewById(R.id.menu_item_add).setOnClickListener(v -> {
// 处理“添加设备”逻辑
popupWindow.dismiss();
navigateToNewActivity();
});
popupView.findViewById(R.id.menu_item_scan).setOnClickListener(v -> {
// 处理“扫一扫”逻辑
popupWindow.dismiss();
});
// 添加遮罩层
addMask();
// 设置 PopupWindow 关闭时移除遮罩
popupWindow.setOnDismissListener(() -> removeMask());
// 显示菜单(相对于锚点视图)
popupWindow.showAsDropDown(anchorView, dpToPx(-130), dpToPx(15), Gravity.END);
}
/**
* 将遮罩层添加到 Activity 的根布局
*/
private void addMask() {
if (getActivity() == null) return;
ViewGroup rootView = (ViewGroup) getActivity().getWindow().getDecorView();
maskView = LayoutInflater.from(getContext()).inflate(R.layout.layout_background_mask, null);
rootView.addView(maskView);
}
/**
* 移除遮罩层
*/
private void removeMask() {
if (getActivity() == null || maskView == null) return;
ViewGroup rootView = (ViewGroup) getActivity().getWindow().getDecorView();
rootView.removeView(maskView);
maskView = null;
}
/**
* 跳转查找设备Activity
*/
private void navigateToNewActivity() {
if (getActivity() == null) return; // 避免 Fragment 未附加到 Activity 时崩溃
Intent intent = new Intent(getActivity(), SelectDeviceActivity.class);
startActivity(intent);
}
/**
* 跳转到新 Activity
* @param device
*/
private void navigateToNewDeviceDetailsActivity(Device device) {
if (getActivity() == null) return; // 避免 Fragment 未附加到 Activity 时崩溃
if(device.getDeviceClassCode().equals("5A A5 01 02")){
Intent intent = new Intent(getActivity(), PhototherapyBoardTwoActivity.class);
intent.putExtra("devices",device);
startActivity(intent);
}else if(device.getDeviceClassCode().equals("5A A5 01 01")){
Intent intent = new Intent(getActivity(), DeviceDetailsActivity.class);
intent.putExtra("devices",device);
startActivity(intent);
}else if(device.getDeviceClassCode().equals("5A A5 02 01")){
Intent intent = new Intent(getActivity(), TherapyHelmetFourActivity.class);
intent.putExtra("devices",device);
startActivity(intent);
}else if(device.getDeviceClassCode().equals("5A A5 02 05")){
Intent intent = new Intent(getActivity(), TherapyHelmetNineteenActivity.class);
intent.putExtra("devices",device);
startActivity(intent);
}
}
/**
* 像素转 sp
* @param px
* @return
*/
private float pxToSp(float px) {
return px / getResources().getDisplayMetrics().scaledDensity;
}
/**
* dp 转像素工具方法
*/
private int dpToPx(int dp) {
float density = getResources().getDisplayMetrics().density;
return Math.round(dp * density);
}
/**
* 获取用户设备列表
*/
private void loadActivity() {
// 创建Retrofit服务实例
RetrofitAPI api = RetrofitClient.getClient(getActivity()).create(RetrofitAPI.class);
// 发起异步请求
api.deviceFindAll().enqueue(new Callback<List<Device>>() {
@Override
public void onResponse(Call<List<Device>> call, Response<List<Device>> response) {
if (response.isSuccessful() && response.body() != null) {
addNewButton(response.body());
deviceLists = response.body();
}
}
@Override
public void onFailure(Call<List<Device>> call, Throwable t) {
if (getActivity() != null) {
Toast.makeText(getContext(), "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
// // todo 离线
// DevicesRepository devicesRepository = new DevicesRepository(getActivity());
// List<Devices> deviceByUsername = devicesRepository.getDevicesByUserId(1L);
// List<Device> list = new ArrayList<>();
// for (Devices devices:deviceByUsername){
// Device device = new Device();
// device.setDeviceMac(devices.getDeviceMac());
// device.setDeviceName(devices.getDeviceName());
// device.setDeviceClassCode(String.valueOf(devices.getDeviceClassId()));
// device.setUserId(devices.getUserId());
// list.add(device);
// }
// addNewButton(list);
// deviceLists = list;
// // /
}
}
});
}
/**
* 注册本地广播接收器
* 用于接收来自BluetoothService的事件
*/
private void registerReceivers() {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothService.ACTION_CONNECTION_STATUS); // 连接状态变化
LocalBroadcastManager.getInstance(getActivity())
.registerReceiver(btReceiver, filter); // 注册广播接收器
}
/**
* 蓝牙事件广播接收器
* 处理三种事件:
* 1. 发现新设备 - 更新设备列表
* 2. 连接状态变化 - 更新UI状态
* 3. 接收到数据 - 显示在消息框
*/
private final BroadcastReceiver btReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
String action = intent.getAction();
if (BluetoothService.ACTION_CONNECTION_STATUS.equals(action)) {
// 更新连接状态显示
String status = intent.getStringExtra(BluetoothService.EXTRA_STATUS);
if(status.equals("DISCONNECTED")){
updateUnConnectionStatus();
}
}
} catch (SecurityException e) {
throw new RuntimeException(e);
}
}
};
@Override
public void onStart() {
super.onStart();
Intent intent = new Intent(getActivity(), BluetoothService.class);
getActivity().bindService(intent, connection, Context.BIND_AUTO_CREATE); // 绑定服务
}
@Override
public void onStop() {
super.onStop();
if (isBound) {
getActivity().unbindService(connection); // 解绑服务
isBound = false;
}
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(btReceiver);
}
private OnJumpToActivityListener onJumpToActivityListener;
// 在 Fragment 中定义接口
public interface OnJumpToActivityListener {
void jumpToActivityAndClose();
}
}但设备按钮为4个时 手机版本显示顺序没问题 但平板版本的+add按钮会在第六个按钮的位置 而不是第五个
最新发布