Compare commits
No commits in common. 'master' and 'main' have entirely different histories.
@ -1,3 +0,0 @@
|
|||||||
# 默认忽略的文件
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectRootManager">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
# 默认忽略的文件
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
@ -1,292 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="WizardSettings">
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="imageWizard">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="imageAssetPanel">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="actionbar">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="clipArt">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
<entry key="imagePath" value="C:\Users\asus\AppData\Local\Temp\ic_android_black_24dp.xml" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="text">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="textAsset">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="launcher">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="foregroundClipArt">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="imagePath" value="C:\Users\asus\AppData\Local\Temp\ic_android_black_24dp.xml" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="foregroundImage">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
<entry key="imagePath" value="C:\Users\asus\Desktop\logo.png" />
|
|
||||||
<entry key="scalingPercent" value="102" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="foregroundText">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="foregroundTextAsset">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="launcherLegacy">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="clipArt">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
<entry key="imagePath" value="C:\Users\asus\AppData\Local\Temp\ic_android_black_24dp.xml" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="text">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="textAsset">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="notification">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="clipArt">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
<entry key="imagePath" value="C:\Users\asus\AppData\Local\Temp\ic_android_black_24dp.xml" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="text">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="textAsset">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="tvBanner">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="foregroundText">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="tvChannel">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="children">
|
|
||||||
<map>
|
|
||||||
<entry key="foregroundClipArt">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="imagePath" value="C:\Users\asus\AppData\Local\Temp\ic_android_black_24dp.xml" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="foregroundImage">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="foregroundText">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="foregroundTextAsset">
|
|
||||||
<value>
|
|
||||||
<PersistentState>
|
|
||||||
<option name="values">
|
|
||||||
<map>
|
|
||||||
<entry key="color" value="000000" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</PersistentState>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,9 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
</component>
|
|
||||||
<component name="VcsProjectSettings">
|
|
||||||
<option name="detectVcsMappingsAutomatically" value="false" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"java.configuration.updateBuildConfiguration": "interactive"
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 692 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 889 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 388 KiB |
|
Before Width: | Height: | Size: 611 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 179 KiB |
@ -1,76 +0,0 @@
|
|||||||
package adapter;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
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 ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ViewHolder> {
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
private List<Product> itemList;
|
|
||||||
private OnItemClickListener listener;
|
|
||||||
|
|
||||||
public interface OnItemClickListener {
|
|
||||||
void onItemClick(Product item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProductAdapter(Context context, List<Product> itemList, OnItemClickListener listener) {
|
|
||||||
this.context = context;
|
|
||||||
this.itemList = itemList;
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
View view = LayoutInflater.from(context).inflate(R.layout.item_product, parent, false);
|
|
||||||
return new ViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
|
||||||
Product item = itemList.get(position);
|
|
||||||
|
|
||||||
holder.tvTitle.setText(item.getName());
|
|
||||||
holder.tvDescription.setText(item.getDescription());
|
|
||||||
holder.tvPrice.setText(String.format("¥%.2f", item.getPrice()));
|
|
||||||
holder.tvCategory.setText(item.getCategory());
|
|
||||||
|
|
||||||
// 设置点击事件
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onItemClick(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return itemList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
TextView tvTitle;
|
|
||||||
TextView tvDescription;
|
|
||||||
TextView tvCategory;
|
|
||||||
TextView tvPrice;
|
|
||||||
|
|
||||||
public ViewHolder(@NonNull View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
tvTitle = itemView.findViewById(R.id.product_name);
|
|
||||||
tvDescription = itemView.findViewById(R.id.product_description);
|
|
||||||
tvCategory = itemView.findViewById(R.id.product_category);
|
|
||||||
tvPrice = itemView.findViewById(R.id.product_price);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,126 +0,0 @@
|
|||||||
package com.example.llrisetabbardemo.models;
|
|
||||||
|
|
||||||
import com.example.llrisetabbardemo.utils.PriceEstimator;
|
|
||||||
|
|
||||||
public class ProductRecognitionInfo {
|
|
||||||
private String productName; // 商品名称
|
|
||||||
private String category; // 商品类别
|
|
||||||
private String description; // 商品描述
|
|
||||||
private PriceEstimator.EstimatedPrice estimatedPrice; // 预估价格信息
|
|
||||||
private float recognitionConfidence; // 识别可信度
|
|
||||||
private String imagePath; // 用于识别的图片路径
|
|
||||||
|
|
||||||
// 默认构造函数
|
|
||||||
public ProductRecognitionInfo() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 完整构造函数
|
|
||||||
public ProductRecognitionInfo(String productName, String category,
|
|
||||||
String description, float recognitionConfidence,
|
|
||||||
String imagePath) {
|
|
||||||
this.productName = productName;
|
|
||||||
this.category = category;
|
|
||||||
this.description = description;
|
|
||||||
this.recognitionConfidence = recognitionConfidence;
|
|
||||||
this.imagePath = imagePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters and Setters
|
|
||||||
public String getProductName() {
|
|
||||||
return productName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProductName(String productName) {
|
|
||||||
this.productName = productName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCategory() {
|
|
||||||
return category;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCategory(String category) {
|
|
||||||
this.category = category;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescription(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PriceEstimator.EstimatedPrice getEstimatedPrice() {
|
|
||||||
return estimatedPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEstimatedPrice(PriceEstimator.EstimatedPrice estimatedPrice) {
|
|
||||||
this.estimatedPrice = estimatedPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getRecognitionConfidence() {
|
|
||||||
return recognitionConfidence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecognitionConfidence(float recognitionConfidence) {
|
|
||||||
this.recognitionConfidence = recognitionConfidence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getImagePath() {
|
|
||||||
return imagePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setImagePath(String imagePath) {
|
|
||||||
this.imagePath = imagePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取格式化的价格字符串
|
|
||||||
public String getFormattedPrice() {
|
|
||||||
if (estimatedPrice != null) {
|
|
||||||
return "¥" + String.format("%.2f", estimatedPrice.suggestedPrice);
|
|
||||||
}
|
|
||||||
return "--";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取价格建议范围字符串
|
|
||||||
public String getFormattedPriceRange() {
|
|
||||||
if (estimatedPrice != null) {
|
|
||||||
return "¥" + String.format("%.2f", estimatedPrice.minSuggestedPrice) +
|
|
||||||
" - ¥" + String.format("%.2f", estimatedPrice.maxSuggestedPrice);
|
|
||||||
}
|
|
||||||
return "--";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取格式化的可信度百分比
|
|
||||||
public String getFormattedConfidence() {
|
|
||||||
return String.format("%.1f%%", recognitionConfidence * 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否有效(有商品名称和类别)
|
|
||||||
public boolean isValid() {
|
|
||||||
return productName != null && !productName.isEmpty() &&
|
|
||||||
category != null && !category.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 克隆对象
|
|
||||||
public ProductRecognitionInfo clone() {
|
|
||||||
ProductRecognitionInfo clone = new ProductRecognitionInfo();
|
|
||||||
clone.productName = this.productName;
|
|
||||||
clone.category = this.category;
|
|
||||||
clone.description = this.description;
|
|
||||||
clone.recognitionConfidence = this.recognitionConfidence;
|
|
||||||
clone.imagePath = this.imagePath;
|
|
||||||
clone.estimatedPrice = this.estimatedPrice;
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ProductRecognitionInfo{" +
|
|
||||||
"productName='" + productName + '\'' +
|
|
||||||
", category='" + category + '\'' +
|
|
||||||
", confidence=" + recognitionConfidence +
|
|
||||||
", price=" + (estimatedPrice != null ? estimatedPrice.suggestedPrice : "null") +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,189 +0,0 @@
|
|||||||
package com.example.llrisetabbardemo.utils;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.Matrix;
|
|
||||||
import android.media.ExifInterface;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.util.Base64;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class ImageUtils {
|
|
||||||
|
|
||||||
// 最大图片大小 (1MB)
|
|
||||||
private static final int MAX_IMAGE_SIZE = 1024 * 1024;
|
|
||||||
|
|
||||||
// 图片压缩质量
|
|
||||||
private static final int COMPRESS_QUALITY = 80;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 压缩图片文件
|
|
||||||
* @param imagePath 原始图片路径
|
|
||||||
* @return 压缩后的图片路径
|
|
||||||
*/
|
|
||||||
public static String compressImage(String imagePath) {
|
|
||||||
try {
|
|
||||||
// 获取图片旋转角度
|
|
||||||
int rotateAngle = getImageRotateAngle(imagePath);
|
|
||||||
|
|
||||||
// 解码图片,获取原始尺寸
|
|
||||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
|
||||||
options.inJustDecodeBounds = true;
|
|
||||||
BitmapFactory.decodeFile(imagePath, options);
|
|
||||||
|
|
||||||
// 计算采样率,使图片尺寸合理
|
|
||||||
int inSampleSize = calculateInSampleSize(options, 1024, 1024);
|
|
||||||
options.inSampleSize = inSampleSize;
|
|
||||||
options.inJustDecodeBounds = false;
|
|
||||||
|
|
||||||
// 解码并旋转图片
|
|
||||||
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
|
|
||||||
if (rotateAngle != 0) {
|
|
||||||
bitmap = rotateBitmap(bitmap, rotateAngle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 压缩图片到指定大小
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
int quality = COMPRESS_QUALITY;
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
|
|
||||||
|
|
||||||
// 如果压缩后的图片还是太大,继续压缩
|
|
||||||
while (baos.toByteArray().length > MAX_IMAGE_SIZE && quality > 10) {
|
|
||||||
baos.reset();
|
|
||||||
quality -= 10;
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存压缩后的图片
|
|
||||||
String compressedPath = createCompressedImagePath();
|
|
||||||
FileOutputStream fos = new FileOutputStream(compressedPath);
|
|
||||||
fos.write(baos.toByteArray());
|
|
||||||
fos.flush();
|
|
||||||
fos.close();
|
|
||||||
|
|
||||||
bitmap.recycle();
|
|
||||||
return compressedPath;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return imagePath; // 如果压缩失败,返回原始路径
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将图片转换为Base64字符串
|
|
||||||
* @param imagePath 图片路径
|
|
||||||
* @return Base64编码的字符串
|
|
||||||
*/
|
|
||||||
public static String imageToBase64(String imagePath) {
|
|
||||||
try {
|
|
||||||
// 先压缩图片
|
|
||||||
String compressedPath = compressImage(imagePath);
|
|
||||||
|
|
||||||
// 读取压缩后的图片
|
|
||||||
Bitmap bitmap = BitmapFactory.decodeFile(compressedPath);
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, COMPRESS_QUALITY, baos);
|
|
||||||
byte[] imageBytes = baos.toByteArray();
|
|
||||||
|
|
||||||
bitmap.recycle();
|
|
||||||
|
|
||||||
// 转换为Base64
|
|
||||||
return Base64.encodeToString(imageBytes, Base64.DEFAULT);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取图片旋转角度
|
|
||||||
*/
|
|
||||||
private static int getImageRotateAngle(String imagePath) {
|
|
||||||
try {
|
|
||||||
ExifInterface exif = new ExifInterface(imagePath);
|
|
||||||
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
|
||||||
switch (orientation) {
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
|
||||||
return 90;
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
|
||||||
return 180;
|
|
||||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
|
||||||
return 270;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 旋转图片
|
|
||||||
*/
|
|
||||||
private static Bitmap rotateBitmap(Bitmap bitmap, int degrees) {
|
|
||||||
if (degrees != 0 && bitmap != null) {
|
|
||||||
Matrix matrix = new Matrix();
|
|
||||||
matrix.setRotate(degrees, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2);
|
|
||||||
try {
|
|
||||||
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
|
||||||
bitmap.recycle();
|
|
||||||
return rotatedBitmap;
|
|
||||||
} catch (OutOfMemoryError e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算图片采样率
|
|
||||||
*/
|
|
||||||
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
|
|
||||||
final int height = options.outHeight;
|
|
||||||
final int width = options.outWidth;
|
|
||||||
int inSampleSize = 1;
|
|
||||||
|
|
||||||
if (height > reqHeight || width > reqWidth) {
|
|
||||||
final int halfHeight = height / 2;
|
|
||||||
final int halfWidth = width / 2;
|
|
||||||
|
|
||||||
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
|
|
||||||
inSampleSize *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return inSampleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建压缩后的图片保存路径
|
|
||||||
*/
|
|
||||||
private static String createCompressedImagePath() throws IOException {
|
|
||||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
|
||||||
String imageFileName = "COMPRESSED_" + timeStamp + ".jpg";
|
|
||||||
|
|
||||||
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
|
|
||||||
if (!storageDir.exists()) {
|
|
||||||
storageDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
File imageFile = new File(storageDir, imageFileName);
|
|
||||||
if (!imageFile.exists()) {
|
|
||||||
imageFile.createNewFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
return imageFile.getAbsolutePath();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
package com.example.llrisetabbardemo.utils;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.media.MediaMetadataRetriever;
|
|
||||||
import android.os.Environment;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class VideoUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从视频中提取关键帧
|
|
||||||
* @param videoPath 视频路径
|
|
||||||
* @return 提取的关键帧图片路径
|
|
||||||
*/
|
|
||||||
public static String extractKeyFrame(String videoPath) {
|
|
||||||
try {
|
|
||||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
|
||||||
retriever.setDataSource(videoPath);
|
|
||||||
|
|
||||||
// 获取视频时长
|
|
||||||
String durationStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
|
|
||||||
long duration = durationStr != null ? Long.parseLong(durationStr) : 0;
|
|
||||||
|
|
||||||
// 提取视频中间部分的帧作为关键帧
|
|
||||||
long frameTime = duration / 2;
|
|
||||||
Bitmap keyFrame = retriever.getFrameAtTime(frameTime * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
|
|
||||||
|
|
||||||
retriever.release();
|
|
||||||
|
|
||||||
if (keyFrame != null) {
|
|
||||||
// 保存关键帧为图片
|
|
||||||
String framePath = saveBitmapToFile(keyFrame);
|
|
||||||
keyFrame.recycle();
|
|
||||||
return framePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存Bitmap到文件
|
|
||||||
* @param bitmap 位图
|
|
||||||
* @return 保存的文件路径
|
|
||||||
*/
|
|
||||||
private static String saveBitmapToFile(Bitmap bitmap) {
|
|
||||||
try {
|
|
||||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
|
||||||
String imageFileName = "VIDEO_FRAME_" + timeStamp + ".jpg";
|
|
||||||
|
|
||||||
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
|
|
||||||
if (!storageDir.exists()) {
|
|
||||||
storageDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
File imageFile = new File(storageDir, imageFileName);
|
|
||||||
FileOutputStream fos = new FileOutputStream(imageFile);
|
|
||||||
|
|
||||||
// 压缩并保存图片
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
|
|
||||||
fos.flush();
|
|
||||||
fos.close();
|
|
||||||
|
|
||||||
return imageFile.getAbsolutePath();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查文件是否为视频文件
|
|
||||||
* @param filePath 文件路径
|
|
||||||
* @return 是否为视频
|
|
||||||
*/
|
|
||||||
public static boolean isVideoFile(String filePath) {
|
|
||||||
if (filePath == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String extension = getFileExtension(filePath).toLowerCase();
|
|
||||||
return extension.equals("mp4") ||
|
|
||||||
extension.equals("3gp") ||
|
|
||||||
extension.equals("mov") ||
|
|
||||||
extension.equals("avi") ||
|
|
||||||
extension.equals("mkv");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件扩展名
|
|
||||||
* @param filePath 文件路径
|
|
||||||
* @return 扩展名
|
|
||||||
*/
|
|
||||||
private static String getFileExtension(String filePath) {
|
|
||||||
int lastDotIndex = filePath.lastIndexOf(".");
|
|
||||||
if (lastDotIndex > 0 && lastDotIndex < filePath.length() - 1) {
|
|
||||||
return filePath.substring(lastDotIndex + 1);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,158 +0,0 @@
|
|||||||
package com.startsmake.llrisetabbardemo.activity;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
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.AddressAdapter;
|
|
||||||
import com.startsmake.llrisetabbardemo.model.Address;
|
|
||||||
import com.startsmake.llrisetabbardemo.service.AddressService;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AddressListActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
private RecyclerView rvAddresses;
|
|
||||||
private Button btnAddAddress;
|
|
||||||
private AddressAdapter addressAdapter;
|
|
||||||
private AddressService addressService;
|
|
||||||
private boolean isFromOrder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_address_list);
|
|
||||||
|
|
||||||
// 检查是否来自订单页面
|
|
||||||
isFromOrder = getIntent().getBooleanExtra("from_order", false);
|
|
||||||
|
|
||||||
initViews();
|
|
||||||
initServices();
|
|
||||||
loadAddresses();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initViews() {
|
|
||||||
rvAddresses = findViewById(R.id.rv_addresses);
|
|
||||||
btnAddAddress = findViewById(R.id.btn_add_address);
|
|
||||||
|
|
||||||
// 设置RecyclerView
|
|
||||||
rvAddresses.setLayoutManager(new LinearLayoutManager(this));
|
|
||||||
addressAdapter = new AddressAdapter(this, null, new AddressAdapter.OnAddressClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onSelect(Address address) {
|
|
||||||
// 如果从订单页面跳转过来,选择地址后返回
|
|
||||||
if (isFromOrder) {
|
|
||||||
Intent resultIntent = new Intent();
|
|
||||||
resultIntent.putExtra("selected_address", address);
|
|
||||||
setResult(RESULT_OK, resultIntent);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEdit(Address address) {
|
|
||||||
// 编辑地址
|
|
||||||
Intent intent = new Intent(AddressListActivity.this, EditAddressActivity.class);
|
|
||||||
intent.putExtra("address", address);
|
|
||||||
startActivityForResult(intent, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDelete(Address address) {
|
|
||||||
// 删除地址
|
|
||||||
deleteAddress(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSetDefault(Address address) {
|
|
||||||
// 设置默认地址
|
|
||||||
setDefaultAddress(address);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
rvAddresses.setAdapter(addressAdapter);
|
|
||||||
|
|
||||||
// 添加新地址按钮
|
|
||||||
btnAddAddress.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
Intent intent = new Intent(AddressListActivity.this, EditAddressActivity.class);
|
|
||||||
startActivityForResult(intent, 100);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 返回按钮
|
|
||||||
findViewById(R.id.tv_back).setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
onBackPressed();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initServices() {
|
|
||||||
addressService = AddressService.getInstance(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadAddresses() {
|
|
||||||
addressService.getUserAddresses(new AddressService.AddressCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(List<Address> addresses) {
|
|
||||||
addressAdapter.setAddresses(addresses);
|
|
||||||
addressAdapter.notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(String message) {
|
|
||||||
Toast.makeText(AddressListActivity.this, message, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteAddress(final Address address) {
|
|
||||||
addressService.deleteAddress(address.getId(), new AddressService.OperationCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess() {
|
|
||||||
Toast.makeText(AddressListActivity.this, "地址删除成功", Toast.LENGTH_SHORT).show();
|
|
||||||
// 重新加载地址列表
|
|
||||||
loadAddresses();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(String message) {
|
|
||||||
Toast.makeText(AddressListActivity.this, message, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setDefaultAddress(final Address address) {
|
|
||||||
addressService.setDefaultAddress(address.getId(), new AddressService.OperationCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess() {
|
|
||||||
Toast.makeText(AddressListActivity.this, "设置默认地址成功", Toast.LENGTH_SHORT).show();
|
|
||||||
// 重新加载地址列表
|
|
||||||
loadAddresses();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(String message) {
|
|
||||||
Toast.makeText(AddressListActivity.this, message, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
if (requestCode == 100 && resultCode == RESULT_OK) {
|
|
||||||
// 地址添加或编辑成功,重新加载列表
|
|
||||||
loadAddresses();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
package com.startsmake.llrisetabbardemo.activity;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
|
|
||||||
import com.startsmake.llrisetabbardemo.R;
|
|
||||||
import com.startsmake.llrisetabbardemo.model.Address;
|
|
||||||
import com.startsmake.llrisetabbardemo.service.AddressService;
|
|
||||||
|
|
||||||
public class EditAddressActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
private EditText etName;
|
|
||||||
private EditText etPhone;
|
|
||||||
private EditText etProvince;
|
|
||||||
private EditText etCity;
|
|
||||||
private EditText etDistrict;
|
|
||||||
private EditText etDetailAddress;
|
|
||||||
private CheckBox cbDefault;
|
|
||||||
private Button btnSave;
|
|
||||||
|
|
||||||
private Address address;
|
|
||||||
private AddressService addressService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_edit_address);
|
|
||||||
|
|
||||||
initViews();
|
|
||||||
initServices();
|
|
||||||
initData();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initViews() {
|
|
||||||
etName = findViewById(R.id.et_name);
|
|
||||||
etPhone = findViewById(R.id.et_phone);
|
|
||||||
etProvince = findViewById(R.id.et_province);
|
|
||||||
etCity = findViewById(R.id.et_city);
|
|
||||||
etDistrict = findViewById(R.id.et_district);
|
|
||||||
etDetailAddress = findViewById(R.id.et_detail_address);
|
|
||||||
cbDefault = findViewById(R.id.cb_default);
|
|
||||||
btnSave = findViewById(R.id.btn_save);
|
|
||||||
|
|
||||||
btnSave.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
saveAddress();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 返回按钮
|
|
||||||
findViewById(R.id.tv_back).setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
onBackPressed();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initServices() {
|
|
||||||
addressService = AddressService.getInstance(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initData() {
|
|
||||||
// 检查是否是编辑模式
|
|
||||||
address = getIntent().getParcelableExtra("address");
|
|
||||||
if (address != null) {
|
|
||||||
// 编辑模式
|
|
||||||
etName.setText(address.getName());
|
|
||||||
etPhone.setText(address.getPhone());
|
|
||||||
etProvince.setText(address.getProvince());
|
|
||||||
etCity.setText(address.getCity());
|
|
||||||
etDistrict.setText(address.getDistrict());
|
|
||||||
etDetailAddress.setText(address.getDetailAddress());
|
|
||||||
cbDefault.setChecked(address.isDefault());
|
|
||||||
} else {
|
|
||||||
// 新增模式,默认设为默认地址
|
|
||||||
cbDefault.setChecked(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveAddress() {
|
|
||||||
// 验证输入
|
|
||||||
String name = etName.getText().toString().trim();
|
|
||||||
String phone = etPhone.getText().toString().trim();
|
|
||||||
String province = etProvince.getText().toString().trim();
|
|
||||||
String city = etCity.getText().toString().trim();
|
|
||||||
String district = etDistrict.getText().toString().trim();
|
|
||||||
String detailAddress = etDetailAddress.getText().toString().trim();
|
|
||||||
boolean isDefault = cbDefault.isChecked();
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(name)) {
|
|
||||||
Toast.makeText(this, "请输入收件人姓名", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(phone)) {
|
|
||||||
Toast.makeText(this, "请输入联系电话", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 简单的手机号验证
|
|
||||||
if (!phone.matches("^1[3-9]\\d{9}$")) {
|
|
||||||
Toast.makeText(this, "请输入正确的手机号码", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(province)) {
|
|
||||||
Toast.makeText(this, "请输入省份", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(city)) {
|
|
||||||
Toast.makeText(this, "请输入城市", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(district)) {
|
|
||||||
Toast.makeText(this, "请输入区县", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(detailAddress)) {
|
|
||||||
Toast.makeText(this, "请输入详细地址", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建或更新地址对象
|
|
||||||
if (address == null) {
|
|
||||||
// 新增地址
|
|
||||||
address = new Address();
|
|
||||||
}
|
|
||||||
|
|
||||||
address.setName(name);
|
|
||||||
address.setPhone(phone);
|
|
||||||
address.setProvince(province);
|
|
||||||
address.setCity(city);
|
|
||||||
address.setDistrict(district);
|
|
||||||
address.setDetailAddress(detailAddress);
|
|
||||||
address.setDefault(isDefault);
|
|
||||||
|
|
||||||
// 保存地址
|
|
||||||
if (TextUtils.isEmpty(address.getId())) {
|
|
||||||
// 新增
|
|
||||||
addressService.addAddress(address, new AddressService.SingleAddressCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Address newAddress) {
|
|
||||||
Toast.makeText(EditAddressActivity.this, "地址添加成功", Toast.LENGTH_SHORT).show();
|
|
||||||
setResult(RESULT_OK);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(String message) {
|
|
||||||
Toast.makeText(EditAddressActivity.this, message, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 更新
|
|
||||||
addressService.updateAddress(address, new AddressService.SingleAddressCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Address updatedAddress) {
|
|
||||||
Toast.makeText(EditAddressActivity.this, "地址更新成功", Toast.LENGTH_SHORT).show();
|
|
||||||
setResult(RESULT_OK);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(String message) {
|
|
||||||
Toast.makeText(EditAddressActivity.this, message, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
package com.startsmake.llrisetabbardemo.activity;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.startsmake.llrisetabbardemo.R;
|
|
||||||
import com.startsmake.llrisetabbardemo.adapter.ImagePreviewAdapter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ImagePreviewActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
public static final String EXTRA_IMAGE_URLS = "image_urls";
|
|
||||||
public static final String EXTRA_CURRENT_POSITION = "current_position";
|
|
||||||
|
|
||||||
private ViewPager2 viewPager;
|
|
||||||
private TextView tvPosition;
|
|
||||||
private ImageView ivClose;
|
|
||||||
private List<String> imageUrls;
|
|
||||||
private int currentPosition;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
// 全屏显示,隐藏状态栏
|
|
||||||
getWindow().getDecorView().setSystemUiVisibility(
|
|
||||||
View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
|
||||||
);
|
|
||||||
setContentView(R.layout.activity_image_preview);
|
|
||||||
|
|
||||||
// 获取传递的图片URL列表和当前位置
|
|
||||||
if (getIntent() != null) {
|
|
||||||
imageUrls = getIntent().getStringArrayListExtra(EXTRA_IMAGE_URLS);
|
|
||||||
currentPosition = getIntent().getIntExtra(EXTRA_CURRENT_POSITION, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化视图
|
|
||||||
viewPager = findViewById(R.id.view_pager_preview);
|
|
||||||
tvPosition = findViewById(R.id.tv_position);
|
|
||||||
ivClose = findViewById(R.id.iv_close);
|
|
||||||
|
|
||||||
// 设置适配器
|
|
||||||
ImagePreviewAdapter adapter = new ImagePreviewAdapter(imageUrls);
|
|
||||||
viewPager.setAdapter(adapter);
|
|
||||||
viewPager.setCurrentItem(currentPosition, false);
|
|
||||||
|
|
||||||
// 更新位置显示
|
|
||||||
updatePositionDisplay(currentPosition);
|
|
||||||
|
|
||||||
// 设置ViewPager页面变化监听
|
|
||||||
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
|
||||||
@Override
|
|
||||||
public void onPageSelected(int position) {
|
|
||||||
super.onPageSelected(position);
|
|
||||||
currentPosition = position;
|
|
||||||
updatePositionDisplay(position);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 设置关闭按钮点击事件
|
|
||||||
ivClose.setOnClickListener(v -> finish());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePositionDisplay(int position) {
|
|
||||||
if (imageUrls != null && !imageUrls.isEmpty()) {
|
|
||||||
tvPosition.setText((position + 1) + "/" + imageUrls.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,271 +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);
|
|
||||||
|
|
||||||
// 确保使用带Context参数的getInstance方法
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册用户 - 使用后端API
|
|
||||||
String username = "用户_" + phone.substring(phone.length() - 4); // 生成默认用户名
|
|
||||||
userManager.registerUserWithApi(phone, password, username, new UserManager.AuthCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(User user) {
|
|
||||||
Toast.makeText(RegisterActivity.this, "注册成功!", Toast.LENGTH_SHORT).show();
|
|
||||||
// 跳转到主页面
|
|
||||||
Intent intent = new Intent(RegisterActivity.this, MainActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(String message) {
|
|
||||||
Toast.makeText(RegisterActivity.this, "注册失败: " + message, 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,127 +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.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.startsmake.llrisetabbardemo.R;
|
|
||||||
import com.startsmake.llrisetabbardemo.model.Address;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AddressAdapter extends RecyclerView.Adapter<AddressAdapter.AddressViewHolder> {
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
private List<Address> addresses;
|
|
||||||
private OnAddressClickListener listener;
|
|
||||||
|
|
||||||
public interface OnAddressClickListener {
|
|
||||||
void onSelect(Address address);
|
|
||||||
void onEdit(Address address);
|
|
||||||
void onDelete(Address address);
|
|
||||||
void onSetDefault(Address address);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AddressAdapter(Context context, List<Address> addresses, OnAddressClickListener listener) {
|
|
||||||
this.context = context;
|
|
||||||
this.addresses = addresses != null ? addresses : new ArrayList<>();
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddresses(List<Address> addresses) {
|
|
||||||
this.addresses = addresses != null ? addresses : new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public AddressViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
View view = LayoutInflater.from(context).inflate(R.layout.item_address, parent, false);
|
|
||||||
return new AddressViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull AddressViewHolder holder, int position) {
|
|
||||||
final Address address = addresses.get(position);
|
|
||||||
|
|
||||||
// 显示地址信息
|
|
||||||
holder.tvName.setText(address.getName());
|
|
||||||
holder.tvPhone.setText(address.getPhone());
|
|
||||||
holder.tvAddress.setText(address.getAddressWithContact());
|
|
||||||
|
|
||||||
// 显示默认标签
|
|
||||||
if (address.isDefault()) {
|
|
||||||
holder.tvDefault.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
holder.tvDefault.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置点击事件
|
|
||||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onSelect(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
holder.btnEdit.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onEdit(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
holder.btnDelete.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onDelete(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
holder.btnSetDefault.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onSetDefault(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return addresses.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
static class AddressViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
TextView tvName;
|
|
||||||
TextView tvPhone;
|
|
||||||
TextView tvAddress;
|
|
||||||
TextView tvDefault;
|
|
||||||
TextView btnEdit;
|
|
||||||
TextView btnDelete;
|
|
||||||
TextView btnSetDefault;
|
|
||||||
|
|
||||||
AddressViewHolder(@NonNull View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
tvName = itemView.findViewById(R.id.tv_name);
|
|
||||||
tvPhone = itemView.findViewById(R.id.tv_phone);
|
|
||||||
tvAddress = itemView.findViewById(R.id.tv_address);
|
|
||||||
tvDefault = itemView.findViewById(R.id.tv_default);
|
|
||||||
btnEdit = itemView.findViewById(R.id.btn_edit);
|
|
||||||
btnDelete = itemView.findViewById(R.id.btn_delete);
|
|
||||||
btnSetDefault = itemView.findViewById(R.id.btn_set_default);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
package com.startsmake.llrisetabbardemo.adapter;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import com.startsmake.llrisetabbardemo.R;
|
|
||||||
import com.startsmake.llrisetabbardemo.activity.ChatActivity;
|
|
||||||
import com.startsmake.llrisetabbardemo.model.Conversation;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapter.ViewHolder> {
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
private List<Conversation> conversationList;
|
|
||||||
|
|
||||||
public ConversationAdapter(Context context, List<Conversation> conversationList) {
|
|
||||||
this.context = context;
|
|
||||||
this.conversationList = conversationList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
View view = LayoutInflater.from(context).inflate(R.layout.item_conversation, parent, false);
|
|
||||||
return new ViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
|
||||||
Conversation conversation = conversationList.get(position);
|
|
||||||
holder.tvUsername.setText(conversation.getUsername());
|
|
||||||
holder.tvLastMessage.setText(conversation.getLastMessage());
|
|
||||||
holder.tvTime.setText(conversation.getTime());
|
|
||||||
|
|
||||||
// 设置未读消息数量
|
|
||||||
if (conversation.getUnreadCount() > 0) {
|
|
||||||
holder.tvUnreadCount.setVisibility(View.VISIBLE);
|
|
||||||
holder.tvUnreadCount.setText(String.valueOf(conversation.getUnreadCount()));
|
|
||||||
} else {
|
|
||||||
holder.tvUnreadCount.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示测试账号标识
|
|
||||||
if (conversation.getId().equals("13800138001") ||
|
|
||||||
conversation.getId().equals("13800138002") ||
|
|
||||||
conversation.getId().equals("13800138003")) {
|
|
||||||
holder.ivTestAccount.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
holder.ivTestAccount.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置点击事件
|
|
||||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
// 跳转到聊天页面
|
|
||||||
Intent intent = new Intent(context, ChatActivity.class);
|
|
||||||
intent.putExtra("chat_title", conversation.getUsername());
|
|
||||||
intent.putExtra("user_id", conversation.getId());
|
|
||||||
context.startActivity(intent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return conversationList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
TextView tvUsername;
|
|
||||||
TextView tvLastMessage;
|
|
||||||
TextView tvTime;
|
|
||||||
TextView tvUnreadCount;
|
|
||||||
ImageView ivTestAccount;
|
|
||||||
|
|
||||||
public ViewHolder(@NonNull View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
tvUsername = itemView.findViewById(R.id.tvUsername);
|
|
||||||
tvLastMessage = itemView.findViewById(R.id.tvLastMessage);
|
|
||||||
tvTime = itemView.findViewById(R.id.tvTime);
|
|
||||||
tvUnreadCount = itemView.findViewById(R.id.tvUnreadCount);
|
|
||||||
ivTestAccount = itemView.findViewById(R.id.ivTestAccount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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,89 +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.Shop;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ShopAdapter extends RecyclerView.Adapter<ShopAdapter.ViewHolder> {
|
|
||||||
|
|
||||||
private List<Shop> shopList;
|
|
||||||
private OnItemClickListener onItemClickListener;
|
|
||||||
|
|
||||||
// 定义点击监听接口
|
|
||||||
public interface OnItemClickListener {
|
|
||||||
void onItemClick(Shop shop, int position);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构造方法
|
|
||||||
public ShopAdapter(List<Shop> shopList) {
|
|
||||||
this.shopList = shopList;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置点击监听器(只有一个方法)
|
|
||||||
public void setOnItemClickListener(OnItemClickListener listener) {
|
|
||||||
this.onItemClickListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
|
||||||
.inflate(R.layout.item_shop, parent, false);
|
|
||||||
return new ViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
|
||||||
Shop shop = shopList.get(position);
|
|
||||||
holder.textName.setText(shop.getName());
|
|
||||||
holder.textDescription.setText(shop.getDescription());
|
|
||||||
|
|
||||||
if (shop.getImage() != null) {
|
|
||||||
holder.imageView.setImageBitmap(shop.getImage());
|
|
||||||
} else {
|
|
||||||
// 使用自定义的默认图片
|
|
||||||
holder.imageView.setImageResource(R.drawable.ic_about);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加点击事件
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
|
||||||
if (onItemClickListener != null) {
|
|
||||||
onItemClickListener.onItemClick(shop, position);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return shopList != null ? shopList.size() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新数据方法
|
|
||||||
public void updateData(List<Shop> newShopList) {
|
|
||||||
this.shopList = newShopList;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
public ImageView imageView;
|
|
||||||
public TextView textName;
|
|
||||||
public TextView textDescription;
|
|
||||||
|
|
||||||
public ViewHolder(View view) {
|
|
||||||
super(view);
|
|
||||||
imageView = view.findViewById(R.id.imgShop);
|
|
||||||
textName = view.findViewById(R.id.txtShopName);
|
|
||||||
textDescription = view.findViewById(R.id.txtShopDescription);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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 {
|
|
||||||
public static final String BASE_URL = "http://10.0.2.2:8080/api/";
|
|
||||||
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,214 +0,0 @@
|
|||||||
package com.startsmake.llrisetabbardemo.api;
|
|
||||||
|
|
||||||
import com.startsmake.llrisetabbardemo.api.response.BaseResponse;
|
|
||||||
import com.startsmake.llrisetabbardemo.api.response.ChatMessageResponse;
|
|
||||||
import com.startsmake.llrisetabbardemo.api.response.ProductResponse;
|
|
||||||
import com.startsmake.llrisetabbardemo.api.response.UserResponse;
|
|
||||||
import com.startsmake.llrisetabbardemo.model.Address;
|
|
||||||
import com.startsmake.llrisetabbardemo.model.Conversation;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import retrofit2.http.Body;
|
|
||||||
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.http.Field;
|
|
||||||
import retrofit2.http.FormUrlEncoded;
|
|
||||||
import retrofit2.http.GET;
|
|
||||||
import retrofit2.http.Header;
|
|
||||||
import retrofit2.http.DELETE;
|
|
||||||
import retrofit2.http.GET;
|
|
||||||
import retrofit2.http.POST;
|
|
||||||
import retrofit2.http.PUT;
|
|
||||||
import retrofit2.http.Path;
|
|
||||||
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);
|
|
||||||
|
|
||||||
// 获取用户信息
|
|
||||||
@GET("api/user/info")
|
|
||||||
Call<UserResponse> getUserInfo(@Header("Authorization") String token);
|
|
||||||
|
|
||||||
// 更新用户信息
|
|
||||||
@POST("/api/users/update")
|
|
||||||
Call<BaseResponse<UserResponse.UserInfo>> updateUserInfo(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Body Map<String, Object> userInfo
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取会话列表
|
|
||||||
@GET("/api/conversations")
|
|
||||||
Call<BaseResponse<List<Conversation>>> getUserConversations(
|
|
||||||
@Header("Authorization") String token
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取会话消息
|
|
||||||
@GET("/api/conversations/messages")
|
|
||||||
Call<BaseResponse<List<ChatMessageResponse>>> getConversationMessages(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Query("userId") String userId,
|
|
||||||
@Query("targetId") String targetId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 发送消息
|
|
||||||
@POST("/api/messages")
|
|
||||||
Call<BaseResponse<ChatMessageResponse>> sendMessage(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Query("targetId") String targetId,
|
|
||||||
@Query("content") String content,
|
|
||||||
@Query("itemId") String itemId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 标记消息已读
|
|
||||||
@PUT("/api/messages/read")
|
|
||||||
Call<BaseResponse> markMessagesAsRead(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Query("userId") String userId,
|
|
||||||
@Query("targetId") String targetId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 订单相关接口
|
|
||||||
|
|
||||||
// 创建订单
|
|
||||||
@POST("/api/orders")
|
|
||||||
Call<BaseResponse<Map<String, Object>>> createOrder(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Body Map<String, Object> orderData
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取订单详情
|
|
||||||
@GET("/api/orders/{id}")
|
|
||||||
Call<BaseResponse<Map<String, Object>>> getOrderDetail(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("id") String orderId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 通过订单号获取订单
|
|
||||||
@GET("/api/orders/order-no/{orderNo}")
|
|
||||||
Call<BaseResponse<Map<String, Object>>> getOrderByOrderNo(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("orderNo") String orderNo
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取买家订单列表
|
|
||||||
@GET("/api/orders/buyer/{buyerId}")
|
|
||||||
Call<BaseResponse<List<Map<String, Object>>>> getBuyerOrders(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("buyerId") String buyerId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取卖家订单列表
|
|
||||||
@GET("/api/orders/seller/{sellerId}")
|
|
||||||
Call<BaseResponse<List<Map<String, Object>>>> getSellerOrders(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("sellerId") String sellerId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 更新订单状态
|
|
||||||
@PUT("/api/orders/{id}/status")
|
|
||||||
Call<BaseResponse<Map<String, Object>>> updateOrderStatus(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("id") String orderId,
|
|
||||||
@Body Map<String, Object> statusData
|
|
||||||
);
|
|
||||||
|
|
||||||
// 更新订单支付信息
|
|
||||||
@PUT("/api/orders/{id}/payment")
|
|
||||||
Call<BaseResponse<Map<String, Object>>> updateOrderPayment(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("id") String orderId,
|
|
||||||
@Body Map<String, Object> paymentData
|
|
||||||
);
|
|
||||||
|
|
||||||
// 取消订单
|
|
||||||
@PUT("/api/orders/{id}/cancel")
|
|
||||||
Call<BaseResponse> cancelOrder(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("id") String orderId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取买家指定状态的订单
|
|
||||||
@GET("/api/orders/buyer/{buyerId}/status/{status}")
|
|
||||||
Call<BaseResponse<List<Map<String, Object>>>> getBuyerOrdersByStatus(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("buyerId") String buyerId,
|
|
||||||
@Path("status") String status
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取卖家指定状态的订单
|
|
||||||
@GET("/api/orders/seller/{sellerId}/status/{status}")
|
|
||||||
Call<BaseResponse<List<Map<String, Object>>>> getSellerOrdersByStatus(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("sellerId") String sellerId,
|
|
||||||
@Path("status") String status
|
|
||||||
);
|
|
||||||
|
|
||||||
// 地址管理相关接口
|
|
||||||
|
|
||||||
// 获取用户地址列表
|
|
||||||
@GET("/api/addresses")
|
|
||||||
Call<BaseResponse<List<Address>>> getUserAddresses(
|
|
||||||
@Header("Authorization") String token
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取用户默认地址
|
|
||||||
@GET("/api/addresses/default")
|
|
||||||
Call<BaseResponse<Address>> getDefaultAddress(
|
|
||||||
@Header("Authorization") String token
|
|
||||||
);
|
|
||||||
|
|
||||||
// 添加新地址
|
|
||||||
@POST("/api/addresses")
|
|
||||||
Call<BaseResponse<Address>> addAddress(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Body Address address
|
|
||||||
);
|
|
||||||
|
|
||||||
// 更新地址
|
|
||||||
@PUT("/api/addresses/{id}")
|
|
||||||
Call<BaseResponse<Address>> updateAddress(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("id") String addressId,
|
|
||||||
@Body Address address
|
|
||||||
);
|
|
||||||
|
|
||||||
// 删除地址
|
|
||||||
@DELETE("/api/addresses/{id}")
|
|
||||||
Call<BaseResponse> deleteAddress(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("id") String addressId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 设置默认地址
|
|
||||||
@PUT("/api/addresses/{id}/default")
|
|
||||||
Call<BaseResponse> setDefaultAddress(
|
|
||||||
@Header("Authorization") String token,
|
|
||||||
@Path("id") String addressId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
package com.startsmake.llrisetabbardemo.api;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
public class TestNetworkConnection extends AsyncTask<Void, Void, String> {
|
|
||||||
|
|
||||||
private Context context;
|
|
||||||
|
|
||||||
public TestNetworkConnection(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String doInBackground(Void... voids) {
|
|
||||||
String result = "";
|
|
||||||
HttpURLConnection urlConnection = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 测试服务器地址
|
|
||||||
URL url = new URL(ApiClient.BASE_URL);
|
|
||||||
urlConnection = (HttpURLConnection) url.openConnection();
|
|
||||||
urlConnection.setConnectTimeout(10000); // 10秒连接超时
|
|
||||||
urlConnection.setReadTimeout(10000); // 10秒读取超时
|
|
||||||
urlConnection.setRequestMethod("GET");
|
|
||||||
|
|
||||||
int responseCode = urlConnection.getResponseCode();
|
|
||||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
|
||||||
// 读取响应
|
|
||||||
InputStream inputStream = urlConnection.getInputStream();
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
String line;
|
|
||||||
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
stringBuilder.append(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = stringBuilder.toString();
|
|
||||||
reader.close();
|
|
||||||
inputStream.close();
|
|
||||||
} else {
|
|
||||||
result = "连接失败,响应码: " + responseCode;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
result = "连接异常: " + e.getMessage();
|
|
||||||
} finally {
|
|
||||||
if (urlConnection != null) {
|
|
||||||
urlConnection.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(String result) {
|
|
||||||
super.onPostExecute(result);
|
|
||||||
Toast.makeText(context, "网络连接测试结果: " + result, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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,105 +0,0 @@
|
|||||||
package com.startsmake.llrisetabbardemo.api.response;
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
|
|
||||||
public class ChatMessageResponse {
|
|
||||||
@SerializedName("id")
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
@SerializedName("senderId")
|
|
||||||
private String senderId;
|
|
||||||
|
|
||||||
@SerializedName("receiverId")
|
|
||||||
private String receiverId;
|
|
||||||
|
|
||||||
@SerializedName("content")
|
|
||||||
private String content;
|
|
||||||
|
|
||||||
@SerializedName("time")
|
|
||||||
private String time;
|
|
||||||
|
|
||||||
@SerializedName("read")
|
|
||||||
private boolean read;
|
|
||||||
|
|
||||||
@SerializedName("type")
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
@SerializedName("senderName")
|
|
||||||
private String senderName;
|
|
||||||
|
|
||||||
@SerializedName("receiverName")
|
|
||||||
private String receiverName;
|
|
||||||
|
|
||||||
// Getters and Setters
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSenderId() {
|
|
||||||
return senderId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSenderId(String senderId) {
|
|
||||||
this.senderId = senderId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getReceiverId() {
|
|
||||||
return receiverId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setReceiverId(String receiverId) {
|
|
||||||
this.receiverId = receiverId;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 isRead() {
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRead(boolean read) {
|
|
||||||
this.read = read;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setType(String type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSenderName() {
|
|
||||||
return senderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSenderName(String senderName) {
|
|
||||||
this.senderName = senderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getReceiverName() {
|
|
||||||
return receiverName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setReceiverName(String receiverName) {
|
|
||||||
this.receiverName = receiverName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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,140 +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;
|
|
||||||
|
|
||||||
@SerializedName("avatar")
|
|
||||||
private String avatar;
|
|
||||||
|
|
||||||
@SerializedName("bio")
|
|
||||||
private String bio;
|
|
||||||
|
|
||||||
@SerializedName("creditScore")
|
|
||||||
private String creditScore;
|
|
||||||
|
|
||||||
@SerializedName("memberLevel")
|
|
||||||
private String memberLevel;
|
|
||||||
|
|
||||||
@SerializedName("wantCount")
|
|
||||||
private Integer wantCount;
|
|
||||||
|
|
||||||
@SerializedName("sellingCount")
|
|
||||||
private Integer sellingCount;
|
|
||||||
|
|
||||||
@SerializedName("soldCount")
|
|
||||||
private Integer soldCount;
|
|
||||||
|
|
||||||
@SerializedName("savedMoney")
|
|
||||||
private String savedMoney;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAvatar() {
|
|
||||||
return avatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAvatar(String avatar) {
|
|
||||||
this.avatar = avatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBio() {
|
|
||||||
return bio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBio(String bio) {
|
|
||||||
this.bio = bio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCreditScore() {
|
|
||||||
return creditScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreditScore(String creditScore) {
|
|
||||||
this.creditScore = creditScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMemberLevel() {
|
|
||||||
return memberLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMemberLevel(String memberLevel) {
|
|
||||||
this.memberLevel = memberLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getWantCount() {
|
|
||||||
return wantCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWantCount(Integer wantCount) {
|
|
||||||
this.wantCount = wantCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getSellingCount() {
|
|
||||||
return sellingCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSellingCount(Integer sellingCount) {
|
|
||||||
this.sellingCount = sellingCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getSoldCount() {
|
|
||||||
return soldCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSoldCount(Integer soldCount) {
|
|
||||||
this.soldCount = soldCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSavedMoney() {
|
|
||||||
return savedMoney;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSavedMoney(String savedMoney) {
|
|
||||||
this.savedMoney = savedMoney;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
package com.startsmake.llrisetabbardemo.decoration;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.view.View;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
public class RoadItemDecoration extends RecyclerView.ItemDecoration {
|
|
||||||
|
|
||||||
private Paint roadPaint;
|
|
||||||
private int roadWidth;
|
|
||||||
|
|
||||||
public RoadItemDecoration(Context context) {
|
|
||||||
roadPaint = new Paint();
|
|
||||||
roadPaint.setColor(Color.GRAY);
|
|
||||||
roadPaint.setStyle(Paint.Style.FILL);
|
|
||||||
roadWidth = dpToPx(context, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
|
|
||||||
@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
|
||||||
int position = parent.getChildAdapterPosition(view);
|
|
||||||
int column = position % 2;
|
|
||||||
|
|
||||||
// 设置道路间距
|
|
||||||
if (column == 0) {
|
|
||||||
outRect.right = roadWidth / 2;
|
|
||||||
} else {
|
|
||||||
outRect.left = roadWidth / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 行间道路
|
|
||||||
if (position >= 2) {
|
|
||||||
outRect.top = roadWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int dpToPx(Context context, int dp) {
|
|
||||||
float density = context.getResources().getDisplayMetrics().density;
|
|
||||||
return Math.round(dp * density);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,75 +1,24 @@
|
|||||||
package com.startsmake.llrisetabbardemo.fragment;
|
package com.startsmake.llrisetabbardemo.fragment;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.app.Fragment;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
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.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 {
|
public class MessageFragment extends Fragment {
|
||||||
|
|
||||||
private RecyclerView rvMessageList;
|
|
||||||
private MessageAdapter messageAdapter;
|
|
||||||
private List<MessageItem> messageList;
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_message, container, false);
|
return 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("测试账号1", "这是测试账号1的消息", "刚刚", 0, false));
|
|
||||||
messageList.add(new MessageItem("测试账号2", "这是测试账号2的消息", "1小时前", 1, false));
|
|
||||||
messageList.add(new MessageItem("测试账号3", "这是测试账号3的消息", "昨天", 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());
|
|
||||||
|
|
||||||
// 根据标题设置对应的用户ID
|
|
||||||
String userId = "";
|
|
||||||
if (item.getTitle().equals("测试账号1")) {
|
|
||||||
userId = "13800138001";
|
|
||||||
} else if (item.getTitle().equals("测试账号2")) {
|
|
||||||
userId = "13800138002";
|
|
||||||
} else if (item.getTitle().equals("测试账号3")) {
|
|
||||||
userId = "13800138003";
|
|
||||||
}
|
|
||||||
|
|
||||||
intent.putExtra("chat_user_id", userId);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||