Compare commits

..

No commits in common. 'liuyuchen_part' and 'main' have entirely different histories.

@ -1,3 +0,0 @@
# 默认忽略的文件
/shelf/
/workspace.xml

@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-11-10T02:14:04.587555600Z">
<DropdownSelection timestamp="2025-10-11T11:49:33.560456900Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\77414\.android\avd\Pixel_9_Pro.avd" />
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\asus\.android\avd\Pixel.avd" />
</handle>
</Target>
</DropdownSelection>

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="NullableNotNullManager">
@ -183,13 +182,6 @@
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="VisualizationToolProject">
<option name="state">
<ProjectState>
<option name="scale" value="0.98814697265625" />
</ProjectState>
</option>
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/LLRiseTabBarDemo.iml" filepath="$PROJECT_DIR$/.idea/LLRiseTabBarDemo.iml" />
</modules>
</component>
</project>

@ -1,9 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
<component name="VcsProjectSettings">
<option name="detectVcsMappingsAutomatically" value="false" />
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

@ -1,74 +1,28 @@
// app/build.gradle
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android' // Kotlin
}
apply plugin: 'com.android.application'
android {
namespace "com.startsmake.llrisetabbardemo"
compileSdk 33
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.startsmake.llrisetabbardemo"
minSdk 21
targetSdk 33
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
namespace "com.startsmake.llrisetabbardemo"
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation 'junit:junit:4.13.2'
implementation 'com.github.bumptech.glide:glide:4.15.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
// AndroidX
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
// Kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.20"
implementation 'com.google.android.flexbox:flexbox:3.0.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
//gson
implementation 'com.google.code.gson:gson:2.10.1'
//
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0'
//
testImplementation 'junit:junit:4.12'
implementation 'com.android.support:appcompat-v7:23.1.0'
implementation project(':mainnavigatetabbar')
//
configurations {
all {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
}
}
}
}

@ -1,19 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.startsmake.llrisetabbardemo">
<!-- 适配Android 13+需要的通知权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 相机权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
@ -21,63 +7,13 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- 登录页面作为启动页 -->
<activity
android:name=".activity.LoginActivity"
android:exported="true">
<activity android:name=".activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 主页面 -->
<activity
android:name=".activity.MainActivity"
android:exported="false" />
<!-- 注册页面 -->
<activity
android:name=".activity.RegisterActivity"
android:exported="false" />
<!-- 忘记密码页面 -->
<activity
android:name=".activity.ForgotPasswordActivity"
android:exported="false" />
<!-- 聊天页面 -->
<activity
android:name=".activity.ChatActivity"
android:exported="false" />
<!-- 搜索页面 -->
<activity
android:name=".activity.SearchActivity"
android:exported="false" />
<!-- 搜索结果页面 -->
<activity
android:name=".activity.SearchResultsActivity"
android:exported="false" />
<!-- 商品详情跳转页面 -->
<activity
android:name=".activity.ProductDetailActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<!-- 添加FileProvider支持用于摄像头功能 -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
</manifest>

@ -1,142 +0,0 @@
package com.startsmake.llrisetabbardemo.activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.adapter.ChatMessageAdapter;
import com.startsmake.llrisetabbardemo.model.ChatMessage;
import java.util.ArrayList;
import java.util.List;
public class ChatActivity extends AppCompatActivity {
private TextView tvTitle;
private ImageView ivBack;
private RecyclerView rvChatMessages;
private EditText etMessage;
private ImageButton btnSend;
private ChatMessageAdapter chatAdapter;
private List<ChatMessage> messageList;
private String chatTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
// 获取传递过来的聊天标题
chatTitle = getIntent().getStringExtra("chat_title");
if (chatTitle == null) {
chatTitle = "聊天";
}
initView();
initData();
setupClickListeners();
}
private void initView() {
tvTitle = findViewById(R.id.tvTitle);
ivBack = findViewById(R.id.ivBack);
rvChatMessages = findViewById(R.id.rvChatMessages);
etMessage = findViewById(R.id.etMessage);
btnSend = findViewById(R.id.btnSend);
tvTitle.setText(chatTitle);
}
private void initData() {
messageList = new ArrayList<>();
// 添加一些初始消息
if ("通知消息".equals(chatTitle)) {
messageList.add(new ChatMessage("系统", "红包到账提醒", "10:30", false));
messageList.add(new ChatMessage("我", "收到了,谢谢!", "10:31", true));
} else if ("刑事组之虎".equals(chatTitle)) {
messageList.add(new ChatMessage("刑事组之虎", "快给ta一个评价吧", "04-19 14:20", false));
messageList.add(new ChatMessage("我", "已经评价了,商品很不错!", "04-19 14:25", true));
} else {
messageList.add(new ChatMessage(chatTitle, "你好!", "刚刚", false));
}
chatAdapter = new ChatMessageAdapter(this, messageList);
rvChatMessages.setLayoutManager(new LinearLayoutManager(this));
rvChatMessages.setAdapter(chatAdapter);
// 滚动到底部
rvChatMessages.scrollToPosition(messageList.size() - 1);
}
private void setupClickListeners() {
// 返回按钮
ivBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
// 发送按钮
btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendMessage();
}
});
}
private void sendMessage() {
String message = etMessage.getText().toString().trim();
if (!TextUtils.isEmpty(message)) {
// 添加新消息到列表
ChatMessage newMessage = new ChatMessage("我", message, "刚刚", true);
messageList.add(newMessage);
chatAdapter.notifyItemInserted(messageList.size() - 1);
// 清空输入框
etMessage.setText("");
// 滚动到底部
rvChatMessages.scrollToPosition(messageList.size() - 1);
// 模拟对方回复(可选)
simulateReply(message);
}
}
private void simulateReply(String userMessage) {
// 延迟模拟回复
rvChatMessages.postDelayed(new Runnable() {
@Override
public void run() {
String reply = generateReply(userMessage);
ChatMessage replyMessage = new ChatMessage(chatTitle, reply, "刚刚", false);
messageList.add(replyMessage);
chatAdapter.notifyItemInserted(messageList.size() - 1);
rvChatMessages.scrollToPosition(messageList.size() - 1);
}
}, 1000);
}
private String generateReply(String userMessage) {
// 简单的回复逻辑
if (userMessage.contains("你好") || userMessage.contains("在吗")) {
return "在的,有什么可以帮您?";
} else if (userMessage.contains("价格") || userMessage.contains("多少钱")) {
return "这个商品价格是xxx元";
} else if (userMessage.contains("谢谢")) {
return "不客气!";
} else {
return "收到您的消息了!";
}
}
}

@ -1,293 +0,0 @@
package com.startsmake.llrisetabbardemo.activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputEditText;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.manager.UserManager;
import java.util.Random;
public class ForgotPasswordActivity extends AppCompatActivity {
private TextInputEditText etPhone, etVerificationCode, etNewPassword;
private Button btnSendCode, btnResetPassword;
private ImageButton btnBack;
private TextView tvLogin;
private CountDownTimer countDownTimer;
private boolean isCounting = false;
private String verificationCode = "";
private UserManager userManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forgot_password);
userManager = UserManager.getInstance(this);
initViews();
setupClickListeners();
}
private void initViews() {
etPhone = findViewById(R.id.et_phone);
etVerificationCode = findViewById(R.id.et_verification_code);
etNewPassword = findViewById(R.id.et_new_password);
btnSendCode = findViewById(R.id.btn_send_code);
btnResetPassword = findViewById(R.id.btn_reset_password);
btnBack = findViewById(R.id.btn_back);
tvLogin = findViewById(R.id.tv_login);
}
private void setupClickListeners() {
// 返回按钮
btnBack.setOnClickListener(v -> finish());
// 发送验证码
btnSendCode.setOnClickListener(v -> sendVerificationCode());
// 重置密码按钮
btnResetPassword.setOnClickListener(v -> attemptResetPassword());
// 返回登录
tvLogin.setOnClickListener(v -> {
Intent intent = new Intent(ForgotPasswordActivity.this, LoginActivity.class);
startActivity(intent);
finish();
});
}
private void sendVerificationCode() {
String phone = etPhone.getText().toString().trim();
if (!validatePhone(phone)) {
return;
}
// 检查用户是否存在
if (!userManager.isPhoneRegistered(phone)) {
etPhone.setError("该手机号未注册");
etPhone.requestFocus();
Toast.makeText(this, "该手机号未注册,请先注册", Toast.LENGTH_SHORT).show();
return;
}
if (!isCounting) {
// 生成随机验证码
verificationCode = generateVerificationCode();
startCountDown();
// 模拟发送验证码(在实际应用中应该通过短信发送)
Toast.makeText(this, "验证码已发送: " + verificationCode, Toast.LENGTH_LONG).show();
}
}
private boolean validatePhone(String phone) {
if (phone.isEmpty()) {
etPhone.setError("请输入手机号");
etPhone.requestFocus();
return false;
}
if (phone.length() != 11) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
if (!phone.startsWith("1")) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
return true;
}
private String generateVerificationCode() {
Random random = new Random();
int code = 100000 + random.nextInt(900000);
return String.valueOf(code);
}
private void startCountDown() {
isCounting = true;
btnSendCode.setEnabled(false);
countDownTimer = new CountDownTimer(60000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
btnSendCode.setText(millisUntilFinished / 1000 + "秒后重发");
}
@Override
public void onFinish() {
isCounting = false;
btnSendCode.setEnabled(true);
btnSendCode.setText("发送验证码");
// 验证码过期
verificationCode = "";
}
}.start();
}
private void attemptResetPassword() {
String phone = etPhone.getText().toString().trim();
String code = etVerificationCode.getText().toString().trim();
String newPassword = etNewPassword.getText().toString().trim();
if (!validateResetInput(phone, code, newPassword)) {
return;
}
// 验证验证码
if (!code.equals(verificationCode)) {
etVerificationCode.setError("验证码错误");
etVerificationCode.requestFocus();
Toast.makeText(this, "请输入正确的验证码", Toast.LENGTH_SHORT).show();
return;
}
// 检查验证码是否过期
if (verificationCode.isEmpty()) {
etVerificationCode.setError("验证码已过期,请重新获取");
etVerificationCode.requestFocus();
Toast.makeText(this, "验证码已过期,请重新获取", Toast.LENGTH_SHORT).show();
return;
}
// 重置密码
boolean success = userManager.resetPassword(phone, newPassword);
if (success) {
performResetSuccess(phone);
} else {
Toast.makeText(this, "重置密码失败,请检查手机号是否正确", Toast.LENGTH_SHORT).show();
etPhone.setError("手机号未注册或不存在");
etPhone.requestFocus();
}
}
private boolean validateResetInput(String phone, String code, String newPassword) {
// 验证手机号
if (phone.isEmpty()) {
etPhone.setError("请输入手机号");
etPhone.requestFocus();
return false;
}
if (phone.length() != 11) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
if (!phone.startsWith("1")) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
// 验证验证码
if (code.isEmpty()) {
etVerificationCode.setError("请输入验证码");
etVerificationCode.requestFocus();
return false;
}
if (code.length() != 6) {
etVerificationCode.setError("验证码格式不正确");
etVerificationCode.requestFocus();
return false;
}
// 验证新密码
if (newPassword.isEmpty()) {
etNewPassword.setError("请输入新密码");
etNewPassword.requestFocus();
return false;
}
if (newPassword.length() < 6) {
etNewPassword.setError("密码至少6位");
etNewPassword.requestFocus();
return false;
}
if (newPassword.length() > 20) {
etNewPassword.setError("密码最多20位");
etNewPassword.requestFocus();
return false;
}
// 检查密码强度(可选增强)
if (!isPasswordStrong(newPassword)) {
etNewPassword.setError("密码过于简单,建议包含字母和数字");
etNewPassword.requestFocus();
return false;
}
return true;
}
private boolean isPasswordStrong(String password) {
// 简单的密码强度检查:至少包含字母和数字
boolean hasLetter = false;
boolean hasDigit = false;
for (char c : password.toCharArray()) {
if (Character.isLetter(c)) {
hasLetter = true;
} else if (Character.isDigit(c)) {
hasDigit = true;
}
// 如果已经满足条件,提前返回
if (hasLetter && hasDigit) {
return true;
}
}
return hasLetter && hasDigit;
}
private void performResetSuccess(String phone) {
Toast.makeText(this, "密码重置成功!", Toast.LENGTH_SHORT).show();
// 重置成功后跳转到登录页面,并传递手机号方便用户登录
Intent intent = new Intent(ForgotPasswordActivity.this, LoginActivity.class);
intent.putExtra("phone", phone);
intent.putExtra("from_forgot_password", true);
startActivity(intent);
finish();
}
@Override
protected void onResume() {
super.onResume();
// 如果从Intent中获取到手机号自动填充
Intent intent = getIntent();
if (intent != null && intent.hasExtra("phone")) {
String phone = intent.getStringExtra("phone");
if (phone != null && !phone.isEmpty()) {
etPhone.setText(phone);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (countDownTimer != null) {
countDownTimer.cancel();
}
}
}

@ -1,179 +0,0 @@
package com.startsmake.llrisetabbardemo.activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputEditText;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.manager.UserManager;
import com.startsmake.llrisetabbardemo.model.User;
public class LoginActivity extends AppCompatActivity {
private TextInputEditText etPhone, etPassword;
private Button btnLogin, btnSkipLogin;
private TextView tvForgotPassword, tvRegister;
private UserManager userManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 初始化用户管理器
userManager = UserManager.getInstance(this);
// 移除自动登录检查,让用户手动登录
// if (userManager.isLoggedIn()) {
// navigateToMain();
// return;
// }
initViews();
setupClickListeners();
// 检查是否有从其他页面传递过来的手机号
handleIntentData();
}
private void initViews() {
etPhone = findViewById(R.id.et_phone);
etPassword = findViewById(R.id.et_password);
btnLogin = findViewById(R.id.btn_login);
btnSkipLogin = findViewById(R.id.btn_skip_login);
tvForgotPassword = findViewById(R.id.tv_forgot_password);
tvRegister = findViewById(R.id.tv_register);
}
private void setupClickListeners() {
// 登录按钮
btnLogin.setOnClickListener(v -> attemptLogin());
// 跳过登录按钮
btnSkipLogin.setOnClickListener(v -> skipToMain());
// 忘记密码
tvForgotPassword.setOnClickListener(v -> {
Intent intent = new Intent(LoginActivity.this, ForgotPasswordActivity.class);
startActivity(intent);
});
// 注册
tvRegister.setOnClickListener(v -> {
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent);
});
}
private void handleIntentData() {
Intent intent = getIntent();
if (intent != null && intent.hasExtra("phone")) {
String phone = intent.getStringExtra("phone");
if (phone != null && !phone.isEmpty()) {
etPhone.setText(phone);
// 自动聚焦到密码输入框
etPassword.requestFocus();
}
}
}
private void attemptLogin() {
String phone = etPhone.getText().toString().trim();
String password = etPassword.getText().toString().trim();
if (!validateInput(phone, password)) {
return;
}
// 使用 UserManager 进行登录验证
User user = userManager.loginUser(phone, password);
if (user != null) {
// 登录成功
performLoginSuccess(user);
} else {
// 登录失败
showLoginError();
}
}
private boolean validateInput(String phone, String password) {
if (phone.isEmpty()) {
etPhone.setError("请输入手机号");
etPhone.requestFocus();
return false;
}
if (password.isEmpty()) {
etPassword.setError("请输入密码");
etPassword.requestFocus();
return false;
}
if (phone.length() != 11) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
if (!phone.startsWith("1")) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
if (password.length() < 6) {
etPassword.setError("密码至少6位");
etPassword.requestFocus();
return false;
}
return true;
}
private void performLoginSuccess(User user) {
// 保存登录状态和用户信息
saveLoginState(user);
Toast.makeText(this, "登录成功!", Toast.LENGTH_SHORT).show();
navigateToMain();
}
private void saveLoginState(User user) {
SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("is_logged_in", true);
editor.putString("user_phone", user.getPhone());
editor.putString("user_name", user.getUsername());
editor.putString("user_token", "mock_token_" + System.currentTimeMillis());
editor.apply();
}
private void showLoginError() {
Toast.makeText(this, "手机号或密码错误", Toast.LENGTH_SHORT).show();
etPassword.setError("密码错误");
etPassword.requestFocus();
}
private void skipToMain() {
Toast.makeText(this, "游客模式进入", Toast.LENGTH_SHORT).show();
navigateToMain();
}
private void navigateToMain() {
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
// 清理资源
}
}

@ -1,224 +1,53 @@
package com.startsmake.llrisetabbardemo.activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import manager.DataManager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.fragment.CityFragment;
import com.startsmake.llrisetabbardemo.fragment.HomeFragment;
import com.startsmake.llrisetabbardemo.fragment.MessageFragment;
import com.startsmake.llrisetabbardemo.fragment.PersonFragment;
import com.startsmake.llrisetabbardemo.fragment.PublishFragment;
import com.startsmake.mainnavigatetabbar.widget.MainNavigateTabBar;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG_PAGE_HOME = "首页";
private static final String TAG_PAGE_CITY = "集市";
private static final String TAG_PAGE_CITY = "同城";
private static final String TAG_PAGE_PUBLISH = "发布";
private static final String TAG_PAGE_MESSAGE = "消息";
private static final String TAG_PAGE_PERSON = "我的";
private MainNavigateTabBar mNavigateTabBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化 DataManager
DataManager.getInstance().init(this);
// 初始化视图,传递 savedInstanceState
initViews(savedInstanceState);
// 检查登录状态(可选)
checkLoginStatus();
}
private void initViews(Bundle savedInstanceState) {
try {
mNavigateTabBar = findViewById(R.id.mainTabBar);
if (mNavigateTabBar == null) {
Toast.makeText(this, "底部导航栏初始化失败", Toast.LENGTH_SHORT).show();
return;
}
mNavigateTabBar.onRestoreInstanceState(savedInstanceState);
mNavigateTabBar = (MainNavigateTabBar) findViewById(R.id.mainTabBar);
// 添加Tab
mNavigateTabBar.addTab(HomeFragment.class, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_home, R.mipmap.comui_tab_home_selected, TAG_PAGE_HOME));
mNavigateTabBar.addTab(CityFragment.class, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_city, R.mipmap.comui_tab_city_selected, TAG_PAGE_CITY));
mNavigateTabBar.addTab(null, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_post, R.mipmap.comui_tab_post, TAG_PAGE_PUBLISH)); // 发布按钮
mNavigateTabBar.addTab(MessageFragment.class, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_message, R.mipmap.comui_tab_message_selected, TAG_PAGE_MESSAGE));
mNavigateTabBar.addTab(PersonFragment.class, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_person, R.mipmap.comui_tab_person_selected, TAG_PAGE_PERSON));
mNavigateTabBar.onRestoreInstanceState(savedInstanceState);
} catch (Exception e) {
Toast.makeText(this, "界面初始化失败", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
mNavigateTabBar.addTab(HomeFragment.class, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_home, R.mipmap.comui_tab_home_selected, TAG_PAGE_HOME));
mNavigateTabBar.addTab(CityFragment.class, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_city, R.mipmap.comui_tab_city_selected, TAG_PAGE_CITY));
mNavigateTabBar.addTab(null, new MainNavigateTabBar.TabParam(0, 0, TAG_PAGE_PUBLISH));
mNavigateTabBar.addTab(MessageFragment.class, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_message, R.mipmap.comui_tab_message_selected, TAG_PAGE_MESSAGE));
mNavigateTabBar.addTab(PersonFragment.class, new MainNavigateTabBar.TabParam(R.mipmap.comui_tab_person, R.mipmap.comui_tab_person_selected, TAG_PAGE_PERSON));
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mNavigateTabBar != null) {
mNavigateTabBar.onSaveInstanceState(outState);
}
mNavigateTabBar.onSaveInstanceState(outState);
}
private void checkLoginStatus() {
// 这里可以根据需要决定是否强制登录
// 如果应用要求必须登录,可以在这里跳转到登录页面
/*
SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
if (!sp.getBoolean("is_logged_in", false)) {
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
}
*/
}
// 发布按钮点击事件
public void onClickPublish(View v) {
// 切换到发布Fragment
switchToPublishFragment();
}
// 切换到发布Fragment
public void switchToPublishFragment() {
try {
PublishFragment publishFragment = new PublishFragment();
// 使用FragmentTransaction来显示发布页面
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// 替换当前显示的Fragment
transaction.replace(R.id.main_container, publishFragment, "PublishFragment");
transaction.addToBackStack("publish"); // 允许用户按返回键回到之前的Fragment
transaction.commit();
} catch (Exception e) {
Toast.makeText(this, "打开发布页面失败", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
// 切换回首页Fragment
public void switchToHomeFragment() {
try {
// 返回到首页
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
} else {
// 如果后退栈为空,直接切换到首页
HomeFragment homeFragment = new HomeFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_container, homeFragment, TAG_PAGE_HOME);
transaction.commit();
}
// 确保底部导航栏选中首页
if (mNavigateTabBar != null) {
mNavigateTabBar.setCurrentSelectedTab(0); // 0 是首页的索引
}
} catch (Exception e) {
Toast.makeText(this, "返回首页失败", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
// 获取HomeFragment实例的方法
public HomeFragment getHomeFragment() {
try {
// 方法1通过Tag查找
Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_PAGE_HOME);
if (fragment instanceof HomeFragment) {
return (HomeFragment) fragment;
}
// 方法2遍历所有Fragment找到HomeFragment实例
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragmentItem : fragments) {
if (fragmentItem instanceof HomeFragment && fragmentItem.isVisible()) {
return (HomeFragment) fragmentItem;
}
}
}
// 方法3查找当前显示的Fragment
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
if (currentFragment instanceof HomeFragment) {
return (HomeFragment) currentFragment;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public void onBackPressed() {
// 处理返回键
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
// 如果有Fragment在后退栈中先弹出
getSupportFragmentManager().popBackStack();
// 确保底部导航栏状态正确
if (mNavigateTabBar != null) {
mNavigateTabBar.setCurrentSelectedTab(0); // 回到首页
}
} else {
// 双击退出应用
if (isTaskRoot()) {
// 如果是应用的根Activity可以实现双击退出
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "再按一次退出应用", Toast.LENGTH_SHORT).show();
handler.postDelayed(() -> doubleBackToExitPressedOnce = false, 2000);
} else {
super.onBackPressed();
}
}
}
// 双击退出相关变量
private boolean doubleBackToExitPressedOnce = false;
private android.os.Handler handler = new android.os.Handler();
@Override
protected void onDestroy() {
super.onDestroy();
// 清理Handler防止内存泄漏
handler.removeCallbacksAndMessages(null);
}
// 切换到指定Tab的方法 - 简化版本
public void switchToTab(int tabIndex) {
if (mNavigateTabBar != null && tabIndex >= 0 && tabIndex <= 4) { // 假设有5个tab
mNavigateTabBar.setCurrentSelectedTab(tabIndex);
}
}
// 显示Toast的便捷方法
public void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
Toast.makeText(this, "发布", Toast.LENGTH_LONG).show();
}
}
}

@ -1,92 +0,0 @@
package com.startsmake.llrisetabbardemo.activity;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.fragment.ItemDetailFragment;
import com.startsmake.llrisetabbardemo.model.Item;
import com.startsmake.llrisetabbardemo.model.Product;
import manager.DataManager;
public class ProductDetailActivity extends AppCompatActivity {
public static final String EXTRA_PRODUCT = "extra_product";
public static final String EXTRA_ITEM = "extra_item";
public static final String EXTRA_PRODUCT_ID = "extra_product_id";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_detail);
// 获取传递的数据
Product product = (Product) getIntent().getSerializableExtra(EXTRA_PRODUCT);
Item item = (Item) getIntent().getSerializableExtra(EXTRA_ITEM);
String productId = getIntent().getStringExtra(EXTRA_PRODUCT_ID);
// 根据不同的数据来源创建Fragment
Item detailItem = null;
if (item != null) {
// 如果直接传递了Item对象
detailItem = item;
} else if (product != null) {
// 如果传递了Product对象转换为Item
detailItem = convertProductToItem(product);
} else if (productId != null) {
// 如果传递了商品ID从DataManager查找
DataManager dataManager = DataManager.getInstance();
Item foundItem = dataManager.getItemById(productId);
if (foundItem != null) {
detailItem = foundItem;
} else {
// 如果找不到尝试从Product列表查找并转换
for (Product p : dataManager.getAllProducts()) {
if (p.getId().equals(productId)) {
detailItem = convertProductToItem(p);
break;
}
}
}
}
if (detailItem != null) {
// 显示商品详情Fragment
showItemDetailFragment(detailItem);
} else {
// 处理数据加载失败的情况
finish();
}
}
private void showItemDetailFragment(Item item) {
ItemDetailFragment fragment = ItemDetailFragment.newInstance(item);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
}
/**
* ProductItem
*/
private Item convertProductToItem(Product product) {
Item item = new Item();
item.setId(product.getId());
item.setTitle(product.getName());
item.setDescription(product.getDescription());
item.setCategory(product.getCategory());
item.setPrice(product.getPrice());
item.setLocation(product.getLocation());
item.setContact(product.getContact());
item.setWantCount(product.getWantCount());
// 设置默认发布时间(如果没有的话)
if (item.getPublishTime() == 0) {
item.setPublishTime(System.currentTimeMillis());
}
return item;
}
}

@ -1,260 +0,0 @@
package com.startsmake.llrisetabbardemo.activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputEditText;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.manager.UserManager;
import com.startsmake.llrisetabbardemo.model.User;
import java.util.Random;
public class RegisterActivity extends AppCompatActivity {
private TextInputEditText etPhone, etVerificationCode, etPassword;
private Button btnSendCode, btnRegister;
private ImageButton btnBack;
private TextView tvLogin;
private CountDownTimer countDownTimer;
private boolean isCounting = false;
private String verificationCode = "";
private UserManager userManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
userManager = UserManager.getInstance(this);
initViews();
setupClickListeners();
}
private void initViews() {
etPhone = findViewById(R.id.et_phone);
etVerificationCode = findViewById(R.id.et_verification_code);
etPassword = findViewById(R.id.et_password);
btnSendCode = findViewById(R.id.btn_send_code);
btnRegister = findViewById(R.id.btn_register);
btnBack = findViewById(R.id.btn_back);
tvLogin = findViewById(R.id.tv_login);
}
private void setupClickListeners() {
// 返回按钮
btnBack.setOnClickListener(v -> finish());
// 发送验证码
btnSendCode.setOnClickListener(v -> sendVerificationCode());
// 注册按钮
btnRegister.setOnClickListener(v -> attemptRegister());
// 立即登录
tvLogin.setOnClickListener(v -> {
Intent intent = new Intent(RegisterActivity.this, LoginActivity.class);
startActivity(intent);
finish();
});
}
private void sendVerificationCode() {
String phone = etPhone.getText().toString().trim();
if (!validatePhone(phone)) {
return;
}
// 检查用户是否已存在
if (userManager.isPhoneRegistered(phone)) {
etPhone.setError("该手机号已注册");
etPhone.requestFocus();
return;
}
if (!isCounting) {
// 生成随机验证码
verificationCode = generateVerificationCode();
startCountDown();
// 模拟发送验证码(在实际应用中应该通过短信发送)
Toast.makeText(this, "验证码已发送: " + verificationCode, Toast.LENGTH_LONG).show();
}
}
private boolean validatePhone(String phone) {
if (phone.isEmpty()) {
etPhone.setError("请输入手机号");
etPhone.requestFocus();
return false;
}
if (phone.length() != 11) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
if (!phone.startsWith("1")) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
return true;
}
private String generateVerificationCode() {
Random random = new Random();
int code = 100000 + random.nextInt(900000);
return String.valueOf(code);
}
private void startCountDown() {
isCounting = true;
btnSendCode.setEnabled(false);
countDownTimer = new CountDownTimer(60000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
btnSendCode.setText(millisUntilFinished / 1000 + "秒后重发");
}
@Override
public void onFinish() {
isCounting = false;
btnSendCode.setEnabled(true);
btnSendCode.setText("发送验证码");
// 验证码过期
verificationCode = "";
}
}.start();
}
private void attemptRegister() {
String phone = etPhone.getText().toString().trim();
String code = etVerificationCode.getText().toString().trim();
String password = etPassword.getText().toString().trim();
if (!validateRegisterInput(phone, code, password)) {
return;
}
// 验证验证码
if (!code.equals(verificationCode)) {
etVerificationCode.setError("验证码错误");
etVerificationCode.requestFocus();
Toast.makeText(this, "请输入正确的验证码", Toast.LENGTH_SHORT).show();
return;
}
// 检查验证码是否过期
if (verificationCode.isEmpty()) {
etVerificationCode.setError("验证码已过期,请重新获取");
etVerificationCode.requestFocus();
Toast.makeText(this, "验证码已过期,请重新获取", Toast.LENGTH_SHORT).show();
return;
}
// 注册用户
boolean success = userManager.registerUser(phone, password);
if (success) {
performRegisterSuccess(phone, password);
} else {
Toast.makeText(this, "注册失败,该手机号已注册", Toast.LENGTH_SHORT).show();
etPhone.setError("该手机号已注册");
etPhone.requestFocus();
}
}
private boolean validateRegisterInput(String phone, String code, String password) {
// 验证手机号
if (phone.isEmpty()) {
etPhone.setError("请输入手机号");
etPhone.requestFocus();
return false;
}
if (phone.length() != 11) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
if (!phone.startsWith("1")) {
etPhone.setError("手机号格式不正确");
etPhone.requestFocus();
return false;
}
// 验证验证码
if (code.isEmpty()) {
etVerificationCode.setError("请输入验证码");
etVerificationCode.requestFocus();
return false;
}
if (code.length() != 6) {
etVerificationCode.setError("验证码格式不正确");
etVerificationCode.requestFocus();
return false;
}
// 验证密码
if (password.isEmpty()) {
etPassword.setError("请输入密码");
etPassword.requestFocus();
return false;
}
if (password.length() < 6) {
etPassword.setError("密码至少6位");
etPassword.requestFocus();
return false;
}
if (password.length() > 20) {
etPassword.setError("密码最多20位");
etPassword.requestFocus();
return false;
}
return true;
}
private void performRegisterSuccess(String phone, String password) {
Toast.makeText(this, "注册成功!", Toast.LENGTH_SHORT).show();
// 自动登录
User user = userManager.loginUser(phone, password);
if (user != null) {
// 跳转到主页面
Intent intent = new Intent(RegisterActivity.this, MainActivity.class);
startActivity(intent);
finish();
} else {
// 如果自动登录失败,跳转到登录页面
Toast.makeText(this, "注册成功,请登录", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(RegisterActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (countDownTimer != null) {
countDownTimer.cancel();
}
}
}

@ -1,380 +0,0 @@
package com.startsmake.llrisetabbardemo.activity;
import android.Manifest;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import manager.DataManager;
import com.startsmake.llrisetabbardemo.model.Item;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.model.Product;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class SearchActivity extends AppCompatActivity {
private EditText searchEditText;
private ImageButton backButton;
private ImageButton cameraButton;
private com.google.android.flexbox.FlexboxLayout historyContainer;
private com.google.android.flexbox.FlexboxLayout recommendContainer;
private TextView clearHistoryText;
private TextView expandHistoryText;
private SharedPreferences sharedPreferences;
private static final String SEARCH_HISTORY = "search_history";
private static final int MAX_HISTORY_COUNT = 6; // 最大存储6条
private static final int VISIBLE_HISTORY_COUNT = 4; // 默认显示4条
private boolean isHistoryExpanded = false;
// 相机相关变量
private static final int CAMERA_REQUEST_CODE = 1001;
private static final int CAMERA_PERMISSION_REQUEST_CODE = 1002;
private String currentPhotoPath;
private List<Product> allProducts;
private List<String> recommendKeywords;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
initViews();
initData();
loadSearchHistory();
setupRecommendations();
}
private void initViews() {
searchEditText = findViewById(R.id.search_edit_text);
backButton = findViewById(R.id.back_button);
cameraButton = findViewById(R.id.camera_button);
historyContainer = findViewById(R.id.history_container);
recommendContainer = findViewById(R.id.recommend_container);
clearHistoryText = findViewById(R.id.clear_history_text);
expandHistoryText = findViewById(R.id.expand_history_text);
TextView searchButton = findViewById(R.id.search_button);
// 设置返回按钮
backButton.setOnClickListener((View v) -> finish());
// 设置搜索按钮点击事件
searchButton.setOnClickListener((View v) -> {
performSearch();
});
// 设置搜索页面的相机按钮
cameraButton.setOnClickListener((View v) -> {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
openCamera();
} else {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
} else {
openCamera();
}
}
});
// 设置搜索功能
searchEditText.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
performSearch();
return true;
}
return false;
});
// 清空历史记录
clearHistoryText.setOnClickListener((View v) -> clearSearchHistory());
// 设置展开/收起按钮
expandHistoryText.setOnClickListener((View v) -> {
isHistoryExpanded = !isHistoryExpanded;
loadSearchHistory();
});
}
// 修改 initData 方法
private void initData() {
sharedPreferences = getSharedPreferences("search_prefs", MODE_PRIVATE);
// 从 DataManager 获取所有商品数据
DataManager dataManager = DataManager.getInstance();
List<Item> allItems = dataManager.getAllItems();
// 转换为 Product 对象(为了保持兼容性)
allProducts = new ArrayList<>();
for (Item item : allItems) {
Product product = dataManager.convertItemToProduct(item);
allProducts.add(product);
}
// 如果 DataManager 中没有数据,使用示例数据
if (allProducts.isEmpty()) {
allProducts.add(new Product("1", "Java编程思想", "计算机专业教材", "学习资料", 45.0, "", 0, "南校区", "卖家信用极好", true));
allProducts.add(new Product("2", "高等数学教材", "大学数学课本", "学习资料", 30.0, "", 0, "北校区", "百分百好评", false));
allProducts.add(new Product("3", "笔记本电脑", "二手联想笔记本", "数码产品", 1200.0, "", 0, "南校区", "卖家信用良好", true));
// ... 其他示例数据
}
// 初始化推荐关键词(保持不变)
recommendKeywords = Arrays.asList(
"Java编程教材", "Python入门书籍", "高等数学课本", "英语四级真题", "考研政治资料",
"二手笔记本电脑", "机械键盘", "无线鼠标", "蓝牙耳机", "平板电脑",
"台灯", "收纳箱", "穿衣镜", "瑜伽垫", "体重秤"
);
}
private void loadSearchHistory() {
Set<String> historySet = sharedPreferences.getStringSet(SEARCH_HISTORY, new HashSet<>());
List<String> historyList = new ArrayList<>(historySet);
// 按照搜索顺序排序(后搜索的在前)
Collections.reverse(historyList);
historyContainer.removeAllViews();
if (historyList.isEmpty()) {
findViewById(R.id.history_title).setVisibility(View.GONE);
clearHistoryText.setVisibility(View.GONE);
expandHistoryText.setVisibility(View.GONE);
} else {
findViewById(R.id.history_title).setVisibility(View.VISIBLE);
clearHistoryText.setVisibility(View.VISIBLE);
// 计算要显示的历史记录数量
int showCount = historyList.size();
if (!isHistoryExpanded && historyList.size() > VISIBLE_HISTORY_COUNT) {
showCount = VISIBLE_HISTORY_COUNT;
}
// 显示历史记录标签
for (int i = 0; i < showCount; i++) {
String keyword = historyList.get(i);
TextView historyTag = createTagView(keyword, true);
historyContainer.addView(historyTag);
}
// 显示展开/收起按钮
if (historyList.size() > VISIBLE_HISTORY_COUNT) {
expandHistoryText.setVisibility(View.VISIBLE);
if (isHistoryExpanded) {
expandHistoryText.setText("收起");
} else {
expandHistoryText.setText("展开更多(" + (historyList.size() - VISIBLE_HISTORY_COUNT) + ")");
}
} else {
expandHistoryText.setVisibility(View.GONE);
}
}
}
private void saveSearchHistory(String query) {
Set<String> historySet = sharedPreferences.getStringSet(SEARCH_HISTORY, new HashSet<>());
Set<String> newSet = new LinkedHashSet<>(); // 使用LinkedHashSet保持顺序
// 先添加新的搜索(确保在最前面)
newSet.add(query);
// 添加其他历史记录(排除重复项)
for (String item : historySet) {
if (!item.equals(query)) {
newSet.add(item);
}
}
// 如果超过最大数量,移除最旧的
if (newSet.size() > MAX_HISTORY_COUNT) {
List<String> list = new ArrayList<>(newSet);
// 保留最新的6条
List<String> newList = list.subList(0, MAX_HISTORY_COUNT);
newSet = new LinkedHashSet<>(newList);
}
sharedPreferences.edit().putStringSet(SEARCH_HISTORY, newSet).apply();
}
// 相机相关方法保持不变
private void openCamera() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Toast.makeText(this, "创建文件失败", Toast.LENGTH_SHORT).show();
}
if (photoFile != null) {
currentPhotoPath = photoFile.getAbsolutePath();
Uri photoURI = FileProvider.getUriForFile(this,
getPackageName() + ".fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, CAMERA_REQUEST_CODE);
}
} else {
Toast.makeText(this, "未找到相机应用", Toast.LENGTH_SHORT).show();
}
}
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return File.createTempFile(
imageFileName,
".jpg",
storageDir
);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK) {
if (currentPhotoPath != null) {
Toast.makeText(this, "拍照成功,开始搜索...", Toast.LENGTH_SHORT).show();
searchEditText.setText("图片搜索中...");
performImageSearch();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openCamera();
} else {
Toast.makeText(this, "需要相机权限才能拍照搜索", Toast.LENGTH_SHORT).show();
}
}
}
// 图片搜索功能
private void performImageSearch() {
List<Product> similarProducts = findSimilarProducts();
if (similarProducts.isEmpty()) {
searchEditText.setText("未找到相似商品");
Toast.makeText(this, "未找到相似商品", Toast.LENGTH_SHORT).show();
} else {
Intent intent = new Intent(this, SearchResultsActivity.class);
intent.putExtra("search_type", "image");
intent.putExtra("search_query", "图片搜索结果");
ArrayList<Product> productList = new ArrayList<>(similarProducts);
intent.putExtra("similar_products", productList);
startActivity(intent);
}
}
private List<Product> findSimilarProducts() {
List<Product> similarProducts = new ArrayList<>();
Collections.shuffle(allProducts);
similarProducts = allProducts.subList(0, Math.min(5, allProducts.size()));
return similarProducts;
}
private void setupRecommendations() {
List<String> randomRecommends = new ArrayList<>(recommendKeywords);
Collections.shuffle(randomRecommends);
List<String> selectedRecommends = randomRecommends.subList(0, Math.min(6, randomRecommends.size()));
recommendContainer.removeAllViews();
for (String keyword : selectedRecommends) {
TextView recommendTag = createTagView(keyword, false);
recommendContainer.addView(recommendTag);
}
}
private TextView createTagView(String keyword, boolean isHistory) {
TextView tagView = new TextView(this);
com.google.android.flexbox.FlexboxLayout.LayoutParams params = new com.google.android.flexbox.FlexboxLayout.LayoutParams(
com.google.android.flexbox.FlexboxLayout.LayoutParams.WRAP_CONTENT,
com.google.android.flexbox.FlexboxLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins(0, 0, 16, 16);
tagView.setLayoutParams(params);
tagView.setPadding(32, 16, 32, 16);
tagView.setText(keyword);
tagView.setTextSize(14);
tagView.setBackgroundResource(R.drawable.tag_background);
tagView.setTextColor(getResources().getColor(android.R.color.darker_gray));
tagView.setOnClickListener(v -> {
searchEditText.setText(keyword);
performSearch();
});
return tagView;
}
// 修改 performSearch 方法,确保使用统一的数据源
private void performSearch() {
String query = searchEditText.getText().toString().trim();
if (!TextUtils.isEmpty(query)) {
saveSearchHistory(query);
// 使用 DataManager 进行搜索
DataManager dataManager = DataManager.getInstance();
List<Item> searchResults = dataManager.searchItems(query);
// 转换为 Product 对象
List<Product> productResults = new ArrayList<>();
for (Item item : searchResults) {
productResults.add(dataManager.convertItemToProduct(item));
}
Intent intent = new Intent(this, SearchResultsActivity.class);
intent.putExtra("search_query", query);
intent.putExtra("search_results", new ArrayList<>(productResults)); // 传递搜索结果
startActivity(intent);
}
}
private void clearSearchHistory() {
sharedPreferences.edit().remove(SEARCH_HISTORY).apply();
loadSearchHistory();
}
@Override
protected void onResume() {
super.onResume();
loadSearchHistory();
}
}

@ -1,784 +0,0 @@
package com.startsmake.llrisetabbardemo.activity;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import manager.DataManager;
import com.startsmake.llrisetabbardemo.model.Item;
import com.google.android.flexbox.FlexboxLayout;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.adapter.SearchAdapter;
import com.startsmake.llrisetabbardemo.model.Product;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
public class SearchResultsActivity extends AppCompatActivity implements SearchAdapter.OnProductClickListener,
DataManager.OnDataChangedListener {
private static final String TAG = "SearchResultsActivity";
private RecyclerView resultsRecyclerView;
private TextView searchResultsTitle;
private TextView searchHintText;
private View searchBoxContainer;
private SearchAdapter searchAdapter;
private List<Product> currentProductList;
private List<Product> allProducts;
private List<Product> baseSearchResults; // 新增:存储基础搜索结果
// 筛选相关视图 - 删除 filterDiscount
private TextView filterPrice;
private TextView filterNew;
private TextView filterRegion;
private TextView filterMore;
// 筛选状态 - 删除 showDiscountOnly
private String currentSort = "price"; // 默认价格排序
private boolean priceAscending = false; // 价格排序方向
private boolean showNewOnly = false; // 是否只显示新发布商品
private String selectedRegion = ""; // 选中的区域
// 新增筛选状态变量
private double minPrice = 0;
private double maxPrice = 0;
private String selectedCategory = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_results);
// 注册数据变化监听器
DataManager.getInstance().registerDataChangedListener(this);
initViews();
initFilterData();
loadSearchResults();
setupFilterListeners();
}
@Override
public void onDataChanged() {
// 数据发生变化时,重新加载搜索结果
Log.d(TAG, "搜索结果页面收到数据变化通知,重新加载数据");
refreshSearchResults();
}
@Override
public void onProductWantCountChanged(String productId, int newCount) {
// 特定商品想要人数变化时,更新对应商品
Log.d(TAG, "搜索结果页面收到商品想要人数变化通知商品ID: " + productId + ", 新人数: " + newCount);
updateProductWantCount(productId, newCount);
}
// 更新特定商品的想要人数
private void updateProductWantCount(String productId, int newCount) {
if (currentProductList != null) {
for (int i = 0; i < currentProductList.size(); i++) {
Product product = currentProductList.get(i);
if (product.getId().equals(productId)) {
product.setWantCount(newCount);
// 通知适配器局部更新
if (searchAdapter != null) {
searchAdapter.notifyItemChanged(i);
}
Log.d(TAG, "更新搜索结果商品 " + productId + " 的想要人数为: " + newCount);
break;
}
}
}
// 同时更新基础搜索结果
if (baseSearchResults != null) {
for (int i = 0; i < baseSearchResults.size(); i++) {
Product product = baseSearchResults.get(i);
if (product.getId().equals(productId)) {
product.setWantCount(newCount);
break;
}
}
}
}
// 刷新搜索结果
private void refreshSearchResults() {
String searchType = getIntent().getStringExtra("search_type");
String query = getIntent().getStringExtra("search_query");
if ("image".equals(searchType)) {
// 图片搜索结果保持不变
List<Product> similarProducts = (List<Product>) getIntent().getSerializableExtra("similar_products");
if (similarProducts != null && !similarProducts.isEmpty()) {
baseSearchResults.clear();
baseSearchResults.addAll(similarProducts);
currentProductList.clear();
currentProductList.addAll(similarProducts);
searchAdapter.updateData(currentProductList);
}
} else {
// 文本搜索结果重新搜索
if (query != null) {
List<Product> searchResults = searchProducts(query);
baseSearchResults.clear();
baseSearchResults.addAll(searchResults);
currentProductList.clear();
currentProductList.addAll(searchResults);
searchAdapter.updateData(currentProductList);
}
}
}
private void initViews() {
resultsRecyclerView = findViewById(R.id.results_recycler_view);
searchResultsTitle = findViewById(R.id.search_results_title);
searchHintText = findViewById(R.id.search_hint_text);
searchBoxContainer = findViewById(R.id.search_box_container);
// 初始化筛选按钮 - 删除 filterDiscount
filterPrice = findViewById(R.id.filter_price);
filterNew = findViewById(R.id.filter_new);
filterRegion = findViewById(R.id.filter_region);
filterMore = findViewById(R.id.filter_more);
// 设置网格布局管理器每行显示2个商品
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
resultsRecyclerView.setLayoutManager(layoutManager);
currentProductList = new ArrayList<>();
allProducts = new ArrayList<>();
baseSearchResults = new ArrayList<>(); // 初始化基础搜索结果
// 使用双参数构造函数传递this作为监听器
searchAdapter = new SearchAdapter(currentProductList, this);
resultsRecyclerView.setAdapter(searchAdapter);
// 设置返回按钮
findViewById(R.id.back_button).setOnClickListener((View v) -> {
finish();
});
// 设置搜索框点击事件 - 跳转到搜索页面
searchBoxContainer.setOnClickListener(v -> {
Intent intent = new Intent(this, SearchActivity.class);
startActivity(intent);
});
}
private void setupFilterListeners() {
// 设置默认排序
currentSort = "price";
// 价格排序
filterPrice.setOnClickListener(v -> {
currentSort = "price";
priceAscending = !priceAscending;
updateFilterUI();
applyFilters();
});
// 删除降价筛选监听器
// 新发布筛选
filterNew.setOnClickListener(v -> {
showNewOnly = !showNewOnly;
updateFilterUI();
applyFilters();
});
// 区域筛选
filterRegion.setOnClickListener(v -> {
showRegionFilterDialog();
});
// 更多筛选
filterMore.setOnClickListener(v -> {
showFilterDialog();
});
}
private void updateFilterUI() {
// 重置所有按钮颜色 - 删除 filterDiscount
filterPrice.setTextColor(0xff666666);
filterNew.setTextColor(0xff666666);
filterRegion.setTextColor(0xff666666);
// 更新按钮文本和颜色
switch (currentSort) {
case "price":
filterPrice.setTextColor(0xff2196F3);
String priceText = priceAscending ? "价格 ↑" : "价格 ↓";
filterPrice.setText(priceText);
break;
}
// 删除降价筛选的UI更新
// 更新新发布筛选
if (showNewOnly) {
filterNew.setTextColor(0xff2196F3);
}
// 更新区域筛选
if (!selectedRegion.isEmpty()) {
filterRegion.setTextColor(0xff2196F3);
filterRegion.setText(selectedRegion + " ▼");
} else {
filterRegion.setText("区域 ▼");
}
// 更新筛选按钮状态(显示是否有激活的筛选条件)
boolean hasActiveFilters = minPrice > 0 || maxPrice > 0 ||
!selectedCategory.isEmpty() || !selectedRegion.isEmpty() ||
showNewOnly; // 删除 showDiscountOnly
if (hasActiveFilters) {
filterMore.setText("筛选 ●");
filterMore.setTextColor(0xff2196F3);
} else {
filterMore.setText("筛选");
filterMore.setTextColor(0xff666666);
}
}
private void showRegionFilterDialog() {
Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_region_filter);
// 设置对话框窗口属性
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.gravity = Gravity.BOTTOM;
window.setAttributes(layoutParams);
}
// 设置区域选项点击事件 - 更新为新的区域选项
String[] regions = {"东丽", "宁河", "其他"};
// 全区域选项
TextView regionAll = dialog.findViewById(R.id.region_all);
if (regionAll != null) {
regionAll.setOnClickListener(v -> {
selectedRegion = "";
updateFilterUI();
applyFilters();
dialog.dismiss();
});
}
// 东丽选项
TextView regionBeijing = dialog.findViewById(R.id.region_dongli);
if (regionBeijing != null) {
regionBeijing.setOnClickListener(v -> {
selectedRegion = "东丽";
updateFilterUI();
applyFilters();
dialog.dismiss();
});
}
// 宁河选项
TextView regionShanghai = dialog.findViewById(R.id.region_ninghe);
if (regionShanghai != null) {
regionShanghai.setOnClickListener(v -> {
selectedRegion = "宁河";
updateFilterUI();
applyFilters();
dialog.dismiss();
});
}
// 其他选项
TextView regionOther = dialog.findViewById(R.id.region_other);
if (regionOther != null) {
regionOther.setOnClickListener(v -> {
selectedRegion = "其他";
updateFilterUI();
applyFilters();
dialog.dismiss();
});
}
dialog.show();
}
private void showFilterDialog() {
Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_filter);
dialog.setCancelable(true);
// 设置对话框窗口属性
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.gravity = Gravity.BOTTOM;
window.setAttributes(layoutParams);
}
EditText etMinPrice = dialog.findViewById(R.id.et_min_price);
EditText etMaxPrice = dialog.findViewById(R.id.et_max_price);
Button btnCancel = dialog.findViewById(R.id.btn_cancel);
Button btnConfirm = dialog.findViewById(R.id.btn_confirm);
TextView btnReset = dialog.findViewById(R.id.btn_reset);
// 设置类别标签点击事件
setupCategoryTags(dialog);
// 设置区域标签点击事件
setupRegionTags(dialog);
// 设置当前筛选状态
if (minPrice > 0) {
etMinPrice.setText(String.valueOf((int) minPrice));
}
if (maxPrice > 0) {
etMaxPrice.setText(String.valueOf((int) maxPrice));
}
btnCancel.setOnClickListener(v -> dialog.dismiss());
btnConfirm.setOnClickListener(v -> {
// 获取价格筛选条件
String minPriceStr = etMinPrice.getText().toString();
String maxPriceStr = etMaxPrice.getText().toString();
if (!minPriceStr.isEmpty()) {
minPrice = Double.parseDouble(minPriceStr);
} else {
minPrice = 0;
}
if (!maxPriceStr.isEmpty()) {
maxPrice = Double.parseDouble(maxPriceStr);
} else {
maxPrice = 0;
}
// 应用筛选
applyFilters();
updateFilterUI();
dialog.dismiss();
});
btnReset.setOnClickListener(v -> {
// 重置所有筛选条件
resetFilters(dialog);
});
dialog.show();
}
private void setupCategoryTags(Dialog dialog) {
// 更新为新的类别 ID 数组
int[] categoryIds = {
R.id.category_digital, R.id.category_clothing, R.id.category_home,
R.id.category_books, R.id.category_beauty, R.id.category_sports,
R.id.category_other
};
// 更新为新的类别名称数组
String[] categories = {"数码产品", "服装鞋帽", "家居日用", "图书文具", "美妆个护", "运动户外", "其他"};
for (int i = 0; i < categoryIds.length; i++) {
TextView categoryView = dialog.findViewById(categoryIds[i]);
final String category = categories[i];
// 设置初始状态
if (category.equals(selectedCategory)) {
categoryView.setBackgroundResource(R.drawable.filter_tag_selected);
categoryView.setTextColor(0xff2196F3);
} else {
categoryView.setBackgroundResource(R.drawable.filter_tag_normal);
categoryView.setTextColor(0xff666666);
}
categoryView.setOnClickListener(v -> {
// 切换选中状态
if (selectedCategory.equals(category)) {
// 取消选中
selectedCategory = "";
categoryView.setBackgroundResource(R.drawable.filter_tag_normal);
categoryView.setTextColor(0xff666666);
} else {
// 选中当前,取消其他
selectedCategory = category;
for (int j = 0; j < categoryIds.length; j++) {
TextView otherView = dialog.findViewById(categoryIds[j]);
if (categories[j].equals(category)) {
otherView.setBackgroundResource(R.drawable.filter_tag_selected);
otherView.setTextColor(0xff2196F3);
} else {
otherView.setBackgroundResource(R.drawable.filter_tag_normal);
otherView.setTextColor(0xff666666);
}
}
}
});
}
}
private void setupRegionTags(Dialog dialog) {
// 更新为新的区域 ID 数组
int[] regionIds = {
R.id.region_dongli, R.id.region_ninghe, R.id.region_other
};
String[] regions = {"东丽", "宁河", "其他"};
// 设置初始状态
for (int i = 0; i < regionIds.length; i++) {
TextView regionView = dialog.findViewById(regionIds[i]);
if (regions[i].equals(selectedRegion)) {
regionView.setBackgroundResource(R.drawable.filter_tag_selected);
regionView.setTextColor(0xff2196F3);
} else {
regionView.setBackgroundResource(R.drawable.filter_tag_normal);
regionView.setTextColor(0xff666666);
}
}
// 设置点击事件
for (int i = 0; i < regionIds.length; i++) {
TextView regionView = dialog.findViewById(regionIds[i]);
final String region = regions[i];
regionView.setOnClickListener(v -> {
selectedRegion = region;
// 更新所有区域标签状态
for (int j = 0; j < regionIds.length; j++) {
TextView otherView = dialog.findViewById(regionIds[j]);
if (regions[j].equals(region)) {
otherView.setBackgroundResource(R.drawable.filter_tag_selected);
otherView.setTextColor(0xff2196F3);
} else {
otherView.setBackgroundResource(R.drawable.filter_tag_normal);
otherView.setTextColor(0xff666666);
}
}
});
}
}
private void resetFilters(Dialog dialog) {
// 重置所有筛选条件
minPrice = 0;
maxPrice = 0;
selectedCategory = "";
selectedRegion = "";
showNewOnly = false;
// 重置UI
EditText etMinPrice = dialog.findViewById(R.id.et_min_price);
EditText etMaxPrice = dialog.findViewById(R.id.et_max_price);
etMinPrice.setText("");
etMaxPrice.setText("");
// 重置类别标签 - 使用新的 ID
int[] categoryIds = {
R.id.category_digital, R.id.category_clothing, R.id.category_home,
R.id.category_books, R.id.category_beauty, R.id.category_sports,
R.id.category_other
};
for (int id : categoryIds) {
TextView categoryView = dialog.findViewById(id);
categoryView.setBackgroundResource(R.drawable.filter_tag_normal);
categoryView.setTextColor(0xff666666);
}
// 重置区域标签 - 使用新的 ID
int[] regionIds = {
R.id.region_dongli, R.id.region_ninghe, R.id.region_other
};
for (int id : regionIds) {
TextView regionView = dialog.findViewById(id);
regionView.setBackgroundResource(R.drawable.filter_tag_normal);
regionView.setTextColor(0xff666666);
}
// 立即应用重置
updateFilterUI();
applyFilters();
}
private void applyFilters() {
// 首先获取基础搜索结果(不包含价格和新发布筛选)
List<Product> baseResults = getBaseSearchResults();
List<Product> filteredList = new ArrayList<>(baseResults);
// 应用价格筛选(只在当前搜索结果范围内)
if (minPrice > 0 || maxPrice > 0) {
Iterator<Product> iterator = filteredList.iterator();
while (iterator.hasNext()) {
Product product = iterator.next();
double price = product.getPrice();
if (minPrice > 0 && price < minPrice) {
iterator.remove();
continue;
}
if (maxPrice > 0 && price > maxPrice) {
iterator.remove();
}
}
}
// 应用类别筛选(只在当前搜索结果范围内)
if (!selectedCategory.isEmpty()) {
Iterator<Product> iterator = filteredList.iterator();
while (iterator.hasNext()) {
Product product = iterator.next();
if (!selectedCategory.equals(product.getCategory())) {
iterator.remove();
}
}
}
// 应用区域筛选(只在当前搜索结果范围内)
if (!selectedRegion.isEmpty()) {
Iterator<Product> iterator = filteredList.iterator();
while (iterator.hasNext()) {
Product product = iterator.next();
if (!selectedRegion.equals(product.getLocation())) {
iterator.remove();
}
}
}
// 应用新发布筛选(只在当前搜索结果范围内)
if (showNewOnly) {
// 这里可以添加新发布商品的判断逻辑
// 例如只显示最近3天内发布的商品
// 暂时使用ID大于5的商品作为新发布商品的模拟
Iterator<Product> iterator = filteredList.iterator();
while (iterator.hasNext()) {
Product product = iterator.next();
try {
int productId = Integer.parseInt(product.getId());
if (productId <= 5) { // ID小于等于5的认为是旧商品
iterator.remove();
}
} catch (NumberFormatException e) {
// 如果ID不是数字保留该商品
}
}
}
// 应用排序(只在当前筛选结果范围内)
switch (currentSort) {
case "price":
Collections.sort(filteredList, new Comparator<Product>() {
@Override
public int compare(Product p1, Product p2) {
if (priceAscending) {
return Double.compare(p1.getPrice(), p2.getPrice());
} else {
return Double.compare(p2.getPrice(), p1.getPrice());
}
}
});
break;
case "comprehensive":
default:
// 默认排序
break;
}
// 更新显示
currentProductList.clear();
currentProductList.addAll(filteredList);
searchAdapter.updateData(currentProductList);
// 显示筛选结果数量
if (filteredList.isEmpty()) {
findViewById(R.id.no_results_text).setVisibility(View.VISIBLE);
resultsRecyclerView.setVisibility(View.GONE);
} else {
findViewById(R.id.no_results_text).setVisibility(View.GONE);
resultsRecyclerView.setVisibility(View.VISIBLE);
}
}
// 修改 getBaseSearchResults 方法
private List<Product> getBaseSearchResults() {
if (baseSearchResults != null && !baseSearchResults.isEmpty()) {
return new ArrayList<>(baseSearchResults);
}
String searchType = getIntent().getStringExtra("search_type");
String query = getIntent().getStringExtra("search_query");
if ("image".equals(searchType)) {
List<Product> similarProducts = (List<Product>) getIntent().getSerializableExtra("similar_products");
if (similarProducts != null && !similarProducts.isEmpty()) {
return new ArrayList<>(similarProducts);
}
} else {
if (query != null) {
// 使用 DataManager 进行搜索
DataManager dataManager = DataManager.getInstance();
List<Item> itemResults = dataManager.searchItems(query);
List<Product> productResults = new ArrayList<>();
for (Item item : itemResults) {
productResults.add(dataManager.convertItemToProduct(item));
}
return productResults;
}
}
return new ArrayList<>();
}
private void initFilterData() {
// 初始化所有商品数据用于筛选 - 使用 DataManager 的真实数据
DataManager dataManager = DataManager.getInstance();
allProducts = dataManager.getAllProducts();
}
// 修改 loadSearchResults 方法
private void loadSearchResults() {
String searchType = getIntent().getStringExtra("search_type");
String query = getIntent().getStringExtra("search_query");
if ("image".equals(searchType)) {
// 图片搜索结果(保持不变)
List<Product> similarProducts = (List<Product>) getIntent().getSerializableExtra("similar_products");
if (similarProducts != null && !similarProducts.isEmpty()) {
searchResultsTitle.setText("图片搜索结果");
baseSearchResults.clear();
baseSearchResults.addAll(similarProducts);
currentProductList.clear();
currentProductList.addAll(similarProducts);
searchAdapter.updateData(currentProductList);
findViewById(R.id.no_results_text).setVisibility(View.GONE);
resultsRecyclerView.setVisibility(View.VISIBLE);
} else {
searchResultsTitle.setText("图片搜索结果");
findViewById(R.id.no_results_text).setVisibility(View.VISIBLE);
resultsRecyclerView.setVisibility(View.GONE);
}
} else {
// 文本搜索结果 - 使用传递的搜索结果或重新搜索
if (query != null) {
searchResultsTitle.setText("搜索结果: " + query);
searchHintText.setText(query);
List<Product> searchResults;
// 检查是否已经传递了搜索结果
List<Product> passedResults = (List<Product>) getIntent().getSerializableExtra("search_results");
if (passedResults != null) {
searchResults = passedResults;
} else {
// 如果没有传递结果,使用 DataManager 重新搜索
DataManager dataManager = DataManager.getInstance();
List<Item> itemResults = dataManager.searchItems(query);
searchResults = new ArrayList<>();
for (Item item : itemResults) {
searchResults.add(dataManager.convertItemToProduct(item));
}
}
baseSearchResults.clear();
baseSearchResults.addAll(searchResults);
if (searchResults.isEmpty()) {
findViewById(R.id.no_results_text).setVisibility(View.VISIBLE);
resultsRecyclerView.setVisibility(View.GONE);
} else {
findViewById(R.id.no_results_text).setVisibility(View.GONE);
resultsRecyclerView.setVisibility(View.VISIBLE);
currentProductList.clear();
currentProductList.addAll(searchResults);
searchAdapter.updateData(currentProductList);
}
} else {
searchResultsTitle.setText("搜索结果");
findViewById(R.id.no_results_text).setVisibility(View.VISIBLE);
resultsRecyclerView.setVisibility(View.GONE);
}
}
// 初始化筛选UI
updateFilterUI();
}
private List<Product> searchProducts(String keyword) {
DataManager dataManager = DataManager.getInstance();
List<Item> itemResults = dataManager.searchItems(keyword);
List<Product> results = new ArrayList<>();
for (Item item : itemResults) {
// 使用 DataManager 的转换方法确保数据一致性
results.add(dataManager.convertItemToProduct(item));
}
return results;
}
@Override
protected void onDestroy() {
super.onDestroy();
// 取消注册数据变化监听器
DataManager.getInstance().unregisterDataChangedListener(this);
}
// 在 SearchResultsActivity 类中添加 onProductClick 方法的具体实现
@Override
public void onProductClick(Product product) {
// 跳转到商品详情页
Intent intent = new Intent(this, ProductDetailActivity.class);
intent.putExtra(ProductDetailActivity.EXTRA_PRODUCT, product);
startActivity(intent);
}
@Override
public void onWantClick(Product product) {
// 处理想要按钮点击事件
product.setWantCount(product.getWantCount() + 1);
// 更新当前显示的商品列表
if (currentProductList != null) {
for (int i = 0; i < currentProductList.size(); i++) {
if (currentProductList.get(i).getId().equals(product.getId())) {
currentProductList.get(i).setWantCount(product.getWantCount());
break;
}
}
}
// 通知适配器更新
if (searchAdapter != null) {
searchAdapter.updateData(currentProductList);
}
Toast.makeText(this, "已添加到想要列表", Toast.LENGTH_SHORT).show();
}
}

@ -1,74 +0,0 @@
package com.startsmake.llrisetabbardemo.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.model.ChatMessage;
import java.util.List;
public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.ViewHolder> {
private Context context;
private List<ChatMessage> messageList;
public ChatMessageAdapter(Context context, List<ChatMessage> messageList) {
this.context = context;
this.messageList = messageList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_chat_message, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ChatMessage message = messageList.get(position);
if (message.isMe()) {
// 自己发送的消息 - 右侧显示
holder.layoutLeft.setVisibility(View.GONE);
holder.layoutRight.setVisibility(View.VISIBLE);
holder.tvRightMessage.setText(message.getContent());
holder.tvRightTime.setText(message.getTime());
} else {
// 对方发送的消息 - 左侧显示
holder.layoutRight.setVisibility(View.GONE);
holder.layoutLeft.setVisibility(View.VISIBLE);
holder.tvLeftMessage.setText(message.getContent());
holder.tvLeftTime.setText(message.getTime());
}
}
@Override
public int getItemCount() {
return messageList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
LinearLayout layoutLeft;
LinearLayout layoutRight;
TextView tvLeftMessage;
TextView tvRightMessage;
TextView tvLeftTime;
TextView tvRightTime;
public ViewHolder(@NonNull View itemView) {
super(itemView);
layoutLeft = itemView.findViewById(R.id.layoutLeft);
layoutRight = itemView.findViewById(R.id.layoutRight);
tvLeftMessage = itemView.findViewById(R.id.tvLeftMessage);
tvRightMessage = itemView.findViewById(R.id.tvRightMessage);
tvLeftTime = itemView.findViewById(R.id.tvLeftTime);
tvRightTime = itemView.findViewById(R.id.tvRightTime);
}
}
}

@ -1,84 +0,0 @@
package com.startsmake.llrisetabbardemo.adapter;
import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.startsmake.llrisetabbardemo.R;
import java.util.List;
public class ImageAdapter extends BaseAdapter {
private Context context;
private List<Uri> imageUris;
private static final int MAX_IMAGES = 9;
public ImageAdapter(Context context, List<Uri> imageUris) {
this.context = context;
this.imageUris = imageUris;
}
@Override
public int getCount() {
return Math.min(imageUris.size() + 1, MAX_IMAGES);
}
@Override
public Object getItem(int position) {
if (position < imageUris.size()) {
return imageUris.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item_image, parent, false);
holder = new ViewHolder();
holder.imageView = convertView.findViewById(R.id.imageView);
holder.deleteButton = convertView.findViewById(R.id.btnDelete);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (position < imageUris.size()) {
// 显示已选择的图片
Uri imageUri = imageUris.get(position);
Glide.with(context)
.load(imageUri)
.placeholder(android.R.drawable.ic_menu_gallery) // 使用系统图标作为占位符
.into(holder.imageView);
holder.deleteButton.setVisibility(View.VISIBLE);
holder.deleteButton.setOnClickListener(v -> {
imageUris.remove(position);
notifyDataSetChanged();
});
} else {
// 显示添加按钮
holder.imageView.setImageResource(android.R.drawable.ic_input_add); // 使用系统图标
holder.deleteButton.setVisibility(View.GONE);
}
return convertView;
}
static class ViewHolder {
ImageView imageView;
ImageView deleteButton;
}
}

@ -1,102 +0,0 @@
package com.startsmake.llrisetabbardemo.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.model.MessageItem;
import java.util.List;
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.ViewHolder> {
private Context context;
private List<MessageItem> messageList;
private OnItemClickListener onItemClickListener;
public MessageAdapter(Context context, List<MessageItem> messageList) {
this.context = context;
this.messageList = messageList;
}
// 添加点击监听接口
public interface OnItemClickListener {
void onItemClick(MessageItem item);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_message, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
MessageItem item = messageList.get(position);
// 设置默认白色头像背景
holder.ivAvatar.setBackgroundResource(R.drawable.bg_avatar_placeholder);
holder.tvTitle.setText(item.getTitle());
holder.tvContent.setText(item.getContent());
holder.tvTime.setText(item.getTime());
// 未读消息数量
if (item.getUnreadCount() > 0) {
holder.tvUnreadCount.setVisibility(View.VISIBLE);
holder.tvUnreadCount.setText(String.valueOf(item.getUnreadCount()));
} else {
holder.tvUnreadCount.setVisibility(View.GONE);
}
// 官方标识
if (item.isOfficial()) {
holder.ivOfficial.setVisibility(View.VISIBLE);
} else {
holder.ivOfficial.setVisibility(View.GONE);
}
// 添加点击事件
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(item);
}
}
});
}
@Override
public int getItemCount() {
return messageList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivAvatar;
TextView tvTitle;
TextView tvContent;
TextView tvTime;
TextView tvUnreadCount;
ImageView ivOfficial;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ivAvatar = itemView.findViewById(R.id.ivAvatar);
tvTitle = itemView.findViewById(R.id.tvTitle);
tvContent = itemView.findViewById(R.id.tvContent);
tvTime = itemView.findViewById(R.id.tvTime);
tvUnreadCount = itemView.findViewById(R.id.tvUnreadCount);
ivOfficial = itemView.findViewById(R.id.ivOfficial);
}
}
}

@ -1,136 +0,0 @@
package com.startsmake.llrisetabbardemo.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.model.Product;
import java.util.List;
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder> {
private List<Product> productList;
private OnProductClickListener listener;
public interface OnProductClickListener {
void onProductClick(Product product);
void onWantClick(Product product);
}
// 单参数构造函数 - 用于不需要点击监听的情况
public SearchAdapter(List<Product> productList) {
this.productList = productList;
this.listener = null;
}
// 双参数构造函数 - 用于需要点击监听的情况
public SearchAdapter(List<Product> productList, OnProductClickListener listener) {
this.productList = productList;
this.listener = listener;
}
// 添加局部更新方法
public void notifyProductChanged(String productId) {
if (productList != null) {
for (int i = 0; i < productList.size(); i++) {
if (productList.get(i).getId().equals(productId)) {
notifyItemChanged(i);
break;
}
}
}
}
public void updateData(List<Product> newList) {
this.productList = newList;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_product, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Product product = productList.get(position);
// 设置商品名称
holder.productName.setText(product.getName());
// 设置价格
holder.productPrice.setText(String.format("¥%.2f", product.getPrice()));
// 设置想要人数(使用真实数据)
holder.productWantCount.setText(product.getWantCount() + "人想要");
// 设置卖家信用(使用真实数据)
holder.sellerRating.setText(product.getSellerRating());
// 设置地区(使用真实数据)
holder.productLocation.setText(product.getLocation());
// 设置包邮标签
holder.freeShippingTag.setVisibility(product.isFreeShipping() ? View.VISIBLE : View.GONE);
// 设置想要按钮点击事件
holder.wantButton.setOnClickListener(v -> {
if (listener != null) {
listener.onWantClick(product);
}
});
// 在 onBindViewHolder 中添加
if (product.isFreeShipping()) {
holder.freeShippingTag.setVisibility(View.VISIBLE);
} else {
holder.freeShippingTag.setVisibility(View.GONE);
}
// 设置整个商品项点击事件
holder.itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onProductClick(product);
}
});
// 这里可以设置商品图片,目前使用默认图片
// 实际项目中应该使用图片加载库如Glide来加载网络图片
// Glide.with(holder.itemView.getContext()).load(product.getImageUrl()).into(holder.productImage);
}
@Override
public int getItemCount() {
return productList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView productImage;
TextView productName;
TextView productPrice;
TextView productWantCount;
TextView sellerRating;
TextView productLocation;
TextView freeShippingTag;
TextView wantButton;
public ViewHolder(@NonNull View itemView) {
super(itemView);
productImage = itemView.findViewById(R.id.product_image);
productName = itemView.findViewById(R.id.product_name);
productPrice = itemView.findViewById(R.id.product_price);
productWantCount = itemView.findViewById(R.id.product_want_count);
sellerRating = itemView.findViewById(R.id.seller_rating);
productLocation = itemView.findViewById(R.id.product_location);
freeShippingTag = itemView.findViewById(R.id.free_shipping_tag);
wantButton = itemView.findViewById(R.id.want_button);
}
}
}

@ -1,29 +0,0 @@
package com.startsmake.llrisetabbardemo.api;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import java.util.concurrent.TimeUnit;
public class ApiClient {
private static final String BASE_URL = "http://localhost:8080/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit == null) {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}

@ -1,43 +0,0 @@
package com.startsmake.llrisetabbardemo.api;
import com.startsmake.llrisetabbardemo.api.response.BaseResponse;
import com.startsmake.llrisetabbardemo.api.response.ProductResponse;
import com.startsmake.llrisetabbardemo.api.response.UserResponse;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface ApiService {
// 获取API状态
@GET("api")
Call<BaseResponse> getApiStatus();
// 用户登录
@FormUrlEncoded
@POST("api/login")
Call<UserResponse> login(@Field("phone") String phone, @Field("password") String password);
// 用户注册
@FormUrlEncoded
@POST("api/register")
Call<UserResponse> register(@Field("phone") String phone, @Field("password") String password,
@Field("username") String username);
// 获取商品列表
@GET("api/products")
Call<BaseResponse<List<ProductResponse>>> getProducts();
// 搜索商品
@GET("api/products/search")
Call<BaseResponse<List<ProductResponse>>> searchProducts(@Query("keyword") String keyword);
// 获取商品详情
@GET("api/products/detail")
Call<BaseResponse<ProductResponse>> getProductDetail(@Query("id") String productId);
}

@ -1,43 +0,0 @@
package com.startsmake.llrisetabbardemo.api.response;
import com.google.gson.annotations.SerializedName;
public class BaseResponse<T> {
@SerializedName("status")
private String status;
@SerializedName("message")
private String message;
@SerializedName("data")
private T data;
// Getters and Setters
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public boolean isSuccess() {
return "success".equals(status);
}
}

@ -1,107 +0,0 @@
package com.startsmake.llrisetabbardemo.api.response;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class ProductResponse {
@SerializedName("id")
private String id;
@SerializedName("title")
private String title;
@SerializedName("description")
private String description;
@SerializedName("category")
private String category;
@SerializedName("price")
private double price;
@SerializedName("image_urls")
private List<String> imageUrls;
@SerializedName("contact")
private String contact;
@SerializedName("publish_time")
private long publishTime;
@SerializedName("seller_id")
private String sellerId;
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public List<String> getImageUrls() {
return imageUrls;
}
public void setImageUrls(List<String> imageUrls) {
this.imageUrls = imageUrls;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public long getPublishTime() {
return publishTime;
}
public void setPublishTime(long publishTime) {
this.publishTime = publishTime;
}
public String getSellerId() {
return sellerId;
}
public void setSellerId(String sellerId) {
this.sellerId = sellerId;
}
}

@ -1,52 +0,0 @@
package com.startsmake.llrisetabbardemo.api.response;
import com.google.gson.annotations.SerializedName;
public class UserResponse extends BaseResponse<UserResponse.UserInfo> {
public static class UserInfo {
@SerializedName("id")
private String id;
@SerializedName("username")
private String username;
@SerializedName("phone")
private String phone;
@SerializedName("token")
private String token;
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
}

@ -1,40 +0,0 @@
package com.startsmake.llrisetabbardemo.decoration;
import android.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int column = position % spanCount;
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount;
outRect.right = (column + 1) * spacing / spanCount;
if (position < spanCount) {
outRect.top = spacing;
}
outRect.bottom = spacing;
} else {
outRect.left = column * spacing / spanCount;
outRect.right = spacing - (column + 1) * spacing / spanCount;
if (position >= spanCount) {
outRect.top = spacing;
}
}
}
}

@ -1,14 +1,12 @@
package com.startsmake.llrisetabbardemo.fragment;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
// 改为 AndroidX
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.startsmake.llrisetabbardemo.R;
/**
@ -23,4 +21,4 @@ public class CityFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_city, container, false);
}
}
}

@ -1,233 +1,20 @@
package com.startsmake.llrisetabbardemo.fragment;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Log;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.GridLayoutManager;
import com.startsmake.llrisetabbardemo.decoration.GridSpacingItemDecoration;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.activity.SearchActivity;
import com.startsmake.llrisetabbardemo.activity.SearchResultsActivity;
import com.startsmake.llrisetabbardemo.activity.ProductDetailActivity;
import com.startsmake.llrisetabbardemo.model.Product;
import com.startsmake.llrisetabbardemo.model.Item;
import com.startsmake.llrisetabbardemo.adapter.SearchAdapter;
import manager.DataManager;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* User:Shine
* Date:2015-10-20
* Description:
*/
public class HomeFragment extends Fragment implements SearchAdapter.OnProductClickListener,
DataManager.OnDataChangedListener {
private static final String TAG = "HomeFragment";
@Override
public void onDataChanged() {
// 数据发生变化时,重新加载数据
Log.d(TAG, "收到数据变化通知,重新加载数据");
refreshData();
}
@Override
public void onProductWantCountChanged(String productId, int newCount) {
// 特定商品想要人数变化时,更新对应商品
Log.d(TAG, "收到商品想要人数变化通知商品ID: " + productId + ", 新人数: " + newCount);
updateProductWantCount(productId, newCount);
}
// 更新特定商品的想要人数
private void updateProductWantCount(String productId, int newCount) {
if (productList != null) {
for (int i = 0; i < productList.size(); i++) {
Product product = productList.get(i);
if (product.getId().equals(productId)) {
product.setWantCount(newCount);
// 通知适配器局部更新
if (searchAdapter != null) {
searchAdapter.notifyItemChanged(i);
}
Log.d(TAG, "更新首页商品 " + productId + " 的想要人数为: " + newCount);
break;
}
}
}
}
// 刷新数据
private void refreshData() {
DataManager dataManager = DataManager.getInstance();
List<Product> newProducts = dataManager.getAllProducts();
if (newProducts != null && !newProducts.isEmpty()) {
productList = newProducts;
if (searchAdapter != null) {
searchAdapter.updateData(productList);
}
Log.d(TAG, "首页数据已刷新,商品数量: " + productList.size());
}
}
// 修改 addNewItem 方法,使其接收 Product 对象
public void addNewItem(Product product) {
try {
Log.d(TAG, "开始添加新商品");
if (product == null) {
Log.e(TAG, "尝试添加空商品");
Toast.makeText(requireContext(), "商品信息无效", Toast.LENGTH_SHORT).show();
return;
}
if (productList == null) {
productList = new ArrayList<>();
}
// 添加到列表顶部
productList.add(0, product);
// 更新适配器
if (searchAdapter != null) {
searchAdapter.updateData(productList);
}
// 显示商品列表,隐藏空状态
if (homeProductsRecyclerView != null && homeNoProductsText != null) {
homeProductsRecyclerView.setVisibility(View.VISIBLE);
homeNoProductsText.setVisibility(View.GONE);
}
Toast.makeText(requireContext(), "刷新商品列表成功!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e(TAG, "添加新商品时出错", e);
Toast.makeText(requireContext(), "刷新商品列表失败,请重试", Toast.LENGTH_SHORT).show();
}
}
// 添加一个新方法来更新整个商品列表
public void updateProductList(List<Product> products) {
Log.d("HomeFragment", "updateProductList被调用收到 " + (products != null ? products.size() : 0) + " 个商品");
if (products != null) {
this.productList = products;
Log.d("HomeFragment", "更新productList当前大小: " + this.productList.size());
if (searchAdapter != null) {
searchAdapter.updateData(products);
Log.d("HomeFragment", "适配器数据已更新");
} else {
Log.e("HomeFragment", "searchAdapter为null无法更新数据");
}
// 根据是否有商品来显示相应界面
if (products.isEmpty()) {
showNoProducts();
Log.d("HomeFragment", "显示无商品界面");
} else {
showHomeProducts(products);
Log.d("HomeFragment", "显示商品列表");
}
} else {
Log.e("HomeFragment", "传入的商品列表为null");
}
}
// 修改初始化数据方法从DataManager获取数据
private void initSearchData() {
Log.d(TAG, "开始初始化数据");
// 从DataManager获取数据而不是使用固定数据
DataManager dataManager = DataManager.getInstance();
productList = dataManager.getAllProducts();
Log.d(TAG, "从DataManager获取到 " + productList.size() + " 个商品");
// 如果DataManager中没有数据使用示例数据作为备选
if (productList.isEmpty()) {
Log.d(TAG, "DataManager中没有数据使用示例数据");
productList = new ArrayList<>();
productList.add(new Product("1", "Java编程思想", "计算机专业教材", "学习资料", 45.0, "", 0, "东丽", "卖家信用极好", true, "138****1234"));
productList.add(new Product("2", "高等数学教材", "大学数学课本", "学习资料", 30.0, "", 0, "宁河", "百分百好评", false, "微信abc123"));
productList.add(new Product("3", "笔记本电脑", "二手联想笔记本", "数码产品", 1200.0, "", 0, "东丽", "卖家信用良好", true, "159****5678"));
productList.add(new Product("4", "台灯", "护眼学习台灯", "生活用品", 25.0, "", 0, "宁河", "卖家信用极好", false, "QQ123456789"));
} else {
Log.d(TAG, "使用DataManager中的数据");
}
// 立即更新适配器并显示商品
if (searchAdapter != null) {
searchAdapter.updateData(productList);
Log.d(TAG, "适配器初始化完成");
// 显示商品列表
if (!productList.isEmpty()) {
showHomeProducts(productList);
} else {
showNoProducts();
}
}
}
private EditText searchEditText;
private ImageButton cameraButton;
private TextView homeSearchButton;
// 首页商品展示相关
private RecyclerView homeProductsRecyclerView;
private TextView homeNoProductsText;
private LinearLayout defaultContent;
// 导航栏按钮 - 更新为新的分类
private TextView tabRecommend, tabDigital, tabClothing, tabHome, tabBooks, tabBeauty, tabSports, tabOther;
// 随机标签相关
private List<String> randomKeywords;
private Handler handler;
private Runnable keywordRunnable;
private static final long KEYWORD_CHANGE_INTERVAL = 3000;
private static final int CAMERA_REQUEST_CODE = 101;
private static final int CAMERA_PERMISSION_REQUEST_CODE = 102;
private String currentPhotoPath;
private List<Product> productList;
private SearchAdapter searchAdapter;
public class HomeFragment extends Fragment {
@Nullable
@Override
@ -235,692 +22,4 @@ public class HomeFragment extends Fragment implements SearchAdapter.OnProductCli
return inflater.inflate(R.layout.fragment_home, container, false);
}
// 修改 initViews 方法,添加缺失的视图初始化
private void initViews(View view) {
try {
searchEditText = view.findViewById(R.id.search_edit_text);
cameraButton = view.findViewById(R.id.camera_button);
homeSearchButton = view.findViewById(R.id.home_search_button);
// 首页商品展示相关视图
homeProductsRecyclerView = view.findViewById(R.id.home_products_recycler_view);
homeNoProductsText = view.findViewById(R.id.home_no_products_text);
defaultContent = view.findViewById(R.id.default_content);
// 初始化导航栏按钮 - 更新为新的分类
tabRecommend = view.findViewById(R.id.tab_recommend);
tabDigital = view.findViewById(R.id.tab_digital);
tabClothing = view.findViewById(R.id.tab_clothing);
tabHome = view.findViewById(R.id.tab_home);
tabBooks = view.findViewById(R.id.tab_books);
tabBeauty = view.findViewById(R.id.tab_beauty);
tabSports = view.findViewById(R.id.tab_sports);
tabOther = view.findViewById(R.id.tab_other);
// 设置点击监听器
setupClickListeners();
Log.d(TAG, "所有视图初始化完成");
} catch (Exception e) {
Log.e(TAG, "初始化视图时出错", e);
Toast.makeText(requireContext(), "界面初始化失败", Toast.LENGTH_SHORT).show();
}
}
private void setupClickListeners() {
if (searchEditText != null) {
searchEditText.setOnClickListener(v -> {
try {
Log.d(TAG, "搜索框被点击");
Intent intent = new Intent(requireActivity(), SearchActivity.class);
startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "点击搜索框时出错", e);
Toast.makeText(requireContext(), "打开搜索页面失败,请重试", Toast.LENGTH_SHORT).show();
}
});
}
if (homeSearchButton != null) {
homeSearchButton.setOnClickListener(v -> {
try {
Log.d(TAG, "搜索按钮被点击");
performHomeSearch();
} catch (Exception e) {
Log.e(TAG, "执行搜索时出错", e);
Toast.makeText(requireContext(), "搜索功能暂不可用,请稍后再试", Toast.LENGTH_SHORT).show();
}
});
}
if (cameraButton != null) {
cameraButton.setOnClickListener(v -> {
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
openCamera();
} else {
requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
}
});
}
}
// 确保RecyclerView正确设置的方法
private void ensureRecyclerViewSetup() {
if (homeProductsRecyclerView == null) {
Log.e(TAG, "homeProductsRecyclerView 为 null");
return;
}
try {
// 检查是否已经有LayoutManager
if (homeProductsRecyclerView.getLayoutManager() == null) {
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 2);
homeProductsRecyclerView.setLayoutManager(gridLayoutManager);
// 设置商品间距
int spacingInPixels = getResources().getDimensionPixelSize(R.dimen.grid_spacing);
homeProductsRecyclerView.addItemDecoration(new GridSpacingItemDecoration(2, spacingInPixels, true));
Log.d(TAG, "设置LayoutManager和间距");
}
// 检查是否已经有Adapter
if (homeProductsRecyclerView.getAdapter() == null) {
if (searchAdapter == null) {
// 使用双参数构造函数传递this作为监听器
searchAdapter = new SearchAdapter(new ArrayList<>(), this);
Log.d(TAG, "创建新的SearchAdapter并设置点击监听");
}
homeProductsRecyclerView.setAdapter(searchAdapter);
Log.d(TAG, "设置Adapter");
}
} catch (Exception e) {
Log.e(TAG, "确保RecyclerView设置时出错", e);
}
}
// 修改 showHomeProducts 方法
private void showHomeProducts(List<Product> products) {
Log.d(TAG, "showHomeProducts被调用商品数量: " + products.size());
// 确保RecyclerView正确设置
ensureRecyclerViewSetup();
if (searchAdapter == null) {
Log.e(TAG, "searchAdapter 为 null");
return;
}
try {
// 更新适配器数据
searchAdapter.updateData(products);
// 设置正确的视图可见性
if (homeProductsRecyclerView != null) {
homeProductsRecyclerView.setVisibility(View.VISIBLE);
Log.d(TAG, "RecyclerView设置为可见");
}
if (homeNoProductsText != null) {
homeNoProductsText.setVisibility(View.GONE);
Log.d(TAG, "无商品文本隐藏");
}
if (defaultContent != null) {
defaultContent.setVisibility(View.GONE);
Log.d(TAG, "默认内容隐藏");
}
Log.d(TAG, "显示商品列表成功,商品数量: " + products.size());
} catch (Exception e) {
Log.e(TAG, "显示首页商品时出错", e);
}
}
// 在 onViewCreated 中确保调用了 setupHomeProductsRecyclerView
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViews(view);
setupHomeProductsRecyclerView(); // 确保这一行被调用
initSearchData(); // 先初始化数据
initRandomKeywords();
setupNavigationButtons();
startKeywordRotation();
// 注册数据变化监听器
DataManager.getInstance().registerDataChangedListener(this);
// 默认显示推荐内容
showRandomRecommendations();
}
// 在 setupNavigationButtons 方法中更新点击事件
private void setupNavigationButtons() {
// 设置初始选中状态 - 推荐按钮
resetTabColors();
resetTabBackgrounds();
tabRecommend.setTextColor(0xff2196F3); // 蓝色
tabRecommend.setBackgroundResource(R.drawable.tab_selected);
View.OnClickListener tabClickListener = v -> {
resetTabColors();
resetTabBackgrounds();
if (v instanceof TextView) {
TextView textView = (TextView) v;
textView.setTextColor(0xff2196F3); // 改为蓝色
textView.setBackgroundResource(R.drawable.tab_selected);
// 根据点击的标签显示不同的内容
int id = v.getId();
if (id == R.id.tab_recommend) {
showRandomRecommendations();
} else if (id == R.id.tab_digital) {
showCategoryProducts("数码产品");
} else if (id == R.id.tab_clothing) {
showCategoryProducts("服装鞋帽");
} else if (id == R.id.tab_home) {
showCategoryProducts("家居日用");
} else if (id == R.id.tab_books) {
showCategoryProducts("图书文具");
} else if (id == R.id.tab_beauty) {
showCategoryProducts("美妆个护");
} else if (id == R.id.tab_sports) {
showCategoryProducts("运动户外");
} else if (id == R.id.tab_other) {
showCategoryProducts("其他");
}
}
};
// 设置所有标签的点击监听器
tabRecommend.setOnClickListener(tabClickListener);
tabDigital.setOnClickListener(tabClickListener);
tabClothing.setOnClickListener(tabClickListener);
tabHome.setOnClickListener(tabClickListener);
tabBooks.setOnClickListener(tabClickListener);
tabBeauty.setOnClickListener(tabClickListener);
tabSports.setOnClickListener(tabClickListener);
tabOther.setOnClickListener(tabClickListener);
}
// 添加分类显示方法
private void showCategoryProducts(String category) {
if (productList == null || productList.isEmpty()) {
showNoProducts();
return;
}
try {
List<Product> categoryProducts = new ArrayList<>();
for (Product product : productList) {
if (category.equals(product.getCategory())) {
categoryProducts.add(product);
}
}
if (categoryProducts.isEmpty()) {
showNoProducts();
Toast.makeText(requireContext(), "暂无" + category + "类商品", Toast.LENGTH_SHORT).show();
} else {
showHomeProducts(categoryProducts);
Toast.makeText(requireContext(), category, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "显示" + category + "类商品时出错", e);
showNoProducts();
}
}
// 更新重置标签方法
private void resetTabColors() {
if (tabRecommend != null) tabRecommend.setTextColor(0xff666666);
if (tabDigital != null) tabDigital.setTextColor(0xff666666);
if (tabClothing != null) tabClothing.setTextColor(0xff666666);
if (tabHome != null) tabHome.setTextColor(0xff666666);
if (tabBooks != null) tabBooks.setTextColor(0xff666666);
if (tabBeauty != null) tabBeauty.setTextColor(0xff666666);
if (tabSports != null) tabSports.setTextColor(0xff666666);
if (tabOther != null) tabOther.setTextColor(0xff666666);
}
private void resetTabBackgrounds() {
tabRecommend.setBackgroundResource(R.drawable.tab_normal);
tabDigital.setBackgroundResource(R.drawable.tab_normal);
tabClothing.setBackgroundResource(R.drawable.tab_normal);
tabHome.setBackgroundResource(R.drawable.tab_normal);
tabBooks.setBackgroundResource(R.drawable.tab_normal);
tabBeauty.setBackgroundResource(R.drawable.tab_normal);
tabSports.setBackgroundResource(R.drawable.tab_normal);
tabOther.setBackgroundResource(R.drawable.tab_normal);
}
// 显示随机推荐商品
private void showRandomRecommendations() {
if (productList == null || productList.isEmpty()) {
showNoProducts();
return;
}
try {
List<Product> shuffledList = new ArrayList<>(productList);
Collections.shuffle(shuffledList);
int count = Math.min(6, shuffledList.size());
List<Product> randomProducts = shuffledList.subList(0, count);
showHomeProducts(randomProducts);
Toast.makeText(requireContext(), "为您推荐", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e(TAG, "显示随机推荐时出错", e);
showNoProducts();
}
}
// 显示新发布商品
private void showNewProducts() {
if (productList == null || productList.isEmpty()) {
showNoProducts();
return;
}
try {
List<Product> newProducts = new ArrayList<>();
for (Product product : productList) {
try {
if (Integer.parseInt(product.getId()) > 3) {
newProducts.add(product);
}
} catch (NumberFormatException e) {
// 如果ID不是数字跳过这个商品
Log.w(TAG, "商品ID不是数字: " + product.getId());
}
}
if (newProducts.isEmpty()) {
showNoProducts();
} else {
showHomeProducts(newProducts);
Toast.makeText(requireContext(), "新发布商品", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "显示新发布商品时出错", e);
showNoProducts();
}
}
// 显示学习资料类商品
private void showStudyProducts() {
if (productList == null || productList.isEmpty()) {
showNoProducts();
return;
}
try {
List<Product> studyProducts = new ArrayList<>();
for (Product product : productList) {
if ("学习资料".equals(product.getCategory())) {
studyProducts.add(product);
}
}
if (studyProducts.isEmpty()) {
showNoProducts();
} else {
showHomeProducts(studyProducts);
Toast.makeText(requireContext(), "学习资料", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "显示学习资料时出错", e);
showNoProducts();
}
}
// 显示生活用品类商品
private void showLifeProducts() {
if (productList == null || productList.isEmpty()) {
showNoProducts();
return;
}
try {
List<Product> lifeProducts = new ArrayList<>();
for (Product product : productList) {
if ("生活用品".equals(product.getCategory())) {
lifeProducts.add(product);
}
}
if (lifeProducts.isEmpty()) {
showNoProducts();
} else {
showHomeProducts(lifeProducts);
Toast.makeText(requireContext(), "生活用品", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "显示生活用品时出错", e);
showNoProducts();
}
}
// 显示关注用户的商品
private void showFollowedProducts() {
if (productList == null || productList.isEmpty()) {
showNoProducts();
Toast.makeText(requireContext(), "您还没有关注任何用户", Toast.LENGTH_SHORT).show();
return;
}
try {
List<Product> followedProducts = new ArrayList<>();
if (productList.size() >= 2) {
followedProducts.add(productList.get(0));
followedProducts.add(productList.get(1));
}
if (followedProducts.isEmpty()) {
showNoProducts();
Toast.makeText(requireContext(), "您还没有关注任何用户", Toast.LENGTH_SHORT).show();
} else {
showHomeProducts(followedProducts);
Toast.makeText(requireContext(), "关注用户的商品", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "显示关注用户商品时出错", e);
showNoProducts();
}
}
// 修改 showNoProducts 方法
private void showNoProducts() {
try {
Log.d(TAG, "显示无商品界面");
if (homeProductsRecyclerView != null) {
homeProductsRecyclerView.setVisibility(View.GONE);
}
if (homeNoProductsText != null) {
homeNoProductsText.setVisibility(View.VISIBLE);
}
if (defaultContent != null) {
defaultContent.setVisibility(View.GONE);
}
} catch (Exception e) {
Log.e(TAG, "显示无商品时出错", e);
}
}
private void showDefaultContent() {
try {
Log.d(TAG, "显示默认内容");
if (homeProductsRecyclerView != null) {
homeProductsRecyclerView.setVisibility(View.GONE);
}
if (homeNoProductsText != null) {
homeNoProductsText.setVisibility(View.GONE);
}
if (defaultContent != null) {
defaultContent.setVisibility(View.VISIBLE);
}
} catch (Exception e) {
Log.e(TAG, "显示默认内容时出错", e);
}
}
// 初始化随机标签列表
private void initRandomKeywords() {
randomKeywords = Arrays.asList(
"Java编程教材", "Python入门书籍", "高等数学课本", "英语四级真题", "考研政治资料", "计算机专业课", "电路分析教程", "机械制图教材", "经济学原理", "心理学导论", "设计素描本", "专业课程笔记", "二手笔记本电脑", "机械键盘", "无线鼠标", "蓝牙耳机", "平板电脑", "智能手机", "充电宝", "U盘硬盘", "显示器", "路由器", "相机镜头", "游戏手柄", "收纳箱", "穿衣镜",
"瑜伽垫", "体重秤", "电风扇", "暖手宝", "床上桌", "衣柜", "鞋架", "晾衣架", "羽毛球拍", "篮球足球", "滑板轮滑", "吉他乐器",
"画笔画具", "围棋象棋", "游泳装备", "健身器材", "登山背包", "帐篷睡袋", "摄影三脚架", "书法字帖"
);
handler = new Handler();
}
// 开始标签轮换
private void startKeywordRotation() {
if (handler == null || searchEditText == null) {
return;
}
keywordRunnable = new Runnable() {
@Override
public void run() {
try {
if (randomKeywords != null && !randomKeywords.isEmpty() && searchEditText != null) {
Collections.shuffle(randomKeywords);
String randomKeyword = randomKeywords.get(0);
searchEditText.setHint(randomKeyword);
}
if (handler != null) {
handler.postDelayed(this, KEYWORD_CHANGE_INTERVAL);
}
} catch (Exception e) {
Log.e(TAG, "标签轮换时出错", e);
}
}
};
handler.post(keywordRunnable);
}
// 首页搜索功能
private void performHomeSearch() {
try {
if (searchEditText == null) {
Log.e(TAG, "搜索框对象为null");
Toast.makeText(requireContext(), "搜索组件初始化失败", Toast.LENGTH_SHORT).show();
return;
}
String currentHint = searchEditText.getHint().toString();
String defaultHint = getResources().getString(R.string.search_hint);
Log.d(TAG, "执行首页搜索,当前提示词: " + currentHint);
if (!currentHint.equals(defaultHint) && randomKeywords != null && randomKeywords.contains(currentHint)) {
Intent intent = new Intent(requireActivity(), SearchResultsActivity.class);
intent.putExtra("search_query", currentHint);
startActivity(intent);
Log.d(TAG, "跳转到搜索结果页面,查询: " + currentHint);
} else {
Intent intent = new Intent(requireActivity(), SearchActivity.class);
startActivity(intent);
Log.d(TAG, "跳转到搜索页面");
}
} catch (Exception e) {
Log.e(TAG, "执行首页搜索时出错", e);
Toast.makeText(requireContext(), "搜索功能暂不可用,请稍后再试", Toast.LENGTH_SHORT).show();
}
}
// 原有的搜索方法保持不变
private void performSearch() {
String query = searchEditText.getText().toString().trim();
if (!query.isEmpty()) {
hideKeyboard();
List<Product> searchResults = searchProducts(query);
if (searchResults.isEmpty()) {
showNoResults();
} else {
showSearchResults(searchResults);
}
} else {
showDefaultContent();
}
}
// 原有的搜索结果显示方法
private void showSearchResults(List<Product> results) {
// 这里使用原有的搜索结果RecyclerView
// searchAdapter.updateData(results);
// searchResultsRecyclerView.setVisibility(View.VISIBLE);
// noResultsText.setVisibility(View.GONE);
// defaultContent.setVisibility(View.GONE);
}
private void showNoResults() {
// 原有的无结果显示逻辑
// searchResultsRecyclerView.setVisibility(View.GONE);
// noResultsText.setVisibility(View.VISIBLE);
// defaultContent.setVisibility(View.GONE);
}
// 在 HomeFragment.java 中,修改搜索方法
private List<Product> searchProducts(String keyword) {
DataManager dataManager = DataManager.getInstance();
List<Item> itemResults = dataManager.searchItems(keyword);
List<Product> productResults = new ArrayList<>();
for (Item item : itemResults) {
productResults.add(dataManager.convertItemToProduct(item));
}
return productResults;
}
// 隐藏软键盘的方法
private void hideKeyboard() {
try {
InputMethodManager imm = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE);
View currentFocus = requireActivity().getCurrentFocus();
if (currentFocus != null) {
imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
}
} catch (Exception e) {
Log.e(TAG, "隐藏键盘时出错", e);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openCamera();
} else {
Toast.makeText(requireContext(), "需要相机权限才能拍照搜索", Toast.LENGTH_SHORT).show();
}
}
}
private void openCamera() {
try {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(requireActivity().getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Toast.makeText(requireContext(), "创建文件失败", Toast.LENGTH_SHORT).show();
}
if (photoFile != null) {
currentPhotoPath = photoFile.getAbsolutePath();
Uri photoURI = FileProvider.getUriForFile(requireContext(),
requireContext().getPackageName() + ".fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, CAMERA_REQUEST_CODE);
}
} else {
Toast.makeText(requireContext(), "未找到相机应用", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "打开相机时出错", e);
Toast.makeText(requireContext(), "打开相机失败", Toast.LENGTH_SHORT).show();
}
}
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return File.createTempFile(
imageFileName,
".jpg",
storageDir
);
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
if (currentPhotoPath != null) {
Toast.makeText(requireContext(), "拍照成功,开始搜索...", Toast.LENGTH_SHORT).show();
if (searchEditText != null) {
searchEditText.setText("图片搜索中...");
}
performSearch();
}
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
// 取消注册数据变化监听器
DataManager.getInstance().unregisterDataChangedListener(this);
if (handler != null && keywordRunnable != null) {
handler.removeCallbacks(keywordRunnable);
}
}
// 在 HomeFragment 类中添加 onProductClick 方法的具体实现
@Override
public void onProductClick(Product product) {
// 跳转到商品详情页
Intent intent = new Intent(requireActivity(), ProductDetailActivity.class);
intent.putExtra(ProductDetailActivity.EXTRA_PRODUCT, product);
startActivity(intent);
}
@Override
public void onWantClick(Product product) {
// 处理想要按钮点击事件
product.setWantCount(product.getWantCount() + 1);
// 更新数据源中的商品数据
if (productList != null) {
for (int i = 0; i < productList.size(); i++) {
if (productList.get(i).getId().equals(product.getId())) {
productList.get(i).setWantCount(product.getWantCount());
break;
}
}
}
// 通知适配器更新
if (searchAdapter != null) {
searchAdapter.updateData(productList);
}
Toast.makeText(requireContext(), "已添加到想要列表", Toast.LENGTH_SHORT).show();
}
// 修改 setupHomeProductsRecyclerView 方法,确保使用双参数构造函数
private void setupHomeProductsRecyclerView() {
if (homeProductsRecyclerView == null) {
Log.e(TAG, "homeProductsRecyclerView 为 null");
return;
}
try {
// 改为 GridLayoutManager一行显示2个商品
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 2);
homeProductsRecyclerView.setLayoutManager(gridLayoutManager);
// 设置商品间距
int spacingInPixels = getResources().getDimensionPixelSize(R.dimen.grid_spacing);
homeProductsRecyclerView.addItemDecoration(new GridSpacingItemDecoration(2, spacingInPixels, true));
// 使用双参数构造函数传递this作为监听器
searchAdapter = new SearchAdapter(new ArrayList<>(), this);
homeProductsRecyclerView.setAdapter(searchAdapter);
Log.d(TAG, "首页RecyclerView设置完成使用网格布局并设置点击监听");
} catch (Exception e) {
Log.e(TAG, "设置RecyclerView时出错", e);
}
}
}
}

@ -1,145 +0,0 @@
package com.startsmake.llrisetabbardemo.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.model.Item;
import com.startsmake.llrisetabbardemo.model.Product;
import manager.DataManager;
public class ItemDetailFragment extends Fragment {
private static final String ARG_ITEM = "item";
private static final String ARG_PRODUCT = "product";
private Item item;
private Product product;
// 使用Item对象的构造方法
public static ItemDetailFragment newInstance(Item item) {
ItemDetailFragment fragment = new ItemDetailFragment();
Bundle args = new Bundle();
args.putSerializable(ARG_ITEM, item);
fragment.setArguments(args);
return fragment;
}
// 使用Product对象的构造方法
public static ItemDetailFragment newInstance(Product product) {
ItemDetailFragment fragment = new ItemDetailFragment();
Bundle args = new Bundle();
args.putSerializable(ARG_PRODUCT, product);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
item = (Item) getArguments().getSerializable(ARG_ITEM);
product = (Product) getArguments().getSerializable(ARG_PRODUCT);
// 如果传递的是Product转换为Item统一处理
if (product != null && item == null) {
item = convertProductToItem(product);
}
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_item_detail, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (item == null) {
Toast.makeText(getContext(), "商品信息加载失败", Toast.LENGTH_SHORT).show();
return;
}
// 初始化视图
ImageView ivItemImage = view.findViewById(R.id.ivItemImage);
TextView tvTitle = view.findViewById(R.id.tvTitle);
TextView tvPrice = view.findViewById(R.id.tvPrice);
TextView tvDescription = view.findViewById(R.id.tvDescription);
TextView tvCategory = view.findViewById(R.id.tvCategory);
TextView tvLocation = view.findViewById(R.id.tvLocation);
TextView tvContact = view.findViewById(R.id.tvContact);
TextView tvPublishTime = view.findViewById(R.id.tvPublishTime);
// +++ 新增:获取返回按钮并设置点击监听 +++
ImageButton backButton = view.findViewById(R.id.back_button);
backButton.setOnClickListener(v -> {
// 关闭当前Fragment或Activity
if (getActivity() != null) {
getActivity().onBackPressed();
}
});
// 设置商品信息
tvTitle.setText(item.getTitle());
tvPrice.setText(String.format("¥%.2f", item.getPrice()));
tvDescription.setText(item.getDescription());
tvCategory.setText("分类:" + item.getCategory());
tvLocation.setText("位置:" + item.getLocation());
tvContact.setText("联系方式:" + item.getContact());
// 设置发布时间
String time = android.text.format.DateFormat.format("yyyy-MM-dd HH:mm", item.getPublishTime()).toString();
tvPublishTime.setText("发布时间:" + time);
// 加载图片(这里使用第一张图片作为主图)
if (item.getImageUrls() != null && !item.getImageUrls().isEmpty()) {
// 实际项目中这里应该加载网络图片,这里用占位符
ivItemImage.setImageResource(R.mipmap.ic_launcher);
} else {
// 如果没有图片,使用默认图片
ivItemImage.setImageResource(R.mipmap.ic_launcher);
}
// 增加浏览数
item.incrementViewCount();
// 联系卖家按钮
view.findViewById(R.id.btnContact).setOnClickListener(v -> {
Toast.makeText(getContext(), "联系卖家:" + item.getContact(), Toast.LENGTH_SHORT).show();
// 这里可以跳转到聊天界面或拨打电话
});
}
/**
* ProductItem
*/
private Item convertProductToItem(Product product) {
Item convertedItem = new Item();
convertedItem.setId(product.getId());
convertedItem.setTitle(product.getName());
convertedItem.setDescription(product.getDescription());
convertedItem.setCategory(product.getCategory());
convertedItem.setPrice(product.getPrice());
convertedItem.setLocation(product.getLocation());
convertedItem.setContact(product.getContact());
convertedItem.setWantCount(product.getWantCount());
// 设置默认发布时间
convertedItem.setPublishTime(System.currentTimeMillis());
return convertedItem;
}
}

@ -1,65 +1,24 @@
package com.startsmake.llrisetabbardemo.fragment;
import android.content.Intent;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.activity.ChatActivity;
import com.startsmake.llrisetabbardemo.adapter.MessageAdapter;
import com.startsmake.llrisetabbardemo.model.MessageItem;
import java.util.ArrayList;
import java.util.List;
/**
* User:Shine
* Date:2015-10-20
* Description:
*/
public class MessageFragment extends Fragment {
private RecyclerView rvMessageList;
private MessageAdapter messageAdapter;
private List<MessageItem> messageList;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_message, container, false);
initView(view);
initData();
return view;
}
private void initView(View view) {
rvMessageList = view.findViewById(R.id.rvMessageList);
rvMessageList.setLayoutManager(new LinearLayoutManager(getContext()));
}
private void initData() {
messageList = new ArrayList<>();
// 添加消息数据 - 所有头像都使用白色背景
messageList.add(new MessageItem("通知消息", "红包到账提醒", "刚刚", 0, true));
messageList.add(new MessageItem("互动消息", "还没有新通知~", "", 0, false));
messageList.add(new MessageItem("闲鱼精选", "[347条] 关注的宝贝上新捡漏...", "6小时前", 347, false));
messageList.add(new MessageItem("刑事组之虎", "快给ta一个评价吧", "04-19", 0, false));
messageList.add(new MessageItem("卖家小助手", "开启急速转卖通道!", "05-25", 0, true));
messageList.add(new MessageItem("豫中玩具批…", "[我完成了评价]", "04-18", 0, false));
messageAdapter = new MessageAdapter(getContext(), messageList);
rvMessageList.setAdapter(messageAdapter);
// 添加点击监听
messageAdapter.setOnItemClickListener(new MessageAdapter.OnItemClickListener() {
@Override
public void onItemClick(MessageItem item) {
// 跳转到聊天页面
Intent intent = new Intent(getActivity(), ChatActivity.class);
intent.putExtra("chat_title", item.getTitle());
startActivity(intent);
}
});
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_message, container, false);
}
}
}

@ -1,195 +1,24 @@
package com.startsmake.llrisetabbardemo.fragment;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.activity.LoginActivity;
import com.startsmake.llrisetabbardemo.manager.UserManager;
/**
* User:Shine
* Date:2015-10-20
* Description:
*/
public class PersonFragment extends Fragment {
private View mLogoutLayout;
private TextView tvUsername, tvUserDesc, tvCreditScore, tvMemberLevel;
private TextView tvWantCount, tvSellingCount, tvSoldCount, tvSavedMoney;
private UserManager userManager;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_person, container, false);
userManager = UserManager.getInstance(requireContext());
initView(view);
setListeners();
updateUI();
return view;
}
private void initView(View view) {
mLogoutLayout = view.findViewById(R.id.ll_logout);
tvUsername = view.findViewById(R.id.tv_username);
tvUserDesc = view.findViewById(R.id.tv_user_desc);
tvCreditScore = view.findViewById(R.id.tv_credit_score);
tvMemberLevel = view.findViewById(R.id.tv_member_level);
tvWantCount = view.findViewById(R.id.tv_want_count);
tvSellingCount = view.findViewById(R.id.tv_selling_count);
tvSoldCount = view.findViewById(R.id.tv_sold_count);
tvSavedMoney = view.findViewById(R.id.tv_saved_money);
}
private void setListeners() {
// 退出登录按钮
if (mLogoutLayout != null) {
mLogoutLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showLogoutDialog();
}
});
}
// 用户名点击登录
if (tvUsername != null) {
tvUsername.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isUserLoggedIn()) {
navigateToLogin();
}
}
});
}
// 用户描述点击登录
if (tvUserDesc != null) {
tvUserDesc.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isUserLoggedIn()) {
navigateToLogin();
}
}
});
}
}
private void showLogoutDialog() {
if (!isUserLoggedIn()) {
Toast.makeText(getActivity(), "您还未登录", Toast.LENGTH_SHORT).show();
navigateToLogin();
return;
}
new AlertDialog.Builder(requireContext())
.setTitle("退出登录")
.setMessage("确定要退出登录吗?退出后可以使用原账号重新登录")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
performLogout();
}
})
.setNegativeButton("取消", null)
.show();
}
private void performLogout() {
// 只清除登录状态,不删除用户数据
clearLoginStatusOnly();
// 更新UI
updateUI();
Toast.makeText(getActivity(), "已退出登录", Toast.LENGTH_SHORT).show();
}
private void clearLoginStatusOnly() {
try {
// 方法1: 使用UserManager退出登录只清除登录状态
if (userManager != null) {
userManager.logout();
}
// 方法2: 只清除登录状态,保留用户数据
SharedPreferences spUser = requireActivity().getSharedPreferences("user_info", android.content.Context.MODE_PRIVATE);
SharedPreferences.Editor editorUser = spUser.edit();
// 只清除登录相关状态,不清除用户数据
editorUser.putBoolean("is_logged_in", false);
editorUser.remove("user_token");
// 注意:不要清除 user_phone 和 user_name这样用户重新登录时可以直接显示
editorUser.apply();
} catch (Exception e) {
Toast.makeText(getActivity(), "退出登录失败", Toast.LENGTH_SHORT).show();
}
}
private void updateUI() {
if (isUserLoggedIn()) {
// 用户已登录的状态
SharedPreferences sp = requireActivity().getSharedPreferences("user_info", android.content.Context.MODE_PRIVATE);
String username = sp.getString("user_name", "用户");
if (tvUsername != null) tvUsername.setText(username);
if (tvUserDesc != null) tvUserDesc.setText("省钱达人,精明购物");
if (tvCreditScore != null) tvCreditScore.setVisibility(View.VISIBLE);
if (tvMemberLevel != null) tvMemberLevel.setVisibility(View.VISIBLE);
if (tvWantCount != null) tvWantCount.setText("5");
if (tvSellingCount != null) tvSellingCount.setText("3");
if (tvSoldCount != null) tvSoldCount.setText("12");
if (tvSavedMoney != null) tvSavedMoney.setText("¥256");
} else {
// 用户未登录的状态
if (tvUsername != null) tvUsername.setText("点击登录");
if (tvUserDesc != null) tvUserDesc.setText("登录查看个人数据");
if (tvCreditScore != null) tvCreditScore.setVisibility(View.GONE);
if (tvMemberLevel != null) tvMemberLevel.setVisibility(View.GONE);
if (tvWantCount != null) tvWantCount.setText("0");
if (tvSellingCount != null) tvSellingCount.setText("0");
if (tvSoldCount != null) tvSoldCount.setText("0");
if (tvSavedMoney != null) tvSavedMoney.setText("¥0");
}
}
private boolean isUserLoggedIn() {
SharedPreferences sp = requireActivity().getSharedPreferences("user_info", android.content.Context.MODE_PRIVATE);
return sp.getBoolean("is_logged_in", false);
}
private void navigateToLogin() {
try {
Intent intent = new Intent(getActivity(), LoginActivity.class);
startActivity(intent);
if (getActivity() != null) {
getActivity().overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
} catch (Exception e) {
Toast.makeText(getActivity(), "跳转失败,请重试", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onResume() {
super.onResume();
updateUI();
return inflater.inflate(R.layout.fragment_person, container, false);
}
}
}

@ -1,268 +0,0 @@
package com.startsmake.llrisetabbardemo.fragment;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.Spinner;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.startsmake.llrisetabbardemo.R;
import com.startsmake.llrisetabbardemo.activity.MainActivity;
import com.startsmake.llrisetabbardemo.adapter.ImageAdapter;
import com.startsmake.llrisetabbardemo.model.Item;
import com.startsmake.llrisetabbardemo.model.Product;
import manager.DataManager;
import java.util.ArrayList;
import java.util.List;
public class PublishFragment extends Fragment {
private static final int REQUEST_CODE_PICK_IMAGES = 1001;
private static final int MAX_IMAGE_COUNT = 9;
private EditText etTitle, etDescription, etPrice, etContact;
private Spinner spinnerCategory, spinnerLocation;
private GridView gridViewImages;
private Button btnPublish;
private ImageAdapter imageAdapter;
private List<Uri> selectedImages = new ArrayList<>();
public PublishFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_publish, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViews(view);
setupSpinners();
setupImageGrid();
setupClickListeners();
}
private void initViews(View view) {
etTitle = view.findViewById(R.id.etTitle);
etDescription = view.findViewById(R.id.etDescription);
etPrice = view.findViewById(R.id.etPrice);
etContact = view.findViewById(R.id.etContact);
spinnerCategory = view.findViewById(R.id.spinnerCategory);
spinnerLocation = view.findViewById(R.id.spinnerLocation);
gridViewImages = view.findViewById(R.id.gridViewImages);
btnPublish = view.findViewById(R.id.btnPublish);
}
private void setupSpinners() {
String[] categories = {"数码产品", "服装鞋帽", "家居日用", "图书文具", "美妆个护", "运动户外", "其他"};
ArrayAdapter<String> categoryAdapter = new ArrayAdapter<>(
requireContext(), android.R.layout.simple_spinner_item, categories);
categoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerCategory.setAdapter(categoryAdapter);
String[] locations = {"东丽", "宁河", "其他"};
ArrayAdapter<String> locationAdapter = new ArrayAdapter<>(
requireContext(), android.R.layout.simple_spinner_item, locations);
locationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerLocation.setAdapter(locationAdapter);
}
private void setupImageGrid() {
imageAdapter = new ImageAdapter(requireContext(), selectedImages);
gridViewImages.setAdapter(imageAdapter);
}
private void setupClickListeners() {
gridViewImages.setOnItemClickListener((parent, view, position, id) -> {
if (position == selectedImages.size() && selectedImages.size() < MAX_IMAGE_COUNT) {
openImagePicker();
}
});
btnPublish.setOnClickListener(v -> publishItem());
}
private void openImagePicker() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(intent, "选择图片"), REQUEST_CODE_PICK_IMAGES);
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_PICK_IMAGES && resultCode == Activity.RESULT_OK) {
if (data != null) {
if (data.getClipData() != null) {
int count = Math.min(data.getClipData().getItemCount(),
MAX_IMAGE_COUNT - selectedImages.size());
for (int i = 0; i < count; i++) {
Uri imageUri = data.getClipData().getItemAt(i).getUri();
selectedImages.add(imageUri);
}
} else if (data.getData() != null) {
selectedImages.add(data.getData());
}
imageAdapter.notifyDataSetChanged();
}
}
}
private void publishItem() {
String title = etTitle.getText().toString().trim();
String description = etDescription.getText().toString().trim();
String priceStr = etPrice.getText().toString().trim();
String contact = etContact.getText().toString().trim();
// 验证输入
if (title.isEmpty()) {
Toast.makeText(requireContext(), "请输入商品标题", Toast.LENGTH_SHORT).show();
return;
}
if (description.isEmpty()) {
Toast.makeText(requireContext(), "请输入商品描述", Toast.LENGTH_SHORT).show();
return;
}
if (priceStr.isEmpty()) {
Toast.makeText(requireContext(), "请输入商品价格", Toast.LENGTH_SHORT).show();
return;
}
if (contact.isEmpty()) {
Toast.makeText(requireContext(), "请输入联系方式", Toast.LENGTH_SHORT).show();
return;
}
try {
double price = Double.parseDouble(priceStr);
if (price <= 0) {
Toast.makeText(requireContext(), "价格必须大于0", Toast.LENGTH_SHORT).show();
return;
}
// 创建物品对象
Item item = new Item();
item.setTitle(title);
item.setDescription(description);
item.setPrice(price);
item.setContact(contact);
item.setCategory(spinnerCategory.getSelectedItem().toString());
item.setLocation(spinnerLocation.getSelectedItem().toString());
item.setPublishTime(System.currentTimeMillis());
item.setUserId("user_" + System.currentTimeMillis());
Log.d("PublishFragment", "准备发布商品: " + item.getTitle() + ", 价格: " + item.getPrice());
// 使用DataManager保存商品并获取对应的Product对象
DataManager dataManager = DataManager.getInstance();
Product newProduct = dataManager.addItemAndGetProduct(item);
Log.d("PublishFragment", "商品已保存到DataManager准备切换到首页");
// 发布成功
Toast.makeText(requireContext(), "发布成功!", Toast.LENGTH_SHORT).show();
clearForm();
// 切换到首页并刷新数据
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
// 直接调用切换首页的方法
mainActivity.switchToHomeFragment();
Log.d("PublishFragment", "已切换到首页,准备刷新数据");
// 延迟一小段时间确保HomeFragment已加载
new android.os.Handler().postDelayed(() -> {
try {
HomeFragment homeFragment = mainActivity.getHomeFragment();
if (homeFragment != null) {
Log.d("PublishFragment", "成功获取HomeFragment实例准备刷新数据");
// 从DataManager获取最新数据并刷新首页
refreshHomeFragment(homeFragment);
} else {
Log.e("PublishFragment", "获取HomeFragment实例失败为null");
// 备选方案:直接重新初始化首页数据
reinitializeHomeData();
}
} catch (Exception e) {
Log.e("PublishFragment", "刷新首页数据时出错", e);
reinitializeHomeData();
}
}, 500); // 增加延迟时间确保Fragment完全加载
}
} catch (NumberFormatException e) {
Toast.makeText(requireContext(), "请输入有效的价格", Toast.LENGTH_SHORT).show();
}
}
// 在 PublishFragment.java 的 publishItem 方法末尾添加
// 发布成功后,通知所有相关页面刷新数据
private void refreshAllData() {
// 这里可以添加事件总线或其他通知机制
// 目前主要依赖各个页面在 onResume 时重新加载数据
Log.d("PublishFragment", "新商品发布成功,建议相关页面刷新数据");
}
// 新增方法:备选方案重新初始化首页数据
private void reinitializeHomeData() {
Log.d("PublishFragment", "使用备选方案重新初始化首页数据");
// 这里可以尝试其他方式刷新首页,比如广播或事件总线
Toast.makeText(requireContext(), "发布成功,请手动刷新首页", Toast.LENGTH_SHORT).show();
}
// 修改刷新首页方法
private void refreshHomeFragment(HomeFragment homeFragment) {
try {
DataManager dataManager = DataManager.getInstance();
List<Product> allProducts = dataManager.getAllProducts();
Log.d("PublishFragment", "从DataManager获取到 " + allProducts.size() + " 个商品");
for (Product product : allProducts) {
Log.d("PublishFragment", "商品: " + product.getName() + ", ID: " + product.getId());
}
// 调用HomeFragment的方法来更新显示
homeFragment.updateProductList(allProducts);
Log.d("PublishFragment", "已调用HomeFragment的updateProductList方法");
} catch (Exception e) {
Log.e("PublishFragment", "刷新首页数据时出错", e);
}
}
private void clearForm() {
etTitle.setText("");
etDescription.setText("");
etPrice.setText("");
etContact.setText("");
selectedImages.clear();
imageAdapter.notifyDataSetChanged();
spinnerCategory.setSelection(0);
spinnerLocation.setSelection(0);
}
}

@ -1,350 +0,0 @@
package com.startsmake.llrisetabbardemo.manager;
import android.content.SharedPreferences;
import android.content.Context;
import android.util.Log;
import com.startsmake.llrisetabbardemo.api.ApiClient;
import com.startsmake.llrisetabbardemo.api.ApiService;
import com.startsmake.llrisetabbardemo.api.response.UserResponse;
import com.startsmake.llrisetabbardemo.model.User;
import com.google.gson.Gson;
import java.util.HashSet;
import java.util.Set;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class UserManager {
private static final String TAG = "UserManager";
private static final String PREF_NAME = "user_data";
private static final String KEY_USERS = "registered_users";
private static final String KEY_CURRENT_USER = "current_user";
private static final String KEY_USER_TOKEN = "user_token";
private static UserManager instance;
private SharedPreferences preferences;
private Gson gson;
private ApiService apiService;
// 认证回调接口
public interface AuthCallback {
void onSuccess(User user);
void onError(String message);
}
private UserManager(Context context) {
preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
gson = new Gson();
apiService = ApiClient.getClient().create(ApiService.class);
}
public static synchronized UserManager getInstance(Context context) {
if (instance == null) {
instance = new UserManager(context);
}
return instance;
}
/**
*
*/
public boolean isLoggedIn() {
return preferences.getBoolean("is_logged_in", false);
}
/**
*
*/
public boolean isPhoneRegistered(String phone) {
Set<String> usersSet = preferences.getStringSet(KEY_USERS, new HashSet<>());
for (String userJson : usersSet) {
User user = gson.fromJson(userJson, User.class);
if (user.getPhone().equals(phone)) {
return true;
}
}
return false;
}
/**
*
*/
public boolean registerUser(String phone, String password) {
// 检查手机号是否已注册
if (isPhoneRegistered(phone)) {
return false;
}
// 创建新用户
User newUser = new User(phone, password);
String userJson = gson.toJson(newUser);
Set<String> usersSet = preferences.getStringSet(KEY_USERS, new HashSet<>());
Set<String> newUsersSet = new HashSet<>(usersSet);
newUsersSet.add(userJson);
return preferences.edit().putStringSet(KEY_USERS, newUsersSet).commit();
}
/**
* API
*/
public void registerUserWithApi(String phone, String password, String username, AuthCallback callback) {
apiService.register(phone, password, username).enqueue(new Callback<UserResponse>() {
@Override
public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().isSuccess()) {
UserResponse.UserInfo userInfo = response.body().getData();
if (userInfo != null) {
// 创建User对象
User user = new User(userInfo.getPhone(), password);
// 设置用户名如果API返回了不同的用户名
user.setUsername(userInfo.getUsername());
// 保存token
saveUserToken(userInfo.getToken());
// 同时保存到本地(以便离线使用)
registerUser(phone, password);
saveCurrentUser(user);
Log.d(TAG, "用户注册成功: " + userInfo.getUsername());
if (callback != null) {
callback.onSuccess(user);
}
}
} else {
// API注册失败尝试本地注册
boolean localRegisterSuccess = registerUser(phone, password);
if (localRegisterSuccess) {
User user = new User(phone, password);
user.setUsername(username);
saveCurrentUser(user);
if (callback != null) {
callback.onSuccess(user);
}
} else {
if (callback != null) {
callback.onError("手机号已被注册");
}
}
}
}
@Override
public void onFailure(Call<UserResponse> call, Throwable t) {
Log.e(TAG, "网络请求失败: " + t.getMessage());
// 网络请求失败,尝试本地注册
boolean localRegisterSuccess = registerUser(phone, password);
if (localRegisterSuccess) {
User user = new User(phone, password);
user.setUsername(username);
saveCurrentUser(user);
if (callback != null) {
callback.onSuccess(user);
}
} else {
if (callback != null) {
callback.onError("网络连接失败,且本地注册失败");
}
}
}
});
}
/**
*
*/
public User loginUser(String phone, String password) {
Set<String> usersSet = preferences.getStringSet(KEY_USERS, new HashSet<>());
for (String userJson : usersSet) {
User user = gson.fromJson(userJson, User.class);
if (user.getPhone().equals(phone) && user.getPassword().equals(password)) {
// 保存当前用户信息
saveCurrentUser(user);
return user;
}
}
return null;
}
/**
* API
*/
public void loginUserWithApi(String phone, String password, AuthCallback callback) {
apiService.login(phone, password).enqueue(new Callback<UserResponse>() {
@Override
public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().isSuccess()) {
UserResponse.UserInfo userInfo = response.body().getData();
if (userInfo != null) {
// 创建User对象
User user = new User(userInfo.getPhone(), password);
// 设置用户名如果API返回了不同的用户名
user.setUsername(userInfo.getUsername());
// 保存token
saveUserToken(userInfo.getToken());
// 保存用户信息
saveCurrentUser(user);
Log.d(TAG, "用户登录成功: " + userInfo.getUsername());
if (callback != null) {
callback.onSuccess(user);
}
}
} else {
Log.e(TAG, "API登录失败回退到本地登录");
// API登录失败尝试本地登录
User localUser = loginUser(phone, password);
if (localUser != null) {
if (callback != null) {
callback.onSuccess(localUser);
}
} else {
if (callback != null) {
callback.onError("手机号或密码错误");
}
}
}
}
@Override
public void onFailure(Call<UserResponse> call, Throwable t) {
Log.e(TAG, "网络请求失败: " + t.getMessage());
// 网络请求失败,尝试本地登录
User localUser = loginUser(phone, password);
if (localUser != null) {
if (callback != null) {
callback.onSuccess(localUser);
}
} else {
if (callback != null) {
callback.onError("网络连接失败,且本地账号不存在");
}
}
}
});
}
/**
* token
*/
private void saveUserToken(String token) {
preferences.edit().putString(KEY_USER_TOKEN, token).apply();
}
/**
* token
*/
public String getUserToken() {
return preferences.getString(KEY_USER_TOKEN, null);
}
/**
* token
*/
public boolean hasValidToken() {
return getUserToken() != null;
}
/**
*
*/
public boolean resetPassword(String phone, String newPassword) {
Set<String> usersSet = preferences.getStringSet(KEY_USERS, new HashSet<>());
Set<String> newUsersSet = new HashSet<>();
boolean found = false;
for (String userJson : usersSet) {
User user = gson.fromJson(userJson, User.class);
if (user.getPhone().equals(phone)) {
// 更新密码
user.setPassword(newPassword);
found = true;
}
newUsersSet.add(gson.toJson(user));
}
if (found) {
boolean success = preferences.edit().putStringSet(KEY_USERS, newUsersSet).commit();
if (success) {
// 如果重置的是当前登录用户,更新当前用户信息
User currentUser = getCurrentUser();
if (currentUser != null && currentUser.getPhone().equals(phone)) {
currentUser.setPassword(newPassword);
saveCurrentUser(currentUser);
}
}
return success;
}
return false;
}
/**
*
*/
private void saveCurrentUser(User user) {
String userJson = gson.toJson(user);
preferences.edit()
.putString(KEY_CURRENT_USER, userJson)
.putBoolean("is_logged_in", true)
.putString("user_phone", user.getPhone())
.putString("user_name", user.getUsername())
.apply();
}
/**
*
*/
public User getCurrentUser() {
String userJson = preferences.getString(KEY_CURRENT_USER, null);
if (userJson != null) {
return gson.fromJson(userJson, User.class);
}
return null;
}
/**
*
*/
public void logout() {
preferences.edit()
.remove(KEY_CURRENT_USER)
.putBoolean("is_logged_in", false)
.remove("user_phone")
.remove("user_name")
.remove(KEY_USER_TOKEN) // 清除token
.apply();
Log.d(TAG, "用户已登出");
}
/**
*
*/
public void saveUserLogin(String phone, String password) {
User user = loginUser(phone, password);
if (user != null) {
saveCurrentUser(user);
}
}
/**
*
*/
public boolean validateLogin(String phone, String password) {
return loginUser(phone, password) != null;
}
/**
*
*/
public boolean isUserExists(String phone) {
return isPhoneRegistered(phone);
}
/**
*
*/
public boolean updatePassword(String phone, String newPassword) {
return resetPassword(phone, newPassword);
}
}

@ -1,28 +0,0 @@
package com.startsmake.llrisetabbardemo.model;
public class ChatMessage {
private String sender;
private String content;
private String time;
private boolean isMe;
public ChatMessage(String sender, String content, String time, boolean isMe) {
this.sender = sender;
this.content = content;
this.time = time;
this.isMe = isMe;
}
// Getter and Setter methods
public String getSender() { return sender; }
public void setSender(String sender) { this.sender = sender; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getTime() { return time; }
public void setTime(String time) { this.time = time; }
public boolean isMe() { return isMe; }
public void setMe(boolean me) { isMe = me; }
}

@ -1,121 +0,0 @@
package com.startsmake.llrisetabbardemo.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Item implements Serializable {
private String id;
private String title;
private String description;
private int wantCount;
private double price;
private List<String> imageUrls;
private String category;
private String location;
private String contact;
private String contactQQ; // 新增QQ联系方式
private String contactWechat; // 新增微信联系方式
private long publishTime;
private String userId;
private int viewCount; // 浏览数
private int likeCount; // 点赞数
public Item() {
imageUrls = new ArrayList<>();
viewCount = 0;
likeCount = 0;
}
// Getter 和 Setter
public int getWantCount() {
return wantCount;
}
public void setWantCount(int wantCount) {
this.wantCount = wantCount;
}
// 构造函数
public Item(String title, String description, double price, String category, String location, String contact) {
this();
this.title = title;
this.description = description;
this.price = price;
this.category = category;
this.location = location;
this.contact = contact;
this.publishTime = System.currentTimeMillis();
this.userId = "user_" + System.currentTimeMillis();
}
// Getter 和 Setter 方法
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public List<String> getImageUrls() { return imageUrls; }
public void setImageUrls(List<String> imageUrls) { this.imageUrls = imageUrls; }
public void addImageUrl(String imageUrl) { this.imageUrls.add(imageUrl); }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
public String getContact() { return contact; }
public void setContact(String contact) { this.contact = contact; }
public String getContactQQ() { return contactQQ; }
public void setContactQQ(String contactQQ) { this.contactQQ = contactQQ; }
public String getContactWechat() { return contactWechat; }
public void setContactWechat(String contactWechat) { this.contactWechat = contactWechat; }
public long getPublishTime() { return publishTime; }
public void setPublishTime(long publishTime) { this.publishTime = publishTime; }
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
public int getViewCount() { return viewCount; }
public void setViewCount(int viewCount) { this.viewCount = viewCount; }
public int getLikeCount() { return likeCount; }
public void setLikeCount(int likeCount) { this.likeCount = likeCount; }
/**
*
*/
public void incrementViewCount() {
this.viewCount++;
}
/**
*
*/
public void incrementLikeCount() {
this.likeCount++;
}
@Override
public String toString() {
return "Item{" +
"id='" + id + '\'' +
", title='" + title + '\'' +
", price=" + price +
", category='" + category + '\'' +
", location='" + location + '\'' +
", publishTime=" + publishTime +
'}';
}
}

@ -1,33 +0,0 @@
package com.startsmake.llrisetabbardemo.model;
public class MessageItem {
private String title;
private String content;
private String time;
private int unreadCount;
private boolean isOfficial;
public MessageItem(String title, String content, String time, int unreadCount, boolean isOfficial) {
this.title = title;
this.content = content;
this.time = time;
this.unreadCount = unreadCount;
this.isOfficial = isOfficial;
}
// Getter and Setter methods
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getTime() { return time; }
public void setTime(String time) { this.time = time; }
public int getUnreadCount() { return unreadCount; }
public void setUnreadCount(int unreadCount) { this.unreadCount = unreadCount; }
public boolean isOfficial() { return isOfficial; }
public void setOfficial(boolean official) { isOfficial = official; }
}

@ -1,134 +0,0 @@
package com.startsmake.llrisetabbardemo.model;
import java.io.Serializable;
import java.util.Objects;
public class Product implements Serializable {
private String id;
private String name;
private String description;
private String category;
private double price;
private String imageUrl;
private int wantCount; // 添加想要人数字段
private String location; // 添加地区字段
private String sellerRating; // 添加卖家信用字段
private boolean freeShipping; // 添加包邮标识
private String contact; // 新增联系方式字段
public Product() {
this.wantCount = 0; // 默认0人想要
this.location = "东丽"; // 默认地区
this.sellerRating = "卖家信用良好"; // 默认信用
this.freeShipping = false; // 默认不包邮
}
public Product(String id, String name, String description, String category, double price, String imageUrl) {
this.id = id;
this.name = name;
this.description = description;
this.category = category;
this.price = price;
this.imageUrl = imageUrl;
this.wantCount = 0; // 默认0人想要
this.location = "东丽"; // 默认地区
this.sellerRating = "卖家信用良好"; // 默认信用
this.freeShipping = false; // 默认不包邮
}
// 全参数构造函数
public Product(String id, String name, String description, String category, double price, String imageUrl,
int wantCount, String location, String sellerRating, boolean freeShipping) {
this.id = id;
this.name = name;
this.description = description;
this.category = category;
this.price = price;
this.imageUrl = imageUrl;
this.wantCount = wantCount;
this.location = location;
this.sellerRating = sellerRating;
this.freeShipping = freeShipping;
}
// 新增全参数构造函数包含contact
public Product(String id, String name, String description, String category, double price, String imageUrl,
int wantCount, String location, String sellerRating, boolean freeShipping, String contact) {
this.id = id;
this.name = name;
this.description = description;
this.category = category;
this.price = price;
this.imageUrl = imageUrl;
this.wantCount = wantCount;
this.location = location;
this.sellerRating = sellerRating;
this.freeShipping = freeShipping;
this.contact = contact;
}
// Getter 和 Setter 方法
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public String getImageUrl() { return imageUrl; }
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
public int getWantCount() { return wantCount; }
public void setWantCount(int wantCount) { this.wantCount = wantCount; }
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
public String getSellerRating() { return sellerRating; }
public void setSellerRating(String sellerRating) { this.sellerRating = sellerRating; }
public boolean isFreeShipping() { return freeShipping; }
public void setFreeShipping(boolean freeShipping) { this.freeShipping = freeShipping; }
// 新增contact的getter和setter
public String getContact() { return contact; }
public void setContact(String contact) { this.contact = contact; }
// 添加 equals 和 hashCode 方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Objects.equals(id, product.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
// 可选:添加 toString 方法便于调试
@Override
public String toString() {
return "Product{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", category='" + category + '\'' +
", price=" + price +
", wantCount=" + wantCount +
", location='" + location + '\'' +
", sellerRating='" + sellerRating + '\'' +
", freeShipping=" + freeShipping +
", contact='" + contact + '\'' +
'}';
}
}

@ -1,27 +0,0 @@
package com.startsmake.llrisetabbardemo.model;
public class User {
private String phone;
private String password;
private String username;
private long registerTime;
public User(String phone, String password) {
this.phone = phone;
this.password = password;
this.username = "用户_" + phone.substring(7);
this.registerTime = System.currentTimeMillis();
}
// Getters and Setters
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public long getRegisterTime() { return registerTime; }
}

@ -1,522 +0,0 @@
package manager;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.startsmake.llrisetabbardemo.api.ApiClient;
import com.startsmake.llrisetabbardemo.api.ApiService;
import com.startsmake.llrisetabbardemo.api.response.BaseResponse;
import com.startsmake.llrisetabbardemo.api.response.ProductResponse;
import com.startsmake.llrisetabbardemo.model.Item;
import com.startsmake.llrisetabbardemo.model.Product;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* - 使
* API
*/
public class DataManager {
private static final String TAG = "DataManager";
private static final String PREF_NAME = "product_data";
private static final String KEY_ITEMS = "items";
// 单例实例
private static DataManager instance;
// 商品列表
private List<Item> itemList;
// API服务实例
private ApiService apiService;
// Context 和 SharedPreferences
private Context context;
private SharedPreferences sharedPreferences;
private Gson gson;
// 数据变化监听器列表
private List<OnDataChangedListener> dataChangedListeners = new CopyOnWriteArrayList<>();
// 回调接口用于通知UI数据加载状态
public interface OnDataLoadedListener {
void onDataLoaded(List<Item> items);
void onError(String message);
}
// 数据变化监听接口
public interface OnDataChangedListener {
void onDataChanged(); // 数据发生变化时调用
void onProductWantCountChanged(String productId, int newCount); // 商品想要人数变化时调用
}
// 私有构造函数,防止外部创建实例
private DataManager() {
itemList = new ArrayList<>();
}
/**
* DataManager Application Activity
*/
public void init(Context context) {
this.context = context.getApplicationContext();
this.sharedPreferences = this.context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
this.gson = new Gson();
// 初始化API服务
apiService = ApiClient.getClient().create(ApiService.class);
// 从本地存储加载数据
loadItemsFromStorage();
}
/**
*
* @return DataManager
*/
public static DataManager getInstance() {
if (instance == null) {
instance = new DataManager();
}
return instance;
}
/**
*
*/
public void registerDataChangedListener(OnDataChangedListener listener) {
if (!dataChangedListeners.contains(listener)) {
dataChangedListeners.add(listener);
Log.d(TAG, "注册数据变化监听器,当前监听器数量: " + dataChangedListeners.size());
}
}
/**
*
*/
public void unregisterDataChangedListener(OnDataChangedListener listener) {
dataChangedListeners.remove(listener);
Log.d(TAG, "取消注册数据变化监听器,当前监听器数量: " + dataChangedListeners.size());
}
/**
*
*/
private void notifyDataChanged() {
for (OnDataChangedListener listener : dataChangedListeners) {
listener.onDataChanged();
}
}
/**
*
*/
private void notifyProductWantCountChanged(String productId, int newCount) {
for (OnDataChangedListener listener : dataChangedListeners) {
listener.onProductWantCountChanged(productId, newCount);
}
}
/**
*
*/
private void loadItemsFromStorage() {
String itemsJson = sharedPreferences.getString(KEY_ITEMS, null);
if (itemsJson != null) {
Type type = new TypeToken<List<Item>>(){}.getType();
List<Item> savedItems = gson.fromJson(itemsJson, type);
if (savedItems != null && !savedItems.isEmpty()) {
itemList = savedItems;
Log.d(TAG, "从本地存储加载商品数据,共" + itemList.size() + "个商品");
} else {
initSampleData();
saveItemsToStorage();
}
} else {
initSampleData();
saveItemsToStorage();
}
}
/**
*
*/
private void saveItemsToStorage() {
if (itemList != null) {
String itemsJson = gson.toJson(itemList);
sharedPreferences.edit().putString(KEY_ITEMS, itemsJson).apply();
Log.d(TAG, "商品数据已保存到本地存储,共" + itemList.size() + "个商品");
}
}
/**
*
*/
private void initSampleData() {
// 示例商品1 - 数码产品
Item item1 = new Item();
item1.setId("item_001");
item1.setTitle("全新iPhone 13 Pro");
item1.setDescription("全新未拆封256GB远峰蓝色国行正品带发票");
item1.setPrice(6999.00);
item1.setCategory("数码产品");
item1.setLocation("东丽");
item1.setContact("138****1234");
item1.setPublishTime(System.currentTimeMillis() - 2 * 60 * 60 * 1000); // 2小时前发布
item1.setWantCount(5); // 设置初始想要人数
itemList.add(item1);
// 示例商品2 - 数码产品
Item item2 = new Item();
item2.setId("item_002");
item2.setTitle("二手笔记本电脑");
item2.setDescription("联想小新i5处理器8GB内存256GB固态硬盘95成新");
item2.setPrice(2500.00);
item2.setCategory("数码产品");
item2.setLocation("东丽");
item2.setContact("微信abc123");
item2.setPublishTime(System.currentTimeMillis() - 5 * 60 * 60 * 1000); // 5小时前发布
item2.setWantCount(3); // 设置初始想要人数
itemList.add(item2);
// 示例商品3 - 服装鞋帽
Item item3 = new Item();
item3.setId("item_003");
item3.setTitle("品牌运动鞋");
item3.setDescription("耐克运动鞋42码只穿过几次几乎全新原盒在");
item3.setPrice(299.00);
item3.setCategory("服装鞋帽");
item3.setLocation("宁河");
item3.setContact("159****5678");
item3.setPublishTime(System.currentTimeMillis() - 24 * 60 * 60 * 1000); // 1天前发布
item3.setWantCount(8); // 设置初始想要人数
itemList.add(item3);
// 示例商品4 - 图书文具
Item item4 = new Item();
item4.setId("item_004");
item4.setTitle("Java编程思想");
item4.setDescription("Java编程思想第5版几乎全新无笔记无划痕");
item4.setPrice(45.00);
item4.setCategory("图书文具");
item4.setLocation("东丽");
item4.setContact("QQ123456789");
item4.setPublishTime(System.currentTimeMillis() - 3 * 24 * 60 * 60 * 1000); // 3天前发布
item4.setWantCount(12); // 设置初始想要人数
itemList.add(item4);
}
/**
*
* @return
*/
public List<Item> getAllItems() {
return itemList;
}
/**
* API
* @param listener
*/
public void fetchItemsFromApi(OnDataLoadedListener listener) {
apiService.getProducts().enqueue(new Callback<BaseResponse<List<ProductResponse>>>() {
@Override
public void onResponse(Call<BaseResponse<List<ProductResponse>>> call,
Response<BaseResponse<List<ProductResponse>>> response) {
if (response.isSuccessful() && response.body() != null && response.body().isSuccess()) {
List<ProductResponse> productResponses = response.body().getData();
if (productResponses != null) {
// 转换为本地Item对象
List<Item> items = convertToItems(productResponses);
// 更新本地缓存
itemList = items;
// 保存到本地存储
saveItemsToStorage();
Log.d(TAG, "从API成功获取商品数据共" + items.size() + "个商品");
// 回调成功
if (listener != null) {
listener.onDataLoaded(items);
}
// 通知数据变化
notifyDataChanged();
} else {
// 返回空数据
if (listener != null) {
listener.onDataLoaded(new ArrayList<>());
}
}
} else {
Log.e(TAG, "API请求失败使用本地数据");
// 如果API请求失败使用本地缓存数据
if (listener != null) {
listener.onDataLoaded(itemList);
listener.onError("网络请求失败,显示本地数据");
}
}
}
@Override
public void onFailure(Call<BaseResponse<List<ProductResponse>>> call, Throwable t) {
Log.e(TAG, "网络请求失败: " + t.getMessage());
// 网络请求失败,使用本地缓存数据
if (listener != null) {
listener.onDataLoaded(itemList);
listener.onError("网络连接失败,请检查网络设置");
}
}
});
}
/**
* ProductResponseItem
*/
private List<Item> convertToItems(List<ProductResponse> productResponses) {
List<Item> items = new ArrayList<>();
for (ProductResponse response : productResponses) {
Item item = new Item();
item.setId(response.getId());
item.setTitle(response.getTitle());
item.setDescription(response.getDescription());
item.setCategory(response.getCategory());
item.setPrice(response.getPrice());
item.setImageUrls(response.getImageUrls());
item.setContact(response.getContact());
item.setPublishTime(response.getPublishTime());
// 设置默认想要人数
item.setWantCount(0);
// 设置默认位置,因为 ProductResponse 可能没有 location 字段
item.setLocation("东丽"); // 或者从其他地方获取,或者设置为空
items.add(item);
}
return items;
}
/**
*
* @param item
*/
public void addItem(Item item) {
// 为新商品生成ID
item.setId("item_" + System.currentTimeMillis());
// 设置发布时间
item.setPublishTime(System.currentTimeMillis());
// 设置初始想要人数
if (item.getWantCount() == 0) {
item.setWantCount(0);
}
// 将新商品添加到列表最前面(最新发布的显示在最前面)
itemList.add(0, item);
// 保存到本地存储
saveItemsToStorage();
Log.d("DataManager", "成功添加新商品:" + item.getTitle() + ",当前商品总数:" + itemList.size());
// 通知数据变化
notifyDataChanged();
}
/**
*
* @param productId ID
* @param wantCount
*/
public void updateProductWantCount(String productId, int wantCount) {
boolean found = false;
for (Item item : itemList) {
if (item.getId().equals(productId)) {
item.setWantCount(wantCount);
found = true;
// 保存到本地存储
saveItemsToStorage();
Log.d(TAG, "更新商品 " + productId + " 的想要人数为: " + wantCount);
// 通知想要人数变化
notifyProductWantCountChanged(productId, wantCount);
break;
}
}
if (found) {
// 同时通知整体数据变化
notifyDataChanged();
}
}
/**
*
* @param productId ID
* @return
*/
public int getProductWantCount(String productId) {
for (Item item : itemList) {
if (item.getId().equals(productId)) {
return item.getWantCount();
}
}
return 0;
}
/**
* Product使
*/
public List<Product> getAllProducts() {
List<Product> products = new ArrayList<>();
Log.d("DataManager", "开始转换 " + itemList.size() + " 个Item到Product");
for (Item item : itemList) {
products.add(convertItemToProduct(item));
}
Log.d("DataManager", "转换完成,返回 " + products.size() + " 个Product");
return products;
}
/**
* ID
* @param id ID
* @return null
*/
public Item getItemById(String id) {
for (Item item : itemList) {
if (item.getId().equals(id)) {
return item;
}
}
return null;
}
/**
*
* @param category
* @return
*/
public List<Item> getItemsByCategory(String category) {
List<Item> result = new ArrayList<>();
for (Item item : itemList) {
if (item.getCategory().equals(category)) {
result.add(item);
}
}
return result;
}
/**
*
* @param keyword
* @return
*/
public List<Item> searchItems(String keyword) {
List<Item> result = new ArrayList<>();
for (Item item : itemList) {
if (item.getTitle().toLowerCase().contains(keyword.toLowerCase()) ||
item.getDescription().toLowerCase().contains(keyword.toLowerCase()) ||
item.getCategory().toLowerCase().contains(keyword.toLowerCase())) {
result.add(item);
}
}
Log.d(TAG, "搜索关键词: " + keyword + ", 找到 " + result.size() + " 个结果");
return result;
}
/**
* API
* @param keyword
* @param listener
*/
public void searchItemsFromApi(String keyword, OnDataLoadedListener listener) {
apiService.searchProducts(keyword).enqueue(new Callback<BaseResponse<List<ProductResponse>>>() {
@Override
public void onResponse(Call<BaseResponse<List<ProductResponse>>> call,
Response<BaseResponse<List<ProductResponse>>> response) {
if (response.isSuccessful() && response.body() != null && response.body().isSuccess()) {
List<ProductResponse> productResponses = response.body().getData();
if (productResponses != null) {
List<Item> items = convertToItems(productResponses);
if (listener != null) {
listener.onDataLoaded(items);
}
} else {
if (listener != null) {
listener.onDataLoaded(new ArrayList<>());
}
}
} else {
// 如果API搜索失败回退到本地搜索
List<Item> localResults = searchItems(keyword);
if (listener != null) {
listener.onDataLoaded(localResults);
}
}
}
@Override
public void onFailure(Call<BaseResponse<List<ProductResponse>>> call, Throwable t) {
Log.e(TAG, "搜索请求失败: " + t.getMessage());
// 网络请求失败,回退到本地搜索
List<Item> localResults = searchItems(keyword);
if (listener != null) {
listener.onDataLoaded(localResults);
}
}
});
}
/**
*
* @return
*/
public int getItemCount() {
return itemList.size();
}
/**
*
*/
public void clearAll() {
itemList.clear();
saveItemsToStorage();
// 通知数据变化
notifyDataChanged();
}
/**
* ItemProduct
*/
public Product convertItemToProduct(Item item) {
Product product = new Product();
product.setId(item.getId());
product.setName(item.getTitle());
product.setDescription(item.getDescription());
product.setCategory(item.getCategory());
product.setPrice(item.getPrice());
product.setLocation(item.getLocation());
product.setContact(item.getContact());
// 设置想要人数从Item中获取
product.setWantCount(item.getWantCount());
product.setSellerRating("卖家信用良好");
product.setFreeShipping(false);
return product;
}
/**
* Product
*/
public Product addItemAndGetProduct(Item item) {
addItem(item);
return convertItemToProduct(item);
}
}

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<stroke
android:width="1dp"
android:color="#e0e0e0" />
<corners android:radius="4dp" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#20FFD700" />
<corners android:radius="8dp" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFD700" />
<corners android:radius="24dp" />
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#20FFD700" />
<corners android:radius="24dp" />
<stroke android:width="1dp" android:color="#FFD700" />
</shape>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f5f5f5" />
<corners android:radius="24dp" />
<stroke
android:width="1dp"
android:color="#e0e0e0" />
</shape>

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners
android:topLeftRadius="0dp"
android:topRightRadius="16dp"
android:bottomLeftRadius="16dp"
android:bottomRightRadius="16dp" />
<stroke
android:width="1dp"
android:color="#e0e0e0" />
</shape>

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#07C160" />
<corners
android:topLeftRadius="16dp"
android:topRightRadius="0dp"
android:bottomLeftRadius="16dp"
android:bottomRightRadius="16dp" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#99000000" />
<corners android:radius="12dp" />
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<stroke android:width="1dp" android:color="#E0E0E0" />
<corners android:radius="8dp" />
</shape>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f0f0f0" />
<corners android:radius="4dp" />
<stroke
android:width="1dp"
android:color="#e0e0e0" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f5f5f5" />
<corners android:radius="18dp" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FF5000" />
<corners android:radius="9dp" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#87CEEB"/>
<corners android:radius="12dp"/>
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<stroke android:width="1dp" android:color="#e0e0e0" />
<corners android:radius="4dp" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#2196F3"/>
<corners android:radius="16dp"/>
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#2196F3"/>
<corners android:radius="12dp"/>
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f8f9fa" />
<corners android:radius="8dp" />
<stroke android:width="1dp" android:color="#dee2e6" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<corners android:radius="12dp"/>
</shape>

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#FFFFFFFF" />
<stroke
android:width="1dp"
android:color="#FFE0E0E0" />
<!-- 添加阴影效果 -->
<padding
android:left="2dp"
android:top="2dp"
android:right="2dp"
android:bottom="2dp" />
</shape>

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="12dp" />
<solid android:color="#FF00BCD4" />
<stroke
android:width="0.5dp"
android:color="#FF0097A7" />
<padding
android:left="8dp"
android:top="2dp"
android:right="8dp"
android:bottom="2dp" />
</shape>

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="22dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#F5F5F5"
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
</vector>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners android:radius="16dp" />
<stroke android:width="1dp" android:color="#f0f0f0" />
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<stroke android:width="1dp" android:color="#e0e0e0" />
<corners android:radius="4dp" />
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f8f9fa" />
<corners android:radius="20dp" />
<stroke android:width="1dp" android:color="#e9ecef" />
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#fff2f2" />
<corners android:radius="20dp" />
<stroke android:width="1dp" android:color="#ff6b35" />
</shape>

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#E3F2FD"
android:endColor="#BBDEFB"
android:angle="90"/>
</shape>

@ -1,15 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF666666"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z M12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
<path
android:fillColor="#FF666666"
android:pathData="M12,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6 6,-2.69 6,-6 -2.69,-6 -6,-6z M12,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
<path
android:fillColor="#FF666666"
android:pathData="M12,9.5c-1.38,0 -2.5,1.12 -2.5,2.5s1.12,2.5 2.5,2.5 2.5,-1.12 2.5,-2.5 -1.12,-2.5 -2.5,-2.5z"/>
</vector>

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/white">
<path
android:fillColor="@android:color/white"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333">
<path
android:fillColor="@android:color/white"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

@ -1,11 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:strokeColor="#FF666666"
android:strokeWidth="2"
android:fillColor="@android:color/transparent"
android:pathData="M9,6l6,6l-6,6"/>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

@ -1,15 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFE44D"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z M12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M12.5,7H11v6l5.25,3.15l0.75,-1.23l-4.5,-2.67z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M7,12.5h10v-1H7z"/>
</vector>

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFE44D"
android:pathData="M20,6h-2.18c0.11,-0.31 0.18,-0.65 0.18,-1c0,-1.66 -1.34,-3 -3,-3c-1.05,0 -1.96,0.54 -2.5,1.35C12.96,2.54 12.05,2 11,2C9.34,2 8,3.34 8,5c0,0.35 0.07,0.69 0.18,1H4c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6z M15,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S14.45,4 15,4z M11,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S10.45,4 11,4z M4,19v-6h6v6H4z M14,19v-6h6v6H14z"/>
</vector>

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF757575"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF4CAF50"
android:pathData="M20,2H4C2.9,2 2,2.9 2,4v12c0,1.1 0.9,2 2,2h4v3c0,0.55 0.45,1 1,1h0.5c0.25,0 0.49,-0.09 0.67,-0.26L13.9,18H20c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2z M20,16h-6.09c-0.18,0 -0.35,0.06 -0.49,0.17l-1.42,1.42V16H4V4h16V16z"/>
<path
android:fillColor="#FF4CAF50"
android:pathData="M11,11h2v2h-2z M11,7h2v2h-2z"/>
</vector>

@ -1,15 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFE44D"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z M12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M11,16h2v2h-2z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5C16,7.79 14.21,6 12,6z"/>
</vector>

@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFE44D"
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3S14.34,11 16,11z M8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8S6.34,11 8,11z M8,13c-2.33,0 -7,1.17 -7,3.5V19h14v-2.5C15,14.17 10.33,13 8,13z M16,13c-0.29,0 -0.62,0.02 -0.97,0.05c1.16,0.84 1.97,1.97 1.97,3.45V19h6v-2.5C23,14.17 18.33,13 16,13z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M20,2H4C2.9,2 2,2.9 2,4v12c0,1.1 0.9,2 2,2h4v-2H4V4h16v12h-4v2h4c1.1,0 2,-0.9 2,-2V4C22,2.9 21.1,2 20,2z"/>
</vector>

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF666666"
android:pathData="M17,7l-1.41,1.41L18.17,11H8v2h10.17l-2.58,2.58L17,17l5,-5L17,7z M4,5h8V3H4C2.9,3 2,3.9 2,5v14c0,1.1 0.9,2 2,2h8v-2H4V5z"/>
</vector>

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF666666"
android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z M18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z M12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>

@ -1,15 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFE44D"
android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M8.5,15H6.5l4,-7 4,7h-2l-1.5,-2.5L8.5,15z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M17,12.5h-4V11h4V12.5z"/>
</vector>

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF5000"
android:pathData="M12,2L4,5v6.09c0,5.05 3.41,9.76 8,10.91c4.59,-1.15 8,-5.86 8,-10.91V5L12,2z"/>
</vector>

@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFE44D"
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z M18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1L18,16z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M15,9H9v2h1v3h4v-3h1V9z"/>
</vector>

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#BDBDBD"
android:pathData="M19,5v14H5V5h14m0-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
<path
android:fillColor="#BDBDBD"
android:pathData="M12,12c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM14,16v2h-4v-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2z"/>
</vector>

@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFE44D"
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9H1l3.89,3.89l0.07,0.14L9,12H6c0,-3.87 3.13,-7 7,-7s7,3.13 7,7s-3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9z"/>
<path
android:fillColor="#FFE44D"
android:pathData="M12,8v5l4.25,2.52l0.77,-1.28l-3.52,-2.09V8z"/>
</vector>

@ -1,39 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF666666"
android:pathData="M3,11h8V3H3V11zM5,5h4v4H5V5z"/>
<path
android:fillColor="#FF666666"
android:pathData="M3,21h8v-8H3V21zM5,15h4v4H5V15z"/>
<path
android:fillColor="#FF666666"
android:pathData="M13,3v8h8V3H13zM19,9h-4V5h4V9z"/>
<path
android:fillColor="#FF666666"
android:pathData="M21,19h-2v2h2V19z"/>
<path
android:fillColor="#FF666666"
android:pathData="M13,13h2v2h-2V13z"/>
<path
android:fillColor="#FF666666"
android:pathData="M15,15h2v2h-2V15z"/>
<path
android:fillColor="#FF666666"
android:pathData="M13,17h2v2h-2V17z"/>
<path
android:fillColor="#FF666666"
android:pathData="M15,19h2v2h-2V19z"/>
<path
android:fillColor="#FF666666"
android:pathData="M17,17h2v2h-2V17z"/>
<path
android:fillColor="#FF666666"
android:pathData="M19,15h2v2h-2V15z"/>
<path
android:fillColor="#FF666666"
android:pathData="M17,13h2v2h-2V13z"/>
</vector>

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF666666"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.82,11.69 4.82,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#2196F3"
android:pathData="M19,6h-2c0,-2.8 -2.2,-5 -5,-5S7,3.2 7,6H5C3.9,6 3,6.9 3,8v12c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V8C21,6.9 20.1,6 19,6z M12,3c1.7,0 3,1.3 3,3H9C9,4.3 10.3,3 12,3z M19,20H5V8h2v2c0,0.6 0.4,1 1,1s1,-0.4 1,-1V8h6v2c0,0.6 0.4,1 1,1s1,-0.4 1,-1V8h2V20z"/>
</vector>

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFE44D"
android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2L9.19,8.63L2,9.24l5.46,4.73L5.82,21z"/>
</vector>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F5F5F5"/>
<corners android:radius="8dp"/>
<stroke android:width="1dp" android:color="#E3F2FD"/>
</shape>

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="12dp" />
<!-- 银白色渐变 -->
<gradient
android:type="linear"
android:startColor="#FFE8E8E8"
android:centerColor="#FFD6D6D6"
android:endColor="#FFC0C0C0"
android:angle="45" />
<stroke
android:width="0.8dp"
android:color="#FFA0A0A0" />
<padding
android:left="8dp"
android:top="2dp"
android:right="8dp"
android:bottom="2dp" />
</shape>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#2196F3" />
<corners android:radius="8dp" />
</shape>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners android:radius="@dimen/product_card_corner_radius" />
<stroke
android:width="1dp"
android:color="#E3F2FD" />
</shape>

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 阴影 -->
<item>
<shape android:shape="rectangle">
<solid android:color="#E3F2FD" />
<corners android:radius="@dimen/product_card_corner_radius" />
</shape>
</item>
<!-- 内容 -->
<item android:top="2dp" android:bottom="2dp" android:left="2dp" android:right="2dp">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
<corners android:radius="@dimen/product_card_corner_radius" />
<stroke
android:width="1dp"
android:color="#BBDEFB" />
</shape>
</item>
</layer-list>

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 设置圆角半径 -->
<corners android:radius="20dp" />
<!-- 背景颜色 -->
<solid android:color="@android:color/white" />
</shape>

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="25dp" />
<!-- 渐变背景 -->
<gradient
android:type="linear"
android:startColor="#FFFFFF"
android:endColor="#F8F9FA"
android:angle="90" />
<stroke
android:width="1dp"
android:color="#E0E0E0" />
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<corners android:radius="24dp"/>
<stroke android:width="1dp" android:color="#E3F2FD"/>
</shape>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<stroke
android:width="0.8dp"
android:color="#999999" />
<corners android:radius="18dp" />
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<corners android:radius="18dp"/>
<stroke android:width="1dp" android:color="#E0E0E0"/>
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#E3F2FD"/>
<corners android:radius="18dp"/>
<stroke android:width="1dp" android:color="#2196F3"/>
</shape>

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f5f5f5" />
<corners android:radius="20dp" />
<stroke
android:width="1dp"
android:color="#e0e0e0" />
</shape>

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 圆角 -->
<corners android:radius="16dp" />
<!-- 背景色 - 白色 -->
<solid android:color="@color/white" />
<!-- 灰色边框 -->
<stroke
android:width="1dp"
android:color="@color/gray_300" />
<!-- 内边距 -->
<padding
android:left="8dp"
android:top="4dp"
android:right="8dp"
android:bottom="4dp" />
</shape>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f5f5f5" />
<stroke android:width="1dp" android:color="#e0e0e0" />
<corners android:radius="16dp" />
</shape>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save