diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/activity/ChatActivity.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/activity/ChatActivity.java new file mode 100644 index 0000000..a7174ee --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/activity/ChatActivity.java @@ -0,0 +1,142 @@ +package com.startsmake.llrisetabbardemo.activity; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import com.startsmake.llrisetabbardemo.R; +import com.startsmake.llrisetabbardemo.adapter.ChatMessageAdapter; +import com.startsmake.llrisetabbardemo.model.ChatMessage; +import java.util.ArrayList; +import java.util.List; + +public class ChatActivity extends AppCompatActivity { + + private TextView tvTitle; + private ImageView ivBack; + private RecyclerView rvChatMessages; + private EditText etMessage; + private ImageButton btnSend; + + private ChatMessageAdapter chatAdapter; + private List messageList; + private String chatTitle; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_chat); + + // 获取传递过来的聊天标题 + chatTitle = getIntent().getStringExtra("chat_title"); + if (chatTitle == null) { + chatTitle = "聊天"; + } + + initView(); + initData(); + setupClickListeners(); + } + + private void initView() { + tvTitle = findViewById(R.id.tvTitle); + ivBack = findViewById(R.id.ivBack); + rvChatMessages = findViewById(R.id.rvChatMessages); + etMessage = findViewById(R.id.etMessage); + btnSend = findViewById(R.id.btnSend); + + tvTitle.setText(chatTitle); + } + + private void initData() { + messageList = new ArrayList<>(); + + // 添加一些初始消息 + if ("通知消息".equals(chatTitle)) { + messageList.add(new ChatMessage("系统", "红包到账提醒", "10:30", false)); + messageList.add(new ChatMessage("我", "收到了,谢谢!", "10:31", true)); + } else if ("刑事组之虎".equals(chatTitle)) { + messageList.add(new ChatMessage("刑事组之虎", "快给ta一个评价吧~", "04-19 14:20", false)); + messageList.add(new ChatMessage("我", "已经评价了,商品很不错!", "04-19 14:25", true)); + } else { + messageList.add(new ChatMessage(chatTitle, "你好!", "刚刚", false)); + } + + chatAdapter = new ChatMessageAdapter(this, messageList); + rvChatMessages.setLayoutManager(new LinearLayoutManager(this)); + rvChatMessages.setAdapter(chatAdapter); + + // 滚动到底部 + rvChatMessages.scrollToPosition(messageList.size() - 1); + } + + private void setupClickListeners() { + // 返回按钮 + ivBack.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + // 发送按钮 + btnSend.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + sendMessage(); + } + }); + } + + private void sendMessage() { + String message = etMessage.getText().toString().trim(); + if (!TextUtils.isEmpty(message)) { + // 添加新消息到列表 + ChatMessage newMessage = new ChatMessage("我", message, "刚刚", true); + messageList.add(newMessage); + chatAdapter.notifyItemInserted(messageList.size() - 1); + + // 清空输入框 + etMessage.setText(""); + + // 滚动到底部 + rvChatMessages.scrollToPosition(messageList.size() - 1); + + // 模拟对方回复(可选) + simulateReply(message); + } + } + + private void simulateReply(String userMessage) { + // 延迟模拟回复 + rvChatMessages.postDelayed(new Runnable() { + @Override + public void run() { + String reply = generateReply(userMessage); + ChatMessage replyMessage = new ChatMessage(chatTitle, reply, "刚刚", false); + messageList.add(replyMessage); + chatAdapter.notifyItemInserted(messageList.size() - 1); + rvChatMessages.scrollToPosition(messageList.size() - 1); + } + }, 1000); + } + + private String generateReply(String userMessage) { + // 简单的回复逻辑 + if (userMessage.contains("你好") || userMessage.contains("在吗")) { + return "在的,有什么可以帮您?"; + } else if (userMessage.contains("价格") || userMessage.contains("多少钱")) { + return "这个商品价格是xxx元"; + } else if (userMessage.contains("谢谢")) { + return "不客气!"; + } else { + return "收到您的消息了!"; + } + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/activity/ProductDetailActivity.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/activity/ProductDetailActivity.java new file mode 100644 index 0000000..27e6137 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/activity/ProductDetailActivity.java @@ -0,0 +1,92 @@ +package com.startsmake.llrisetabbardemo.activity; + +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.FragmentTransaction; + +import com.startsmake.llrisetabbardemo.R; +import com.startsmake.llrisetabbardemo.fragment.ItemDetailFragment; +import com.startsmake.llrisetabbardemo.model.Item; +import com.startsmake.llrisetabbardemo.model.Product; +import manager.DataManager; + +public class ProductDetailActivity extends AppCompatActivity { + + public static final String EXTRA_PRODUCT = "extra_product"; + public static final String EXTRA_ITEM = "extra_item"; + public static final String EXTRA_PRODUCT_ID = "extra_product_id"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_product_detail); + + // 获取传递的数据 + Product product = (Product) getIntent().getSerializableExtra(EXTRA_PRODUCT); + Item item = (Item) getIntent().getSerializableExtra(EXTRA_ITEM); + String productId = getIntent().getStringExtra(EXTRA_PRODUCT_ID); + + // 根据不同的数据来源创建Fragment + Item detailItem = null; + + if (item != null) { + // 如果直接传递了Item对象 + detailItem = item; + } else if (product != null) { + // 如果传递了Product对象,转换为Item + detailItem = convertProductToItem(product); + } else if (productId != null) { + // 如果传递了商品ID,从DataManager查找 + DataManager dataManager = DataManager.getInstance(); + Item foundItem = dataManager.getItemById(productId); + if (foundItem != null) { + detailItem = foundItem; + } else { + // 如果找不到,尝试从Product列表查找并转换 + for (Product p : dataManager.getAllProducts()) { + if (p.getId().equals(productId)) { + detailItem = convertProductToItem(p); + break; + } + } + } + } + + if (detailItem != null) { + // 显示商品详情Fragment + showItemDetailFragment(detailItem); + } else { + // 处理数据加载失败的情况 + finish(); + } + } + + private void showItemDetailFragment(Item item) { + ItemDetailFragment fragment = ItemDetailFragment.newInstance(item); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.fragment_container, fragment); + transaction.commit(); + } + + /** + * 将Product对象转换为Item对象 + */ + private Item convertProductToItem(Product product) { + Item item = new Item(); + item.setId(product.getId()); + item.setTitle(product.getName()); + item.setDescription(product.getDescription()); + item.setCategory(product.getCategory()); + item.setPrice(product.getPrice()); + item.setLocation(product.getLocation()); + item.setContact(product.getContact()); + item.setWantCount(product.getWantCount()); + + // 设置默认发布时间(如果没有的话) + if (item.getPublishTime() == 0) { + item.setPublishTime(System.currentTimeMillis()); + } + + return item; + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/ChatMessageAdapter.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/ChatMessageAdapter.java new file mode 100644 index 0000000..6f80a10 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/ChatMessageAdapter.java @@ -0,0 +1,74 @@ +package com.startsmake.llrisetabbardemo.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import com.startsmake.llrisetabbardemo.R; +import com.startsmake.llrisetabbardemo.model.ChatMessage; +import java.util.List; + +public class ChatMessageAdapter extends RecyclerView.Adapter { + + private Context context; + private List messageList; + + public ChatMessageAdapter(Context context, List messageList) { + this.context = context; + this.messageList = messageList; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(context).inflate(R.layout.item_chat_message, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + ChatMessage message = messageList.get(position); + + if (message.isMe()) { + // 自己发送的消息 - 右侧显示 + holder.layoutLeft.setVisibility(View.GONE); + holder.layoutRight.setVisibility(View.VISIBLE); + holder.tvRightMessage.setText(message.getContent()); + holder.tvRightTime.setText(message.getTime()); + } else { + // 对方发送的消息 - 左侧显示 + holder.layoutRight.setVisibility(View.GONE); + holder.layoutLeft.setVisibility(View.VISIBLE); + holder.tvLeftMessage.setText(message.getContent()); + holder.tvLeftTime.setText(message.getTime()); + } + } + + @Override + public int getItemCount() { + return messageList.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + LinearLayout layoutLeft; + LinearLayout layoutRight; + TextView tvLeftMessage; + TextView tvRightMessage; + TextView tvLeftTime; + TextView tvRightTime; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + layoutLeft = itemView.findViewById(R.id.layoutLeft); + layoutRight = itemView.findViewById(R.id.layoutRight); + tvLeftMessage = itemView.findViewById(R.id.tvLeftMessage); + tvRightMessage = itemView.findViewById(R.id.tvRightMessage); + tvLeftTime = itemView.findViewById(R.id.tvLeftTime); + tvRightTime = itemView.findViewById(R.id.tvRightTime); + } + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/ImageAdapter.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/ImageAdapter.java new file mode 100644 index 0000000..ba35e48 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/ImageAdapter.java @@ -0,0 +1,84 @@ +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 imageUris; + private static final int MAX_IMAGES = 9; + + public ImageAdapter(Context context, List 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; + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/MessageAdapter.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/MessageAdapter.java new file mode 100644 index 0000000..cd92caa --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/adapter/MessageAdapter.java @@ -0,0 +1,102 @@ +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 { + + private Context context; + private List messageList; + private OnItemClickListener onItemClickListener; + + public MessageAdapter(Context context, List 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); + } + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/ApiClient.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/ApiClient.java new file mode 100644 index 0000000..d51c769 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/ApiClient.java @@ -0,0 +1,29 @@ +package com.startsmake.llrisetabbardemo.api; + +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +import java.util.concurrent.TimeUnit; + +public class ApiClient { + private static final String BASE_URL = "http://localhost:8080/"; + private static Retrofit retrofit = null; + + public static Retrofit getClient() { + if (retrofit == null) { + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .build(); + + retrofit = new Retrofit.Builder() + .baseUrl(BASE_URL) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + } + return retrofit; + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/ApiService.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/ApiService.java new file mode 100644 index 0000000..bbb3e3c --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/ApiService.java @@ -0,0 +1,43 @@ +package com.startsmake.llrisetabbardemo.api; + +import com.startsmake.llrisetabbardemo.api.response.BaseResponse; +import com.startsmake.llrisetabbardemo.api.response.ProductResponse; +import com.startsmake.llrisetabbardemo.api.response.UserResponse; + +import java.util.List; + +import retrofit2.Call; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Query; + +public interface ApiService { + // 获取API状态 + @GET("api") + Call getApiStatus(); + + // 用户登录 + @FormUrlEncoded + @POST("api/login") + Call login(@Field("phone") String phone, @Field("password") String password); + + // 用户注册 + @FormUrlEncoded + @POST("api/register") + Call register(@Field("phone") String phone, @Field("password") String password, + @Field("username") String username); + + // 获取商品列表 + @GET("api/products") + Call>> getProducts(); + + // 搜索商品 + @GET("api/products/search") + Call>> searchProducts(@Query("keyword") String keyword); + + // 获取商品详情 + @GET("api/products/detail") + Call> getProductDetail(@Query("id") String productId); +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/BaseResponse.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/BaseResponse.java new file mode 100644 index 0000000..cbb62ab --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/BaseResponse.java @@ -0,0 +1,43 @@ +package com.startsmake.llrisetabbardemo.api.response; + +import com.google.gson.annotations.SerializedName; + +public class BaseResponse { + @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); + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/ProductResponse.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/ProductResponse.java new file mode 100644 index 0000000..4f2e865 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/ProductResponse.java @@ -0,0 +1,107 @@ +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 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 getImageUrls() { + return imageUrls; + } + + public void setImageUrls(List 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; + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/UserResponse.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/UserResponse.java new file mode 100644 index 0000000..791fdab --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/api/response/UserResponse.java @@ -0,0 +1,52 @@ +package com.startsmake.llrisetabbardemo.api.response; + +import com.google.gson.annotations.SerializedName; + +public class UserResponse extends BaseResponse { + public static class UserInfo { + @SerializedName("id") + private String id; + + @SerializedName("username") + private String username; + + @SerializedName("phone") + private String phone; + + @SerializedName("token") + private String token; + + // Getters and Setters + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/decoration/GridSpacingItemDecoration.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/decoration/GridSpacingItemDecoration.java new file mode 100644 index 0000000..d592933 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/decoration/GridSpacingItemDecoration.java @@ -0,0 +1,40 @@ +package com.startsmake.llrisetabbardemo.decoration; + +import android.graphics.Rect; +import android.view.View; +import androidx.recyclerview.widget.RecyclerView; + +public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { + + private int spanCount; + private int spacing; + private boolean includeEdge; + + public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) { + this.spanCount = spanCount; + this.spacing = spacing; + this.includeEdge = includeEdge; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + int position = parent.getChildAdapterPosition(view); + int column = position % spanCount; + + if (includeEdge) { + outRect.left = spacing - column * spacing / spanCount; + outRect.right = (column + 1) * spacing / spanCount; + + if (position < spanCount) { + outRect.top = spacing; + } + outRect.bottom = spacing; + } else { + outRect.left = column * spacing / spanCount; + outRect.right = spacing - (column + 1) * spacing / spanCount; + if (position >= spanCount) { + outRect.top = spacing; + } + } + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/fragment/ItemDetailFragment.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/fragment/ItemDetailFragment.java new file mode 100644 index 0000000..a924916 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/fragment/ItemDetailFragment.java @@ -0,0 +1,135 @@ +package com.startsmake.llrisetabbardemo.fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.startsmake.llrisetabbardemo.R; +import com.startsmake.llrisetabbardemo.model.Item; +import com.startsmake.llrisetabbardemo.model.Product; +import manager.DataManager; + +public class ItemDetailFragment extends Fragment { + + private static final String ARG_ITEM = "item"; + private static final String ARG_PRODUCT = "product"; + + private Item item; + private Product product; + + // 使用Item对象的构造方法 + public static ItemDetailFragment newInstance(Item item) { + ItemDetailFragment fragment = new ItemDetailFragment(); + Bundle args = new Bundle(); + args.putSerializable(ARG_ITEM, item); + fragment.setArguments(args); + return fragment; + } + + // 使用Product对象的构造方法 + public static ItemDetailFragment newInstance(Product product) { + ItemDetailFragment fragment = new ItemDetailFragment(); + Bundle args = new Bundle(); + args.putSerializable(ARG_PRODUCT, product); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + item = (Item) getArguments().getSerializable(ARG_ITEM); + product = (Product) getArguments().getSerializable(ARG_PRODUCT); + + // 如果传递的是Product,转换为Item统一处理 + if (product != null && item == null) { + item = convertProductToItem(product); + } + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_item_detail, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (item == null) { + Toast.makeText(getContext(), "商品信息加载失败", Toast.LENGTH_SHORT).show(); + return; + } + + // 初始化视图 + ImageView ivItemImage = view.findViewById(R.id.ivItemImage); + TextView tvTitle = view.findViewById(R.id.tvTitle); + TextView tvPrice = view.findViewById(R.id.tvPrice); + TextView tvDescription = view.findViewById(R.id.tvDescription); + TextView tvCategory = view.findViewById(R.id.tvCategory); + TextView tvLocation = view.findViewById(R.id.tvLocation); + TextView tvContact = view.findViewById(R.id.tvContact); + TextView tvPublishTime = view.findViewById(R.id.tvPublishTime); + + // 设置商品信息 + tvTitle.setText(item.getTitle()); + tvPrice.setText(String.format("¥%.2f", item.getPrice())); + tvDescription.setText(item.getDescription()); + tvCategory.setText("分类:" + item.getCategory()); + tvLocation.setText("位置:" + item.getLocation()); + tvContact.setText("联系方式:" + item.getContact()); + + // 设置发布时间 + String time = android.text.format.DateFormat.format("yyyy-MM-dd HH:mm", item.getPublishTime()).toString(); + tvPublishTime.setText("发布时间:" + time); + + // 加载图片(这里使用第一张图片作为主图) + if (item.getImageUrls() != null && !item.getImageUrls().isEmpty()) { + // 实际项目中这里应该加载网络图片,这里用占位符 + ivItemImage.setImageResource(R.mipmap.ic_launcher); + } else { + // 如果没有图片,使用默认图片 + ivItemImage.setImageResource(R.mipmap.ic_launcher); + } + + // 增加浏览数 + item.incrementViewCount(); + + // 联系卖家按钮 + view.findViewById(R.id.btnContact).setOnClickListener(v -> { + Toast.makeText(getContext(), "联系卖家:" + item.getContact(), Toast.LENGTH_SHORT).show(); + // 这里可以跳转到聊天界面或拨打电话 + }); + } + + /** + * 将Product对象转换为Item对象 + */ + private Item convertProductToItem(Product product) { + Item convertedItem = new Item(); + convertedItem.setId(product.getId()); + convertedItem.setTitle(product.getName()); + convertedItem.setDescription(product.getDescription()); + convertedItem.setCategory(product.getCategory()); + convertedItem.setPrice(product.getPrice()); + convertedItem.setLocation(product.getLocation()); + convertedItem.setContact(product.getContact()); + convertedItem.setWantCount(product.getWantCount()); + + // 设置默认发布时间 + convertedItem.setPublishTime(System.currentTimeMillis()); + + return convertedItem; + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/fragment/PublishFragment.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/fragment/PublishFragment.java new file mode 100644 index 0000000..3827e52 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/fragment/PublishFragment.java @@ -0,0 +1,268 @@ +package com.startsmake.llrisetabbardemo.fragment; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.GridView; +import android.widget.Spinner; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.startsmake.llrisetabbardemo.R; +import com.startsmake.llrisetabbardemo.activity.MainActivity; +import com.startsmake.llrisetabbardemo.adapter.ImageAdapter; + +import com.startsmake.llrisetabbardemo.model.Item; +import com.startsmake.llrisetabbardemo.model.Product; +import manager.DataManager; + +import java.util.ArrayList; +import java.util.List; + +public class PublishFragment extends Fragment { + + private static final int REQUEST_CODE_PICK_IMAGES = 1001; + private static final int MAX_IMAGE_COUNT = 9; + + private EditText etTitle, etDescription, etPrice, etContact; + private Spinner spinnerCategory, spinnerLocation; + private GridView gridViewImages; + private Button btnPublish; + + private ImageAdapter imageAdapter; + private List selectedImages = new ArrayList<>(); + + public PublishFragment() { + // Required empty public constructor + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_publish, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + initViews(view); + setupSpinners(); + setupImageGrid(); + setupClickListeners(); + } + + private void initViews(View view) { + etTitle = view.findViewById(R.id.etTitle); + etDescription = view.findViewById(R.id.etDescription); + etPrice = view.findViewById(R.id.etPrice); + etContact = view.findViewById(R.id.etContact); + spinnerCategory = view.findViewById(R.id.spinnerCategory); + spinnerLocation = view.findViewById(R.id.spinnerLocation); + gridViewImages = view.findViewById(R.id.gridViewImages); + btnPublish = view.findViewById(R.id.btnPublish); + } + + private void setupSpinners() { + String[] categories = {"数码产品", "服装鞋帽", "家居日用", "图书文具", "美妆个护", "运动户外", "其他"}; + ArrayAdapter categoryAdapter = new ArrayAdapter<>( + requireContext(), android.R.layout.simple_spinner_item, categories); + categoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinnerCategory.setAdapter(categoryAdapter); + + String[] locations = {"北京", "上海", "广州", "深圳", "杭州", "成都", "武汉", "其他"}; + ArrayAdapter locationAdapter = new ArrayAdapter<>( + requireContext(), android.R.layout.simple_spinner_item, locations); + locationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinnerLocation.setAdapter(locationAdapter); + } + + private void setupImageGrid() { + imageAdapter = new ImageAdapter(requireContext(), selectedImages); + gridViewImages.setAdapter(imageAdapter); + } + + private void setupClickListeners() { + gridViewImages.setOnItemClickListener((parent, view, position, id) -> { + if (position == selectedImages.size() && selectedImages.size() < MAX_IMAGE_COUNT) { + openImagePicker(); + } + }); + + btnPublish.setOnClickListener(v -> publishItem()); + } + + private void openImagePicker() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("image/*"); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + startActivityForResult(Intent.createChooser(intent, "选择图片"), REQUEST_CODE_PICK_IMAGES); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_CODE_PICK_IMAGES && resultCode == Activity.RESULT_OK) { + if (data != null) { + if (data.getClipData() != null) { + int count = Math.min(data.getClipData().getItemCount(), + MAX_IMAGE_COUNT - selectedImages.size()); + for (int i = 0; i < count; i++) { + Uri imageUri = data.getClipData().getItemAt(i).getUri(); + selectedImages.add(imageUri); + } + } else if (data.getData() != null) { + selectedImages.add(data.getData()); + } + imageAdapter.notifyDataSetChanged(); + } + } + } + + private void publishItem() { + String title = etTitle.getText().toString().trim(); + String description = etDescription.getText().toString().trim(); + String priceStr = etPrice.getText().toString().trim(); + String contact = etContact.getText().toString().trim(); + + // 验证输入 + if (title.isEmpty()) { + Toast.makeText(requireContext(), "请输入商品标题", Toast.LENGTH_SHORT).show(); + return; + } + if (description.isEmpty()) { + Toast.makeText(requireContext(), "请输入商品描述", Toast.LENGTH_SHORT).show(); + return; + } + if (priceStr.isEmpty()) { + Toast.makeText(requireContext(), "请输入商品价格", Toast.LENGTH_SHORT).show(); + return; + } + if (contact.isEmpty()) { + Toast.makeText(requireContext(), "请输入联系方式", Toast.LENGTH_SHORT).show(); + return; + } + + try { + double price = Double.parseDouble(priceStr); + if (price <= 0) { + Toast.makeText(requireContext(), "价格必须大于0", Toast.LENGTH_SHORT).show(); + return; + } + + // 创建物品对象 + Item item = new Item(); + item.setTitle(title); + item.setDescription(description); + item.setPrice(price); + item.setContact(contact); + item.setCategory(spinnerCategory.getSelectedItem().toString()); + item.setLocation(spinnerLocation.getSelectedItem().toString()); + item.setPublishTime(System.currentTimeMillis()); + item.setUserId("user_" + System.currentTimeMillis()); + + Log.d("PublishFragment", "准备发布商品: " + item.getTitle() + ", 价格: " + item.getPrice()); + + // 使用DataManager保存商品并获取对应的Product对象 + DataManager dataManager = DataManager.getInstance(); + Product newProduct = dataManager.addItemAndGetProduct(item); + + Log.d("PublishFragment", "商品已保存到DataManager,准备切换到首页"); + + // 发布成功 + Toast.makeText(requireContext(), "发布成功!", Toast.LENGTH_SHORT).show(); + clearForm(); + + // 切换到首页并刷新数据 + if (getActivity() instanceof MainActivity) { + MainActivity mainActivity = (MainActivity) getActivity(); + + // 直接调用切换首页的方法 + mainActivity.switchToHomeFragment(); + + Log.d("PublishFragment", "已切换到首页,准备刷新数据"); + + // 延迟一小段时间确保HomeFragment已加载 + new android.os.Handler().postDelayed(() -> { + try { + HomeFragment homeFragment = mainActivity.getHomeFragment(); + if (homeFragment != null) { + Log.d("PublishFragment", "成功获取HomeFragment实例,准备刷新数据"); + // 从DataManager获取最新数据并刷新首页 + refreshHomeFragment(homeFragment); + } else { + Log.e("PublishFragment", "获取HomeFragment实例失败,为null"); + // 备选方案:直接重新初始化首页数据 + reinitializeHomeData(); + } + } catch (Exception e) { + Log.e("PublishFragment", "刷新首页数据时出错", e); + reinitializeHomeData(); + } + }, 500); // 增加延迟时间确保Fragment完全加载 + } + + } catch (NumberFormatException e) { + Toast.makeText(requireContext(), "请输入有效的价格", Toast.LENGTH_SHORT).show(); + } + } + + // 在 PublishFragment.java 的 publishItem 方法末尾添加 +// 发布成功后,通知所有相关页面刷新数据 + private void refreshAllData() { + // 这里可以添加事件总线或其他通知机制 + // 目前主要依赖各个页面在 onResume 时重新加载数据 + Log.d("PublishFragment", "新商品发布成功,建议相关页面刷新数据"); + } + + // 新增方法:备选方案重新初始化首页数据 + private void reinitializeHomeData() { + Log.d("PublishFragment", "使用备选方案重新初始化首页数据"); + // 这里可以尝试其他方式刷新首页,比如广播或事件总线 + Toast.makeText(requireContext(), "发布成功,请手动刷新首页", Toast.LENGTH_SHORT).show(); + } + + // 修改刷新首页方法 + private void refreshHomeFragment(HomeFragment homeFragment) { + try { + DataManager dataManager = DataManager.getInstance(); + List allProducts = dataManager.getAllProducts(); + + Log.d("PublishFragment", "从DataManager获取到 " + allProducts.size() + " 个商品"); + for (Product product : allProducts) { + Log.d("PublishFragment", "商品: " + product.getName() + ", ID: " + product.getId()); + } + + // 调用HomeFragment的方法来更新显示 + homeFragment.updateProductList(allProducts); + Log.d("PublishFragment", "已调用HomeFragment的updateProductList方法"); + + } catch (Exception e) { + Log.e("PublishFragment", "刷新首页数据时出错", e); + } + } + + + private void clearForm() { + etTitle.setText(""); + etDescription.setText(""); + etPrice.setText(""); + etContact.setText(""); + selectedImages.clear(); + imageAdapter.notifyDataSetChanged(); + spinnerCategory.setSelection(0); + spinnerLocation.setSelection(0); + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/manager/UserManager.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/manager/UserManager.java new file mode 100644 index 0000000..173bf8f --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/manager/UserManager.java @@ -0,0 +1,350 @@ +package com.startsmake.llrisetabbardemo.manager; + +import android.content.SharedPreferences; +import android.content.Context; +import android.util.Log; +import com.startsmake.llrisetabbardemo.api.ApiClient; +import com.startsmake.llrisetabbardemo.api.ApiService; +import com.startsmake.llrisetabbardemo.api.response.UserResponse; +import com.startsmake.llrisetabbardemo.model.User; +import com.google.gson.Gson; +import java.util.HashSet; +import java.util.Set; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class UserManager { + private static final String TAG = "UserManager"; + private static final String PREF_NAME = "user_data"; + private static final String KEY_USERS = "registered_users"; + private static final String KEY_CURRENT_USER = "current_user"; + private static final String KEY_USER_TOKEN = "user_token"; + + private static UserManager instance; + private SharedPreferences preferences; + private Gson gson; + private ApiService apiService; + + // 认证回调接口 + public interface AuthCallback { + void onSuccess(User user); + void onError(String message); + } + + private UserManager(Context context) { + preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + gson = new Gson(); + apiService = ApiClient.getClient().create(ApiService.class); + } + + public static synchronized UserManager getInstance(Context context) { + if (instance == null) { + instance = new UserManager(context); + } + return instance; + } + + /** + * 检查是否已登录 + */ + public boolean isLoggedIn() { + return preferences.getBoolean("is_logged_in", false); + } + + /** + * 检查手机号是否已注册 + */ + public boolean isPhoneRegistered(String phone) { + Set usersSet = preferences.getStringSet(KEY_USERS, new HashSet<>()); + for (String userJson : usersSet) { + User user = gson.fromJson(userJson, User.class); + if (user.getPhone().equals(phone)) { + return true; + } + } + return false; + } + + /** + * 注册用户(本地注册) + */ + public boolean registerUser(String phone, String password) { + // 检查手机号是否已注册 + if (isPhoneRegistered(phone)) { + return false; + } + + // 创建新用户 + User newUser = new User(phone, password); + String userJson = gson.toJson(newUser); + + Set usersSet = preferences.getStringSet(KEY_USERS, new HashSet<>()); + Set newUsersSet = new HashSet<>(usersSet); + newUsersSet.add(userJson); + + return preferences.edit().putStringSet(KEY_USERS, newUsersSet).commit(); + } + + /** + * 注册用户(通过后端API) + */ + public void registerUserWithApi(String phone, String password, String username, AuthCallback callback) { + apiService.register(phone, password, username).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null && response.body().isSuccess()) { + UserResponse.UserInfo userInfo = response.body().getData(); + if (userInfo != null) { + // 创建User对象 + User user = new User(userInfo.getPhone(), password); + // 设置用户名(如果API返回了不同的用户名) + user.setUsername(userInfo.getUsername()); + // 保存token + saveUserToken(userInfo.getToken()); + // 同时保存到本地(以便离线使用) + registerUser(phone, password); + saveCurrentUser(user); + + Log.d(TAG, "用户注册成功: " + userInfo.getUsername()); + if (callback != null) { + callback.onSuccess(user); + } + } + } else { + // API注册失败,尝试本地注册 + boolean localRegisterSuccess = registerUser(phone, password); + if (localRegisterSuccess) { + User user = new User(phone, password); + user.setUsername(username); + saveCurrentUser(user); + if (callback != null) { + callback.onSuccess(user); + } + } else { + if (callback != null) { + callback.onError("手机号已被注册"); + } + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e(TAG, "网络请求失败: " + t.getMessage()); + // 网络请求失败,尝试本地注册 + boolean localRegisterSuccess = registerUser(phone, password); + if (localRegisterSuccess) { + User user = new User(phone, password); + user.setUsername(username); + saveCurrentUser(user); + if (callback != null) { + callback.onSuccess(user); + } + } else { + if (callback != null) { + callback.onError("网络连接失败,且本地注册失败"); + } + } + } + }); + } + + /** + * 用户登录(本地登录) + */ + public User loginUser(String phone, String password) { + Set usersSet = preferences.getStringSet(KEY_USERS, new HashSet<>()); + + for (String userJson : usersSet) { + User user = gson.fromJson(userJson, User.class); + if (user.getPhone().equals(phone) && user.getPassword().equals(password)) { + // 保存当前用户信息 + saveCurrentUser(user); + return user; + } + } + return null; + } + + /** + * 用户登录(通过后端API) + */ + public void loginUserWithApi(String phone, String password, AuthCallback callback) { + apiService.login(phone, password).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null && response.body().isSuccess()) { + UserResponse.UserInfo userInfo = response.body().getData(); + if (userInfo != null) { + // 创建User对象 + User user = new User(userInfo.getPhone(), password); + // 设置用户名(如果API返回了不同的用户名) + user.setUsername(userInfo.getUsername()); + // 保存token + saveUserToken(userInfo.getToken()); + // 保存用户信息 + saveCurrentUser(user); + + Log.d(TAG, "用户登录成功: " + userInfo.getUsername()); + if (callback != null) { + callback.onSuccess(user); + } + } + } else { + Log.e(TAG, "API登录失败,回退到本地登录"); + // API登录失败,尝试本地登录 + User localUser = loginUser(phone, password); + if (localUser != null) { + if (callback != null) { + callback.onSuccess(localUser); + } + } else { + if (callback != null) { + callback.onError("手机号或密码错误"); + } + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e(TAG, "网络请求失败: " + t.getMessage()); + // 网络请求失败,尝试本地登录 + User localUser = loginUser(phone, password); + if (localUser != null) { + if (callback != null) { + callback.onSuccess(localUser); + } + } else { + if (callback != null) { + callback.onError("网络连接失败,且本地账号不存在"); + } + } + } + }); + } + + /** + * 保存用户token + */ + private void saveUserToken(String token) { + preferences.edit().putString(KEY_USER_TOKEN, token).apply(); + } + + /** + * 获取用户token + */ + public String getUserToken() { + return preferences.getString(KEY_USER_TOKEN, null); + } + + /** + * 检查是否有有效的token + */ + public boolean hasValidToken() { + return getUserToken() != null; + } + + /** + * 重置密码 + */ + public boolean resetPassword(String phone, String newPassword) { + Set usersSet = preferences.getStringSet(KEY_USERS, new HashSet<>()); + Set newUsersSet = new HashSet<>(); + boolean found = false; + + for (String userJson : usersSet) { + User user = gson.fromJson(userJson, User.class); + if (user.getPhone().equals(phone)) { + // 更新密码 + user.setPassword(newPassword); + found = true; + } + newUsersSet.add(gson.toJson(user)); + } + + if (found) { + boolean success = preferences.edit().putStringSet(KEY_USERS, newUsersSet).commit(); + if (success) { + // 如果重置的是当前登录用户,更新当前用户信息 + User currentUser = getCurrentUser(); + if (currentUser != null && currentUser.getPhone().equals(phone)) { + currentUser.setPassword(newPassword); + saveCurrentUser(currentUser); + } + } + return success; + } + return false; + } + + /** + * 保存当前登录用户 + */ + private void saveCurrentUser(User user) { + String userJson = gson.toJson(user); + preferences.edit() + .putString(KEY_CURRENT_USER, userJson) + .putBoolean("is_logged_in", true) + .putString("user_phone", user.getPhone()) + .putString("user_name", user.getUsername()) + .apply(); + } + + /** + * 获取当前用户 + */ + public User getCurrentUser() { + String userJson = preferences.getString(KEY_CURRENT_USER, null); + if (userJson != null) { + return gson.fromJson(userJson, User.class); + } + return null; + } + + /** + * 用户登出 + */ + public void logout() { + preferences.edit() + .remove(KEY_CURRENT_USER) + .putBoolean("is_logged_in", false) + .remove("user_phone") + .remove("user_name") + .remove(KEY_USER_TOKEN) // 清除token + .apply(); + Log.d(TAG, "用户已登出"); + } + + /** + * 保存用户登录信息(兼容旧代码) + */ + public void saveUserLogin(String phone, String password) { + User user = loginUser(phone, password); + if (user != null) { + saveCurrentUser(user); + } + } + + /** + * 验证登录(兼容旧代码) + */ + public boolean validateLogin(String phone, String password) { + return loginUser(phone, password) != null; + } + + /** + * 检查用户是否存在(兼容旧代码) + */ + public boolean isUserExists(String phone) { + return isPhoneRegistered(phone); + } + + /** + * 更新密码(兼容旧代码) + */ + public boolean updatePassword(String phone, String newPassword) { + return resetPassword(phone, newPassword); + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/ChatMessage.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/ChatMessage.java new file mode 100644 index 0000000..5693307 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/ChatMessage.java @@ -0,0 +1,28 @@ +package com.startsmake.llrisetabbardemo.model; + +public class ChatMessage { + private String sender; + private String content; + private String time; + private boolean isMe; + + public ChatMessage(String sender, String content, String time, boolean isMe) { + this.sender = sender; + this.content = content; + this.time = time; + this.isMe = isMe; + } + + // Getter and Setter methods + public String getSender() { return sender; } + public void setSender(String sender) { this.sender = sender; } + + public String getContent() { return content; } + public void setContent(String content) { this.content = content; } + + public String getTime() { return time; } + public void setTime(String time) { this.time = time; } + + public boolean isMe() { return isMe; } + public void setMe(boolean me) { isMe = me; } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/Item.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/Item.java new file mode 100644 index 0000000..858c4cf --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/Item.java @@ -0,0 +1,121 @@ +package com.startsmake.llrisetabbardemo.model; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class Item implements Serializable { + private String id; + private String title; + private String description; + private int wantCount; + private double price; + private List imageUrls; + private String category; + private String location; + private String contact; + private String contactQQ; // 新增QQ联系方式 + private String contactWechat; // 新增微信联系方式 + private long publishTime; + private String userId; + private int viewCount; // 浏览数 + private int likeCount; // 点赞数 + + public Item() { + imageUrls = new ArrayList<>(); + viewCount = 0; + likeCount = 0; + } + + // Getter 和 Setter + public int getWantCount() { + return wantCount; + } + + public void setWantCount(int wantCount) { + this.wantCount = wantCount; + } + + // 构造函数 + public Item(String title, String description, double price, String category, String location, String contact) { + this(); + this.title = title; + this.description = description; + this.price = price; + this.category = category; + this.location = location; + this.contact = contact; + this.publishTime = System.currentTimeMillis(); + this.userId = "user_" + System.currentTimeMillis(); + } + + // Getter 和 Setter 方法 + public String getId() { return id; } + public void setId(String id) { this.id = id; } + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + + public String getDescription() { return description; } + public void setDescription(String description) { this.description = description; } + + public double getPrice() { return price; } + public void setPrice(double price) { this.price = price; } + + public List getImageUrls() { return imageUrls; } + public void setImageUrls(List imageUrls) { this.imageUrls = imageUrls; } + public void addImageUrl(String imageUrl) { this.imageUrls.add(imageUrl); } + + public String getCategory() { return category; } + public void setCategory(String category) { this.category = category; } + + public String getLocation() { return location; } + public void setLocation(String location) { this.location = location; } + + public String getContact() { return contact; } + public void setContact(String contact) { this.contact = contact; } + + public String getContactQQ() { return contactQQ; } + public void setContactQQ(String contactQQ) { this.contactQQ = contactQQ; } + + public String getContactWechat() { return contactWechat; } + public void setContactWechat(String contactWechat) { this.contactWechat = contactWechat; } + + public long getPublishTime() { return publishTime; } + public void setPublishTime(long publishTime) { this.publishTime = publishTime; } + + public String getUserId() { return userId; } + public void setUserId(String userId) { this.userId = userId; } + + public int getViewCount() { return viewCount; } + public void setViewCount(int viewCount) { this.viewCount = viewCount; } + + public int getLikeCount() { return likeCount; } + public void setLikeCount(int likeCount) { this.likeCount = likeCount; } + + /** + * 增加浏览数 + */ + public void incrementViewCount() { + this.viewCount++; + } + + /** + * 增加点赞数 + */ + public void incrementLikeCount() { + this.likeCount++; + } + + @Override + public String toString() { + return "Item{" + + "id='" + id + '\'' + + ", title='" + title + '\'' + + ", price=" + price + + ", category='" + category + '\'' + + ", location='" + location + '\'' + + ", publishTime=" + publishTime + + '}'; + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/MessageItem.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/MessageItem.java new file mode 100644 index 0000000..40e105b --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/MessageItem.java @@ -0,0 +1,33 @@ +package com.startsmake.llrisetabbardemo.model; + +public class MessageItem { + private String title; + private String content; + private String time; + private int unreadCount; + private boolean isOfficial; + + public MessageItem(String title, String content, String time, int unreadCount, boolean isOfficial) { + this.title = title; + this.content = content; + this.time = time; + this.unreadCount = unreadCount; + this.isOfficial = isOfficial; + } + + // Getter and Setter methods + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + + public String getContent() { return content; } + public void setContent(String content) { this.content = content; } + + public String getTime() { return time; } + public void setTime(String time) { this.time = time; } + + public int getUnreadCount() { return unreadCount; } + public void setUnreadCount(int unreadCount) { this.unreadCount = unreadCount; } + + public boolean isOfficial() { return isOfficial; } + public void setOfficial(boolean official) { isOfficial = official; } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/User.java b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/User.java new file mode 100644 index 0000000..75ac13a --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/com/startsmake/llrisetabbardemo/model/User.java @@ -0,0 +1,27 @@ +package com.startsmake.llrisetabbardemo.model; + +public class User { + private String phone; + private String password; + private String username; + private long registerTime; + + public User(String phone, String password) { + this.phone = phone; + this.password = password; + this.username = "用户_" + phone.substring(7); + this.registerTime = System.currentTimeMillis(); + } + + // Getters and Setters + public String getPhone() { return phone; } + public void setPhone(String phone) { this.phone = phone; } + + public String getPassword() { return password; } + public void setPassword(String password) { this.password = password; } + + public String getUsername() { return username; } + public void setUsername(String username) { this.username = username; } + + public long getRegisterTime() { return registerTime; } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/java/manager/DataManager.java b/LLRiseTabBarDemo/app/src/main/java/manager/DataManager.java new file mode 100644 index 0000000..2761ce4 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/java/manager/DataManager.java @@ -0,0 +1,522 @@ +package manager; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.startsmake.llrisetabbardemo.api.ApiClient; +import com.startsmake.llrisetabbardemo.api.ApiService; +import com.startsmake.llrisetabbardemo.api.response.BaseResponse; +import com.startsmake.llrisetabbardemo.api.response.ProductResponse; +import com.startsmake.llrisetabbardemo.model.Item; +import com.startsmake.llrisetabbardemo.model.Product; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * 数据管理类 - 使用单例模式管理商品数据 + * 负责商品的增删改查操作,支持从后端API获取数据 + */ +public class DataManager { + + private static final String TAG = "DataManager"; + private static final String PREF_NAME = "product_data"; + private static final String KEY_ITEMS = "items"; + + // 单例实例 + private static DataManager instance; + + // 商品列表 + private List itemList; + + // API服务实例 + private ApiService apiService; + + // Context 和 SharedPreferences + private Context context; + private SharedPreferences sharedPreferences; + private Gson gson; + + // 数据变化监听器列表 + private List dataChangedListeners = new CopyOnWriteArrayList<>(); + + // 回调接口,用于通知UI数据加载状态 + public interface OnDataLoadedListener { + void onDataLoaded(List items); + void onError(String message); + } + + // 数据变化监听接口 + public interface OnDataChangedListener { + void onDataChanged(); // 数据发生变化时调用 + void onProductWantCountChanged(String productId, int newCount); // 商品想要人数变化时调用 + } + + // 私有构造函数,防止外部创建实例 + private DataManager() { + itemList = new ArrayList<>(); + } + + /** + * 初始化 DataManager(需要在 Application 或第一个 Activity 中调用) + */ + public void init(Context context) { + this.context = context.getApplicationContext(); + this.sharedPreferences = this.context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); + this.gson = new Gson(); + + // 初始化API服务 + apiService = ApiClient.getClient().create(ApiService.class); + + // 从本地存储加载数据 + loadItemsFromStorage(); + } + + /** + * 获取单例实例 + * @return DataManager 实例 + */ + public static DataManager getInstance() { + if (instance == null) { + instance = new DataManager(); + } + return instance; + } + + /** + * 注册数据变化监听器 + */ + public void registerDataChangedListener(OnDataChangedListener listener) { + if (!dataChangedListeners.contains(listener)) { + dataChangedListeners.add(listener); + Log.d(TAG, "注册数据变化监听器,当前监听器数量: " + dataChangedListeners.size()); + } + } + + /** + * 取消注册数据变化监听器 + */ + public void unregisterDataChangedListener(OnDataChangedListener listener) { + dataChangedListeners.remove(listener); + Log.d(TAG, "取消注册数据变化监听器,当前监听器数量: " + dataChangedListeners.size()); + } + + /** + * 通知数据变化 + */ + private void notifyDataChanged() { + for (OnDataChangedListener listener : dataChangedListeners) { + listener.onDataChanged(); + } + } + + /** + * 通知商品想要人数变化 + */ + private void notifyProductWantCountChanged(String productId, int newCount) { + for (OnDataChangedListener listener : dataChangedListeners) { + listener.onProductWantCountChanged(productId, newCount); + } + } + + /** + * 从本地存储加载商品数据 + */ + private void loadItemsFromStorage() { + String itemsJson = sharedPreferences.getString(KEY_ITEMS, null); + if (itemsJson != null) { + Type type = new TypeToken>(){}.getType(); + List savedItems = gson.fromJson(itemsJson, type); + if (savedItems != null && !savedItems.isEmpty()) { + itemList = savedItems; + Log.d(TAG, "从本地存储加载商品数据,共" + itemList.size() + "个商品"); + } else { + initSampleData(); + saveItemsToStorage(); + } + } else { + initSampleData(); + saveItemsToStorage(); + } + } + + /** + * 保存商品数据到本地存储 + */ + private void saveItemsToStorage() { + if (itemList != null) { + String itemsJson = gson.toJson(itemList); + sharedPreferences.edit().putString(KEY_ITEMS, itemsJson).apply(); + Log.d(TAG, "商品数据已保存到本地存储,共" + itemList.size() + "个商品"); + } + } + + /** + * 初始化示例数据 + */ + private void initSampleData() { + // 示例商品1 - 数码产品 + Item item1 = new Item(); + item1.setId("item_001"); + item1.setTitle("全新iPhone 13 Pro"); + item1.setDescription("全新未拆封,256GB,远峰蓝色,国行正品,带发票"); + item1.setPrice(6999.00); + item1.setCategory("数码产品"); + item1.setLocation("北京"); + item1.setContact("138****1234"); + item1.setPublishTime(System.currentTimeMillis() - 2 * 60 * 60 * 1000); // 2小时前发布 + item1.setWantCount(5); // 设置初始想要人数 + itemList.add(item1); + + // 示例商品2 - 数码产品 + Item item2 = new Item(); + item2.setId("item_002"); + item2.setTitle("二手笔记本电脑"); + item2.setDescription("联想小新,i5处理器,8GB内存,256GB固态硬盘,95成新"); + item2.setPrice(2500.00); + item2.setCategory("数码产品"); + item2.setLocation("上海"); + item2.setContact("微信:abc123"); + item2.setPublishTime(System.currentTimeMillis() - 5 * 60 * 60 * 1000); // 5小时前发布 + item2.setWantCount(3); // 设置初始想要人数 + itemList.add(item2); + + // 示例商品3 - 服装鞋帽 + Item item3 = new Item(); + item3.setId("item_003"); + item3.setTitle("品牌运动鞋"); + item3.setDescription("耐克运动鞋,42码,只穿过几次,几乎全新,原盒在"); + item3.setPrice(299.00); + item3.setCategory("服装鞋帽"); + item3.setLocation("广州"); + item3.setContact("159****5678"); + item3.setPublishTime(System.currentTimeMillis() - 24 * 60 * 60 * 1000); // 1天前发布 + item3.setWantCount(8); // 设置初始想要人数 + itemList.add(item3); + + // 示例商品4 - 图书文具 + Item item4 = new Item(); + item4.setId("item_004"); + item4.setTitle("Java编程思想"); + item4.setDescription("Java编程思想第5版,几乎全新,无笔记无划痕"); + item4.setPrice(45.00); + item4.setCategory("图书文具"); + item4.setLocation("杭州"); + item4.setContact("QQ:123456789"); + item4.setPublishTime(System.currentTimeMillis() - 3 * 24 * 60 * 60 * 1000); // 3天前发布 + item4.setWantCount(12); // 设置初始想要人数 + itemList.add(item4); + } + + /** + * 获取所有商品列表(本地缓存) + * @return 商品列表 + */ + public List getAllItems() { + return itemList; + } + + /** + * 从后端API获取所有商品列表 + * @param listener 数据加载回调 + */ + public void fetchItemsFromApi(OnDataLoadedListener listener) { + apiService.getProducts().enqueue(new Callback>>() { + @Override + public void onResponse(Call>> call, + Response>> response) { + if (response.isSuccessful() && response.body() != null && response.body().isSuccess()) { + List productResponses = response.body().getData(); + if (productResponses != null) { + // 转换为本地Item对象 + List items = convertToItems(productResponses); + // 更新本地缓存 + itemList = items; + // 保存到本地存储 + saveItemsToStorage(); + Log.d(TAG, "从API成功获取商品数据,共" + items.size() + "个商品"); + // 回调成功 + if (listener != null) { + listener.onDataLoaded(items); + } + // 通知数据变化 + notifyDataChanged(); + } else { + // 返回空数据 + if (listener != null) { + listener.onDataLoaded(new ArrayList<>()); + } + } + } else { + Log.e(TAG, "API请求失败,使用本地数据"); + // 如果API请求失败,使用本地缓存数据 + if (listener != null) { + listener.onDataLoaded(itemList); + listener.onError("网络请求失败,显示本地数据"); + } + } + } + + @Override + public void onFailure(Call>> call, Throwable t) { + Log.e(TAG, "网络请求失败: " + t.getMessage()); + // 网络请求失败,使用本地缓存数据 + if (listener != null) { + listener.onDataLoaded(itemList); + listener.onError("网络连接失败,请检查网络设置"); + } + } + }); + } + + /** + * 将ProductResponse转换为Item对象 + */ + private List convertToItems(List productResponses) { + List items = new ArrayList<>(); + for (ProductResponse response : productResponses) { + Item item = new Item(); + item.setId(response.getId()); + item.setTitle(response.getTitle()); + item.setDescription(response.getDescription()); + item.setCategory(response.getCategory()); + item.setPrice(response.getPrice()); + item.setImageUrls(response.getImageUrls()); + item.setContact(response.getContact()); + item.setPublishTime(response.getPublishTime()); + // 设置默认想要人数 + item.setWantCount(0); + + // 设置默认位置,因为 ProductResponse 可能没有 location 字段 + item.setLocation("北京"); // 或者从其他地方获取,或者设置为空 + + items.add(item); + } + return items; + } + + /** + * 添加新商品(发布新商品时调用) + * @param item 商品对象 + */ + public void addItem(Item item) { + // 为新商品生成ID + item.setId("item_" + System.currentTimeMillis()); + // 设置发布时间 + item.setPublishTime(System.currentTimeMillis()); + // 设置初始想要人数 + if (item.getWantCount() == 0) { + item.setWantCount(0); + } + // 将新商品添加到列表最前面(最新发布的显示在最前面) + itemList.add(0, item); + + // 保存到本地存储 + saveItemsToStorage(); + + Log.d("DataManager", "成功添加新商品:" + item.getTitle() + ",当前商品总数:" + itemList.size()); + + // 通知数据变化 + notifyDataChanged(); + } + + /** + * 更新商品的想要人数 + * @param productId 商品ID + * @param wantCount 新的想要人数 + */ + public void updateProductWantCount(String productId, int wantCount) { + boolean found = false; + for (Item item : itemList) { + if (item.getId().equals(productId)) { + item.setWantCount(wantCount); + found = true; + // 保存到本地存储 + saveItemsToStorage(); + Log.d(TAG, "更新商品 " + productId + " 的想要人数为: " + wantCount); + + // 通知想要人数变化 + notifyProductWantCountChanged(productId, wantCount); + break; + } + } + + if (found) { + // 同时通知整体数据变化 + notifyDataChanged(); + } + } + + /** + * 获取商品的想要人数 + * @param productId 商品ID + * @return 想要人数 + */ + public int getProductWantCount(String productId) { + for (Item item : itemList) { + if (item.getId().equals(productId)) { + return item.getWantCount(); + } + } + return 0; + } + + /** + * 获取所有商品作为Product列表(供首页使用) + */ + public List getAllProducts() { + List products = new ArrayList<>(); + Log.d("DataManager", "开始转换 " + itemList.size() + " 个Item到Product"); + + for (Item item : itemList) { + products.add(convertItemToProduct(item)); + } + + Log.d("DataManager", "转换完成,返回 " + products.size() + " 个Product"); + return products; + } + + /** + * 根据ID查找商品 + * @param id 商品ID + * @return 商品对象,找不到返回null + */ + public Item getItemById(String id) { + for (Item item : itemList) { + if (item.getId().equals(id)) { + return item; + } + } + return null; + } + + /** + * 根据分类筛选商品 + * @param category 分类名称 + * @return 该分类下的商品列表 + */ + public List getItemsByCategory(String category) { + List result = new ArrayList<>(); + for (Item item : itemList) { + if (item.getCategory().equals(category)) { + result.add(item); + } + } + return result; + } + + /** + * 根据关键词搜索商品(本地搜索) + * @param keyword 搜索关键词 + * @return 匹配的商品列表 + */ + public List searchItems(String keyword) { + List result = new ArrayList<>(); + for (Item item : itemList) { + if (item.getTitle().toLowerCase().contains(keyword.toLowerCase()) || + item.getDescription().toLowerCase().contains(keyword.toLowerCase()) || + item.getCategory().toLowerCase().contains(keyword.toLowerCase())) { + result.add(item); + } + } + Log.d(TAG, "搜索关键词: " + keyword + ", 找到 " + result.size() + " 个结果"); + return result; + } + + /** + * 从后端API搜索商品 + * @param keyword 搜索关键词 + * @param listener 搜索结果回调 + */ + public void searchItemsFromApi(String keyword, OnDataLoadedListener listener) { + apiService.searchProducts(keyword).enqueue(new Callback>>() { + @Override + public void onResponse(Call>> call, + Response>> response) { + if (response.isSuccessful() && response.body() != null && response.body().isSuccess()) { + List productResponses = response.body().getData(); + if (productResponses != null) { + List items = convertToItems(productResponses); + if (listener != null) { + listener.onDataLoaded(items); + } + } else { + if (listener != null) { + listener.onDataLoaded(new ArrayList<>()); + } + } + } else { + // 如果API搜索失败,回退到本地搜索 + List localResults = searchItems(keyword); + if (listener != null) { + listener.onDataLoaded(localResults); + } + } + } + + @Override + public void onFailure(Call>> call, Throwable t) { + Log.e(TAG, "搜索请求失败: " + t.getMessage()); + // 网络请求失败,回退到本地搜索 + List localResults = searchItems(keyword); + if (listener != null) { + listener.onDataLoaded(localResults); + } + } + }); + } + + /** + * 获取商品数量 + * @return 商品总数 + */ + public int getItemCount() { + return itemList.size(); + } + + /** + * 清空所有数据(主要用于测试) + */ + public void clearAll() { + itemList.clear(); + saveItemsToStorage(); + // 通知数据变化 + notifyDataChanged(); + } + + /** + * 将Item对象转换为Product对象 + */ + public Product convertItemToProduct(Item item) { + Product product = new Product(); + product.setId(item.getId()); + product.setName(item.getTitle()); + product.setDescription(item.getDescription()); + product.setCategory(item.getCategory()); + product.setPrice(item.getPrice()); + product.setLocation(item.getLocation()); + product.setContact(item.getContact()); + // 设置想要人数(从Item中获取) + product.setWantCount(item.getWantCount()); + product.setSellerRating("卖家信用良好"); + product.setFreeShipping(false); + return product; + } + + /** + * 添加商品并返回对应的Product对象 + */ + public Product addItemAndGetProduct(Item item) { + addItem(item); + return convertItemToProduct(item); + } +} \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_avatar_placeholder.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_avatar_placeholder.xml new file mode 100644 index 0000000..4947039 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_avatar_placeholder.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_input.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_input.xml new file mode 100644 index 0000000..a5a2d18 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_input.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_message_left.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_message_left.xml new file mode 100644 index 0000000..b73bbc7 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_message_left.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_message_right.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_message_right.xml new file mode 100644 index 0000000..2f28ecb --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_chat_message_right.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_delete_button.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_delete_button.xml new file mode 100644 index 0000000..f587175 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_delete_button.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_edittext.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_edittext.xml new file mode 100644 index 0000000..306f171 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_edittext.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_image_border.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_image_border.xml new file mode 100644 index 0000000..01788a4 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_image_border.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_search_edittext.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_search_edittext.xml new file mode 100644 index 0000000..76833e1 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_search_edittext.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/bg_unread_count.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_unread_count.xml new file mode 100644 index 0000000..b8d4012 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/bg_unread_count.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/button_blue.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/button_blue.xml new file mode 100644 index 0000000..5b702b4 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/button_blue.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/button_border.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/button_border.xml new file mode 100644 index 0000000..3f148f2 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/button_border.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/button_primary.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/button_primary.xml new file mode 100644 index 0000000..b5282ae --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/button_primary.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/button_primary_xiangxi.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/button_primary_xiangxi.xml new file mode 100644 index 0000000..efa6695 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/button_primary_xiangxi.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/button_secondary.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/button_secondary.xml new file mode 100644 index 0000000..8b74a61 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/button_secondary.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/card_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/card_background.xml new file mode 100644 index 0000000..3d7cdf1 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/card_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/circle_bg.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/circle_bg.xml new file mode 100644 index 0000000..ea8461b --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/circle_bg.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/credit_bg.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/credit_bg.xml new file mode 100644 index 0000000..f59b09c --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/credit_bg.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/default_product_image.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/default_product_image.xml new file mode 100644 index 0000000..9adfdde --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/default_product_image.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/dialog_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/dialog_background.xml new file mode 100644 index 0000000..2582a90 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/dialog_background.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/edittext_border.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/edittext_border.xml new file mode 100644 index 0000000..3f148f2 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/edittext_border.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/filter_tag_normal.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/filter_tag_normal.xml new file mode 100644 index 0000000..e997521 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/filter_tag_normal.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/filter_tag_selected.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/filter_tag_selected.xml new file mode 100644 index 0000000..1df4001 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/filter_tag_selected.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/gradient_header.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/gradient_header.xml new file mode 100644 index 0000000..32ebb9c --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/gradient_header.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_about.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_about.xml new file mode 100644 index 0000000..54b0dca --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_about.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_add.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_add.xml new file mode 100644 index 0000000..4f8587b --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_add.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_arrow_right.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_arrow_right.xml new file mode 100644 index 0000000..ddefa26 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_arrow_right.xml @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_budget_tracker.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_budget_tracker.xml new file mode 100644 index 0000000..ea6726a --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_budget_tracker.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_coupons.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_coupons.xml new file mode 100644 index 0000000..033a8ef --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_coupons.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_default_avatar.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_default_avatar.xml new file mode 100644 index 0000000..cb653a9 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_default_avatar.xml @@ -0,0 +1,9 @@ + + + diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_feedback.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_feedback.xml new file mode 100644 index 0000000..1466d2a --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_feedback.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_help.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_help.xml new file mode 100644 index 0000000..76f4076 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_help.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_invite_friends.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_invite_friends.xml new file mode 100644 index 0000000..9e838d0 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_invite_friends.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_logout.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_logout.xml new file mode 100644 index 0000000..9f93fb9 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_logout.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_more.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_more.xml new file mode 100644 index 0000000..7b7f6d0 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_more.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_my_listings.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_my_listings.xml new file mode 100644 index 0000000..b9bc256 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_my_listings.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_official.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_official.xml new file mode 100644 index 0000000..ab8bbd6 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_official.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_price_alert.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_price_alert.xml new file mode 100644 index 0000000..0691442 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_price_alert.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_product_placeholder.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_product_placeholder.xml new file mode 100644 index 0000000..ba08cee --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_product_placeholder.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_purchase_history.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_purchase_history.xml new file mode 100644 index 0000000..4642d7b --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_purchase_history.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_qr_code.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_qr_code.xml new file mode 100644 index 0000000..73aa177 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_qr_code.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_settings.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 0000000..a30678b --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_store.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_store.xml new file mode 100644 index 0000000..c9a9932 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_store.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/ic_wishlist.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_wishlist.xml new file mode 100644 index 0000000..7a9f8da --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/ic_wishlist.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/image_border.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/image_border.xml new file mode 100644 index 0000000..dde274b --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/image_border.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/member_bg.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/member_bg.xml new file mode 100644 index 0000000..c769ea4 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/member_bg.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/price_tag_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/price_tag_background.xml new file mode 100644 index 0000000..55cdc8d --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/price_tag_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/product_card_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/product_card_background.xml new file mode 100644 index 0000000..1ae6b56 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/product_card_background.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/product_card_background_with_shadow.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/product_card_background_with_shadow.xml new file mode 100644 index 0000000..f871cc0 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/product_card_background_with_shadow.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/search_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/search_background.xml new file mode 100644 index 0000000..938293d --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/search_background.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/search_box_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/search_box_background.xml new file mode 100644 index 0000000..12778a6 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/search_box_background.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/tab_normal.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/tab_normal.xml new file mode 100644 index 0000000..3528c8c --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/tab_normal.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/tab_selected.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/tab_selected.xml new file mode 100644 index 0000000..98c7b33 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/tab_selected.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/tag_normal_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_normal_background.xml new file mode 100644 index 0000000..a1ec96d --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_normal_background.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/tag_normal_background1.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_normal_background1.xml new file mode 100644 index 0000000..3a04279 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_normal_background1.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/tag_selected_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_selected_background.xml new file mode 100644 index 0000000..2480dd0 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_selected_background.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/tag_selected_background1.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_selected_background1.xml new file mode 100644 index 0000000..5d9ebab --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_selected_background1.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/tag_small.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_small.xml new file mode 100644 index 0000000..ee79e00 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/tag_small.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/drawable/want_button_background.xml b/LLRiseTabBarDemo/app/src/main/res/drawable/want_button_background.xml new file mode 100644 index 0000000..0bfcde8 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/drawable/want_button_background.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/layout/activity_chat.xml b/LLRiseTabBarDemo/app/src/main/res/layout/activity_chat.xml new file mode 100644 index 0000000..9dd7fcd --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/layout/activity_chat.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/layout/activity_product_detail.xml b/LLRiseTabBarDemo/app/src/main/res/layout/activity_product_detail.xml new file mode 100644 index 0000000..a9ee9c5 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/layout/activity_product_detail.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/LLRiseTabBarDemo/app/src/main/res/layout/dialog_filter.xml b/LLRiseTabBarDemo/app/src/main/res/layout/dialog_filter.xml new file mode 100644 index 0000000..adde062 --- /dev/null +++ b/LLRiseTabBarDemo/app/src/main/res/layout/dialog_filter.xml @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +