重构数据模型命名
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Fri Dec 12 04:27:50 GMT 2025
|
||||
#Fri Dec 12 05:20:34 GMT 2025
|
||||
stageCount=1
|
||||
libraryProject=
|
||||
baseVersion=15.12
|
||||
publishVersion=15.12.0
|
||||
buildCount=2
|
||||
buildCount=5
|
||||
baseBetaVersion=15.12.1
|
||||
|
||||
@@ -28,7 +28,7 @@ import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import cc.winboll.studio.contacts.activities.SettingsActivity;
|
||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
|
||||
import cc.winboll.studio.contacts.model.MainServiceBean;
|
||||
import cc.winboll.studio.contacts.fragments.CallLogFragment;
|
||||
import cc.winboll.studio.contacts.fragments.ContactsFragment;
|
||||
import cc.winboll.studio.contacts.fragments.LogFragment;
|
||||
|
||||
@@ -1,31 +1,37 @@
|
||||
package cc.winboll.studio.contacts.activities;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/03/31 15:15:54
|
||||
* @Describe 应用介绍窗口
|
||||
*/
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
|
||||
import cc.winboll.studio.libaes.models.APPInfo;
|
||||
import cc.winboll.studio.libaes.views.AboutView;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
|
||||
import cc.winboll.studio.libaes.views.AboutView;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/03/31 15:15:54
|
||||
* @Describe 应用介绍窗口
|
||||
*/
|
||||
public class AboutActivity extends AppCompatActivity implements IWinBoLLActivity {
|
||||
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "AboutActivity";
|
||||
private static final String BRANCH_NAME = "contacts";
|
||||
|
||||
Context mContext;
|
||||
Toolbar mToolbar;
|
||||
// ====================== 成员变量区 ======================
|
||||
private Context mContext;
|
||||
private Toolbar mToolbar;
|
||||
|
||||
// ====================== 接口实现区 ======================
|
||||
@Override
|
||||
public Activity getActivity() {
|
||||
return this;
|
||||
@@ -36,58 +42,75 @@ public class AboutActivity extends AppCompatActivity implements IWinBoLLActivity
|
||||
return TAG;
|
||||
}
|
||||
|
||||
// ====================== 生命周期函数区 ======================
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "onCreate: 关于页面开始创建");
|
||||
|
||||
mContext = this;
|
||||
setContentView(R.layout.activity_about);
|
||||
|
||||
mToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(mToolbar);
|
||||
mToolbar.setSubtitle(TAG);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
AboutView aboutView = CreateAboutView();
|
||||
// 在 Activity 的 onCreate 或其他生命周期方法中调用
|
||||
// LinearLayout layout = new LinearLayout(this);
|
||||
// layout.setOrientation(LinearLayout.VERTICAL);
|
||||
// // 创建布局参数(宽度和高度)
|
||||
// ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
|
||||
// ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
// ViewGroup.LayoutParams.MATCH_PARENT
|
||||
// );
|
||||
// addContentView(aboutView, params);
|
||||
|
||||
LinearLayout layout = findViewById(R.id.aboutviewroot_ll);
|
||||
// 创建布局参数(宽度和高度)
|
||||
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
);
|
||||
layout.addView(aboutView, params);
|
||||
|
||||
// 初始化工具栏
|
||||
initToolbar();
|
||||
// 初始化关于页面视图
|
||||
initAboutView();
|
||||
// 注册Activity管理
|
||||
WinBoLLActivityManager.getInstance().add(this);
|
||||
|
||||
LogUtils.d(TAG, "onCreate: 关于页面初始化完成");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
LogUtils.d(TAG, "onDestroy: 关于页面开始销毁");
|
||||
WinBoLLActivityManager.getInstance().registeRemove(this);
|
||||
LogUtils.d(TAG, "onDestroy: 关于页面销毁完成");
|
||||
}
|
||||
|
||||
public AboutView CreateAboutView() {
|
||||
String szBranchName = "contacts";
|
||||
// ====================== 控件初始化函数区 ======================
|
||||
private void initToolbar() {
|
||||
LogUtils.d(TAG, "initToolbar: 初始化工具栏");
|
||||
// Java7 适配:添加强制类型转换
|
||||
mToolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(mToolbar);
|
||||
mToolbar.setSubtitle(TAG);
|
||||
// 非空判断,避免空指针异常
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAboutView() {
|
||||
LogUtils.d(TAG, "initAboutView: 初始化关于页面内容视图");
|
||||
AboutView aboutView = createAboutView();
|
||||
LinearLayout layout = (LinearLayout) findViewById(R.id.aboutviewroot_ll);
|
||||
|
||||
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
);
|
||||
layout.addView(aboutView, params);
|
||||
LogUtils.d(TAG, "initAboutView: AboutView已添加到布局");
|
||||
}
|
||||
|
||||
// ====================== 业务逻辑函数区 ======================
|
||||
private AboutView createAboutView() {
|
||||
LogUtils.d(TAG, "createAboutView: 构建APP信息并创建AboutView");
|
||||
APPInfo appInfo = new APPInfo();
|
||||
appInfo.setAppName("Contacts");
|
||||
appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll);
|
||||
appInfo.setAppDescription("这是可以根据正则表达式匹配拦截骚扰电话的手机拨号应用。");
|
||||
appInfo.setAppGitName("WinBoLL");
|
||||
appInfo.setAppGitOwner("Studio");
|
||||
appInfo.setAppGitAPPBranch(szBranchName);
|
||||
appInfo.setAppGitAPPSubProjectFolder(szBranchName);
|
||||
appInfo.setAppGitAPPBranch(BRANCH_NAME);
|
||||
appInfo.setAppGitAPPSubProjectFolder(BRANCH_NAME);
|
||||
appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=Contacts");
|
||||
appInfo.setAppAPKName("Contacts");
|
||||
appInfo.setAppAPKFolderName("Contacts");
|
||||
|
||||
return new AboutView(mContext, appInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package cc.winboll.studio.contacts.activities;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/02/20 17:15:46
|
||||
* @Describe 拨号窗口
|
||||
*/
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -20,99 +15,144 @@ import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import cc.winboll.studio.contacts.MainActivity;
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/02/20 17:15:46
|
||||
* @Describe 拨号窗口
|
||||
*/
|
||||
public class CallActivity extends AppCompatActivity {
|
||||
public static final String TAG = "CallActivity";
|
||||
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "CallActivity";
|
||||
private static final int REQUEST_CALL_PHONE = 1;
|
||||
|
||||
// ====================== UI控件区 ======================
|
||||
private EditText phoneNumberEditText;
|
||||
private TextView callStatusTextView;
|
||||
private Button dialButton;
|
||||
|
||||
// ====================== 业务成员区 ======================
|
||||
private TelephonyManager telephonyManager;
|
||||
private MyPhoneStateListener phoneStateListener;
|
||||
|
||||
// ====================== 生命周期函数区 ======================
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
//setContentView(R.layout.activity_main);
|
||||
LogUtils.d(TAG, "onCreate: 拨号页面开始创建");
|
||||
setContentView(R.layout.activity_call);
|
||||
|
||||
phoneNumberEditText = findViewById(R.id.phone_number);
|
||||
Button dialButton = findViewById(R.id.dial_button);
|
||||
callStatusTextView = findViewById(R.id.call_status);
|
||||
|
||||
dialButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String phoneNumber = phoneNumberEditText.getText().toString().trim();
|
||||
if (!phoneNumber.isEmpty()) {
|
||||
if (ContextCompat.checkSelfPermission(CallActivity.this, Manifest.permission.CALL_PHONE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(CallActivity.this,
|
||||
new String[]{Manifest.permission.CALL_PHONE},
|
||||
REQUEST_CALL_PHONE);
|
||||
} else {
|
||||
dialPhoneNumber(phoneNumber);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(CallActivity.this, "请输入电话号码", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化TelephonyManager和PhoneStateListener
|
||||
telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
|
||||
phoneStateListener = new MyPhoneStateListener();
|
||||
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == REQUEST_CALL_PHONE) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
String phoneNumber = phoneNumberEditText.getText().toString().trim();
|
||||
dialPhoneNumber(phoneNumber);
|
||||
} else {
|
||||
Toast.makeText(this, "未授予拨打电话权限", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dialPhoneNumber(String phoneNumber) {
|
||||
Intent intent = new Intent(Intent.ACTION_CALL);
|
||||
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private class MyPhoneStateListener extends PhoneStateListener {
|
||||
@Override
|
||||
public void onCallStateChanged(int state, String incomingNumber) {
|
||||
switch (state) {
|
||||
case TelephonyManager.CALL_STATE_IDLE:
|
||||
callStatusTextView.setText("电话已挂断");
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||
callStatusTextView.setText("正在通话中");
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_RINGING:
|
||||
callStatusTextView.setText("来电: " + incomingNumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 初始化控件
|
||||
initViews();
|
||||
// 初始化电话状态监听
|
||||
initPhoneStateListener();
|
||||
LogUtils.d(TAG, "onCreate: 拨号页面初始化完成");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
// 取消监听
|
||||
if (telephonyManager != null) {
|
||||
LogUtils.d(TAG, "onDestroy: 拨号页面开始销毁");
|
||||
// 取消电话状态监听,避免内存泄漏
|
||||
if (telephonyManager != null && phoneStateListener != null) {
|
||||
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
|
||||
LogUtils.d(TAG, "onDestroy: 电话状态监听已取消");
|
||||
}
|
||||
LogUtils.d(TAG, "onDestroy: 拨号页面销毁完成");
|
||||
}
|
||||
|
||||
// ====================== 权限回调函数区 ======================
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
LogUtils.d(TAG, "onRequestPermissionsResult: 权限请求回调,requestCode=" + requestCode);
|
||||
if (requestCode == REQUEST_CALL_PHONE) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
LogUtils.d(TAG, "onRequestPermissionsResult: 拨打电话权限授予成功");
|
||||
String phoneNumber = phoneNumberEditText.getText().toString().trim();
|
||||
dialPhoneNumber(phoneNumber);
|
||||
} else {
|
||||
LogUtils.w(TAG, "onRequestPermissionsResult: 拨打电话权限被拒绝");
|
||||
Toast.makeText(this, "未授予拨打电话权限", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 控件初始化函数区 ======================
|
||||
private void initViews() {
|
||||
LogUtils.d(TAG, "initViews: 初始化UI控件");
|
||||
// Java7 适配:添加强制类型转换
|
||||
phoneNumberEditText = (EditText) findViewById(R.id.phone_number);
|
||||
dialButton = (Button) findViewById(R.id.dial_button);
|
||||
callStatusTextView = (TextView) findViewById(R.id.call_status);
|
||||
|
||||
// 设置拨号按钮点击事件
|
||||
dialButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String phoneNumber = phoneNumberEditText.getText().toString().trim();
|
||||
LogUtils.d(TAG, "initViews: 拨号按钮点击,号码=" + phoneNumber);
|
||||
if (phoneNumber.isEmpty()) {
|
||||
Toast.makeText(CallActivity.this, "请输入电话号码", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// 权限检查
|
||||
if (ContextCompat.checkSelfPermission(CallActivity.this, Manifest.permission.CALL_PHONE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
LogUtils.w(TAG, "initViews: 拨打电话权限未授予,发起权限申请");
|
||||
ActivityCompat.requestPermissions(CallActivity.this,
|
||||
new String[]{Manifest.permission.CALL_PHONE},
|
||||
REQUEST_CALL_PHONE);
|
||||
} else {
|
||||
dialPhoneNumber(phoneNumber);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====================== 电话状态监听初始化函数区 ======================
|
||||
private void initPhoneStateListener() {
|
||||
LogUtils.d(TAG, "initPhoneStateListener: 初始化电话状态监听");
|
||||
telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
|
||||
phoneStateListener = new MyPhoneStateListener();
|
||||
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
|
||||
}
|
||||
|
||||
// ====================== 核心业务函数区 ======================
|
||||
private void dialPhoneNumber(String phoneNumber) {
|
||||
LogUtils.d(TAG, "dialPhoneNumber: 发起拨号,号码=" + phoneNumber);
|
||||
Intent intent = new Intent(Intent.ACTION_CALL);
|
||||
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
|
||||
LogUtils.e(TAG, "dialPhoneNumber: 拨打电话权限缺失,拨号失败");
|
||||
return;
|
||||
}
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
// ====================== 内部电话状态监听类 ======================
|
||||
private class MyPhoneStateListener extends PhoneStateListener {
|
||||
@Override
|
||||
public void onCallStateChanged(int state, String incomingNumber) {
|
||||
super.onCallStateChanged(state, incomingNumber);
|
||||
switch (state) {
|
||||
case TelephonyManager.CALL_STATE_IDLE:
|
||||
callStatusTextView.setText("电话已挂断");
|
||||
LogUtils.d(TAG, "MyPhoneStateListener: 通话状态-挂断");
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||
callStatusTextView.setText("正在通话中");
|
||||
LogUtils.d(TAG, "MyPhoneStateListener: 通话状态-通话中");
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_RINGING:
|
||||
callStatusTextView.setText("来电: " + incomingNumber);
|
||||
LogUtils.d(TAG, "MyPhoneStateListener: 通话状态-来电,号码=" + incomingNumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,80 @@
|
||||
package cc.winboll.studio.contacts.activities;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/02/20 20:18:26
|
||||
*/
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/02/20 20:18:26
|
||||
* @Describe 拨号盘窗口(跳转到系统拨号界面)
|
||||
*/
|
||||
public class DialerActivity extends AppCompatActivity {
|
||||
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "DialerActivity";
|
||||
|
||||
// ====================== UI控件区 ======================
|
||||
private EditText phoneNumberEditText;
|
||||
private Button dialButton;
|
||||
|
||||
// ====================== 生命周期函数区 ======================
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "onCreate: 拨号盘页面开始创建");
|
||||
setContentView(R.layout.activity_dialer);
|
||||
|
||||
phoneNumberEditText = findViewById(R.id.phone_number_edit_text);
|
||||
Button dialButton = findViewById(R.id.dial_button);
|
||||
// 初始化UI控件与点击事件
|
||||
initViews();
|
||||
LogUtils.d(TAG, "onCreate: 拨号盘页面初始化完成");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
LogUtils.d(TAG, "onDestroy: 拨号盘页面已销毁");
|
||||
}
|
||||
|
||||
// ====================== 控件初始化函数区 ======================
|
||||
private void initViews() {
|
||||
LogUtils.d(TAG, "initViews: 初始化UI控件");
|
||||
// Java7 适配:添加强制类型转换
|
||||
phoneNumberEditText = (EditText) findViewById(R.id.phone_number_edit_text);
|
||||
dialButton = (Button) findViewById(R.id.dial_button);
|
||||
|
||||
// 设置拨号按钮点击事件
|
||||
dialButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String phoneNumber = phoneNumberEditText.getText().toString();
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber));
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String phoneNumber = phoneNumberEditText.getText().toString().trim();
|
||||
LogUtils.d(TAG, "initViews: 拨号按钮点击,输入号码=" + phoneNumber);
|
||||
|
||||
// 空号码校验
|
||||
if (phoneNumber.isEmpty()) {
|
||||
LogUtils.w(TAG, "initViews: 拨号失败,号码为空");
|
||||
Toast.makeText(DialerActivity.this, "请输入有效电话号码", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// 跳转到系统拨号界面
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber));
|
||||
if (intent.resolveActivity(getPackageManager()) != null) {
|
||||
startActivity(intent);
|
||||
LogUtils.d(TAG, "initViews: 成功跳转到系统拨号界面");
|
||||
} else {
|
||||
LogUtils.e(TAG, "initViews: 跳转失败,无可用拨号应用");
|
||||
Toast.makeText(DialerActivity.this, "未找到可用拨号应用", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.contacts.adapters.PhoneConnectRuleAdapter;
|
||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
|
||||
import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
|
||||
import cc.winboll.studio.contacts.beans.RingTongBean;
|
||||
import cc.winboll.studio.contacts.beans.SettingsModel;
|
||||
import cc.winboll.studio.contacts.model.MainServiceBean;
|
||||
import cc.winboll.studio.contacts.model.PhoneConnectRuleModel;
|
||||
import cc.winboll.studio.contacts.model.RingTongBean;
|
||||
import cc.winboll.studio.contacts.model.SettingsModel;
|
||||
import cc.winboll.studio.contacts.bobulltoon.TomCat;
|
||||
import cc.winboll.studio.contacts.dun.Rules;
|
||||
import cc.winboll.studio.contacts.services.MainService;
|
||||
|
||||
@@ -11,84 +11,123 @@ import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.LogView;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/03/02 16:07:04
|
||||
* @Describe 规则单元测试页面
|
||||
*/
|
||||
public class UnitTestActivity extends Activity {
|
||||
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "UnitTestActivity";
|
||||
|
||||
LogView logView;
|
||||
// ====================== UI控件区 ======================
|
||||
private LogView logView;
|
||||
private EditText etPhone;
|
||||
|
||||
// ====================== 生命周期函数区 ======================
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "onCreate: 单元测试页面开始创建");
|
||||
setContentView(R.layout.activity_unittest);
|
||||
logView = findViewById(R.id.logview);
|
||||
|
||||
// 初始化控件
|
||||
initViews();
|
||||
LogUtils.d(TAG, "onCreate: 单元测试页面初始化完成");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
LogUtils.d(TAG, "onDestroy: 单元测试页面开始销毁");
|
||||
if (logView != null) {
|
||||
// 若LogView有停止方法,建议调用避免资源泄漏
|
||||
// logView.stop();
|
||||
LogUtils.d(TAG, "onDestroy: LogView资源已处理");
|
||||
}
|
||||
LogUtils.d(TAG, "onDestroy: 单元测试页面销毁完成");
|
||||
}
|
||||
|
||||
// ====================== 控件初始化函数区 ======================
|
||||
private void initViews() {
|
||||
LogUtils.d(TAG, "initViews: 初始化UI控件");
|
||||
// Java7 适配:添加强制类型转换
|
||||
logView = (LogView) findViewById(R.id.logview);
|
||||
etPhone = (EditText) findViewById(R.id.phone_et);
|
||||
|
||||
// 启动日志视图
|
||||
logView.start();
|
||||
LogUtils.d(TAG, "initViews: LogView已启动");
|
||||
}
|
||||
|
||||
// ====================== 点击事件测试函数区 ======================
|
||||
/**
|
||||
* 测试单个号码匹配规则
|
||||
*/
|
||||
public void onTestPhone(View view) {
|
||||
// 开始测试数据
|
||||
EditText etPhone = findViewById(R.id.phone_et);
|
||||
Rules rules = Rules.getInstance(this);
|
||||
LogUtils.d(TAG, "onTestPhone: 开始测试单个号码规则匹配");
|
||||
String phone = etPhone.getText().toString().trim();
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
|
||||
}
|
||||
|
||||
public void onTestMain(View view) {
|
||||
LogUtils.d(TAG, "IntUtils.unittest_getIntInRange();");
|
||||
IntUtils.unittest_getIntInRange();
|
||||
|
||||
Rules rules = Rules.getInstance(this);
|
||||
|
||||
// 如果没有规则就添加测试规则
|
||||
if (rules.getPhoneBlacRuleBeanList().size() == 0) {
|
||||
// 手机号码允许
|
||||
// 中国手机号码正则表达式,以1开头,第二位可以是3、4、5、6、7、8、9,后面跟9位数字
|
||||
String regex = "^1[3-9]\\d{9}$";
|
||||
rules.add(regex, true, true);
|
||||
|
||||
// 指定区号号码允许
|
||||
regex = "^0660\\d+$";
|
||||
rules.add(regex, true, true);
|
||||
|
||||
// 指定区号号码允许
|
||||
regex = "^020\\d+$";
|
||||
rules.add(regex, true, true);
|
||||
|
||||
// 添加默认拒接规则
|
||||
regex = ".*";
|
||||
rules.add(regex, false, true);
|
||||
|
||||
// 保存规则到文件
|
||||
rules.saveRules();
|
||||
if (phone.isEmpty()) {
|
||||
LogUtils.w(TAG, "onTestPhone: 测试号码为空,跳过匹配");
|
||||
return;
|
||||
}
|
||||
|
||||
// 开始测试数据
|
||||
String phone = "16769764848";
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
Rules rules = Rules.getInstance(this);
|
||||
boolean isAllowed = rules.isAllowed(phone);
|
||||
LogUtils.d(TAG, String.format("onTestPhone: 测试号码: %s | 匹配结果: %s", phone, isAllowed));
|
||||
}
|
||||
|
||||
phone = "16856582777";
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
/**
|
||||
* 批量测试预设号码规则匹配
|
||||
*/
|
||||
public void onTestMain(View view) {
|
||||
LogUtils.d(TAG, "onTestMain: 开始批量测试号码规则匹配");
|
||||
// 测试IntUtils工具类方法
|
||||
LogUtils.d(TAG, "onTestMain: 执行 IntUtils.unittest_getIntInRange() 测试");
|
||||
IntUtils.unittest_getIntInRange();
|
||||
|
||||
phone = "17519703124";
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
// 初始化规则实例
|
||||
Rules rules = Rules.getInstance(this);
|
||||
// 无规则时添加测试规则集
|
||||
initTestRulesIfEmpty(rules);
|
||||
|
||||
phone = "0205658955";
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
// 预设测试号码列表
|
||||
String[] testPhones = {
|
||||
"16769764848", "16856582777", "17519703124",
|
||||
"0205658955", "0108965253", "+8616769764848",
|
||||
"4005816769764848", "95566"
|
||||
};
|
||||
|
||||
phone = "0108965253";
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
// 遍历测试号码并输出结果
|
||||
for (String phone : testPhones) {
|
||||
boolean isAllowed = rules.isAllowed(phone);
|
||||
LogUtils.d(TAG, String.format("onTestMain: 测试号码: %s | 匹配结果: %s", phone, isAllowed));
|
||||
}
|
||||
LogUtils.d(TAG, "onTestMain: 批量号码规则测试完成");
|
||||
}
|
||||
|
||||
phone = "+8616769764848";
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
// ====================== 私有工具函数区 ======================
|
||||
/**
|
||||
* 规则集为空时初始化测试规则
|
||||
*/
|
||||
private void initTestRulesIfEmpty(Rules rules) {
|
||||
if (rules.getPhoneBlacRuleBeanList().size() == 0) {
|
||||
LogUtils.d(TAG, "initTestRulesIfEmpty: 当前无规则,添加测试规则集");
|
||||
// 规则1:中国手机号允许
|
||||
rules.add("^1[3-9]\\d{9}$", true, true);
|
||||
// 规则2:0660区号号码允许
|
||||
rules.add("^0660\\d+$", true, true);
|
||||
// 规则3:020区号号码允许
|
||||
rules.add("^020\\d+$", true, true);
|
||||
// 规则4:默认拒接所有号码
|
||||
rules.add(".*", false, true);
|
||||
|
||||
phone = "4005816769764848";
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
|
||||
phone = "95566";
|
||||
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
|
||||
// 保存规则到本地
|
||||
rules.saveRules();
|
||||
LogUtils.d(TAG, "initTestRulesIfEmpty: 测试规则集已保存");
|
||||
} else {
|
||||
LogUtils.d(TAG, "initTestRulesIfEmpty: 当前已有规则,跳过初始化");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package cc.winboll.studio.contacts.activities;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/03/31 15:16:45
|
||||
* @Describe 应用窗口基类
|
||||
*/
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
@@ -12,13 +7,22 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
|
||||
import cc.winboll.studio.libaes.models.AESThemeBean;
|
||||
import cc.winboll.studio.libaes.utils.AESThemeUtil;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/03/31 15:16:45
|
||||
* @Describe 应用窗口基类,统一处理主题设置与导航返回
|
||||
*/
|
||||
public class WinBollActivity extends AppCompatActivity implements IWinBoLLActivity {
|
||||
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "WinBollActivity";
|
||||
|
||||
// ====================== 成员变量区 ======================
|
||||
protected volatile AESThemeBean.ThemeType mThemeType;
|
||||
|
||||
// ====================== 接口实现区 ======================
|
||||
@Override
|
||||
public Activity getActivity() {
|
||||
return this;
|
||||
@@ -29,14 +33,24 @@ public class WinBollActivity extends AppCompatActivity implements IWinBoLLActivi
|
||||
return TAG;
|
||||
}
|
||||
|
||||
// ====================== 生命周期函数区 ======================
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
LogUtils.d(TAG, "onCreate: 基类页面开始创建");
|
||||
// 优先设置主题,再执行父类初始化
|
||||
mThemeType = getThemeType();
|
||||
setThemeStyle();
|
||||
super.onCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "onCreate: 基类主题设置完成,当前主题类型=" + mThemeType);
|
||||
}
|
||||
|
||||
// ====================== 主题相关函数区 ======================
|
||||
/**
|
||||
* 获取当前应用主题类型
|
||||
*/
|
||||
AESThemeBean.ThemeType getThemeType() {
|
||||
LogUtils.d(TAG, "getThemeType: 获取应用主题类型");
|
||||
// 注释的SharedPreferences逻辑保留,便于后续扩展
|
||||
/*SharedPreferences sharedPreferences = getSharedPreferences(
|
||||
SHAREDPREFERENCES_NAME, MODE_PRIVATE);
|
||||
return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))];
|
||||
@@ -44,17 +58,27 @@ public class WinBollActivity extends AppCompatActivity implements IWinBoLLActivi
|
||||
return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用当前主题样式
|
||||
*/
|
||||
void setThemeStyle() {
|
||||
//setTheme(AESThemeBean.getThemeStyle(getThemeType()));
|
||||
LogUtils.d(TAG, "setThemeStyle: 开始设置应用主题");
|
||||
// 替换原注释逻辑,使用AESThemeUtil获取的主题ID
|
||||
setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext()));
|
||||
LogUtils.d(TAG, "setThemeStyle: 主题设置完成");
|
||||
}
|
||||
|
||||
// ====================== 菜单与导航函数区 ======================
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if(item.getItemId() == android.R.id.home) {
|
||||
LogUtils.d(TAG, "onOptionsItemSelected: 菜单选项点击,itemId=" + item.getItemId());
|
||||
// 处理导航栏返回按钮点击事件
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
LogUtils.d(TAG, "onOptionsItemSelected: 点击导航返回按钮,关闭当前页面");
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package cc.winboll.studio.contacts.adapters;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/02/26 13:09:32
|
||||
* @Describe CallLogAdapter
|
||||
*/
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
@@ -13,125 +8,167 @@ import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.contacts.beans.CallLogModel;
|
||||
import cc.winboll.studio.contacts.model.CallLogModel;
|
||||
import cc.winboll.studio.contacts.utils.ContactUtils;
|
||||
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/02/26 13:09:32
|
||||
* @Describe 通话记录列表适配器
|
||||
*/
|
||||
public class CallLogAdapter extends RecyclerView.Adapter<CallLogAdapter.CallLogViewHolder> {
|
||||
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "CallLogAdapter";
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
|
||||
// ====================== 成员变量区 ======================
|
||||
private Context mContext;
|
||||
private List<CallLogModel> callLogList;
|
||||
ContactUtils mContactUtils;
|
||||
Context mContext;
|
||||
private ContactUtils mContactUtils;
|
||||
|
||||
// ====================== 构造函数区 ======================
|
||||
public CallLogAdapter(Context context, List<CallLogModel> callLogList) {
|
||||
mContext = context;
|
||||
this.mContactUtils = ContactUtils.getInstance(mContext);
|
||||
LogUtils.d(TAG, "CallLogAdapter: 初始化适配器,数据量=" + callLogList.size());
|
||||
this.mContext = context;
|
||||
this.callLogList = callLogList;
|
||||
this.mContactUtils = ContactUtils.getInstance(mContext);
|
||||
}
|
||||
|
||||
public void relaodContacts() {
|
||||
this.mContactUtils.relaodContacts();
|
||||
}
|
||||
|
||||
// ====================== 公共方法区 ======================
|
||||
/**
|
||||
* 重新加载联系人数据
|
||||
*/
|
||||
public void relaodContacts() {
|
||||
LogUtils.d(TAG, "relaodContacts: 开始重新加载联系人数据");
|
||||
this.mContactUtils.relaodContacts();
|
||||
notifyDataSetChanged();
|
||||
LogUtils.d(TAG, "relaodContacts: 联系人数据加载完成,列表已刷新");
|
||||
}
|
||||
|
||||
// ====================== RecyclerView 重写方法区 ======================
|
||||
@NonNull
|
||||
@Override
|
||||
public CallLogViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LogUtils.d(TAG, "onCreateViewHolder: 创建列表项ViewHolder");
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_call_log, parent, false);
|
||||
return new CallLogViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull CallLogViewHolder holder, int position) {
|
||||
LogUtils.d(TAG, "onBindViewHolder: 绑定列表项数据,position=" + position);
|
||||
final CallLogModel callLog = callLogList.get(position);
|
||||
holder.phoneNumber.setText(callLog.getPhoneNumber() + "☎" + mContactUtils.getContactsName(callLog.getPhoneNumber()));
|
||||
holder.phoneNumber.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
|
||||
// 绑定通话号码与联系人名称
|
||||
String contactName = mContactUtils.getContactsName(callLog.getPhoneNumber());
|
||||
String phoneText = callLog.getPhoneNumber() + "☎" + (contactName == null ? "" : contactName);
|
||||
holder.phoneNumber.setText(phoneText);
|
||||
|
||||
// 号码长按弹出菜单事件
|
||||
holder.phoneNumber.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View p1) {
|
||||
// 弹出复制菜单
|
||||
PopupMenu menu = new PopupMenu(mContext, holder.phoneNumber);
|
||||
//加载菜单资源
|
||||
menu.getMenuInflater().inflate(R.menu.toolbar_calllog_phonenumber, menu.getMenu());
|
||||
//设置点击事件的响应
|
||||
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
int nItemId = menuItem.getItemId();
|
||||
if (nItemId == R.id.item_calllog_phonenumber_copy) {
|
||||
// Gets a handle to the clipboard service.
|
||||
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
// Creates a new text clip to put on the clipboard
|
||||
ClipData clip = ClipData.newPlainText("simple text", callLog.getPhoneNumber());
|
||||
// Set the clipboard's primary clip.
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show();
|
||||
} else if (nItemId == R.id.item_calllog_phonenumber_add_contact) {
|
||||
//ToastUtils.show(callLog.getPhoneNumber());
|
||||
ContactUtils.jumpToAddContact(mContext, callLog.getPhoneNumber());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
//一定要调用show()来显示弹出式菜单
|
||||
menu.show();
|
||||
|
||||
showPhonePopupMenu(holder.phoneNumber, callLog);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
holder.callStatus.setText(callLog.getCallStatus());
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
holder.callDate.setText(dateFormat.format(callLog.getCallDate()));
|
||||
|
||||
// 初始化拉动后拨号控件
|
||||
holder.dialAOHPCTCSeekBar.setThumb(holder.itemView.getContext().getDrawable(R.drawable.ic_call));
|
||||
holder.dialAOHPCTCSeekBar.setBlurRightDP(80);
|
||||
holder.dialAOHPCTCSeekBar.setThumbOffset(0);
|
||||
holder.dialAOHPCTCSeekBar.setOnOHPCListener(
|
||||
new AOHPCTCSeekBar.OnOHPCListener(){
|
||||
@Override
|
||||
public void onOHPCommit() {
|
||||
String phoneNumber = callLog.getPhoneNumber().replaceAll("\\s", "");
|
||||
ToastUtils.show(phoneNumber);
|
||||
Intent intent = new Intent(Intent.ACTION_CALL);
|
||||
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
|
||||
// 添加 FLAG_ACTIVITY_NEW_TASK 标志
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
holder.itemView.getContext().startActivity(intent);
|
||||
}
|
||||
});
|
||||
// 绑定通话状态与时间
|
||||
holder.callStatus.setText(callLog.getCallStatus());
|
||||
holder.callDate.setText(DATE_FORMAT.format(callLog.getCallDate()));
|
||||
|
||||
// 初始化滑动拨号SeekBar
|
||||
initDialSeekBar(holder.dialAOHPCTCSeekBar, callLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return callLogList.size();
|
||||
return callLogList == null ? 0 : callLogList.size();
|
||||
}
|
||||
|
||||
// ====================== 私有工具方法区 ======================
|
||||
/**
|
||||
* 显示号码操作弹窗菜单
|
||||
*/
|
||||
private void showPhonePopupMenu(View anchorView, final CallLogModel callLog) {
|
||||
LogUtils.d(TAG, "showPhonePopupMenu: 弹出号码操作菜单");
|
||||
PopupMenu menu = new PopupMenu(mContext, anchorView);
|
||||
menu.getMenuInflater().inflate(R.menu.toolbar_calllog_phonenumber, menu.getMenu());
|
||||
|
||||
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
int itemId = menuItem.getItemId();
|
||||
if (itemId == R.id.item_calllog_phonenumber_copy) {
|
||||
// 复制号码到剪贴板
|
||||
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("call_log_phone", callLog.getPhoneNumber());
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show();
|
||||
LogUtils.d(TAG, "showPhonePopupMenu: 号码" + callLog.getPhoneNumber() + "已复制到剪贴板");
|
||||
} else if (itemId == R.id.item_calllog_phonenumber_add_contact) {
|
||||
// 跳转到添加联系人页面
|
||||
ContactUtils.jumpToAddContact(mContext, callLog.getPhoneNumber());
|
||||
LogUtils.d(TAG, "showPhonePopupMenu: 跳转添加联系人页面,号码=" + callLog.getPhoneNumber());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
menu.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化滑动拨号SeekBar
|
||||
*/
|
||||
private void initDialSeekBar(AOHPCTCSeekBar seekBar, final CallLogModel callLog) {
|
||||
LogUtils.d(TAG, "initDialSeekBar: 初始化滑动拨号控件");
|
||||
seekBar.setThumb(seekBar.getContext().getDrawable(R.drawable.ic_call));
|
||||
seekBar.setBlurRightDP(80);
|
||||
seekBar.setThumbOffset(0);
|
||||
|
||||
seekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() {
|
||||
@Override
|
||||
public void onOHPCommit() {
|
||||
String phoneNumber = callLog.getPhoneNumber().replaceAll("\\s", "");
|
||||
LogUtils.d(TAG, "initDialSeekBar: 滑动拨号触发,号码=" + phoneNumber);
|
||||
ToastUtils.show(phoneNumber);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_CALL);
|
||||
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====================== ViewHolder 内部类 ======================
|
||||
public class CallLogViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView phoneNumber, callStatus, callDate;
|
||||
Button dialButton;
|
||||
TextView phoneNumber;
|
||||
TextView callStatus;
|
||||
TextView callDate;
|
||||
AOHPCTCSeekBar dialAOHPCTCSeekBar;
|
||||
|
||||
public CallLogViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
phoneNumber = itemView.findViewById(R.id.phone_number);
|
||||
callStatus = itemView.findViewById(R.id.call_status);
|
||||
callDate = itemView.findViewById(R.id.call_date);
|
||||
dialAOHPCTCSeekBar = itemView.findViewById(R.id.aohpctcseekbar_dial);
|
||||
// Java7 适配:添加强制类型转换
|
||||
phoneNumber = (TextView) itemView.findViewById(R.id.phone_number);
|
||||
callStatus = (TextView) itemView.findViewById(R.id.call_status);
|
||||
callDate = (TextView) itemView.findViewById(R.id.call_date);
|
||||
dialAOHPCTCSeekBar = (AOHPCTCSeekBar) itemView.findViewById(R.id.aohpctcseekbar_dial);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package cc.winboll.studio.contacts.adapters;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/02/26 13:35:44
|
||||
* @Describe ContactAdapter
|
||||
*/
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
@@ -20,111 +15,142 @@ import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.contacts.beans.ContactModel;
|
||||
import cc.winboll.studio.contacts.model.ContactModel;
|
||||
import cc.winboll.studio.contacts.utils.ContactUtils;
|
||||
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/02/26 13:35:44
|
||||
* @Describe 联系人列表适配器
|
||||
*/
|
||||
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {
|
||||
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "ContactAdapter";
|
||||
// 移除未使用的 REQUEST_CALL_PHONE 常量,精简冗余代码
|
||||
|
||||
private static final int REQUEST_CALL_PHONE = 1;
|
||||
|
||||
// ====================== 成员变量区 ======================
|
||||
private Context mContext;
|
||||
private List<ContactModel> contactList;
|
||||
Context mContext;
|
||||
|
||||
// ====================== 构造函数区 ======================
|
||||
public ContactAdapter(Context context, List<ContactModel> contactList) {
|
||||
mContext = context;
|
||||
LogUtils.d(TAG, "ContactAdapter: 初始化适配器,联系人数量=" + contactList.size());
|
||||
this.mContext = context;
|
||||
this.contactList = contactList;
|
||||
}
|
||||
|
||||
// ====================== RecyclerView 重写方法区 ======================
|
||||
@NonNull
|
||||
@Override
|
||||
public ContactViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LogUtils.d(TAG, "onCreateViewHolder: 创建联系人列表项ViewHolder");
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_contact, parent, false);
|
||||
return new ContactViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) {
|
||||
LogUtils.d(TAG, "onBindViewHolder: 绑定联系人列表项数据,position=" + position);
|
||||
final ContactModel contact = contactList.get(position);
|
||||
holder.llPhoneNumberMain.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View p1) {
|
||||
// 弹出复制菜单
|
||||
PopupMenu menu = new PopupMenu(mContext, holder.llPhoneNumberMain);
|
||||
//加载菜单资源
|
||||
menu.getMenuInflater().inflate(R.menu.toolbar_contact_phonenumber, menu.getMenu());
|
||||
//设置点击事件的响应
|
||||
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
int nItemId = menuItem.getItemId();
|
||||
if (nItemId == R.id.item_contact_phonenumber_copy) {
|
||||
// Gets a handle to the clipboard service.
|
||||
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
// Creates a new text clip to put on the clipboard
|
||||
ClipData clip = ClipData.newPlainText("simple text", contact.getNumber());
|
||||
// Set the clipboard's primary clip.
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show();
|
||||
} else if (nItemId == R.id.item_calllog_phonenumber_edit_contact) {
|
||||
//ToastUtils.show("Test");
|
||||
Long nContactId = ContactUtils.getContactIdByPhone(mContext, contact.getNumber());
|
||||
//ToastUtils.show(String.format("%d", nContactId));
|
||||
ContactUtils.jumpToEditContact(mContext, contact.getNumber(), nContactId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
//一定要调用show()来显示弹出式菜单
|
||||
menu.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 绑定联系人名称与号码
|
||||
holder.contactName.setText(contact.getName());
|
||||
holder.contactNumber.setText(contact.getNumber());
|
||||
|
||||
// 初始化拉动后拨号控件
|
||||
holder.dialAOHPCTCSeekBar.setThumb(holder.itemView.getContext().getDrawable(R.drawable.ic_call));
|
||||
holder.dialAOHPCTCSeekBar.setBlurRightDP(80);
|
||||
holder.dialAOHPCTCSeekBar.setThumbOffset(0);
|
||||
holder.dialAOHPCTCSeekBar.setOnOHPCListener(
|
||||
new AOHPCTCSeekBar.OnOHPCListener(){
|
||||
@Override
|
||||
public void onOHPCommit() {
|
||||
String phoneNumber = contact.getNumber().replaceAll("\\s", "");
|
||||
ToastUtils.show(phoneNumber);
|
||||
Intent intent = new Intent(Intent.ACTION_CALL);
|
||||
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
|
||||
// 添加 FLAG_ACTIVITY_NEW_TASK 标志
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
holder.itemView.getContext().startActivity(intent);
|
||||
}
|
||||
});
|
||||
// 长按联系人条目弹出操作菜单
|
||||
holder.llPhoneNumberMain.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
showContactPopupMenu(holder.llPhoneNumberMain, contact);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化滑动拨号SeekBar
|
||||
initDialSeekBar(holder.dialAOHPCTCSeekBar, contact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return contactList.size();
|
||||
// 增加空指针判断,避免空列表崩溃
|
||||
return contactList == null ? 0 : contactList.size();
|
||||
}
|
||||
|
||||
// ====================== 私有工具方法区 ======================
|
||||
/**
|
||||
* 显示联系人操作弹窗菜单
|
||||
*/
|
||||
private void showContactPopupMenu(View anchorView, final ContactModel contact) {
|
||||
LogUtils.d(TAG, "showContactPopupMenu: 弹出联系人操作菜单");
|
||||
PopupMenu menu = new PopupMenu(mContext, anchorView);
|
||||
menu.getMenuInflater().inflate(R.menu.toolbar_contact_phonenumber, menu.getMenu());
|
||||
|
||||
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
int itemId = menuItem.getItemId();
|
||||
if (itemId == R.id.item_contact_phonenumber_copy) {
|
||||
// 复制联系人号码到剪贴板
|
||||
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("contact_phone", contact.getNumber());
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show();
|
||||
LogUtils.d(TAG, "showContactPopupMenu: 联系人号码" + contact.getNumber() + "已复制到剪贴板");
|
||||
} else if (itemId == R.id.item_calllog_phonenumber_edit_contact) {
|
||||
// 跳转到编辑联系人页面
|
||||
Long contactId = ContactUtils.getContactIdByPhone(mContext, contact.getNumber());
|
||||
ContactUtils.jumpToEditContact(mContext, contact.getNumber(), contactId);
|
||||
LogUtils.d(TAG, "showContactPopupMenu: 跳转编辑联系人页面,号码=" + contact.getNumber() + ",ID=" + contactId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
menu.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化滑动拨号SeekBar
|
||||
*/
|
||||
private void initDialSeekBar(AOHPCTCSeekBar seekBar, final ContactModel contact) {
|
||||
LogUtils.d(TAG, "initDialSeekBar: 初始化滑动拨号控件");
|
||||
seekBar.setThumb(seekBar.getContext().getDrawable(R.drawable.ic_call));
|
||||
seekBar.setBlurRightDP(80);
|
||||
seekBar.setThumbOffset(0);
|
||||
|
||||
seekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() {
|
||||
@Override
|
||||
public void onOHPCommit() {
|
||||
String phoneNumber = contact.getNumber().replaceAll("\\s", "");
|
||||
LogUtils.d(TAG, "initDialSeekBar: 滑动拨号触发,号码=" + phoneNumber);
|
||||
ToastUtils.show(phoneNumber);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_CALL);
|
||||
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====================== ViewHolder 内部类 ======================
|
||||
public class ContactViewHolder extends RecyclerView.ViewHolder {
|
||||
LinearLayout llPhoneNumberMain;
|
||||
LinearLayout llPhoneNumberMain;
|
||||
TextView contactName;
|
||||
TextView contactNumber;
|
||||
AOHPCTCSeekBar dialAOHPCTCSeekBar;
|
||||
|
||||
public ContactViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
llPhoneNumberMain = itemView.findViewById(R.id.itemcontactLinearLayout1);
|
||||
contactName = itemView.findViewById(R.id.contact_name);
|
||||
contactNumber = itemView.findViewById(R.id.contact_number);
|
||||
dialAOHPCTCSeekBar = itemView.findViewById(R.id.aohpctcseekbar_dial);
|
||||
// Java7 适配:添加强制类型转换
|
||||
llPhoneNumberMain = (LinearLayout) itemView.findViewById(R.id.itemcontactLinearLayout1);
|
||||
contactName = (TextView) itemView.findViewById(R.id.contact_name);
|
||||
contactNumber = (TextView) itemView.findViewById(R.id.contact_number);
|
||||
dialAOHPCTCSeekBar = (AOHPCTCSeekBar) itemView.findViewById(R.id.aohpctcseekbar_dial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package cc.winboll.studio.contacts.adapters;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/02/20 14:20:38
|
||||
* @Describe ImagePagerAdapter
|
||||
*/
|
||||
public class ImagePagerAdapter {
|
||||
|
||||
public static final String TAG = "ImagePagerAdapter";
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
package cc.winboll.studio.contacts.adapters;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/03/02 17:27:41
|
||||
* @Describe PhoneConnectRuleAdapter
|
||||
*/
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -17,226 +12,230 @@ import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
|
||||
import cc.winboll.studio.contacts.model.PhoneConnectRuleModel;
|
||||
import cc.winboll.studio.contacts.dun.Rules;
|
||||
import cc.winboll.studio.contacts.views.LeftScrollView;
|
||||
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/03/02 17:27:41
|
||||
* @Describe 通话规则列表适配器,支持简单查看/编辑两种视图切换
|
||||
*/
|
||||
public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
// ====================== 常量定义区 ======================
|
||||
public static final String TAG = "PhoneConnectRuleAdapter";
|
||||
|
||||
private static final int VIEW_TYPE_SIMPLE = 0;
|
||||
private static final int VIEW_TYPE_EDIT = 1;
|
||||
private static final String NULL_RULE_TEXT = "[NULL]";
|
||||
|
||||
private Context context;
|
||||
private List<PhoneConnectRuleModel> ruleList;
|
||||
// ====================== 成员变量区 ======================
|
||||
private Context mContext;
|
||||
private List<PhoneConnectRuleModel> mRuleList;
|
||||
|
||||
// ====================== 构造函数区 ======================
|
||||
public PhoneConnectRuleAdapter(Context context, List<PhoneConnectRuleModel> ruleList) {
|
||||
this.context = context;
|
||||
this.ruleList = ruleList;
|
||||
LogUtils.d(TAG, "PhoneConnectRuleAdapter: 初始化适配器,规则数量=" + ruleList.size());
|
||||
this.mContext = context;
|
||||
this.mRuleList = ruleList;
|
||||
}
|
||||
|
||||
// ====================== RecyclerView 重写方法区 ======================
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
if (viewType == VIEW_TYPE_SIMPLE) {
|
||||
LogUtils.d(TAG, "onCreateViewHolder: 创建简单视图ViewHolder");
|
||||
View view = inflater.inflate(R.layout.view_phone_connect_rule_simple, parent, false);
|
||||
return new SimpleViewHolder(parent, view);
|
||||
} else {
|
||||
LogUtils.d(TAG, "onCreateViewHolder: 创建编辑视图ViewHolder");
|
||||
View view = inflater.inflate(R.layout.view_phone_connect_rule, parent, false);
|
||||
return new EditViewHolder(parent, view);
|
||||
return new EditViewHolder(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
|
||||
final PhoneConnectRuleModel model = ruleList.get(position);
|
||||
final PhoneConnectRuleModel model = mRuleList.get(position);
|
||||
LogUtils.d(TAG, "onBindViewHolder: 绑定规则数据,position=" + position + ",视图类型=" + getItemViewType(position));
|
||||
|
||||
if (holder instanceof SimpleViewHolder) {
|
||||
final SimpleViewHolder simpleViewHolder = (SimpleViewHolder) holder;
|
||||
String szView = model.getRuleText().trim().equals("") ?"[NULL]": model.getRuleText();
|
||||
simpleViewHolder.tvRuleText.setText(szView);
|
||||
simpleViewHolder.checkBoxAllow.setChecked(model.isAllowConnection());
|
||||
simpleViewHolder.checkBoxAllow.setEnabled(false);
|
||||
simpleViewHolder.checkBoxEnable.setChecked(model.isEnable());
|
||||
simpleViewHolder.checkBoxEnable.setEnabled(false);
|
||||
simpleViewHolder.scrollView.setOnActionListener(new LeftScrollView.OnActionListener(){
|
||||
|
||||
@Override
|
||||
public void onUp() {
|
||||
ArrayList<PhoneConnectRuleModel> list = Rules.getInstance(context).getPhoneBlacRuleBeanList();
|
||||
if (position > 0) {
|
||||
ToastUtils.show("onUp");
|
||||
simpleViewHolder.scrollView.smoothScrollTo(0, 0);
|
||||
// PhoneConnectRuleModel newBean = new PhoneConnectRuleModel();
|
||||
// newBean.setRuleText(list.get(position).getRuleText());
|
||||
// newBean.setIsAllowConnection(list.get(position).isAllowConnection());
|
||||
// newBean.setIsEnable(list.get(position).isEnable());
|
||||
// newBean.setIsSimpleView(list.get(position).isSimpleView());
|
||||
list.add(position - 1, list.get(position));
|
||||
list.remove(position + 1);
|
||||
Rules.getInstance(context).saveRules();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDown() {
|
||||
ArrayList<PhoneConnectRuleModel> list = Rules.getInstance(context).getPhoneBlacRuleBeanList();
|
||||
if (position < list.size() - 1) {
|
||||
ToastUtils.show("onDown");
|
||||
simpleViewHolder.scrollView.smoothScrollTo(0, 0);
|
||||
// PhoneConnectRuleModel newBean = new PhoneConnectRuleModel();
|
||||
// newBean.setRuleText(list.get(position).getRuleText());
|
||||
// newBean.setIsAllowConnection(list.get(position).isAllowConnection());
|
||||
// newBean.setIsEnable(list.get(position).isEnable());
|
||||
// newBean.setIsSimpleView(list.get(position).isSimpleView());
|
||||
list.add(position + 2, list.get(position));
|
||||
list.remove(position);
|
||||
Rules.getInstance(context).saveRules();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEdit() {
|
||||
simpleViewHolder.scrollView.smoothScrollTo(0, 0);
|
||||
model.setIsSimpleView(false);
|
||||
notifyDataSetChanged();
|
||||
//notifyItemChanged(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete() {
|
||||
YesNoAlertDialog.show(simpleViewHolder.scrollView.getContext(), "删除确认", "是否删除该通话规则?", new YesNoAlertDialog.OnDialogResultListener(){
|
||||
|
||||
@Override
|
||||
public void onYes() {
|
||||
simpleViewHolder.scrollView.smoothScrollTo(0, 0);
|
||||
model.setIsSimpleView(true);
|
||||
ArrayList<PhoneConnectRuleModel> list = Rules.getInstance(context).getPhoneBlacRuleBeanList();
|
||||
list.remove(position);
|
||||
Rules.getInstance(context).saveRules();
|
||||
notifyDataSetChanged();
|
||||
//notifyItemChanged(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNo() {
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
// simpleViewHolder.editButton.setOnClickListener(new View.OnClickListener() {
|
||||
// @Override
|
||||
// public void onClick(View v) {
|
||||
// model.setIsSimpleView(false);
|
||||
// notifyItemChanged(position);
|
||||
// }
|
||||
// });
|
||||
// simpleViewHolder.deleteButton.setOnClickListener(new View.OnClickListener() {
|
||||
// @Override
|
||||
// public void onClick(View v) {
|
||||
// model.setIsSimpleView(false);
|
||||
// ArrayList<PhoneConnectRuleModel> list = Rules.getInstance(context).getPhoneBlacRuleBeanList();
|
||||
// list.remove(position);
|
||||
// Rules.getInstance(context).saveRules();
|
||||
// notifyItemChanged(position);
|
||||
// }
|
||||
// });
|
||||
// // 触摸事件处理
|
||||
// simpleViewHolder.contentLayout.setOnTouchListener(new View.OnTouchListener() {
|
||||
// @Override
|
||||
// public boolean onTouch(View v, MotionEvent event) {
|
||||
// switch (event.getAction()) {
|
||||
// case MotionEvent.ACTION_DOWN:
|
||||
// simpleViewHolder.startX = event.getX();
|
||||
// simpleViewHolder.isSwiping = true;
|
||||
// break;
|
||||
// case MotionEvent.ACTION_MOVE:
|
||||
// if (simpleViewHolder.isSwiping) {
|
||||
// float deltaX = simpleViewHolder.startX - event.getX();
|
||||
// if (deltaX > 0) { // 左滑
|
||||
// float translationX = Math.max(-simpleViewHolder.actionLayout.getWidth(), -deltaX);
|
||||
// simpleViewHolder.contentLayout.setTranslationX(translationX);
|
||||
// simpleViewHolder.actionLayout.setVisibility(View.VISIBLE);
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// case MotionEvent.ACTION_UP:
|
||||
// simpleViewHolder.isSwiping = false;
|
||||
// if (simpleViewHolder.contentLayout.getTranslationX() < -simpleViewHolder.actionLayout.getWidth() / 2) {
|
||||
// // 保持按钮显示
|
||||
// simpleViewHolder.contentLayout.setTranslationX(-actionLayout.getWidth());
|
||||
// } else {
|
||||
// // 恢复原状
|
||||
// simpleViewHolder.contentLayout.animate().translationX(0).setDuration(200).start();
|
||||
// simpleViewHolder.actionLayout.setVisibility(View.INVISIBLE);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// });
|
||||
bindSimpleViewHolder((SimpleViewHolder) holder, model, position);
|
||||
} else if (holder instanceof EditViewHolder) {
|
||||
final EditViewHolder editViewHolder = (EditViewHolder) holder;
|
||||
editViewHolder.editText.setText(model.getRuleText());
|
||||
editViewHolder.checkBoxAllow.setChecked(model.isAllowConnection());
|
||||
editViewHolder.checkBoxEnable.setChecked(model.isEnable());
|
||||
editViewHolder.buttonConfirm.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
model.setRuleText(editViewHolder.editText.getText().toString());
|
||||
model.setIsAllowConnection(editViewHolder.checkBoxAllow.isChecked());
|
||||
model.setIsEnable(editViewHolder.checkBoxEnable.isChecked());
|
||||
model.setIsSimpleView(true);
|
||||
Rules.getInstance(context).saveRules();
|
||||
notifyItemChanged(position);
|
||||
Toast.makeText(context, "保存成功", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
bindEditViewHolder((EditViewHolder) holder, model, position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return ruleList.size();
|
||||
return mRuleList == null ? 0 : mRuleList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
PhoneConnectRuleModel model = ruleList.get(position);
|
||||
// 这里可以根据模型的状态来决定视图类型,简单起见,假设点击按钮后进入编辑视图
|
||||
return model.isSimpleView() ? VIEW_TYPE_SIMPLE : VIEW_TYPE_EDIT;
|
||||
return mRuleList.get(position).isSimpleView() ? VIEW_TYPE_SIMPLE : VIEW_TYPE_EDIT;
|
||||
}
|
||||
|
||||
// ====================== 私有视图绑定方法区 ======================
|
||||
/**
|
||||
* 绑定简单视图数据
|
||||
*/
|
||||
private void bindSimpleViewHolder(final SimpleViewHolder holder, final PhoneConnectRuleModel model, final int position) {
|
||||
// 绑定规则文本,空值显示[NULL]
|
||||
String ruleText = model.getRuleText().trim().isEmpty() ? NULL_RULE_TEXT : model.getRuleText().trim();
|
||||
holder.tvRuleText.setText(ruleText);
|
||||
// 设置复选框状态并禁用编辑
|
||||
holder.checkBoxAllow.setChecked(model.isAllowConnection());
|
||||
holder.checkBoxAllow.setEnabled(false);
|
||||
holder.checkBoxEnable.setChecked(model.isEnable());
|
||||
holder.checkBoxEnable.setEnabled(false);
|
||||
|
||||
// 设置左滑操作监听
|
||||
holder.scrollView.setOnActionListener(new LeftScrollView.OnActionListener() {
|
||||
@Override
|
||||
public void onUp() {
|
||||
LogUtils.d(TAG, "onUp: 规则上移,position=" + position);
|
||||
moveRuleUp(position);
|
||||
holder.scrollView.smoothScrollTo(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDown() {
|
||||
LogUtils.d(TAG, "onDown: 规则下移,position=" + position);
|
||||
moveRuleDown(position);
|
||||
holder.scrollView.smoothScrollTo(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEdit() {
|
||||
LogUtils.d(TAG, "onEdit: 切换到编辑视图,position=" + position);
|
||||
model.setIsSimpleView(false);
|
||||
notifyItemChanged(position);
|
||||
holder.scrollView.smoothScrollTo(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete() {
|
||||
LogUtils.d(TAG, "onDelete: 触发规则删除确认,position=" + position);
|
||||
showDeleteConfirmDialog(holder.scrollView.getContext(), model, position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定编辑视图数据
|
||||
*/
|
||||
private void bindEditViewHolder(final EditViewHolder holder, final PhoneConnectRuleModel model, final int position) {
|
||||
// 绑定规则文本到输入框
|
||||
holder.editText.setText(model.getRuleText());
|
||||
// 绑定复选框状态
|
||||
holder.checkBoxAllow.setChecked(model.isAllowConnection());
|
||||
holder.checkBoxEnable.setChecked(model.isEnable());
|
||||
|
||||
// 确认按钮点击事件
|
||||
holder.buttonConfirm.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String newRuleText = holder.editText.getText().toString().trim();
|
||||
model.setRuleText(newRuleText);
|
||||
model.setIsAllowConnection(holder.checkBoxAllow.isChecked());
|
||||
model.setIsEnable(holder.checkBoxEnable.isChecked());
|
||||
model.setIsSimpleView(true);
|
||||
|
||||
// 保存规则并刷新视图
|
||||
Rules.getInstance(mContext).saveRules();
|
||||
notifyItemChanged(position);
|
||||
Toast.makeText(mContext, "保存成功", Toast.LENGTH_SHORT).show();
|
||||
LogUtils.d(TAG, "bindEditViewHolder: 规则保存成功,position=" + position + ",规则内容=" + newRuleText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====================== 私有业务工具方法区 ======================
|
||||
/**
|
||||
* 规则上移
|
||||
*/
|
||||
private void moveRuleUp(int position) {
|
||||
if (position <= 0) {
|
||||
ToastUtils.show("已到顶部,无法上移");
|
||||
return;
|
||||
}
|
||||
ArrayList<PhoneConnectRuleModel> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList();
|
||||
swapRulePosition(ruleList, position, position - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 规则下移
|
||||
*/
|
||||
private void moveRuleDown(int position) {
|
||||
ArrayList<PhoneConnectRuleModel> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList();
|
||||
if (position >= ruleList.size() - 1) {
|
||||
ToastUtils.show("已到底部,无法下移");
|
||||
return;
|
||||
}
|
||||
swapRulePosition(ruleList, position, position + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 交换规则位置
|
||||
*/
|
||||
private void swapRulePosition(ArrayList<PhoneConnectRuleModel> list, int fromPos, int toPos) {
|
||||
PhoneConnectRuleModel temp = list.get(fromPos);
|
||||
list.set(fromPos, list.get(toPos));
|
||||
list.set(toPos, temp);
|
||||
Rules.getInstance(mContext).saveRules();
|
||||
notifyDataSetChanged();
|
||||
LogUtils.d(TAG, "swapRulePosition: 规则位置交换完成,from=" + fromPos + ",to=" + toPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示删除确认弹窗
|
||||
*/
|
||||
private void showDeleteConfirmDialog(Context dialogContext, final PhoneConnectRuleModel model, final int position) {
|
||||
YesNoAlertDialog.show(dialogContext, "删除确认", "是否删除该通话规则?", new YesNoAlertDialog.OnDialogResultListener() {
|
||||
@Override
|
||||
public void onYes() {
|
||||
ArrayList<PhoneConnectRuleModel> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList();
|
||||
ruleList.remove(position);
|
||||
Rules.getInstance(mContext).saveRules();
|
||||
notifyDataSetChanged();
|
||||
LogUtils.d(TAG, "showDeleteConfirmDialog: 规则删除成功,position=" + position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNo() {
|
||||
LogUtils.d(TAG, "showDeleteConfirmDialog: 用户取消删除规则,position=" + position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====================== ViewHolder 内部类区 ======================
|
||||
static class SimpleViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final LeftScrollView scrollView;
|
||||
private final TextView tvRuleText;
|
||||
CheckBox checkBoxAllow;
|
||||
LeftScrollView scrollView;
|
||||
TextView tvRuleText;
|
||||
CheckBox checkBoxAllow;
|
||||
CheckBox checkBoxEnable;
|
||||
|
||||
|
||||
public SimpleViewHolder(@NonNull ViewGroup parent, @NonNull View itemView) {
|
||||
super(itemView);
|
||||
scrollView = itemView.findViewById(R.id.scrollView);
|
||||
LayoutInflater inflater = LayoutInflater.from(itemView.getContext());
|
||||
View viewContent = inflater.inflate(R.layout.view_phone_connect_rule_simple_content, parent, false);
|
||||
tvRuleText = viewContent.findViewById(R.id.ruletext_tv);
|
||||
checkBoxAllow = viewContent.findViewById(R.id.checkbox_allow);
|
||||
checkBoxEnable = viewContent.findViewById(R.id.checkbox_enable);
|
||||
//tvRuleText = new TextView(itemView.getContext());
|
||||
scrollView = (LeftScrollView) itemView.findViewById(R.id.scrollView);
|
||||
// 初始化简单视图内容布局
|
||||
LayoutInflater inflater = LayoutInflater.from(itemView.getContext());
|
||||
View viewContent = inflater.inflate(R.layout.view_phone_connect_rule_simple_content, parent, false);
|
||||
tvRuleText = (TextView) viewContent.findViewById(R.id.ruletext_tv);
|
||||
checkBoxAllow = (CheckBox) viewContent.findViewById(R.id.checkbox_allow);
|
||||
checkBoxEnable = (CheckBox) viewContent.findViewById(R.id.checkbox_enable);
|
||||
// 设置内容宽度并添加到滚动视图
|
||||
scrollView.setContentWidth(parent.getWidth());
|
||||
//scrollView.setContentWidth(600);
|
||||
scrollView.addContentLayout(viewContent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class EditViewHolder extends RecyclerView.ViewHolder {
|
||||
@@ -245,17 +244,14 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
|
||||
CheckBox checkBoxEnable;
|
||||
Button buttonConfirm;
|
||||
|
||||
public EditViewHolder(@NonNull ViewGroup parent, @NonNull View itemView) {
|
||||
public EditViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
editText = itemView.findViewById(R.id.edit_text);
|
||||
checkBoxAllow = itemView.findViewById(R.id.checkbox_allow);
|
||||
checkBoxEnable = itemView.findViewById(R.id.checkbox_enable);
|
||||
buttonConfirm = itemView.findViewById(R.id.button_confirm);
|
||||
// Java7 适配:添加强制类型转换
|
||||
editText = (EditText) itemView.findViewById(R.id.edit_text);
|
||||
checkBoxAllow = (CheckBox) itemView.findViewById(R.id.checkbox_allow);
|
||||
checkBoxEnable = (CheckBox) itemView.findViewById(R.id.checkbox_enable);
|
||||
buttonConfirm = (Button) itemView.findViewById(R.id.button_confirm);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCheckBoxTouchListener(CheckBox checkBox) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ package cc.winboll.studio.contacts.dun;
|
||||
*/
|
||||
import android.content.Context;
|
||||
import cc.winboll.studio.contacts.activities.SettingsActivity;
|
||||
import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
|
||||
import cc.winboll.studio.contacts.beans.SettingsModel;
|
||||
import cc.winboll.studio.contacts.model.PhoneConnectRuleModel;
|
||||
import cc.winboll.studio.contacts.model.SettingsModel;
|
||||
import cc.winboll.studio.contacts.services.MainService;
|
||||
import cc.winboll.studio.contacts.utils.ContactUtils;
|
||||
import cc.winboll.studio.contacts.utils.IntUtils;
|
||||
|
||||
@@ -19,7 +19,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.contacts.adapters.CallLogAdapter;
|
||||
import cc.winboll.studio.contacts.beans.CallLogModel;
|
||||
import cc.winboll.studio.contacts.model.CallLogModel;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.concurrent.Executors;
|
||||
|
||||
import cc.winboll.studio.contacts.R;
|
||||
import cc.winboll.studio.contacts.adapters.ContactAdapter;
|
||||
import cc.winboll.studio.contacts.beans.ContactModel;
|
||||
import cc.winboll.studio.contacts.model.ContactModel;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cc.winboll.studio.contacts.beans;
|
||||
package cc.winboll.studio.contacts.model;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
@@ -1,4 +1,4 @@
|
||||
package cc.winboll.studio.contacts.beans;
|
||||
package cc.winboll.studio.contacts.model;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
@@ -1,4 +1,4 @@
|
||||
package cc.winboll.studio.contacts.beans;
|
||||
package cc.winboll.studio.contacts.model;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
@@ -1,4 +1,4 @@
|
||||
package cc.winboll.studio.contacts.beans;
|
||||
package cc.winboll.studio.contacts.model;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
@@ -1,4 +1,4 @@
|
||||
package cc.winboll.studio.contacts.beans;
|
||||
package cc.winboll.studio.contacts.model;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
@@ -1,4 +1,4 @@
|
||||
package cc.winboll.studio.contacts.beans;
|
||||
package cc.winboll.studio.contacts.model;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
@@ -19,7 +19,7 @@ import android.telecom.InCallService;
|
||||
import android.telephony.TelephonyManager;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import cc.winboll.studio.contacts.ActivityStack;
|
||||
import cc.winboll.studio.contacts.beans.RingTongBean;
|
||||
import cc.winboll.studio.contacts.model.RingTongBean;
|
||||
import cc.winboll.studio.contacts.dun.Rules;
|
||||
import cc.winboll.studio.contacts.fragments.CallLogFragment;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
@@ -12,7 +12,7 @@ import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
|
||||
import cc.winboll.studio.contacts.model.MainServiceBean;
|
||||
import cc.winboll.studio.contacts.services.MainService;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ import android.content.ServiceConnection;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
|
||||
import cc.winboll.studio.contacts.beans.RingTongBean;
|
||||
import cc.winboll.studio.contacts.model.MainServiceBean;
|
||||
import cc.winboll.studio.contacts.model.RingTongBean;
|
||||
import cc.winboll.studio.contacts.bobulltoon.TomCat;
|
||||
import cc.winboll.studio.contacts.dun.Rules;
|
||||
import cc.winboll.studio.contacts.handlers.MainServiceHandler;
|
||||
|
||||
@@ -9,7 +9,7 @@ import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.widget.TextView;
|
||||
import cc.winboll.studio.contacts.beans.SettingsModel;
|
||||
import cc.winboll.studio.contacts.model.SettingsModel;
|
||||
import cc.winboll.studio.contacts.dun.Rules;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user