设备拉黑删除

来帮你设计黑名单功能。首先修改adapter添加菜单处理逻辑:

typescript 复制代码
package com.tplink.trainingapp.clients.view;

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.tplink.apps.architecture.BaseMvvmActivity;
import com.tplink.design.dialog.TPModalBottomSheet;
import com.tplink.design.menu.TPPopupMenu;
import com.tplink.trainingapp.R;
import com.tplink.trainingapp.clients.adapter.BlacklistAdapter;
import com.tplink.trainingapp.clients.viewmodel.ClientViewModel;
import com.tplink.trainingapp.databinding.ActivityBlacklistBinding;

public class BlacklistActivity extends BaseMvvmActivity<ActivityBlacklistBinding> 
    implements BlacklistAdapter.OnDeviceActionListener {
    
    private ClientViewModel viewModel;
    private BlacklistAdapter adapter;
    
    @Nullable
    @Override
    protected ActivityBlacklistBinding bindContentView(@Nullable Bundle bundle) {
        return ActivityBlacklistBinding.inflate(getLayoutInflater());
    }
    
    @Override
    protected void subscribeViewModel(@Nullable Bundle bundle) {
        viewModel = new ViewModelProvider(this).get(ClientViewModel.class);
        
        setupToolbar();
        setupRecyclerView();
        observeViewModel();
    }
    
    private void setupToolbar() {
        viewBinding.toolbar.setTitle("黑名单");
        viewBinding.toolbar.setNavigationOnClickListener(view -> {
            onBackPressed();
        });
        
        // 设置支持菜单
        setSupportActionBar(viewBinding.toolbar);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.blacklist_toolbar_menu, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if (item.getItemId() == R.id.menu_add) {
            showAddDeviceMenu();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    private void showAddDeviceMenu() {
        View anchorView = findViewById(R.id.menu_add);
        if (anchorView == null) {
            anchorView = viewBinding.toolbar;
        }
        
        TPPopupMenu popupMenu = new TPPopupMenu(this, anchorView, R.menu.add_device_menu)
            .setIconEnable(true);
        popupMenu.setOnMenuItemClickListener(item -> {
            if (item.getItemId() == R.id.menu_add_by_user) {
                // TODO: 实现选择用户端功能
                return true;
            } else if (item.getItemId() == R.id.menu_add_by_mac) {
                showAddByMacModal();
                return true;
            }
            return false;
        });
        popupMenu.show();
    }
    
    private void showAddByMacModal() {
        new TPModalBottomSheet.Builder()
            .setScreenType(TPModalBottomSheet.ScreenType.FULL_SCREEN)
            .setDividerEnable(false)
            .setTitle("Add by MAC Address")
            .setEndOptionText("Save")
            .setContentLayoutId(R.layout.fragment_blacklist)
            .setContentViewListener(new TPModalBottomSheet.OnModalContentViewListener() {
                @Override
                public void onContentViewCreated(TPModalBottomSheet tpModalBottomSheet, View view) {
                    EditText macInput = view.findViewById(R.id.et_mac_address);
                    
                    tpModalBottomSheet.setEndOptionClickListener(new TPModalBottomSheet.OnEndOptionClickListener() {
                        @Override
                        public void onEndOptionClick(TPModalBottomSheet modalBottomSheet) {
                            String macAddress = macInput.getText().toString().trim();
                            if (!macAddress.isEmpty()) {
                                viewModel.blockDeviceByMac(macAddress);
                                modalBottomSheet.dismiss();
                            }
                        }
                    });
                }
            })
            .show(getSupportFragmentManager(), "tp");
    }
    
    private void setupRecyclerView() {
        adapter = new BlacklistAdapter(this);
        adapter.setOnDeviceActionListener(this);
        
        viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
        viewBinding.recyclerView.setAdapter(adapter);
    }
    
    private void observeViewModel() {
        viewModel.getBlacklistItems().observe(this, items -> {
            if (items == null || items.isEmpty()) {
                showEmptyView();
            } else {
                showDeviceList();
                adapter.updateItems(items);
            }
        });
    }
    
    private void showEmptyView() {
        viewBinding.recyclerView.setVisibility(View.GONE);
        viewBinding.emptyLayout.setVisibility(View.VISIBLE);
        viewBinding.emptyImage.setImageResource(R.drawable.ic_empty_device);
        viewBinding.emptyText.setText("没有设备记录");
    }
    
    private void showDeviceList() {
        viewBinding.recyclerView.setVisibility(View.VISIBLE);
        viewBinding.emptyLayout.setVisibility(View.GONE);
    }
    
    @Override
    public void onUnblockDevice(String identifier, int position) {
        viewModel.unblockDevice(identifier);
    }
    
    @Override
    public void onDeleteDevice(String identifier, int position) {
        viewModel.deleteBlacklistDevice(identifier);
    }
}
java 复制代码
package com.tplink.trainingapp.clients.adapter;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.tplink.design.list.TPSingleLineItemView;
import com.tplink.design.list.TPSingleLineItemViewHolder;
import com.tplink.design.list.TPTwoLineItemView;
import com.tplink.design.list.TPTwoLineItemViewHolder;
import com.tplink.design.menu.TPPopupMenu;
import com.tplink.trainingapp.R;
import com.tplink.trainingapp.clients.viewmodel.ClientViewModel;

import java.util.ArrayList;
import java.util.List;

public class BlacklistAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    
    private static final int TYPE_DEVICE = 0;  // 设备名称+MAC类型
    private static final int TYPE_MAC_ONLY = 1; // 纯MAC地址类型
    
    private List<ClientViewModel.BlacklistItem> blacklistItems;
    private Context context;
    private OnDeviceActionListener listener;
    
    // 操作监听接口
    public interface OnDeviceActionListener {
        void onUnblockDevice(String identifier, int position);
        void onDeleteDevice(String identifier, int position);
    }
    
    public BlacklistAdapter(Context context) {
        this.context = context;
        this.blacklistItems = new ArrayList<>();
    }
    
    public void setOnDeviceActionListener(OnDeviceActionListener listener) {
        this.listener = listener;
    }
    
    public void updateItems(List<ClientViewModel.BlacklistItem> items) {
        this.blacklistItems.clear();
        this.blacklistItems.addAll(items);
        notifyDataSetChanged();
    }
    
    @Override
    public int getItemViewType(int position) {
        ClientViewModel.BlacklistItem item = blacklistItems.get(position);
        return item.isMacOnly() ? TYPE_MAC_ONLY : TYPE_DEVICE;
    }
    
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == TYPE_MAC_ONLY) {
            return TPSingleLineItemViewHolder.create(parent);
        } else {
            return TPTwoLineItemViewHolder.create(parent);
        }
    }
    
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        ClientViewModel.BlacklistItem item = blacklistItems.get(position);
        
        if (getItemViewType(position) == TYPE_MAC_ONLY) {
            // 纯MAC地址显示
            bindMacOnlyItem((TPSingleLineItemViewHolder) holder, item, position);
        } else {
            // 设备名称+MAC显示
            bindDeviceItem((TPTwoLineItemViewHolder) holder, item, position);
        }
    }
    
    private void bindMacOnlyItem(TPSingleLineItemViewHolder holder, ClientViewModel.BlacklistItem item, int position) {
        TPSingleLineItemView lineItem = (TPSingleLineItemView) holder.itemView;
        
        // 设置图标(根据MAC地址显示通用设备图标)
        lineItem.setStartIcon(R.mipmap.icon_laptop); // 可以用一个通用图标
        
        // 设置图标尺寸
        ViewGroup.LayoutParams layoutParams = lineItem.getStartIcon().getLayoutParams();
        int iconSize = (int) context.getResources().getDimension(com.tplink.design.R.dimen.tpds_all_dp_40);
        layoutParams.width = iconSize;
        layoutParams.height = iconSize;
        lineItem.getStartIcon().setLayoutParams(layoutParams);
        
        lineItem.setTitleText(item.getMacAddress());
        lineItem.setEndIcon(R.drawable.ic_blocked);
        lineItem.showDivider(true);
        
        setupLongClickListener(lineItem, item.getIdentifier(), position);
    }
    
    private void bindDeviceItem(TPTwoLineItemViewHolder holder, ClientViewModel.BlacklistItem item, int position) {
        TPTwoLineItemView lineItem = (TPTwoLineItemView) holder.itemView;
        
        // 设置设备图标 - 根据设备名称判断类型
        if (item.getDisplayName().toLowerCase().contains("iphone") || 
            item.getDisplayName().toLowerCase().contains("phone") ||
            item.getDisplayName().toLowerCase().contains("mobile")) {
            lineItem.setStartIcon(R.mipmap.icon_games);
        } else {
            lineItem.setStartIcon(R.mipmap.icon_laptop);
        }
        
        // 设置图标尺寸
        ViewGroup.LayoutParams layoutParams = lineItem.getStartIcon().getLayoutParams();
        int iconSize = (int) context.getResources().getDimension(com.tplink.design.R.dimen.tpds_all_dp_40);
        layoutParams.width = iconSize;
        layoutParams.height = iconSize;
        lineItem.getStartIcon().setLayoutParams(layoutParams);
        
        lineItem.setTitleText(item.getDisplayName());
        
        // 显示MAC地址
        String macText = "MAC: " + item.getMacAddress();
        lineItem.setContentText(macText);
        
        // 设置禁用图标
        lineItem.setEndIcon(R.drawable.ic_blocked);
        
        lineItem.showDivider(true);
        
        setupLongClickListener(lineItem, item.getIdentifier(), position);
    }
    
    private void setupLongClickListener(View itemView, String identifier, int position) {
        itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                TPPopupMenu popupMenu = new TPPopupMenu(context, v, R.menu.blacklist_menu)
                    .setIconEnable(true);
                popupMenu.setOnMenuItemClickListener(item -> {
                    if (item.getItemId() == R.id.menu_unblock) {
                        showUnblockConfirmDialog(identifier, position);
                        return true;
                    } else if (item.getItemId() == R.id.menu_delete) {
                        showDeleteConfirmDialog(identifier, position);
                        return true;
                    }
                    return false;
                });
                popupMenu.show();
                return true;
            }
        });
    }
    
    @Override
    public int getItemCount() {
        return blacklistItems.size();
    }
    
    // 显示解除拉黑确认对话框
    private void showUnblockConfirmDialog(String identifier, int position) {
        new androidx.appcompat.app.AlertDialog.Builder(context)
            .setTitle("解除拉黑")
            .setMessage("确定要将 \"" + identifier + "\" 从黑名单中移除吗?")
            .setPositiveButton("确定", (dialog, which) -> {
                if (listener != null) {
                    listener.onUnblockDevice(identifier, position);
                }
            })
            .setNegativeButton("取消", null)
            .show();
    }
    
    // 显示删除确认对话框
    private void showDeleteConfirmDialog(String identifier, int position) {
        new androidx.appcompat.app.AlertDialog.Builder(context)
            .setTitle("删除设备")
            .setMessage("确定要永久删除 \"" + identifier + "\" 吗?")
            .setPositiveButton("确定", (dialog, which) -> {
                if (listener != null) {
                    listener.onDeleteDevice(identifier, position);
                }
            })
            .setNegativeButton("取消", null)
            .show();
    }
}
typescript 复制代码
package com.tplink.trainingapp.clients.viewmodel;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import java.util.ArrayList;
import java.util.List;

public class ClientViewModel extends ViewModel {
    
    // 黑名单项目类型
    public static class BlacklistItem {
        private String displayName;
        private String macAddress;
        private boolean isMacOnly; // 是否只是MAC地址
        
        // 构造函数 - 设备名称+MAC
        public BlacklistItem(String deviceName, String macAddress) {
            this.displayName = deviceName;
            this.macAddress = macAddress;
            this.isMacOnly = false;
        }
        
        // 构造函数 - 纯MAC地址
        public BlacklistItem(String macAddress) {
            this.displayName = macAddress;
            this.macAddress = macAddress;
            this.isMacOnly = true;
        }
        
        // Getters
        public String getDisplayName() { return displayName; }
        public String getMacAddress() { return macAddress; }
        public boolean isMacOnly() { return isMacOnly; }
        
        public String getIdentifier() {
            return isMacOnly ? macAddress : displayName;
        }
    }
    
    // 主网络在线设备数量
    private MutableLiveData<Integer> mainOnlineCount = new MutableLiveData<>(4);
    
    // 主网络离线设备数量  
    private MutableLiveData<Integer> mainOfflineCount = new MutableLiveData<>(3);
    
    // 访客网络设备数量
    private MutableLiveData<Integer> guestCount = new MutableLiveData<>(1);
    
    // 刷新状态
    private MutableLiveData<Boolean> isRefreshing = new MutableLiveData<>(false);
    
    // 黑名单项目
    private MutableLiveData<List<BlacklistItem>> blacklistItems = new MutableLiveData<>(new ArrayList<>());
    
    // 获取主网络在线设备数量
    public LiveData<Integer> getMainOnlineCount() {
        return mainOnlineCount;
    }
    
    // 获取主网络离线设备数量
    public LiveData<Integer> getMainOfflineCount() {
        return mainOfflineCount;
    }
    
    // 获取访客网络设备数量
    public LiveData<Integer> getGuestCount() {
        return guestCount;
    }
    
    // 获取刷新状态
    public LiveData<Boolean> getRefreshingState() {
        return isRefreshing;
    }
    
    // 获取黑名单项目
    public LiveData<List<BlacklistItem>> getBlacklistItems() {
        return blacklistItems;
    }
    
    // 刷新数据
    public void refreshData() {
        isRefreshing.setValue(true);
        
        // 模拟网络请求延时
        new android.os.Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mainOnlineCount.setValue((int) (Math.random() * 5) + 1);
                mainOfflineCount.setValue((int) (Math.random() * 4) + 1);
                guestCount.setValue((int) (Math.random() * 3) + 1);
                
                isRefreshing.setValue(false);
            }
        }, 1500);
    }
    
    // 拉黑设备(设备名称)
    public void blockDevice(String deviceName) {
        List<BlacklistItem> currentList = blacklistItems.getValue();
        if (currentList == null) {
            currentList = new ArrayList<>();
        }
        
        // 检查是否已存在
        boolean exists = currentList.stream()
            .anyMatch(item -> item.getIdentifier().equals(deviceName));
        
        if (!exists) {
            List<BlacklistItem> newList = new ArrayList<>(currentList);
            newList.add(new BlacklistItem(deviceName, "99-99-99-99-99-99")); // 模拟MAC
            blacklistItems.setValue(newList);
        }
    }
    
    // 通过MAC地址拉黑
    public void blockDeviceByMac(String macAddress) {
        List<BlacklistItem> currentList = blacklistItems.getValue();
        if (currentList == null) {
            currentList = new ArrayList<>();
        }
        
        // 检查是否已存在
        boolean exists = currentList.stream()
            .anyMatch(item -> item.getMacAddress().equals(macAddress));
        
        if (!exists) {
            List<BlacklistItem> newList = new ArrayList<>(currentList);
            newList.add(new BlacklistItem(macAddress)); // 纯MAC地址项目
            blacklistItems.setValue(newList);
        }
    }
    
    // 解除拉黑
    public void unblockDevice(String identifier) {
        List<BlacklistItem> currentList = blacklistItems.getValue();
        if (currentList != null) {
            List<BlacklistItem> newList = new ArrayList<>();
            for (BlacklistItem item : currentList) {
                if (!item.getIdentifier().equals(identifier)) {
                    newList.add(item);
                }
            }
            blacklistItems.setValue(newList);
        }
    }
    
    // 删除黑名单设备
    public void deleteBlacklistDevice(String identifier) {
        unblockDevice(identifier); // 删除就是从黑名单中移除
    }
    
    // 更新主网络在线设备数量
    public void updateMainOnlineCount(int count) {
        mainOnlineCount.setValue(count);
    }
    
    // 更新主网络离线设备数量
    public void updateMainOfflineCount(int count) {
        mainOfflineCount.setValue(count);
    }
    
    // 更新访客网络设备数量
    public void updateGuestCount(int count) {
        guestCount.setValue(count);
    }
    
    // 获取当前主网络在线设备数量的值
    public int getCurrentMainOnlineCount() {
        Integer count = mainOnlineCount.getValue();
        return count != null ? count : 0;
    }
    
    // 获取当前主网络离线设备数量的值
    public int getCurrentMainOfflineCount() {
        Integer count = mainOfflineCount.getValue();
        return count != null ? count : 0;
    }
    
    // 获取当前访客网络设备数量的值
    public int getCurrentGuestCount() {
        Integer count = guestCount.getValue();
        return count != null ? count : 0;
    }
}
ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:navigationIcon="@drawable/toolbar_icon_back"
        app:navigationIconTint="?attr/colorOnBackground"
        app:title="黑名单"
        app:titleCentered="true"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="MissingConstraints" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:padding="16dp"
        app:layout_constraintTop_toBottomOf="@id/toolbar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <!-- 空状态布局 -->
    <LinearLayout
        android:id="@+id/emptyLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center"
        android:visibility="gone"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <ImageView
            android:id="@+id/emptyImage"
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:layout_marginBottom="16dp"
            android:alpha="0.6"
            tools:src="@drawable/ic_empty_device" />

        <TextView
            android:id="@+id/emptyText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="没有设备记录"
            android:textColor="?attr/colorOnSurface"
            android:textSize="16sp"
            android:alpha="0.6" />

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

🎯 功能概述

实现了完整的设备黑名单管理功能,包括:

  • 设备列表长按显示拉黑/删除菜单
  • 拉黑/删除前显示确认对话框
  • 黑名单页面管理已拉黑设备
  • 支持解除拉黑和删除操作
  • 空状态显示

📁 已创建的文件

1. ClientListAdapter.java (已修改)

  • 添加了设备操作监听接口 OnDeviceActionListener
  • 实现长按菜单处理(在线设备:拉黑,离线设备:拉黑+删除)
  • 添加确认对话框 showBlockConfirmDialog()showDeleteConfirmDialog()

2. BlacklistActivity.java (新建)

  • 黑名单管理页面
  • 空状态和设备列表状态切换
  • 实现设备操作接口处理解除拉黑和删除

3. BlacklistAdapter.java (新建)

  • 黑名单设备列表适配器
  • 支持长按菜单(解除拉黑、删除)
  • 确认对话框处理

4. ClientViewModel.java (已修改)

  • 添加黑名单数据管理
  • blockDevice() - 拉黑设备
  • unblockDevice() - 解除拉黑
  • deleteBlacklistDevice() - 删除黑名单设备

5. ClientPageActivity.java (已修改)

  • 添加工具栏菜单支持
  • 实现黑名单页面跳转

6. ClientMainFragment.java (已修改)

  • 实现设备操作接口
  • 处理拉黑和删除操作反馈

7. activity_blacklist.xml (新建)

  • 黑名单页面布局
  • 包含RecyclerView和空状态布局

🎨 需要的资源文件

菜单文件 (res/menu/)

xml 复制代码
<!-- clients_online_menu.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_block"
        android:title="拉黑"
        android:icon="@drawable/ic_block" />
</menu>

<!-- clients_offline_menu.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_block"
        android:title="拉黑"
        android:icon="@drawable/ic_block" />
    <item
        android:id="@+id/menu_delete"
        android:title="删除"
        android:icon="@drawable/ic_delete" />
</menu>

<!-- blacklist_menu.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_unblock"
        android:title="解除拉黑"
        android:icon="@drawable/ic_unblock" />
    <item
        android:id="@+id/menu_delete"
        android:title="删除"
        android:icon="@drawable/ic_delete" />
</menu>

<!-- device_update_toolbar_menu.xml (修改) -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_blacklist"
        android:title="黑名单"
        android:icon="@drawable/ic_blacklist"
        android:showAsAction="always" />
</menu>

图标资源 (res/drawable/)

  • ic_block.xml - 拉黑图标
  • ic_unblock.xml - 解除拉黑图标
  • ic_delete.xml - 删除图标
  • ic_blacklist.xml - 黑名单图标
  • ic_blocked.xml - 已被拉黑状态图标
  • ic_empty_device.xml - 空设备状态图标
  • toolbar_icon_back.xml - 返回图标

🔄 工作流程

  1. 设备列表操作

    • 用户长按设备 → 显示菜单
    • 点击"拉黑"/"删除" → 显示确认对话框
    • 确认后 → 调用ViewModel方法更新数据
  2. 黑名单管理

    • 主页面工具栏点击黑名单图标 → 跳转黑名单页面
    • 黑名单为空 → 显示空状态图片和提示
    • 黑名单有设备 → 显示设备列表
    • 长按黑名单设备 → 解除拉黑/删除菜单
  3. 数据状态管理

    • 所有数据通过ClientViewModel的LiveData管理
    • 支持Activity和Fragment之间数据共享
    • 自动响应数据变化更新UI

🎯 使用方法

  1. 将所有文件添加到对应目录
  2. 创建所需的菜单和图标资源
  3. 在AndroidManifest.xml中注册BlacklistActivity
  4. 确保string资源包含必要的文本
xml 复制代码
<!-- AndroidManifest.xml -->
<activity
    android:name=".clients.view.BlacklistActivity"
    android:label="黑名单"
    android:parentActivityName=".clients.view.ClientPageActivity" />

现在你有了一个完整的黑名单功能实现! 🎉��已经为你完整设计了黑名单功能!主要实现了:

✨ 核心功能

  1. 长按菜单 - 在线设备显示"拉黑",离线设备显示"拉黑+删除"
  2. 确认对话框 - 所有操作前都有确认提示
  3. 黑名单页面 - 专门管理已拉黑设备,支持解除拉黑和删除
  4. 空状态显示 - 没有设备时显示图片和提示文字
  5. 数据同步 - 通过ViewModel在Activity和Fragment间共享数据

🔧 实现架构

  • ClientListAdapter - 添加了设备操作接口和确认对话框
  • BlacklistActivity + BlacklistAdapter - 完整的黑名单管理
  • ClientViewModel - 统一的数据状态管理
  • activity_blacklist.xml - 黑名单页面布局

📋 你还需要准备的资源:

菜单文件 (res/menu/):

  • clients_online_menu.xml (包含拉黑选项)
  • clients_offline_menu.xml (包含拉黑+删除选项)
  • blacklist_menu.xml (包含解除拉黑+删除选项)
  • 修改 device_update_toolbar_menu.xml (添加黑名单图标)

图标资源 (res/drawable/):

  • 各种操作图标 (拉黑、删除、黑名单等)
  • 空设备状态图标

在AndroidManifest.xml注册BlacklistActivity

现在你的黑名单功能已经完整实现了!用户可以长按设备进行拉黑/删除,点击工具栏进入黑名单管理,所有操作都有确认提示和反馈。🎉

你的需求,需要修改以下几个地方:

1. BlacklistActivity 修改

2. ClientViewModel 修改 - 支持MAC地址管理

3. BlacklistAdapter 修改 - 支持不同类型显示

4. 需要创建的菜单XML文件

ini 复制代码
<item
    android:id="@+id/menu_add"
    android:title="添加"
    android:icon="@drawable/ic_add"
    app:showAsAction="always" />
    
ini 复制代码
<item
    android:id="@+id/menu_add_by_user"
    android:title="选择用户端"
    android:icon="@drawable/ic_device" />

<item
    android:id="@+id/menu_add_by_mac"
    android:title="通过MAC位新增"
    android:icon="@drawable/ic_mac_address" />
    

5. 总结需要修改的主要逻辑

主要修改点总结:

  1. BlacklistActivity - 添加工具栏菜单,处理添加设备的弹窗逻辑
  2. ClientViewModel - 创建BlacklistItem内部类,支持两种类型的黑名单项目
  3. BlacklistAdapter - 使用ViewType区分显示,支持TPSingleLineItemView和TPTwoLineItemView
  4. 菜单文件 - 创建工具栏菜单和弹出菜单XML

关键实现逻辑:

  • BlacklistItem类:区分普通设备(显示设备名+MAC)和纯MAC地址(只显示MAC)
  • ViewType机制:adapter根据item类型返回不同的ViewHolder
  • TPModalBottomSheet:全屏模态面板处理MAC地址输入
  • 数据流 :输入的MAC地址通过blockDeviceByMac()方法添加到黑名单

注意点:

  • 纯MAC地址项目使用TPSingleLineItemView显示
  • 普通设备项目使用TPTwoLineItemView显示设备名和MAC地址
  • 需要创建fragment_blacklist.xml布局文件(包含TextView和EditText)
  • 需要添加相关图标资源(ic_add, ic_device, ic_mac_address等)

这样就完成了黑名单功能的MAC地址添加支持,用户可以通过右上角菜单添加纯MAC地址到黑名单中。

相关推荐
用户03321266636710 分钟前
Java 设置 Excel 行高列宽:告别手动调整,拥抱自动化高效!
java·excel
2501_9096867011 分钟前
基于SpringBoot的网上点餐系统
java·spring boot·后端
neoooo16 分钟前
Spring Boot 3 + Kafka 实战指南
java·spring boot·kafka
天天摸鱼的java工程师17 分钟前
聊聊线程池中哪几种状态,分别表示什么?8 年 Java 开发:从业务踩坑到源码拆解(附监控实战)
java·后端
杨杨杨大侠21 分钟前
第4篇:AOP切面编程 - 无侵入式日志拦截
java·后端·开源
末央&31 分钟前
【JavaEE】文件IO操作
java·服务器·java-ee
渣哥34 分钟前
面试官问我Java继承本质,我用一个故事征服了他
java
yaoxin5211231 小时前
168. Java Lambda 表达式 - 专用比较器
java·开发语言
Dcs1 小时前
GPT-5来了!它将如何颠覆开发者的工作方式?
java